写 Markdown 的人迟早会撞上一堵墙你想把某句结论标成红色翻遍语法手册发现根本没有这个语法。标题、加粗、斜体、引用、代码块、列表、表格——Markdown 原生能表达的样式就这么多至于字体颜色、字号大小、背景底色这类排版自由语法层面压根没给你留口子。这时候唯一的出路就是往 Markdown 里内嵌 HTML借浏览器的渲染能力把想要的效果补回来。这篇内容就是把我这几年在技术文档、笔记系统和邮件模板里反复折腾内嵌 HTML 的经验摊开讲一遍包括怎么写、为什么会失效、哪些平台会吃掉你的代码以及我踩过的那些坑。不管你是刚学 Markdown 语法的新手还是已经写了几年文档想精细化控制排版的老手下面的内容都能直接抄作业。1. Markdown 原生语法的表达天花板在哪1.1 你能用原生语法做到的其实比想象中少先把 Markdown 的原生能力列清楚很多人才会明白为什么非要引入 HTML。标准 Markdown以 CommonMark 为基准支持的样式包括六个级别的标题、粗体、斜体、删除线GFM 扩展、行内代码、代码块、引用块、有序/无序/任务列表、链接、图片、分隔线、表格GFM 扩展、脚注部分扩展。这些语法覆盖了 90% 的写作需求但它们有一个共同特征——全部是语义标记不是样式标记。语义标记的意思是你只能告诉渲染器这是一个强调至于强调出来是红色还是绿色、是 14px 还是 20px决定权在渲染器的 CSS 主题手里。你在 Typora 里看到的加粗是深黑色换到另一个编辑器里可能就是深蓝色这不是你的问题是主题的问题。而一旦你确实需要这句话必须显示为红色这种样式级的控制原生语法就彻底缴械了。我见过太多人卡在这一步明明只是想让一句警告语醒目一点试了**警告**、试了 警告、试了反引号都觉得力度不够最后只能去 Google Markdown 怎么设置字体颜色然后发现答案全都指向内嵌 HTML。这不是 Markdown 的缺陷而是它的设计哲学——把内容和呈现分离。理解这一点你就不会再纠结为什么 Markdown 不支持颜色了而是会转向我用什么手段合法地绕过这个限制。1.2 渲染器才是真正的裁判语法只是入场券内嵌 HTML 最坑的地方在于语法正确不代表渲染正确。Markdown 本身只是一套文本到 HTML 的转换规则最终你这堆标签能不能生效完全取决于渲染器有没有开 HTML 白名单、有没有把危险标签和属性过滤掉。举个最典型的例子。你在本地用 VS Code 的 Markdown 预览写了一段span stylecolor:red重点/span预览里红得漂漂亮亮满心欢喜推到代码托管平台的 README 里结果打开一看——颜色没了只剩纯文本。原因很简单这类平台为了防止 XSS 攻击对用户提交的 HTML 做了严格的清洗sanitizestyle属性几乎是最先被剥离的一批。同样一段代码在 Typora、Obsidian 里正常在上面这个场景里就是废的。所以我在写任何需要内嵌 HTML 的文档之前都会先确认三件事这份文档最终会在哪里被阅读那个渲染器支持哪些标签和属性有没有官方的白名单文档这三件事想不清楚写再多标签都是白费。后面第 6 节我会专门做一张常见渲染器的支持度对照表这里先建立一个意识内嵌 HTML 是看环境吃饭的技术写之前先问环境。1.3 什么时候该上 HTML什么时候该收手不是所有排版需求都值得动用 HTML滥用内嵌标签会把一份干净的 Markdown 变成一坨四不像的代码。我的判断标准很简单分三种情况。第一种纯语义能表达的就别碰 HTML。加粗用**强调用*警告用引用块代码用反引号。这些是跨平台兼容性最好的写法没有任何渲染器会拒绝它们。第二种结构性需求优先考虑 Markdown 扩展比如表格、任务列表、脚注都有原生或 GFM 写法别用table去手搓一个表格除非你需要合并单元格这种原生做不到的事。第三种只有纯样式需求才动用 HTML比如必须出现的红色警告、必须放大的结论、必须有底色的术语高亮这些是原生语法确实无能为力的地方。提示内嵌 HTML 越多文档的可移植性越差。同一份文档要发布到多个平台时能少用就少用能只用一种标签解决就别堆三种。还有一个现实问题很多团队的文档是需要多人协作的你把一段 HTML 塞进去下一个来改文档的人可能根本看不懂这是在干嘛。所以我在团队内部有个不成文的约定——凡是用了内嵌 HTML 的地方旁边都留一行注释说明用途Markdown 注释用!-- --免得后人踩坑。2. 字体颜色从最笨的 span 写法讲起2.1 已经废弃的 font 标签为什么还在被使用逛技术社区时你大概率见过这种写法font colorred这段文字是红的/font。作为一个写过前端的人我第一反应是——font标签在 HTML4 就已经不推荐、HTML5 里被正式移除了。但奇怪的是它至今在 Markdown 内嵌场景里活得很好很多编辑器对它的支持度甚至比span还高。原因不难理解。font是呈现型标签语义就是改字体外观浏览器出于历史兼容仍然会渲染它而且它的属性简单到只有color、size、face几个很难被当成安全隐患过滤掉。相比之下span style...依赖 CSS 引擎一旦渲染器开启 HTML 清洗style属性首当其冲。所以结论有点反直觉在兼容性摇摆不定的 Markdown 环境里老掉牙的font有时候比现代的span更稳。但我不会无脑推荐font。它的问题同样明显color只接受颜色名或十六进制色值没法做透明度、没法做渐变、没法继承复杂样式size属性取值是 1 到 7 的档位而不是像素值控制粒度粗糙得离谱。我的实际做法是两套都写按环境选目标环境支持 CSS 就用span环境不明确或者需要极致兼容就用font。下面把两种写法都列清楚。!-- 方案Aspan 内联样式支持绝大多数现代渲染器 -- span stylecolor:#e74c3c;这段文字是红色/span !-- 方案B老式 font 标签兼容性更广但功能有限 -- font color#e74c3c这段文字是红色/font2.2 色值怎么写才不容易翻车颜色值有三种写法颜色名red、blue、三位十六进制#f00、六位十六进制#ff0000。颜色名最好写但选择有限只有一百多个标准名三位十六进制是简写#f00等于#ff0000但只有在两两相同时才能简写六位十六进制最通用也最精确。写色值有几个我吃过亏的细节。第一别漏掉井号colore74c3c是无效的浏览器会忽略整个声明文字就变成默认色而且不报错你根本不知道哪里错了。第二色值大小写不敏感#E74C3C和#e74c3c等价但团队协作时建议统一成小写方便检索。第三慎用纯黑纯红#000000和#ff0000在深色主题下会非常刺眼我一般用#e74c3c这种略偏柔和的红色做警告色正文用#24292e或直接继承默认色。还有一个隐藏坑有些渲染器会把颜色强行反转或者覆盖。深色主题的编辑器里你设的深色文字可能直接看不见。所以我给自己的规矩是——永远不要用极端的明暗色值选中间调这样在浅色和深色主题下都不至于完全消失。用途推荐色值说明警告/重点#e74c3c柔和红深色浅色主题下都可辨识成功/通过#27ae60中绿对比度适中提示/信息#2980b9稳重蓝适合链接和说明次要文字#7f8c8d中性灰用于弱化信息正文默认不设置跟随主题兼容性最好2.3 批量改色的偷懒思路文档里如果散落着几十处红色标记要统一换成另一种颜色一个个改会让人崩溃。我通常分两步处理先用编辑器的全局替换把结构统一比如把font colorred全部替换成span classwarn然后在文档末尾或者头部用一个style块统一定义.warn的颜色。这样以后改色只需要动一行 CSS。不过要注意style标签的支持度比内联样式还要窄很多平台直接把它整个过滤掉。所以这套方法只在你完全掌控渲染环境的场景下可用比如自建的文档站点、Typora 这种本地编辑器、或者支持自定义 CSS 的笔记软件。如果文档是要发到公共平台的还是老老实实用内联样式虽然啰嗦但至少不会全部失效。!-- 仅在可控环境下使用公共平台大多会过滤 style 标签 -- style .warn { color: #e74c3c; font-weight: bold; } .tip { color: #2980b9; } /style span classwarn这是统一管理的警告样式/span3. 字号与背景色让关键信息真正跳出来3.1 font-size 的绝对单位与相对单位之争字号控制比颜色更容易失控核心分歧在于用绝对单位还是相对单位。px是绝对单位写死 20px 就是 20pxem是相对单位相对于父元素的字号rem相对于根元素字号%也是相对父元素。看起来rem最优雅但在 Markdown 内嵌场景里它反而是最危险的选择。原因在于Markdown 文档最终渲染时的根元素是由宿主页面决定的可能是 16px也可能是 14px甚至会被主题动态调整。你写1.5rem以为是 24px实际可能是 21px完全不可控。而em嵌套起来会累积父级套了em子级再套em最后字号会指数级膨胀我见过有人把标题套成了巨无霸字号。所以我的实际建议是在内嵌 HTML 里统一用 px虽然不够响应式但胜在所见即所得不会因为环境变化给你惊吓。span stylefont-size:20px;放大到 20px 的结论句/span span stylefont-size:12px; color:#7f8c8d;缩小到 12px 的辅助说明/span字号设置还有个容易忽略的边界——不要用它来模拟标题。有人为了绕过标题层级限制直接把一段普通文字用font-size撑大成标题的样子这在纯视觉上能骗过眼睛但文档结构里它依然是正文段落目录提取、大纲导航、屏幕阅读器全都识别不到。该用##就用##字号只用来做强调性的局部变化。3.2 背景色不是刷墙留白才是关键背景色最常见的写法是background-color配合内边距padding一起用效果才完整。只加背景不加留白文字会紧贴色块边缘看起来像被勒住了非常局促。我一般给padding留 2px 到 6px 的水平空间视觉上就舒展多了。span stylebackground-color:#fff3cd; padding:2px 6px; border-radius:3px; 带底色和圆角的高亮术语 /span这里的border-radius是个加分项不是必需的但它能让色块从生硬的矩形变成柔和的标签感视觉档次完全不同。不过要提醒一句border-radius的支持度比background-color更低如果你的目标环境过滤了它色块会退回直角功能上不受影响只是观感差一点可以接受。背景色还有个大坑是对比度。浅黄底配深灰字很好看但浅黄底配浅灰字就成了隐形文字。我踩过一次坑文档里用浅灰底配了灰色字自己在大屏上看没问题结果同事在笔记本上调低亮度后完全看不清。后来我养成了习惯设背景色时永远同时设一个高对比的文字色深底配浅字浅底配深字绝不偷懒只设一个。3.3 mark、kbd 这类语义标签的意外好用除了span硬怼样式HTML 里还有一类语义标签天生就带默认样式而且往往比手写样式更容易被渲染器放行。最典型的是mark它代表高亮标记浏览器默认给黄底黑字正好就是我想要的高亮效果一行标签搞定不用写任何 CSS。这句话里的 mark关键词/mark 会自动带上黄色高亮底色。 按下 kbdCtrl/kbd kbdS/kbd 保存文档。kbd更妙它专门表示键盘输入默认渲染成带边框的小方块做教程时标注快捷键非常合适。类似的还有code行内代码不过 Markdown 的反引号更常用、abbr缩写鼠标悬停显示全称、sub/sup上下标写化学式和脚注很方便。这些标签的好处是语义明确、样式稳定、兼容性好能用它们解决的需求我优先不用span。标签语义默认效果典型用途mark高亮标记黄底黑字关键词强调kbd键盘输入带边框方块快捷键说明abbr缩写悬停显示全称专业术语sub下标下沉小字化学式sup上标上浮小字数学幂次del删除中间划线修订痕迹4. 换行、缩进与空行Markdown 里最容易翻车的地方4.1 行尾两个空格是隐形陷阱Markdown 最反直觉的规则之一是单个换行符会被渲染成一个空格段落内的换行不会真正断行。要让一行真正断开标准做法是在行尾敲两个空格再回车。这个规则坑过无数人因为那两个空格是完全不可见的改了之后你根本不知道这行到底有没有加上。我不太推荐依赖行尾空格原因是它太脆弱了。编辑器可能自动清理行尾空白代码格式化工具可能帮你删掉别人复制粘贴时也可能丢掉。相比之下显式写br更可靠虽然不够纯 Markdown但意图清晰、不易丢失、所有渲染器都认。这是第一行br这是第二行用 br 强制换行。 这是第一行 这是第二行靠行尾两个空格换行不推荐空格容易丢。有意思的是br在 GFM 表格里几乎是唯一的换行方案。表格单元格里你想让文字分两行行尾空格和反斜杠都不一定管用只有br稳如磐石。所以做复杂表格时我基本都会在单元格里塞br。4.2 br 与段落边界什么时候该用哪个br是软换行它只换行不分段两个空行产生的是硬分段会生成独立的p段落上下还有段间距。这两个效果视觉上差别很大用错会让排版显得很业余。我的判断标准是信息属于同一个语义单元用br信息属于不同单元用空行分段。比如地址信息的多行、诗歌的每一句、代码注释的连续几行这些是同单元内的换行用br。而两个不同的论点、两个独立的段落就用空行隔开。踩过的坑是有人为了让段落之间紧凑一点把本该分段的两个段落用br连起来结果整段文字挤在一起阅读体验很差。4.3 块级 HTML 前后的空行规则内嵌块级标签比如div、table、details时标签前后最好各留一个空行否则很多 Markdown 解析器会把它们当成行内元素处理导致渲染错位。这是 CommonMark 规则里比较微妙的部分HTML 块必须在独立的行上开始前面不能紧贴文本。这段普通文字之后要空一行再开始块级标签。 div styletext-align:center; 居中的块级内容 /div 块级标签结束之后也要空一行再继续写普通文字。如果偷懒不空行你可能会发现div里的内容跟前后文字糊在一起或者style完全失效。这个坑很难从报错里看出来因为根本不报错只是效果不对得靠经验反推。5. 表格、图片与折叠块里的 HTML 增强5.1 表格单元格里能塞什么GFM 表格本身能力有限不能合并单元格、不能设置列宽、不能控制对齐之外的东西。要在单元格里做更复杂的排版只能内嵌 HTML。最常用的是用br换行、用span上色、用code或反引号显示代码片段。| 参数 | 说明 | 默认值 | | --- | --- | --- | | timeout | span stylecolor:#e74c3c;超时时间毫秒/span | 3000 | | retry | 重试次数br建议不超过 3 | 1 |注意表格里的内嵌 HTML 兼容性比正文更差有些渲染器只允许表格单元格里出现最基础的标签。所以我会给表格内容做个优先级排序纯文本 brspan 其他。能不用颜色就不用因为表格本身已经有结构了视觉上不需要太多装饰。如果你真的需要合并单元格、复杂表头这类能力就得放弃 Markdown 表格语法改用完整的table手写。代价是代码量陡增维护困难。我的经验是复杂表格别硬塞进 Markdown导出成图片或者用外部链接更合适。5.2 图片尺寸、对齐与图注Markdown 的图片语法![]()没法控制尺寸想要指定宽高必须用img标签。这也是内嵌 HTML 最常见的用途之一。img src./images/demo.png width360 alt演示图 div styletext-align:center; img src./images/demo.png width360 alt演示图 br span stylefont-size:12px; color:#7f8c8d;图 1演示图说明/span /div这里几个细节值得说。width只写数字不写单位写360表示 360 像素写80%表示相对宽度两种都合法但别写360px部分渲染器不认。alt属性务必写图片加载失败时它是唯一的兜底方案对视障用户也是必需的。图注用span缩小字号加灰色比直接写普通文字更像正式的图注观感更专业。图片路径也是老生常谈的坑。相对路径./images/x.png依赖文档和图片的相对位置文档移动后图片就没了绝对路径/images/x.png依赖站点根目录本地预览时常常失效。我的做法是图片和文档放在同一个目录或者同级子目录用最简单的相对路径同时保证图片文件名不含空格和中文避免各种 URL 编码问题。5.3 details 标签做折叠与问答details和summary这对标签组合能在 Markdown 里实现折叠面板效果非常适合做 FAQ、参考答案、长代码的展开查看。写法很简单summary里放折叠状态下可见的标题剩下的内容默认隐藏点击展开。details summary点击展开查看完整配置/summary bash npm install --save-dev markdown-it这里可以放任意 Markdown 内容包括代码块和列表。这个标签的兼容性其实相当好主流渲染器基本都支持而且它不依赖任何 CSS是 HTML 原生行为。我特别喜欢用它来放那些不影响主线阅读但需要备查的内容比如完整的错误日志、备选方案、参考资料。这样正文保持清爽有需要的人点开就能看到细节。不过要提醒一点details内部嵌套 Markdown 时summary和内容之间必须留空行否则 Markdown 不会被解析代码块会变成纯文本。这是我在实际使用中反复确认过的细节。6. 各家渲染器的实测差异与应对6.1 常见渲染环境的支持度对照写了一段时间内嵌 HTML 之后你会发现最该掌握的不是标签语法而是目标环境的白名单。下面这张表是我在不同环境里反复实测后总结的各家差异相当大。渲染环境行内 stylestyle 标签brdetails备注VS Code 预览支持支持支持支持默认 html 开启Typora支持部分支持支持支持偏好设置可调Obsidian支持支持支持支持style 作用于整篇代码托管平台 README过滤过滤支持支持只留少量属性主流技术社区编辑器过滤过滤支持部分支持白名单清洗邮件客户端部分支持不支持支持不支持用表格布局更稳从表里能看出一个规律越开放的环境越允许样式越公开的环境越保守。本地编辑器和私有笔记软件几乎不限制因为它们信任用户而面向公众的平台一律按最严格的标准清洗因为要防 XSS。理解了这个规律你就不会再有为什么本地好好的发出去就废了的困惑。6.2 导出 Word、PDF 时的样式留存问题很多人写 Markdown 的最终目的是导出成 Word 或 PDF 交付这时候内嵌 HTML 的表现又是另一回事。常见的导出链路有两条一条是走转换工具比如 pandoc一条是用编辑器的内置导出。pandoc 这类工具的思路是把 Markdown 转成抽象语法树再输出目标格式。内嵌的 HTML 在转换过程中要么被当作文本原样保留很难看要么被丢弃样式全失。span stylecolor:red转成 Word 后红色可能保留也可能变成纯文本加一堆乱码般的标签完全取决于版本的映射策略。我的应对策略是为交付格式单独准备一份源文件。日常写作的 Markdown 可以随便用内嵌 HTML 增强观感但要导出 Word 交付时我会把内嵌标签全部清理掉改用目标格式自己支持的样式体系Word 的样式或 CSS。虽然多一道工序但比交付一份满是失效标签的文档强得多。注意导出前一定要打开生成的文件亲自检查尤其是颜色和图片。这两项是最容易在转换中丢失的。7. 我用坏过的几种写法以及补救思路有几个失败的写法我印象特别深拿出来说说省得你再走一遍。第一种在代码块里写 HTML 想让它被渲染。行内代码和代码块是转义区里面的内容原样输出不会被解析成标签。有人不知道这点把span stylecolor:red放进反引号里结果页面上显示的就是一串标签文本。记住代码块里只有文本没有渲染。第二种标签跨段落使用。我见过有人写div stylecolor:red然后空了好几行才写/div中间夹着普通 Markdown 内容。这在多数解析器里会出问题因为 HTML 块和 Markdown 段落的边界是分开处理的跨块标签往往被强行闭合样式作用范围和你预期完全不符。标签尽量在同一个块内闭合需要大面积改样式就用独立的div包住整块别让标签跨越空行。第三种属性值里的引号用错。HTML 属性可以用单引号、双引号某些情况下也可以不加引号。但在style属性里CSS 声明本身通常需要引号配对写stylefont-family:微软雅黑是合法的但如果你外层用了单引号又内层也单引号就会断裂。内联样式统一用双引号包裹属性、内层需要引号时用单引号这是一个不会出错的安全组合。第四种忘记块级元素的独立成行要求。这条前面提过但值得再强调一次因为它造成的看不出错误的效果异常太难排查了。div、table、details这类块级标签前面必须是空行或用行首开始不能跟在文字后面。补救思路其实统一遇到样式不生效先怀疑环境再怀疑语法最后怀疑自己。把标签简化到最小可用比如先用font colorred测试环境是否放行颜色放行了再升级到span和复杂样式。这种从简到繁的调试顺序比对着复杂标签反复试错效率高得多。我个人的做法是在本地建一个测试页里面放上十几种常用的内嵌写法每次换新环境先往这个页面里贴一遍看哪些能活下来。这个页面跟了我三年帮我省下了大量写完了发出去才发现全废了的时间。最后分享一个小技巧如果你发现自己频繁需要某种内嵌样式说明它已经成了你的刚需这时候与其每次手写一堆标签不如在编辑器的自定义片段snippet里存一条模板输入几个字母就能展开成完整的标签结构。我给自己配了红色警告、黄色高亮、折叠块三个片段日常写文档的效率提升非常明显。工具服务人不是反过来。