算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
email-html-mjml【设计与创意】Responsive HTML email template generation using MJML 5.x framework. Use when the user asks to create, generate, design, or build an email template — including welcome emails, promotional blasts, transactional templates, newsletters, or any responsive email. Also use when the user asks to compile MJML to HTML, work with or edit existing MJML templates…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
.mjml files, or troubleshoot email rendering issues across clients.
license: MIT
compatibility: Requires Node.js 20 or later (LTS 20/22/24) for npx mjml compilation. Install MJML per project (npm install -D mjml). Works with Claude Code and Claude.ai.
metadata:
author: Framix
version: 2.0.0
documentation: https://github.com/framix-team/skill-email-html-mjmlGenerate valid, cross-client MJML 5.x templates and compile them to production-ready HTML. The primary goal is compatibility: Outlook (2013–365), Gmail (web/app), Apple Mail, and major mobile clients. Every output must be compilable with --config.validationLevel=strict and survive Gmail's 102KB clip limit.
<mjml> with a full <mj-head>compilation.md. Run npx mjml with --config.minify=true.mjml source AND compiled .html<mj-column> inside <mj-section>. Sections cannot be nested.<mj-group> to prevent mobile stacking for side-by-side elements (social bars, logo rows). Use <mj-section gutter="..."> for equal spacing between columns instead of padding tricks.<mj-font> for web fonts (prevents Times New Roman fallback). Always provide a fallback stack (Arial, sans-serif). For <mj-section> background images, always set both background-size and a fallback background-color.inline="inline" on <mj-style> for custom CSS. Prefer component attributes (color, font-size) over CSS classes for critical styles.<mj-image> MUST have alt. Always set <mj-title> (populates aria-label). Maintain WCAG 2.1 AA 4.5:1 contrast. For heading roles, use mj-html-attributes — direct role/aria-level attributes on mj-text are illegal under strict validation (see Accessibility Checklist below).<mj-attributes> with <mj-all>, component defaults, and <mj-class> to eliminate repetitive inline styles.<mj-hero> for full-bleed hero banners; it falls back to a regular section in unsupported clients. Avoid <mj-accordion> and <mj-carousel> — client support is too poor to be useful.{{firstName}}) need no wrapping — they pass through text, attributes, mj-title and mj-preview untouched. Only block tags containing < or > ({% if x < 5 %}, {{#if a<b}}) need <!-- htmlmin:ignore --> protection, or minify silently corrupts them. An <mj-raw> between content components inside a column emits its content between </tr> and <tr> — invalid markup; put mj-raw between sections, and keep templating tags out of <mj-style> (see compilation.md).MJML 5 mj-include is disabled by default:
<mj-include> tags are silently ignored unless includes are explicitly enabled — a deliberate security change from MJML 4--config.allowIncludes true. Node API: pass ignoreIncludes: false--config.includePath (CLI) or includePath (Node) — only MJML, HTML, and CSS includes are supported--config.validationLevel=strict does not catch this — a dropped include still exits 0 and still writes the .html. A clean compile is NOT proof the include landed; grep the output for known partial content before deliveringOutlook:
<mj-section> and <mj-hero> — nowhere elsetop, center, bottom) — pixel values ignoredbackground-repeat="no-repeat" with explicit background-size<mj-font> hides @font-face from Outlook via MSO conditional commentsGmail:
--config.minify=trueiOS / Android stacking:
htmlnano collapses runs to a single space where html-minifier removed them (verified: v4 emits <![endif]--><div class="mj-column-per-50", v5 emits <![endif]--> <div ...). The anti-stacking defence that still works is the font-size:0px MJML puts on the parent <td>, which is emitted in both versions--config.minifyOptions '{"collapseWhitespace":"all"}' (JSON string form required)<mj-group>Vertical-align bug:
vertical-align, ALL columns in that section must explicitly set itJavaScript:
onclick, no clipboard API, no interactivity of any kind. Interactive-looking elements (copy buttons, toggles) are purely decorative.<mj-head>
<mj-raw>
<meta name="color-scheme" content="light dark">
<meta name="supported-color-schemes" content="light dark">
</mj-raw>
<!-- Light logo visible by default; dark logo hidden -->
<mj-style inline="inline">
.dark-logo { display: none !important; }
</mj-style>
<!-- Dark mode overrides -->
<mj-style>
@media (prefers-color-scheme: dark) {
.light-logo { display: none !important; }
.dark-logo { display: block !important; }
}
</mj-style>
</mj-head>
Safe neutrals: #121212 (not #000000) and #F1F1F1 (not #FFFFFF) — prevents jarring forced inversions.
<mj-title> is set (screen reader email label + aria-label)lang attribute on root <mjml> tagalt on every <mj-image> and <mj-social-element>mj-html-attributes (NOT as a direct attribute on mj-text):
<!-- In mj-head -->
<mj-html-attributes>
<mj-selector path=".email-heading div">
<mj-html-attribute name="role">heading</mj-html-attribute>
<mj-html-attribute name="aria-level">1</mj-html-attribute>
</mj-selector>
</mj-html-attributes>
<!-- On the component -->
<mj-text css-class="email-heading" ...>Heading text</mj-text>
<mj-text> blocksBefore writing any MJML, read the component file(s) for the components you'll use.
| Group | Components | Load when | File |
|---|---|---|---|
| Head | mj-attributes, mj-font, mj-style, mj-preview, mj-breakpoint, mj-html-attributes | Setting up head, global styles | components/head.md |
| Layout | mj-body, mj-section, mj-column, mj-group, mj-wrapper | Building structure / grid | components/layout.md |
| Content | mj-text, mj-image, mj-button, mj-divider, mj-spacer, mj-table | Adding content blocks | components/content.md |
| Interactive | mj-accordion, mj-carousel, mj-social, mj-navbar | Interactive or social elements | components/interactive.md |
| Advanced | mj-hero, mj-raw, mj-include | Hero banners, template tags, partials | components/advanced.md |
General reference (hierarchy, ending tags, validation, width math, Gmail clip): mjml-reference.md
Read compilation.md for the full workflow. Key command:
npx mjml template.mjml -o dist/template.html --config.minify=true --config.validationLevel=strict
Hard rules:
npm install -g mjmlnpx or ./node_modules/.bin/mjmlpackage.json, suggest npm install -D mjmlAll four compile clean under --config.validationLevel=strict --config.minify=true on MJML 5.4.0.
| File | Use as a reference for |
|---|---|
assets/examples/basic-layout.mjml | Structure only. MJML docs example: 6-section layout (header, image hero + button, intro, 2-col image+text, 3-col icons, social row). Intentionally bare-bones — no mj-head, no dark mode, placeholder copy. Not a production template. |
assets/examples/order-confirmation.mjml | Transactional. Full mj-head (mj-attributes + mj-class + mj-font + mj-html-attributes), receipt mj-table with scope="col" headers, Handlebars in mj-raw with htmlmin:ignore, conditional block, and mj-include of partials/footer.mjml. Requires --config.allowIncludes true. |
assets/examples/promo-sale.mjml | Promotional. mj-hero and mj-section background images (VML generated), mj-navbar, mj-group non-stacking row, mj-social, mj-breakpoint, plus the MJML 5 gutter / border / inner-padding attributes. |
assets/examples/newsletter.mjml | Editorial + dark mode. The full dark-mode pattern from above, mj-wrapper, mj-html-attributes for aria-level 1 and 2, and vertical-align set on every column in each section. |
All copy, image URLs, and brands in these files are placeholders — replace them; do not ship them as-is.
Always deliver:
<name>.mjml — complete MJML source (editable, version-controllable)<name>.html — compiled output (production-ready, send via ESP)Name files after the email type: welcome.mjml, promo-sale.mjml, order-confirmation.mjml