邮件客户端仅支持内联样式和带type="text/css"的块,外部css、flex/grid、媒体查询及高级选择器均被过滤或忽略,布局须用table实现。

邮件模板里引入 CSS 后部分样式不生效,根本原因不是“CSS 写错了”,而是绝大多数邮件客户端压根不认你写的那些规则——它们只吃内联样式和 <style></style> 块里的嵌入式 CSS,其余一概过滤或忽略。
为什么 <link rel="stylesheet"> 和 @import 完全无效
Gmail、Outlook、Apple Mail 等主流客户端在解析 HTML 邮件时,会主动剥离 中的外部资源引用。哪怕你确认 href 路径正确、服务器返回 200,这些标签也会被静默丢弃。
-
<link rel="stylesheet" href="%7B%%20static%20'css/email.css'%20%%7D">→ 被忽略,连请求都不会发 -
@import url('https://cdn.example.com/email.css');→ 不解析,直接跳过整条规则 -
{% static %}模板标签 → 渲染后是空字符串或非法路径,因为邮件发送阶段不走 Django 的静态文件服务逻辑
为什么 Flex/Grid/媒体查询看起来“写了但没用”
不是兼容性差,是根本没实现。Outlook Desktop 用 MS Word 渲染引擎,Gmail Web 版禁用 @media,所有现代布局方案(display: flex、display: grid、position: absolute)均不支持。
-
display: flex→ 在 Gmail 中等同于没写,元素退回文档流左对齐 -
@media (max-width: 600px)→ Gmail Android/iOS 完全无视,Apple Mail 可能识别但行为不一致 -
margin属性 → Outlook 和 QQ 邮箱基本忽略,padding更可靠
为什么 <style></style> 块里的规则有时也失效
<style></style> 是允许的,但有硬性限制:必须声明 type="text/css",且不能含任何客户端不识别的语法(如自定义属性、calc()、某些伪类)。
- 漏写
type="text/css"→ Outlook 2016/2019 直接跳过整个<style></style>块 - 用了
:is()或:where()→ 所有旧客户端解析失败,整段 CSS 被丢弃 - 选择器含空格但结构不匹配 → 比如写
.container .btn,但实际 DOM 是<div class="container btn">,那规则根本不会应用 <h3>真正能落地的写法只有两种</h3> <p>别试图“适配”,直接按邮件客户端的能力边界来写。所有样式必须落到具体元素上,且优先级要靠结构而非权重。</p> <ul><li>内联样式为主:<code><td style="font-family: Arial, sans-serif; color: #333; padding: 12px;"> <li> <code><style></style>块为辅,仅放通用重置或字体声明,且开头必须带type="text/css" - 布局全部用
<table>:宽度用 <code>width="600",对齐用align="center",分栏用嵌套<td width="50%"> <li>避免依赖 class 名:客户端可能剥离 <code>class属性,或对 scoped 样式完全无感
最容易被忽略的一点:本地预览成功 ≠ 邮件里能看。Gmail Web 版会重写你的 <style></style> 并加 !important,但只对它认得的属性生效;Outlook 对 line-height 有默认放大逻辑,必须显式设为 1.4 类固定值。真机测试不是可选项,是上线前最后一道关卡。











