都 2019 年了, 手机查看 html 邮件的体验怎么还那么差?
试想一下, 你在夜深人静的时候, 准备睡前查看一下订阅的邮件周报, 而且还是一个精心设计过的 HTML 富文本邮件. 只不过它只能在 pc 上完美展现, 在手机上最大的字号只有不到 4 像素, 图片也变成了马赛克, 会是一种怎样的虐心体验.
最近做了一个群发邮件的手机端适配需求就是要解决这个体验问题, 先上效果.
优化前:
优化后:
当然, pc 端和网页版也要完美适配, outlook,foxmail 和网页版效果如下:
一, 实现思路
参考比较常见的响应式布局, 在 PC 端使用左图布局, 移动端右图. 转换时将图片的宽度由定宽改为铺满, 使标题等文字换行展示.
1 邮箱渲染 HTML 的兼容性问题很多, 在桌面和移动端渲染电子邮件大约有上百万种不同的组合方式, 所以我们要找出一个最小子集来书写 HTML 和样式. 然后用平稳退化和渐进增强的思路, 对其他要适配的设备和客户端进行保底处理和浏览体验优化.
2 邮件里不能执行脚本, 各种邮件客户端对 media query 的支持程度非常有限, 所以不可能根据接收邮件的终端来构建不同的 dom 和 CSSom, 必须撸一套代码适配所有终端.
3 本次迭代的目标是提升手机端阅读体验, 以机端原生邮箱客户端和 QQ 邮箱作为基础. 然后用各种 hack 手段来适配其他设备和客户端. 比如用 ghost table 适配 outlook,media query 适配网页版等等. 本次的目标是针对公司内部用户的邮件推送优化, 所以覆盖的客户端和操作系统比较有限, 如果要覆盖更多的设备其实原理也一样, 见招拆招就好, 原则就是在不影响之前已适配的设备客户端的情况下对新设备做支持.
4 移动端 web 的常规优化对邮件 HTML 同样适用, 比如使用更小的字体, 图片格式选型和压缩, 高精度图片适配 retina 屏, 用 CSS 绘制小图标代替图片等等.
二, 基本原则
1 由于 OutLook 从 2003 版本为了安全开始便使用 Word HTML 引擎进行渲染, 所以我们只能使用 table 布局, 标签也只能使用 table / tr / td / span / img / a,colspan / rowspan 也不能放心使用. 如果要实现复杂布局, 就要使用 table 嵌套.
2 body 以外的内容全部无效, 比如 outlook 网页版, 它会把 body 替换成一个类名叫 x_body 的 div, 然后把 body 的内容全部塞进去.
3 style 标签的支持程度非常碎片化, media query 的支持更加有限, 所以要用属性和 style 行内样式来保底布局.
4 邮件 HTML 里没有任何脚本.
5 不要简写样式, 比如: padding: 12px 会在 outlook2013 失效, 改为 padding-left/padding-right/padding-top/padding-bottom,font 简写也一样.
6 对于 img 标签, 用属性来控制尺寸, style = "width:100px" 这样的代码在 outlook2013 会失效, 而且图片会把定宽的 td 和 table 撑开. width="100%" 这样的 CSS 属性也是无效的.
7 Outlook 2007-2013 不支持图片的 margin 与 padding 样式, 必要的时候可以尝试 hspace 和 vspace 属性 (非常不建议, 用父元素的 margin 和 padding 来代替就好了).
三, 实现过程中各个终端遇到的问题和解决方法
1 QQ 邮箱手机客户端 (版本信息: IOS11,5.6.2)
QQ 邮箱收 @qq.com 的邮件, 会完全过滤 style 标签, 但是收其他域的邮件会保留 style 标签并且不支持 media query. 所以要适配 QQ 邮箱有两个重点.
第一就是保证行内样式渲染正常. 本次最大的一个功能点就是封面图手机端铺满, pc 端定宽, QQ 邮箱又只能支持行内样式, 所以封面图就在 style 里定义了宽度 100%, 然后针对其他设备和客户端写各种 hack 让它定宽.
第二是我们要用一些 style 样式来调整 pc 和网页上的布局, 就要用如下办法来避免对手机 QQ 邮箱产生副作用.
- /* 通过 outlook 专属标记属性来避免 QQ 邮箱手机版加载 */
- <!--[if mso]>
- <style type="text/css">
- </style>
- <![endif]-->
- <!-- 通过 media 属性来避免 QQ 邮箱手机版加载 -->
- <style type="text/css" media="screen and (min-width:900px)"></style>
2 手机原生邮件客户端 (版本信息: IOS11,5.6.2)
这个最省心, 支持 media query, 支持 display:flex, 在 QQ 手机邮箱的基础上针对原生客户端又做了一些体验优化.
3 outlook 客户端 (版本信息: 2007-2016)
这个最麻烦, 就是前面说的 Word HTML 引擎. 支持 style, 不支持 media query, 不支持 img 样式. 我们这个需求最大的功能点就是在大于 900 宽度的屏幕上封面图按 260 宽渲染, 在小于 900 宽度下铺满屏幕. outlook2013 之前又只支持用 attr 来固定图片宽高, CSS 定义 width 完全无效, 还会撑破 td 和 table), 一旦写了固定值就会影响到上面说的手机邮箱客户端, 怎么处理这个冲突就是关键点了.
一开始的想法比较简单, 直接用 style 覆盖 attr 不就好了吗?
<img src="#" width="260" style="width:100%">
结果 outlook2016 出来打脸, 在 pc 上铺满屏了.
好, 再利用 outlook2016 支持 style 的特性, 用! important 提高优先级覆盖回来:
- <style>
- img{width:260px!importnat;}
- </style>
记得第一条不? 手机 QQ 邮箱收内部邮件的时候, 支持 style 不支持 media query. 这么一来手机 QQ 邮箱上又定宽了, 被逼进绝路.
只好祭出 ghost table, 把用于其他客户端的那个正常的图片隐藏了, 然后显示一个专门用于 outlook 的图.
- <!--[if mso]>
- <table style="display: none">
- <tr>
- <td>
- <![endif]-->
- <a href="#" class="cover">
- <img src="#.jpg" border="0" width="100%">
- </a>
- <!--[if mso]>
- </td>
- </tr>
- </table>
- <a href="#" class="cover">
- <img class="img" src="#.jpg" border="0" alt="fsight" width="260" height="150">
- </a>
- <![endif]-->
同理可以使用这个 outlook 专有的标记来隐藏所有用于其他客户端展示的 dom 元素, 针对 outlook 做定制, 甚至可以暴力一点写两套.
这里还遇到一个问题点就是 go 在渲染邮件模板的时候会自动过滤掉所有的注释, 所以需要使用 safe 标记, 并且转义写到一行内.
- {
- {
- safe "<!--[if mso]> <table align=\"left\"border=\"0\"cellpadding=\"0\"cellspacing=\"0\"width=\"570\"> <tr> <td width=\"570\"> <![endif]-->"
- }
- }
- code...
- {
- {
- safe "<!--[if mso]></td></tr></table><![endif]-->"
- }
- }
最后就是垂直居中问题, 常规的图文混排垂直居中方法就是
<div><img src="#" style="vertical-align:middle"><span style="vertical-align:middle"> 文字 </span></div>
放到 outlook 里当然无效, td 本身的垂直居中在各个版本中的表现也是各不相同. 调试了半天, 居然是给 td 一个定高就搞定了.
3 outlook 网页版
有点小坑, 它会把 style 里面的样式改写并且把 @media 里面的代码清空.
会变为:
所以使用了在 style 里面写 media 属性的方法来兼容 (为了避免手机 QQ 邮箱会加载这段样式).
4 QQ 邮箱网页版 ( https://mail.qq.com https://email.tencent.com/ )
PC 版没啥好说的, 完全支持各种特性, 只是移动版有点小麻烦:
- @media (min-width: 900px) {
- .item{}
- }
- @media (max-width: 900px) {
- .item{}
- }
会被替换为
- @media (min-width: 900px) {
- .item{} // 仔细看这里, 有个花括号被吃掉了
- @media (max-width: 900px) {
- .item{}
- }
除了最后一个双} 保留了, 其他的 "}}" 都被替换为 "}". 我估计是正则替换问题, 要破也很简单, 把 media 写到 style 属性, 或者分多个 style 标签即可.
另外 iPad 模式下 QQ 邮箱 Web 版会出现一个宽度 200 的侧边栏. 所以邮件正文实际使用的空间会少, 写 max-width 的时候需要注意 (你以为它有 768px, 实际上只有 568px).
5 Mac 原生客户端和 foxmail 客户端 (版本信息: win7.2/mac1.2)
这几个客户端也很好搞, 支持 media query, 支持 flex, 可以根据屏幕大小随意定制样式. 这次只是使用 900px 作为手机和 pc 的分界点. foxmail 有个特性就是边栏的宽度不算在 media query 内, 所以当左边栏拉的比较宽的时候, 内容会安装手机样式渲染.
这个也好解决, 在 640 和 900 之间多写几个 media 区间来适配就好了, 体力活.
6 转发问题
通过上面的工作, 系统发的邮件虽然可以适配了, 但是转发的时候就还是会有问题, 因为用户转发的是经过客户端处理过的邮件, 要么是 CSS 不全, 要么是 ghost table 没了. 目前来看手机 QQ 邮箱客户端保持的最好, 转发效果基本无损. 其他的暂时无解, 所以以防万一请在你的邮件里加上链接:"如果无法正常浏览请点击", 跳转到网页让用户查看完美的页面.
四, 参考资料
1 邮件样式支持速查表:
https://www.campaignmonitor.com/css/
2 outlook 各版本标记:
https://stackoverflow.design/email/base/mso
3 不同邮件服务商读取 HTML 邮件已知问题一览表:
http://app1.studiocloud.com/support/index.php?/article/AA-00861/0/Issues-with-HTML-Emails-in-Different-Email-Clients.html
来源: http://www.tuicool.com/articles/AfEvEr2