MJML 入门指南:从 `mj-body`、`mj-section` 到 `mj-column` 理解响应式邮件网格布局
MJML 入门指南从mj-body、mj-section到mj-column理解响应式邮件网格布局【免费下载链接】mjmlMJML: the only framework that makes responsive email easy项目地址: https://gitcode.com/gh_mirrors/mj/mjml导读本文以 MJML 官方入门文档doc/getting_started.md为骨架系统讲解响应式邮件的基础网格模型——mj-body邮件内容容器、mj-section水平区块与mj-column响应式列三者如何层层嵌套、协同工作并深入剖析自动/手动列宽分配与gutter间距的实现原理。读完本文你将掌握 MJML 中最核心的版式骨架编写能力任意邮件都能用一个 body、若干 section、每个 section 内若干 column的思维拆解成标准网格并能精确控制每列宽度与列间间距。一、为什么 MJML 把邮件拆成网格一封响应式邮件responsive email在外观上可能千差万别但从结构上看它和一个普通的 HTML 模板一样可以被拆解成许多部分放入一个网格grid系统中对齐。MJML 的核心设计思想正是用语义化标签描述网格把表格嵌套、媒体查询、邮件客户端兼容等复杂细节全部交给编译引擎详见 doc/guide.md 的 Overview 描述。这个网格体系由三个层级构成从上到下依次为标签职责对应源码mj-body整封邮件的文档体包含全部内容并定义全局容器宽度packages/mjml-body/src/index.jsmj-section水平方向的一个区块section负责纵向切分邮件packages/mjml-section/src/index.jsmj-column区块内的列column横向切分区块是响应式的核心packages/mjml-column/src/index.js最基本的骨架如下mjml mj-body mj-section mj-column !-- 该列内的内容组件如 mj-text、mj-image、mj-button -- /mj-column /mj-section /mj-body /mjml可以这样理解三层关系mj-body是画布mj-section把画布纵向分成一行一行的横条mj-column再把每个横条横向切成一格一格的单元格——任何 MJML 内容组件最终都必须放进mj-column中这是 MJML 版式的基本约束。二、mj-body整封邮件的容器mj-body标签代表邮件的正文body包含整封文档的所有内容。它既是一个逻辑容器也直接决定了整封邮件的版式基准宽度。在源码中mj-body组件声明了三个可配置属性packages/mjml-body/src/index.js#L7-L11属性类型默认值说明widthunit(px)600px邮件内容区的总宽度只接受像素单位background-colorcolor无邮件正文的背景色idstring无输出到body标签的 id其中width直接决定了下文所有百分比列宽换算的基准。它的默认值是600px见 packages/mjml-body/src/index.js#L13-L15这也是邮件行业最主流的阅读宽度。在渲染时mj-body会把自身的width作为containerWidth传递给所有子组件packages/mjml-body/src/index.js#L17-L22因此修改mj-body的width会等比影响所有以百分比定义宽度的列mjml mj-body width640px mj-section mj-column !-- 此时容器基准宽度为 640px -- /mj-column /mj-section /mj-body /mjml三、mj-section定义水平区块在mj-body内部你首先用mj-section定义邮件中的各个区块。一封典型的营销邮件通常由多个mj-section纵向堆叠组成例如公司头部Company Header、图片头部Image Header、介绍文字、双列内容区、图标区、社交图标区等。mj-section本身承担以下职责见 packages/mjml-section/src/index.js容纳列一个mj-section内可以声明一个或多个mj-column统一背景支持background-color、background-url、background-repeat、background-size、background-position等属性可让整个区块铺上纯色或背景图packages/mjml-section/src/index.js#L9-L33统一内边距默认padding为20px 0上下 20px、左右 0也可分别用padding-top/bottom/left/right覆盖向外传递版式上下文mj-section通过getChildContext()把containerWidth、gutter、direction等值下发给所有列packages/mjml-section/src/index.js#L45-L55这是后续列宽与间距计算的数据来源。简单示例mjml mj-body mj-section background-color#f0f0f0 mj-column !-- 区块内容 -- /mj-column /mj-section /mj-body /mjml四、mj-column响应式的关键官方文档强调Inside any section, there should be columns (even if you need only one column).Columns are what makes MJML responsive.任何 section 内都应放列即使你只需要一列。列是 MJML 响应式的关键。4.1 自动宽度分配Auto sizingMJML 翻译引擎的默认行为是把 section 的空间默认 600px可通过mj-body的width修改按照你声明的列数平均分配。例如下面的布局声明了 2 个列引擎就会生成一个每列占 50% 总宽各 300px的布局mjml mj-body mj-section mj-column !-- First column content -- /mj-column mj-column !-- Second column content -- /mj-column /mj-section /mj-body /mjml依此类推加第三列降到 33%加第四列降到 25%。这个等分逻辑在源码中非常直观mj-column在未显式声明width时以parseFloat(parentWidth) / nonRawSiblings父容器宽度 ÷ 非 raw 兄弟节点数量作为自己的宽度packages/mjml-column/src/index.js#L48-L50。重要提示任何放进mj-column的 MJML 组件如mj-text、mj-image、mj-button其宽度都会自动等同于所在列的 100% 宽度。也就是说列宽定了列内组件的可用宽度也就定了无需也不建议为每个组件单独设置与列宽相关的宽度。4.2 手动宽度设置Manual sizing你也可以用mj-column的width属性手动指定列宽单位支持像素px或百分比%。例如mjml mj-body mj-section mj-column width200px !-- First column content -- /mj-column mj-column width400px !-- Second column content -- /mj-column /mj-section /mj-body /mjml上面的布局中左列固定 200px右列固定 400px合计正好 600px。width的合法值由unit(px,%)类型约束packages/mjml-column/src/index.js#L30底层由 packages/mjml-core/src/helpers/widthParser.js 解析它会从宽度字符串中提取单位px或%百分数在计算时保留小数精度parseFloat像素则取整。需要特别说明的是无论手动还是自动分配最终输出的都是配合媒体查询的百分比类名如mj-column-per-50、mj-column-per-33-333333、mj-column-px-200由 packages/mjml-core/src/helpers/mediaQueries.js 统一生成media only screen and (min-width: breakpoint)样式块桌面端按设定宽度并排显示移动端低于断点自动堆叠为 100% 宽度——这正是响应式的来源。4.3 列的更多可选属性除宽度外mj-column还支持一系列用于精修外观的属性packages/mjml-column/src/index.js#L8-L31属性类型说明background-colorcolor列的背景色padding/padding-top/bottom/left/rightunit(px,%)列的内边距会从列宽中扣除border/border-top/bottom/left/rightstring列的外边框border-radiusstring列的外圆角开启后自动使用border-collapse: separateinner-border/inner-border-radiusstring列内层表格的边框与圆角常用于实现边框嵌套效果见 packages/mjml/test/column-border-radius.test.jsvertical-alignenum(top,bottom,middle)列内容的垂直对齐默认topdirectionenum(ltr,rtl)列内文字的书写方向五、Section gutter列与列之间的一致间距当你在一个mj-section内放多个列时列与列之间默认是紧贴的。要添加一致的间距可以在mj-section上设置gutter属性。gutter 声明在 section 上并作用于它的所有列packages/mjml-section/src/index.js#L25支持px与%两种单位。mjml mj-body mj-section gutter4% mj-column !-- First column content -- /mj-column mj-column !-- Second column content -- /mj-column /mj-section /mj-body /mjml上面的布局中两个列之间会出现 4% 的间距。当邮件在移动端堆叠成单列时这个 gutter 会自动转换为列与列之间的垂直间距下文的移动端行为会详细说明。5.1 gutter 的自动扣除机制理解 gutter 最关键的规则是gutter 会自动从你在mj-column上声明的宽度中扣除你不需要自己手工计算列宽。举个例子声明4%的 gutter并放置两个宽度各为50%的mj-column那么实际渲染出的每列宽度将是48%两列之间各让出2%合计 4%作为 gutter 间距。这段声明 50% 4% gutter → 实际 48% 列宽 2% 双边距的换算在源码中有完整实现packages/mjml-column/src/index.js#L267-L298reduction gutter × (sibling - 1) / sibling reducedWidth max(0, parsedWidth - reduction)同时gutter 间距被拆成首列只加右侧、末列只加左侧、中间列两侧各一半的 paddingpackages/mjml-column/src/index.js#L341-L379最终以mj-column-gutter-{sibling}-{index}-{unit}-{value}这类类名 媒体查询规则输出。这一行为有专门的测试用例验证packages/mjml/test/section-gutter.test.js#L4-L29// 输入mj-section gutter4% 两列无宽度 // 断言 // .mj-column-per-48 { width:48% !important; max-width: 48%; } // .mj-column-gutter-2-1-per-4 { padding: 0% 2% 0% 0% !important; } // .mj-column-gutter-2-2-per-4 { padding: 0% 0% 0% 2% !important; }5.2 gutter 的移动端行为当多个列在移动端堆叠为单列时gutter 会自动转为列与列之间的垂直间距——也就是说桌面端横向的列间距在移动端变成了堆叠列之间的纵向留白且不会在左右外边缘产生多余的边距packages/mjml-column/src/index.js#L381-L394。对于放在mj-grouppackages/mjml-group/src/index.js中的列行为略有不同group 内的列在移动端不会堆叠因此 gutter 会保持桌面端的水平 padding 形式内联输出避免重复的媒体查询规则见 packages/mjml/test/section-gutter.test.js#L68-L95。5.3 用 padding 处理边缘间距gutter 只负责列与列之间的间距列组与 section 左右边缘之间的间距需要借助mj-section的padding属性。padding默认值为20px 0即上下 20px、左右 0。你可以这样为左右边缘留白mjml mj-body mj-section gutter4% padding0 24px mj-column !-- First column content -- /mj-column mj-column !-- Second column content -- /mj-column /mj-section /mj-body /mjml实际使用时也可以把 gutter 与百分比 padding 组合例如padding4%gutter4%section 内边距与列间距各司其职、互不干扰该组合在 packages/mjml/test/section-gutter.test.js 的多组测试中均有覆盖。六、从入门到实战一个完整的双列 gutter 示例综合以上内容把官方文档中的零散示例组装成一封可实际编译的最小邮件mjml mj-body width600px background-color#f6f6f6 mj-section background-color#ffffff padding20px gutter4% mj-column width50% vertical-alignmiddle mj-text font-size16px color#333333 左侧内容一段介绍文字宽度自动铺满所在列。 /mj-text /mj-column mj-column width50% vertical-alignmiddle mj-image width200px srchttps://example.com/your-image.png alt右侧图片 /mj-image /mj-column /mj-section /mj-body /mjml用 CLI 编译README.md 中提供了完整命令说明mjml input.mjml -o output.html或在 Node.js 中调用packages/mjml/src/index.jsimport mjml2html from mjml const { html, errors } await mjml2html( mjml mj-body mj-section gutter4% mj-columnmj-textLeft/mj-text/mj-column mj-columnmj-textRight/mj-text/mj-column /mj-section /mj-body /mjml ) console.log(html) if (errors.length) console.error(errors)七、源码级验证列宽与 gutter 是怎么算出来的为了让自动等分 gutter 自动扣除不只停留在文档描述层面这里梳理一下底层计算链路均可在仓库中直接核对mj-body设定基准width默认600px通过getChildContext()注入containerWidthpackages/mjml-body/src/index.js#L17-L22。mj-section传递 guttermj-section把自身的gutter、direction与containerWidth一并下发给子列packages/mjml-section/src/index.js#L45-L55。mj-column计算实际列宽未声明width时按父宽 / 非 raw 兄弟数等分声明后先解析单位packages/mjml-core/src/helpers/widthParser.js再扣除自身padding、border、inner-border与 gutter 分摊值packages/mjml-column/src/index.js#L38-L68。媒体查询落地所有列宽与 gutter padding 类名被收集进mediaQueries最终由 packages/mjml-core/src/helpers/mediaQueries.js 生成media only screen and (min-width: breakpoint)样式块实现桌面并排、移动堆叠的响应式效果。测试兜底仓库中 packages/mjml/test/section-gutter.test.js 覆盖了百分比/像素 gutter、混合单位、奇数像素取整平衡如 3 列 200px 4% gutter 会输出 185px/184px 以保持总宽一致、RTL 方向等多种场景可作为理解引擎行为的活文档。八、小结至此MJML 入门阶段最核心的版式知识已经齐备mj-body是邮件的画布与宽度基准默认 600pxmj-section是纵向堆叠的水平区块负责分区与统一背景/内边距mj-column是横向切分的响应式列自动等分或手动指定宽度gutter在 section 上声明、作用于所有列自动从列宽中扣除并转换为移动端的垂直间距padding负责处理列组与 section 边缘的留白。掌握body → section → column这一层骨架之后就可以放心地往列里填充mj-text、mj-image、mj-button、mj-divider、mj-social等标准组件完整组件清单可参考 doc/components_1.md 与 doc/components_2.md并将它们组合成一封结构清晰、跨客户端稳定的响应式邮件。【免费下载链接】mjmlMJML: the only framework that makes responsive email easy项目地址: https://gitcode.com/gh_mirrors/mj/mjml创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

