Emmet: 文本 `{text}` 与多 `$` 编号补零:文案填充与多位补零
前 8 课你学会了 Emmet 的 8 个 HTML 结构操作符(
>+^*().class#id[attr])和 1 个编号操作符($)。但有两类"语义"场景没解决——"按钮里塞 'Click me'"和"10 张卡片每张文案带 001、002"。前者靠{text}文本填充,后者靠多$补零。本课把这两个操作符组合起来,让你的简写从"造结构"升级到"造内容"。
1. 你将学到
- 文本填充
{text}的花括号语法(含特殊字符自动转义) {text}紧邻父级 vs>{text}嵌套:两种"位置模式"的差异- 编号
$与{text}组合:每行文案带数字(item 1, item 2, ...) - 多位补零
$$$$$$$$$:让 001、002、003 自动生成 - 起始值
$@N与反向$@-:从指定编号开始、倒序编号
2. 一个前端开发者的真实故事
(1) 痛点:标签造完了,文案还是要逐字手敲
Alice 在做产品落地页的"特性展示"区,需要 6 张卡片,每张卡片包含图标、标题、描述、按钮。她先用第 06 课的 () 和隐式标签写好了卡片结构:
section.features>(.card*6>i.icon+h3+p+button.btn)
结构 1 行就搞定了,Emmet 展开 6 张 card,每张含 icon、h3、p、button。但接下来 Alice 要给每张卡片写文案:标题"高性能"、"易用"、"可扩展"、"安全"、"跨平台"、"开源",描述每张 30 字,按钮文案"了解更多"重复 6 次。
Alice 一开始是手敲——展开后的 HTML 30+ 行空白标签,她逐个填文案。光填标题就花了 5 分钟,描述又 10 分钟,最后按钮"了解更多"敲了 6 遍(直接复制粘贴)。
更要命的是分页页码:100 页产品列表,每页底部有 <li>第 1 页</li> 到 <li>第 100 页</li>,Alice 写完 30 行就崩溃了。她试着用 $:(ul.pagination>li>a{第 $ 页})*100——展开后是 第 1 页 到 第 100 页,但前 9 页都是"第 1 页"、"第 2 页"这种单字符数字,看起来像 bug。她想要"01"、"02"、...、"99"、"100"——必须前 9 页两位补零、最后 10 页正常显示。
(2) {text} 与多 $ 补零的解法
Emmet 提供两个互补机制解决 Alice 的问题:
文本填充 {text}:把花括号内的内容作为标签的文本节点插入。Alice 的 6 张卡片可以这么写:
section.features>(.card*6>(i.icon)+h3{高性能}+p{这是第一张描述}+button.btn{了解更多})
但 6 张卡片每张文案不同,*6 不能简单重复文案——这时需要循环模板,配合 $ 编号使用。
编号 $ 与多位补零:$ 是当前序号,$$ 补零到 2 位,$$$ 补零到 3 位。Alice 的分页页码可以这么写:
(ul.pagination>li>a{第 $$ 页})*100
展开后是 第 01 页、第 02 页、...、第 99 页、第 100 页——前 9 页自动补零到 2 位,第 10 页起正常显示。
Alice 用一行简写重写整个特性区:
section.features>(h2{产品特性})+((.card>(i.icon)+h3{特性 $}+p{这是第 $ 个特性,共 6 个}+button.btn{了解更多})*6)
100 行分页:
(ul.pagination>li>a{第 $$ 页})*100
Alice 验证之后惊呼:"6 张卡片的文案从 30 行手写降到 1 行,100 行分页从 200 行降到 1 行。Emmet 在'批量造内容'场景的提效是 50 倍以上。"
(3) 收益
{text} 和多 $ 补零是 Emmet 处理"文案工厂化"的核心。前者让你在简写里直接写文案(不用展开后再填),后者让重复元素的序号自动跑、补零、起始、倒序。学完本课,Alice 写 6 张特性卡片只要 15 秒,100 行分页只要 10 秒;同时这一课也是 Phase 3 的第一课——下一课将进入 Lorem Ipsum 占位文案与隐式标签细节。
3. 文本填充 {text} 的定义
{text} 是 Emmet 给标签插入文本节点的语法。写在花括号内的内容会原样成为标签内部的文本——可以是任意字符(包括中文、空格、标点)。
(1) 简写规则
| 简写 | 展开结果 | 说明 |
|---|---|---|
a{Click me} |
<a href="">Click me</a> |
单标签 + 单段文案 |
p{Hello world} |
<p>Hello world</p> |
p 标签 + 文案 |
button{提交} |
<button>提交</button> |
中英文案均可 |
a{<strong>bold</strong>} |
<a href=""><strong>bold</strong></a> |
< > 自动转义为 HTML 实体 |
{text} 中的特殊字符(< > &)会被 Emmet 自动转义为 HTML 实体(< > &)。这是 HTML5 安全要求——避免用户输入的尖括号破坏文档结构。如果你想插入真正的 HTML 标签(如让 <strong> 被解析为标签而非文本),需要用第 13 课的"过滤器"或直接展开后手动修改。
(2) {text} 在标签内的位置
| 位置 | 简写 | 展开 |
|---|---|---|
| 紧跟标签名 | a{Click me} |
<a href="">Click me</a> |
配合 > 嵌套 |
p>{Click }+a{here} |
<p>Click <a href="">here</a></p> |
单独 {text} |
{ to continue} |
to continue(裸文本,作为独立元素) |
配合 $ 编号 |
li{item $}*3 |
<li>item 1</li>、<li>item 2</li>、<li>item 3</li> |
4. {text} 的两种位置:紧邻父级 vs 嵌套
这是 Emmet 文本填充最精妙的设计。{text} 紧跟标签名时,不改变父级上下文;但 >{text} 会把上下文推进一层。两者的区别是新手最常踩的坑。
(1) 紧邻模式 a{click}+b{here}
当 {text} 紧跟在标签名(无 > 前缀)后,文本被视为该标签的直接子节点,但不改变父级上下文——这意味着后续的 + 兄弟元素仍然和当前标签在同一层。
a{click}+b{here}
<a href="">click</a><b>here</b>
(2) 嵌套模式 a>{click}+b{here}
当 {text} 前加 > 时,Emmet 把 > 后的 {text} 视为子元素,并且把父级上下文推进到 a 内部——后续的 + 兄弟元素在 a 内部追加。
a>{click}+b{here}
<a href="">click<b>here</b></a>
(3) 多元素混合文本 p{Click }+a{here}+{ to continue}
这个官方文档的经典案例展示两种模式的差异:
p{Click }+a{here}+{ to continue}
<p>Click </p>
<a href="">here</a> to continue
p>{Click }+a{here}+{ to continue}
<p>Click <a href="">here</a> to continue</p>
<p> 内。差异来自 >:第一版的 {Click } 让 p 变成"有 click 文案的 p"(不再下钻),第二版的 >{Click } 让上下文从 p 推进到 p 内部,后续 +a{here} 和 +{ to continue} 都在 p 内部追加。
▶ 示例:基础文本填充 a{Click me}(难度⭐)
Emmet 官方文档的首个文本填充案例——给 a 标签加一段文案。
缩写:
a{Click me}
展开:
<a href="">Click me</a>
输出:
TEXT 📖 仅展示解析:a 是标签名(默认带 href=""),{Click me} 是文本节点。Emmet 自动为 a 添加 href="" 属性(HTML5 默认行为),文本 "Click me" 作为 a 的子节点。注意:a 标签后的 {text} 不会改变父级上下文——如果后面接 +b{some},b 会与 a 平级,而不是 a 的子节点。
▶ 示例:多元素混合文本 p>{Click }+a{here}+{ to continue}(难度⭐⭐)
用嵌套模式把"Click here to continue"完整放进 <p> 内。
缩写:
p>{Click }+a{here}+{ to continue}
展开:
<p>Click <a href="">here</a> to continue</p>
输出:
TEXT 📖 仅展示解析:p>{Click } 让上下文推进到 p 内部,"Click " 是 p 的第一个文本子节点;+a{here} 在 p 内部追加一个带 "here" 文案的 a;+{ to continue} 在 p 内部追加裸文本 " to continue"。最终 p 内有 3 个子节点:文本 "Click "、a 标签、文本 " to continue"。如果不写 >(即 p{Click }+a{here}+{ to continue}),p 就只含 "Click ",a 和裸文本会成为根级兄弟——结果是 <p>Click </p> 后跟 <a>here</a> 和裸文本。
5. 编号 $ 与多位补零
$ 是 Emmet 的编号占位符(第 08 课已介绍)。本课扩展它的两个高阶用法:多位补零与起始/反向控制。
(1) 多位补零 $$ $$$ $$$$
第 08 课用单 $ 生成 1、2、3。当数字范围超过 9 时(如 100 行表格的序号),单 $ 会显示为 1、2、...、9、10、11(混合位数)。多位 $ 让编号自动补零到指定位数:
$ 数 |
展开形态(*5) |
适用场景 |
|---|---|---|
$ |
1, 2, 3, 4, 5 | 简单列表 |
$$ |
01, 02, 03, 04, 05 | 小型列表、月份 |
$$$ |
001, 002, 003, 004, 005 | 订单号、表格行 ID |
$$$$ |
0001, 0002, ... | 千行以上表格、章节号 |
$ 的个数决定补零的最小位数。如果实际数字超过这个位数,Emmet 不截断——*12 用 $$ 会展开为 01, 02, ..., 09, 10, 11, 12(前 9 个补零,后 3 个正常)。这是"补零位数 = 最小宽度"的语义。
(2) 起始值 $@N 与反向 $@-
默认编号从 1 升序。用 @N 改为从 N 开始,用 @- 改为降序:
| 修饰符 | 含义 | 示例(*5) |
|---|---|---|
$(默认) |
升序,从 1 | 1, 2, 3, 4, 5 |
$@3 |
升序,从 3 开始 | 3, 4, 5, 6, 7 |
$@- |
降序(迭代次数 → 1) | 5, 4, 3, 2, 1 |
$@-3 |
降序,从 3 开始倒推 | *5 → 7, 6, 5, 4, 3(按 @-3 起始值 3 + 降序,迭代次数叠加) |
$@-3 在 Emmet 1.2+ 支持;常见组合是 $@N(起始值)和 $@-(降序起始于迭代次数)。@N 中 N 是起始值,不是结束值。
▶ 示例:编号 + 文本 ul>li{item $}*3(难度⭐)
把 $ 嵌入 {text} 文本,让每个 li 文案带自动编号。
缩写:
ul>li{item $}*3
展开:
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
输出:
TEXT 📖 仅展示解析:li{item $} 是"li 标签 + 一段文本(item + 当前编号)",*3 让这个模板重复 3 次。每次重复,$ 被替换为当前迭代编号(1、2、3)。最终 3 个 li 各自包含一段 "item N" 文案。这是 Emmet 在"待办清单"、"特性列表"、"FAQ 序号"等场景的核心模式。注意:item 后有一个空格,这是文本的一部分(不是操作符)。
▶ 示例:补零 ul>li{$$}*5(难度⭐)
2 位补零——前 9 个元素自动补零,超过 9 正常显示。
缩写:
ul>li{$$}*5
展开:
<ul>
<li>01</li>
<li>02</li>
<li>03</li>
<li>04</li>
<li>05</li>
</ul>
输出:
TEXT 📖 仅展示解析:$$ 表示"当前编号用 2 位数字显示"。*5 让 li 重复 5 次,每次的 $ 值是 1、2、3、4、5——经过 2 位补零后变成 01、02、03、04、05。如果 *12,会展开为 01、02、...、09、10、11、12——前 9 个补零,后 3 个超过 2 位则正常显示(不截断)。补零场景:分页页码、月份、产品 SKU 编号。
▶ 示例:起始值 + 反向 ol>li{Step $@3}*5(难度⭐⭐)
从 3 开始升序的 5 步流程——用 $@3 控制起始值。
缩写:
ol>li{Step $@3}*5
展开:
<ol>
<li>Step 3</li>
<li>Step 4</li>
<li>Step 5</li>
<li>Step 6</li>
<li>Step 7</li>
</ol>
输出:
TEXT 📖 仅展示解析:$@3 表示"当前编号从 3 开始"。ol>li 让 li 成为 ol 的有序子项;{Step $@3} 是文本模板,"Step " 是固定字符串,$@3 是从 3 开始的当前编号。*5 让 li 重复 5 次,编号依次为 3、4、5、6、7。这是 Emmet 在"分页页码从某页开始"、"产品章节从第 3 章开始"、"步骤编号不从 1 开始"等场景的标准模式。如果想反向(从 5 降到 1),改用 $@-(基于迭代次数自动倒推)。
6. 完整示例:分页器 + 编号 + 文本填充
把 {text}、多 $ 补零、$@N 起始值组合起来——一个有 100 页的分页器,每页用 2 位补零显示。
▶ 示例:100 页分页器(难度⭐⭐)
缩写:
(ul.pagination>li.page$$>a{第 $$ 页})*100
展开(节选):
<ul class="pagination">
<li class="page01"><a href="">第 01 页</a></li>
<li class="page02"><a href="">第 02 页</a></li>
<li class="page03"><a href="">第 03 页</a></li>
<!-- ... -->
<li class="page09"><a href="">第 09 页</a></li>
<li class="page10"><a href="">第 10 页</a></li>
<li class="page11"><a href="">第 11 页</a></li>
<!-- ... -->
<li class="page99"><a href="">第 99 页</a></li>
<li class="page100"><a href="">第 100 页</a></li>
</ul>
输出:
TEXT 📖 仅展示解析:本例综合了本课全部操作符——{} (文本填充)、$ (编号)、$$ (2 位补零)、() (分组)、* (乘法)、.class、> (嵌套)。外层括号让整个 li 模板成为可重复单元;li.page$$ 同时在 class 名和 {text} 中使用 $$,确保 class 和文案编号一致;a 标签作为 li 的子节点,文案是"第 XX 页"。注意:100 页分页的实际 HTML 有 100 个 li,本节选只展示前 3、9-11、99-100。补零位数 = 2:前 9 页是 01-09,第 10 页起超过 2 位则正常显示(10、11、...)。如果想要 3 位补零(001-100),改用 $$$。
❓ 常见问题
{text} 中写尖括号 < > 会被怎么处理?< 变 <、> 变 >、& 变 &。这是 HTML5 安全要求,避免用户输入破坏文档结构。所以 a{<strong>bold</strong>} 展开为 <a href=""><strong>bold</strong></a>(尖括号变成实体字符,浏览器显示为纯文本 "<strong>bold</strong>",不会解析为标签)。如果想插入真正的 HTML 标签,需要用过滤器或手动修改。a{click}+b{here} 和 a>{click}+b{here} 展开后有什么关键区别?<a>click</a><b>here</b>;后者(嵌套模式)把 <b> 嵌入 <a> 内:<a>click<b>here</b></a>。关键差异在 >:紧邻模式不改变父级上下文,嵌套模式把上下文推进一层。判断口诀——"花括号前有 > 就进一层,没有就保持原层"。这是 Emmet 文本填充最精妙的设计,新手必须掌握的边界。$ 同一个 {text} 块内能多次出现吗?多个 $ 是同一编号还是不同编号?{text} 块内的所有 $ 共享同一个编号(即当前迭代计数)。例如 li{item $: 第 $ 个}*3 展开为 <li>item 1: 第 1 个</li>、<li>item 2: 第 2 个</li>、<li>item 3: 第 3 个</li>。多个 $ 主要用于补零位数控制($ 显示原始编号、$$ 2 位补零、$$$ 3 位补零)。如果想让同一元素内的不同 $ 显示不同编号(如 i=1, j=2),需要嵌套多个 * 重复结构。$@N 的 N 可以是负数吗?N=0 是什么意思?$@-5*3 表示从 -5 开始升序(-5、-4、-3);$@0*3 表示从 0 开始升序(0、1、2)。但实际开发中很少用负数或 0 作为起始值(HTML 中负数序号无意义,0 作为起始会跳过 1)。常见用法:$@1 显式从 1 开始(与默认行为等价,但代码更明确)、$@100 从 100 开始(分页深页场景)。反向用 $@-,不要混用 $@-N。📖 小节
{text}是文本填充语法,把花括号内内容作为标签的文本节点(如li{item $}*3→ "item 1"、"item 2"、"item 3"){text}中的<>&自动转义为 HTML 实体(<>&)- 紧邻模式
a{text}不改变父级上下文,嵌套模式a>{text}推进上下文一层 $是编号占位符,多$自动补零:$$2 位、$$$3 位、$$$$4 位(补零位数 = 最小宽度,超过不截断)$@N从 N 开始编号,$@-降序(基于迭代次数)
📝 作业
- 基础题(难度⭐):用一行 Emmet 简写分别展开为:(a) 一个
button{Sign Up}标签;(b) 一个<strong>标签带文案 "Warning";(c) 一个p>lorem段落(即<p>Lorem ipsum...</p>,本课不涉及,下课展开 Lorem)。 - 进阶题(难度⭐⭐):写一个 12 项"月份列表"
ol>li{第 $$ 月}*12,验证展开结果(应为"第 01 月"到"第 12 月")。然后改写为"季度列表"ol>li{第 $ 季度}*4,验证编号为 1-4。再写一个"产品特性区",包含 5 张卡片,每张卡片有<h3>Feature $</h3>和<p>Description for feature $</p>,要求完全用一行 Emmet 简写。 - 挑战题(难度⭐⭐⭐):编写一个 100 页分页器,每页用 3 位补零(
第 001 页到第 100 页)。要求:(a) class 用page$$$(3 位补零);(b) 文本用第 $$$ 页(3 位补零);(c) 起始页用$@1(与默认行为一致但显式声明)。用一行 Emmet 简写验证展开结果,并解释为什么$$$在超过 99 时不会截断为 3 位(提示:Emmet 补零 = 最小宽度,不是最大宽度)。