都 9102 年了 HTML 邮件总不会还得用
<table>
吧?
答案是没错你还得用…… 最近又跳进 HTML 邮件大坑,实现了一版响应式的 HTML 邮件,这里记录一下,提醒自己下次不要再接这样的需求不能再犯同样的错误。
客户端支持情况
webmail 对 HTML 邮件的支持程度普遍不错,允许使用 <style>
、绝大多数布局相关的 CSS 属性(position、float、甚至 flex)都支持,比较尴尬的是基本上每一家都会有一些不太准确的“优化”,Gmail、QQ 邮箱都有。
客户端是水最深的地方,桌面版的 Mail.app、Outlook 对 HTML 邮件的支持程度非常好,没怎么出问题,但是移动端就非常狂野了,表现最差的是 QQ 邮箱。但这些都比不过 Windows 版 Outlook,稳坐业界毒瘤一把手。
Gmail
2016 年开始支持内联 <style>
和 media query,因此可以放心实现响应式布局。需要注意的有:
<style>
必须在<head>
里面,而且貌似<head>
里不能包含其他内容(比如<meta>
);<style>
内容不能超过 8K,不能嵌套@
(比如在@media
区块里写@font-face
);- 会为了覆盖文字颜色修改邮件 DOM 结构,给内容节点包额外的节点;
- 不支持引入 SVG,只能用 JPG、PNG、GIF 等常规图片格式;
- 除了
<td background="">
,不支持图片背景background-image
; - 可以针对 Gmail 写样式(比较 hack,庆幸暂时没用上);
网易邮箱
web 端没什么问题,移动端所推的网易邮箱大师对布局支持并不好,需要准确复刻设计稿的话建议回归 <table>
+固定宽度,放弃响应式。
网易邮箱大师有个独特的优化,如果某个节点的字数超出宽度限制而且有设置字号,不管这个节点有没有 text-overflow: ellipsis; overflow: hidden;
之类,它都会尝试缩减字号以确保当前宽度能够显示全部文字。不设置字号反而不会有这个问题。
如果这个节点除了自身宽度还有边距等可能占据水平空间的属性,整个页面的布局都会被影响。
QQ 邮箱
web 端支持内联 <style>
并且会统一给选择器加上 .qmbox
前缀, @media
区块里的第一个选择器会漏加,可能是用来加前缀的正则表达式考虑不充分……
移动端不支持内联 <style>
而且字号选择有点诡异。
阿里邮箱
应该说网页端支持程度不错,但是有几个非常坑的:
- 支持
<style>
但是会删掉所有的!important
,极大限制了邮件模板的兼容策略(最坑的没有之一); - 会自动处理
<table>
增加一层<div>
包裹而且很容易算错宽度(反过来说就是内容得写死宽度);
移动端也有一些需要注意:
- 不支持图片背景
background-image
,但允许<td background="">
; <style>
中如果有错误的样式,会导致之后的样式全都不生效;
Outlook
Office 365 Mac 版 Outlook 用的是 webkit,兼容性非常好,无论是网页版还是客户端,都支持内联 <style>
,计算动态宽度也没有问题。然而 Windows 版 Outlook 用来渲染邮件正文的还是 Word 2007 HTML,兼容性非常差,即便是 Office 365 版本也是如此。需要支持的话只能用 <table>
,详细可以参考 https://segmentfault.com/a/1190000008864116
兼容过 IE6-8 的前端开发应该很熟悉下面这个针对 Word 2007 HTML 的 hack:
<!--[if mso]><![endif]-->
更多针对 mso 的 hack 可以参考 https://cm.engineering/fixing-bugs-with-outlook-specific-css-f4b8ae5be4f4
实际编写过程中发现的问题:
- div 宽度设置不管用,水平居中一定要用表格;
- div 嵌套之后,外部 div 背景色填充有问题,只有内部 div 有内容的地方会显示背景色,整体效果支离破碎;
用 <table>
吧……
噢,还有一个特别管用的调试建议,由于 Windows Outlook 和 Word 用的是同一个渲染引擎(Word 2007 HTML),你可以通过在 Word 查看 html 来调试样式。
Takeaways
响应式布局
先上一个通用的响应式 HTML 邮件模板:
<!DOCTYPE html>
<html>
<head>
<style>
.root { max-width: 375px; }
@media (min-width: 600px) {
.root { max-width: 600px; }
}
@media (min-width: 750px) {
.root { max-width: 750px; }
}
</style>
</head>
<!--[if mso]><body style="margin: 0; text-align: center;"><table width="600" cellspacing="0" cellpadding="0" style="margin: 0 auto;"><tr><td><![endif]-->
<!--[if !mso]><!--><body style="margin: 0;"><!--<![endif]-->
<div class="root" style="margin: 0 auto; text-align: left"></div>
<!--[if mso]></td></tr></table><![endif]-->
</body>
</html>
- Windows Outlook 使用 table 实现水平居中并定宽 600px
- 其他客户端使用
.root
节点实现响应式(375px、600px、750px 三档)以及水平居中
Spark 收件箱查看的时候会无视
.root { text-align: left; max-width: 600px }
同时其他邮箱客户端在没有body { text-align: center; }
的情况下都可以水平居中.root
响应式字号
不考虑阿里邮箱的话可以直接用 font-size: 42px !important;
,要考虑阿里邮箱的话需要如下 hack:
<div class="root">
<h1 style="font-size: 20px"><span></span></h1>
</div>
<style>
@media (min-width: 750px) {
/* 阿里邮箱会过滤样式中的 !important */
h1 span { font-size: 24px; }
}
</style>