OpenFang 内置 TypeScript 专家技能解读:从严格模式到类型级安全的 TypeScript 类型系统实战指南

OpenFang 内置 TypeScript 专家技能解读:从严格模式到类型级安全的 TypeScript 类型系统实战指南

人工智能大模型AI Agent自主智能体Agent 编排MCP Clients知识图谱 【免费下载链接】openfang Open-source Agent Operating System 项目地址: https://gitcode.com/gh_mirrors/op/openfang 点击查看 免费下载 导读 本文以 OpenFang 开源 Agent 操作系统中随二进制…

2026/9/21 15:46:55 阅读更多 →
agentic-awesome-skills 实战:用 apify-competitor-intelligence 构建跨平台竞品情报工作流

agentic-awesome-skills 实战:用 apify-competitor-intelligence 构建跨平台竞品情报工作流

AI 技能AI 插件 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,115 agentic skills. Includes CLI, local MCP, catalog, …

2026/9/21 15:45:50 阅读更多 →
Babysitter安全模型完全解析:信任边界、最小权限与凭证管理

Babysitter安全模型完全解析:信任边界、最小权限与凭证管理

Babysitter安全模型完全解析:信任边界、最小权限与凭证管理 【免费下载链接】babysitter Babysitter enforces obedience on agentic workforces and enables them to manage extremely complex tasks and workflows through deterministic, hallucination-free sel…

2026/9/21 15:45:50 阅读更多 →

最新新闻

舌尖毁了沈子钰实战避坑:3步搞定配置与高频面试题

舌尖毁了沈子钰实战避坑:3步搞定配置与高频面试题

舌尖毁了沈子钰实战避坑:3步搞定配置与高频面试题 配置环境就卡半天,是不是让你怀疑人生?明明照着文档敲,结果报错一堆,进度条转了半小时还没动静。这种痛苦,每个开发者都经历过。更尴尬的是,面试时遇到关于底层原理的 高频面试题…

2026/9/21 19:38:06 阅读更多 →
2026最新微信小号怎么申请?3个致命坑导致封号,手把手教你合规养号

2026最新微信小号怎么申请?3个致命坑导致封号,手把手教你合规养号

2026最新微信小号怎么申请?3个致命坑导致封号,手把手教你合规养号 你是不是也遇到过这种情况:想注册个微信小号用来接私活、测试消息推送或者隔离工作生活,结果照着网上那些“2026最新”的教程操作,要么手机号被占用,要么刚注册完就收不到验证…

2026/9/21 19:38:06 阅读更多 →
手机投屏电视怎么设置全解:新手避坑指南与底层逻辑

手机投屏电视怎么设置全解:新手避坑指南与底层逻辑

手机投屏电视怎么设置全解:新手避坑指南与底层逻辑 你是不是也遇到过这种情况?手里拿着手机,对着电视屏幕折腾半天,画面就是过不过去。或者好不容易连上了,卡得跟PPT一样,声音还不同步。很多教程只告诉你“点这个图标,选那个设备”,但一旦遇到连不…

2026/9/21 19:38:06 阅读更多 →
手写实现选择地址组件避坑指南

手写实现选择地址组件避坑指南

手写实现选择地址组件避坑指南 盯着屏幕上一长串红色的 StackTrace ,手指在键盘上悬停却敲不出下一个字符。这种因为 Address 组件报错而导致的页面崩溃,几乎是前端开发者职业生涯中的“初体验”。很多新人拿到一个现成的 UI…

2026/9/21 19:38:06 阅读更多 →
3分钟吃透fbx是什么格式,这份速查手册让你面试不慌

3分钟吃透fbx是什么格式,这份速查手册让你面试不慌

3分钟吃透fbx是什么格式,这份速查手册让你面试不慌 看了一堆教程还是不会写项目?别急,很多老鸟第一反应也是懵的。今天咱们不整虚的,直接给你一份 fbx是什么格式 的 速查手册 ,专门解决你在3D资产导入、游戏引擎对接时遇到的那些幺蛾子。…

2026/9/21 19:38:06 阅读更多 →
5个致命坑:一文搞懂五笔反查工具选型与避坑

5个致命坑:一文搞懂五笔反查工具选型与避坑

5个致命坑:一文搞懂五笔反查工具选型与避坑 看了一堆教程还是不会写项目?别急,这真不是你笨。很多开发者在做输入法辅助工具或文本处理系统时,盯着屏幕上的报错发呆,明明逻辑看着没错,一跑起来就崩。今天咱们不聊虚的,直接切入正题,帮你一文搞懂【五…

2026/9/21 19:37:05 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →