【翻译】Emmet(Zen Coding)官方文档 之二 缩写
【说明】本系列博文是依据 Emmet 官方文档翻译的,原文地址为:http://docs.emmet.io/,部分内容已经在博主之前的博文中节选过,为方便已经收藏过之前博文的朋友,没有删除这些博文,仅将其完整的收录于本系列中。
缩写
缩写是 Emmet 的核心:这些特殊的表达式在运行时被解析并翻译成结构化的代码块,比如 HTML。缩写的语法看上去很像带有用于生成代码的扩展的 CSS 选择器。许多 web 程序员已经知道如何使用它。
如下缩写
#page>div.logo+ul#navigation>li*5>a{Item $}
将生成:
<div id="page"> <div class="logo"></div> <ul id="navigation"> <li><a href="">Item 1</a></li> <li><a href="">Item 2</a></li> <li><a href="">Item 3</a></li> <li><a href="">Item 4</a></li> <li><a href="">Item 5</a></li> </ul> </div>
只需要按一个键。在很多编辑器(如 Eclipse、 Sublime Text 2 Espresso 等)中插件需要 tabstop 标记,所以只要在想要生成代码的地方按下 Tab 键,就会很快递归地生成代码。
缩写是优化的(但不限于)生成 HTML 和 XML 的方法,它可以使书写繁琐的标记变得轻而易举。可以通过掌握语法来释放 Emmet 缩写的威力。
缩写语法
Emmet 使用类似于 CSS 选择器的语法描述元素在生成的文档树中的位置及其属性。
元素
可以使用元素名(如 div 或者 p)来生成 HTML 标签。Emmet 没有预定义的有效元素名的集合,可以把任何单词当作标签来生成和使用:div
→ <div></div>
, foo
→ <foo></foo>
等。
嵌套运算符
嵌套运算符用于以缩写的方式安排元素在生成文档树中的位置:将其放在内部或成为相邻的元素。
子: >
可以使用 > 运算符指定嵌套元素在另一个元素内部:
div>ul>li
生成的结果为:
<div> <ul> <li></li> </ul> </div>
兄弟: +
使用 +
运算符将相邻的其它元素处理为同级:
div+p+bq
生成的结果为:
<div></div> <p></p> <blockquote></blockquote>
上升: ^
使用 >
运算符将会降低所有后续所有元素在生成树中的级别,每一级的兄弟元素也被解析成相同深度的元素:
div+div>p>span+em
将生成:
<div></div> <div> <p><span></span><em></em></p> </div>
使用 ^
运算符,能够提升元素在生成树中的一个级别,并同时影响其后的元素:
div+div>p>span+em^bq
将生成:
<div></div> <div> <p><span></span><em></em></p> <blockquote></blockquote> </div>
可以连续使用多个 ^
运算符,每次提高一个级别:
div+div>p>span+em^^^bq
将生成:
<div></div> <div> <p><span></span><em></em></p> </div> <blockquote></blockquote>
重复: *
使用 *
运算符可以定义一组元素:
ul>li*5
将生成:
<ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul>
分组: ()
括号用于在复杂的 Emmet 缩写中处理一组子树:
div>(header>ul>li*2>a)+footer>p
将生成:
<div> <header> <ul> <li><a href=""></a></li> <li><a href=""></a></li> </ul> </header> <footer> <p></p> </footer> </div>
如果想与浏览器 DOM 协同工作,可能想要对文档片段分组:每个组包含一个子树,所有的后续元素都插入到与组中第一个元素相同的级别中。
能够在组中嵌套组并且使用 *
运算符绑定它们:
(div>dl>(dt+dd)*3)+footer>p
将生成:
<div> <dl> <dt></dt> <dd></dd> <dt></dt> <dd></dd> <dt></dt> <dd></dd> </dl> </div> <footer> <p></p> </footer>
使用分组,可以使用单个缩写逐个写出整页的标签,不过尽量不要这么做。
属性运算符
属性运算符用于编辑所生成的元素的属性,在 HTML 和 XML 中可以快速地为生成元素添加 class
属性。
ID 和 CLASS
在 CSS 中,可以使用 elem#id
和 elem.class
注解来达到为元素指定 id
或 class 属性的目的。
在 Emmet 中,可以使用几乎相同的语法来为指定的元素添加这些属性:element:
div#header+div.page+div#footer.class1.class2.class3
生成:
<div id="header"></div> <div class="page"></div> <div id="footer" class="class1 class2 class3"></div>
自定义属性
可以使用 [attr]
注解(就像在 CSS 中一样)来为元素添加自定义属性:
td[title="Hello world!" colspan=3]
将生成:
<td title="Hello world!" colspan="3"></td>
- 能够在方括号中放置许多属性,
- 可以不为属性指定值:
td[colspan title]
将生成<td colspan="" title="">
,如果你的编辑器支持,可以使用 tab 来跳到每个空属性中填写。 - 属性可以用单引号或双引号作为定界符。
- 如果属性不包含空格,不需要用定界符括住它:
td[title=hello colspan=3]
是正确的。
编号: $
使用 *
运算符可以重复生成元素,如果带 $
就可以为它们编号。把 $
放在元素名、属性名或者属性值中,将为每个元素生成正确的编号:
ul>li.item$*5
将生成:
<ul> <li class="item1"></li> <li class="item2"></li> <li class="item3"></li> <li class="item4"></li> <li class="item5"></li> </ul>
使用多 $
可以填充前导的零:
ul>li.item$$$*5
将生成:
<ul> <li class="item001"></li> <li class="item002"></li> <li class="item003"></li> <li class="item004"></li> <li class="item005"></li> </ul>
改变编号的基数和方向
使用 @
,可以改变数字的走向(升序或降序)和基数(例如起始值)。
在 $ 后添加 @- 来改变数字走向:
ul>li.item$@-*5
将生成:
<ul> <li class="item5"></li> <li class="item4"></li> <li class="item3"></li> <li class="item2"></li> <li class="item1"></li> </ul>
在 $ 后面添加 @N 改变编号的基数:
ul>li.item$@3*5
将生成:
<ul> <li class="item3"></li> <li class="item4"></li> <li class="item5"></li> <li class="item6"></li> <li class="item7"></li> </ul>
这些附加的运算符可以同时使用:
ul>li.item$@-3*5
将生成:
<ul> <li class="item7"></li> <li class="item6"></li> <li class="item5"></li> <li class="item4"></li> <li class="item3"></li> </ul>
文本: {}
可以用花括号向元素中添加文本:
a{Click me}
将生成:
<a href="">Click me</a>
注意,这个 {text}
是被当成独立元素解析的(类似于 div
, p
),但当其跟在其它元素后面时则有所不同。例如, a{click}
和 a>{click}
产生相同的输出,但是 a{click}+b{here}
和 a>{click}+b{here}
的输出就不同了:
<!-- a{click}+b{here} --> <a href="">click</a><b>here</b> <!-- a>{click}+b{here} --> <a href="">click<b>here</b></a>
在第二示例中, <b>
元素放在了 <a>
元素的里面。差别如下:当 {text}
写在元素的后面,它不影响父元素的上下文。下面是展示这种差别的重要性的较复杂的例子:
p>{Click }+a{here}+{ to continue}
生成:
<p>Click <a href="">here</a> to continue</p>
在这个例子里, 我们用 > 运算符明确的将 Click here to continue
下移一级,放在 <p>
元素内,但对于 a
元素的内容就不需要了,因为 <a>
仅有 here
这一部分内容,它不改变父元素的上下文。
作为比较,下面是不带有 > 运算符的相同缩写:
p{Click }+a{here}+{ to continue}
生成:
<p>Click </p> <a href="">here</a> to continue
缩写格式的注意事项
当熟悉了 Emmet 的缩写语法后,可能会想要使用一些格式来生成更可读的缩写。例如,在元素和运算符之间使用空格间隔:
(header > ul.nav > li*5) + footer
但是这种写法是错误的,因为空格是 Emmet 停止缩写解析的标识符。
请多用户误以为每个缩写都应写在新行上,但是他们错了:可以在文本的任意位置键入和扩展缩写。
(此处原文使用脚本做了一段示例,限于博客的体例,我没有办法将原文的示例脚本放在本文中,因此用截屏工具录下了一段屏幕,放在此处,有兴趣的朋友,可以去原文地址去看原文中的示例)
这也就是为什么当想要停止解析和扩展时,Emmet 需要一些标志的原因。如果你仍然认为复杂的缩写需要一些格式使其更易读:
- 缩写不是模板语言,它们不需要”易读“,它们必须”可快速扩展和移动“。
- 不需要写复杂的缩写。不要认为在 web 编程中”键入“是最慢的运算。想快速找出构建单个的复杂缩写比构造和键入一些较短较简单的缩写更慢。
元素类型
在 HTML 和 XML 文档中,当展开缩写时,所有缩写部分都实时转换成 HTML/XML 标签。但是某些标签——如 a
或者 img
——转换成带有预定义属性的元素: <a href=""></a>
的 <img src="" alt="" />
。Emmet 怎么知道什么时候添加所需的属性呢?
所有元素定义都以如下格式存放在 snippets.json 文件中:
{ "html": { "abbreviations": { "a": "<a href=\"\">", "link": "<link rel=\"stylesheet\" href=\"\" />" ... }, "snippets": { "cc:ie6": "<!--[if lte IE 6]>\n\t${child}|\n<![endif]-->" ... } }, "css": { ... } }
正像上面的代码展示的那样,第一级定义了语法名称。语法一节内元素定义被分成了两个小节: snippets(片段) 和 abbreviations(缩写)。
Snippets(片段)
Snippets(片段)就是普通的代码块,和所有程序编辑中的普通代码一样。可以在这一部分键入任何内容,它将被原样输出。
Abbreviations(缩写)
Abbreviations(缩写)是带有数据提示的真实构建块。由于 Emmet 常用于书写 HTML/XML 标签,缩写定义使用 XML 格式来描述元素。
Emmet 解析缩写定义并检索以下数据:
- 元素名;
- 默认属性;
- 属性的顺序;
- 属性的默认值;
- 元素的关闭标签。
仔细观察上面的 HTML 缩写定义。link
元素的定义是 <link rel="stylesheet" href="" />
(双绰号被 JSON 忽略;或者用单绰号代替)。这个定义是说此标签是用来生成 link
的缩写,它被命名为 link 并且饮食两个属性:带有默认值 “stylesheet” 的 rel 和带有空值的 href (严格遵造顺序),并且生成的元素包含关闭标签。
当 link
缩写被展开时,将得到如下 HTML 输出:
<link rel="stylesheet" href="">
允许覆盖默认属性或者添加新属性:
link[rel=prefetch title="Hello world"]
生成:
<link rel="prefetch" href="" title="Hello world">
还可以添加子元素,这将强制 Emmet 输出关闭标签:
link>xsl:apply-templates
将输出:
<link rel="stylesheet" href=""> <xsl:apply-templates></xsl:apply-templates> </link>
Aliases(别名)
在 snippets.json
的缩写一节,还能够定义别名:常用缩写的短写形式。别名能够用来定义:
- 长标签的短名字;
- 常用缩写的引用。
在 snippets.json
文件中,可以找到如下定义:
...
"html": {
"abbreviations": {
"bq": "blockquote",
"ol+": "ol>li"
}
}
上面的示例中,当展开 bq
缩写,Emmet 会找到 blockquote
缩写的定义。如果它不存在,将简单的输出 <blockquote></blockquote>
元素。ol+
缩写的输出结果与 ol>li
相同。
ol+
定义可能会产生歧义,因为它的末尾包含 +
, + 还是 sibling(兄弟)运算符。
Emmet 正确地展开这些缩写,并且加号由于历史原因遗留了下来。需要记住的是,不要使用加号来创建缩写的别名。
隐式标签名称
即使拥有能够通过短缩写生成巨型 HTML 的最强劲的缩写引擎,书写标签仍然可能很繁琐。
许多情况下,可以跳过输入标签名,Emmet 能够替你补全它。例如,你可以用 .content 代替 div.content
,并将其展开至 <div class="content"></div>。
它是如何工作的呢
在展开缩写时,Emmet 试图捕捉上下文中的父元素,比如 HTML 元素,将缩写展开到父元素中。如果上下文捕捉成功,Emmet 使用它的名字来充当未写出的隐式标签名:
就像上面的例子展示的那样,Emmet 每次都寻找父标签的名字来作为要展开的缩写中的隐去的标签名。下面是一些父元素的解决规则:
li
的父元素为ul
和ol
tr
的父元素为table
,tbody
,thead
和tfoot
td
的父元素tr
option
的父元素为select
和optgroup
来看看一些缩写的隐式标签和显式标签的关系:
.wrap>.content |
div.wrap>div.content |
em>.info |
em>span.info |
ul>.item*3 |
ul>li.item*3 |
table>#row$*4>[colspan=2] |
table>tr#row$*4>td[colspan=2] |
“Lorem Ipsum” 生成
“Lorem ipsum” 虚拟文本是许多 web 程序员测试他们的 HTML 模板在带有真实数据时的外观的。程序员们经常用第三方服务来生成 “Lorem ipsum” 文本,但是现在他们可以在编辑器中这样做。展开 lorem
或 lipsum
缩写将生成如下片段:
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi non quis exercitationem culpa nesciunt nihil aut nostrum explicabo reprehenderit optio amet ab temporibus asperiores quasi cupiditate. Voluptatum ducimus voluptates voluptas?
lorem
不仅是正常的片段——它还是一个生成器。每次展开它,都将生成包含 30 个单词的虚拟文本,切割成几个句子。
可以在缩写中指定一些单词如何生成。例如,lorem100
将生成包含 100 个单词的虚拟文本。
重复 “Lorem ipsum”
可以在重复元素中使用 lorem
生成器来填充完整的随机语句。例如,p*4>lorem
缩写将生成如下的内容:
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Qui dicta minus molestiae vel beatae natus eveniet ratione temporibus aperiam harum alias officiis assumenda officia quibusdam deleniti eos cupiditate dolore doloribus!</p> <p>Ad dolore dignissimos asperiores dicta facere optio quod commodi nam tempore recusandae. Rerum sed nulla eum vero expedita ex delectus voluptates rem at neque quos facere sequi unde optio aliquam!</p> <p>Tenetur quod quidem in voluptatem corporis dolorum dicta sit pariatur porro quaerat autem ipsam odit quam beatae tempora quibusdam illum! Modi velit odio nam nulla unde amet odit pariatur at!</p> <p>Consequatur rerum amet fuga expedita sunt et tempora saepe? Iusto nihil explicabo perferendis quos provident delectus ducimus necessitatibus reiciendis optio tempora unde earum doloremque commodi laudantium ad nulla vel odio?</p>
而且,当 lorem
元素自我复制时,lorem
生成器可以利用隐式标签名,因此可以缩短缩写的写法:
ul.generic-list>lorem10.item*4
将生成:
<ul class="generic-list"> <li class="item">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam vero.</li> <li class="item">Laboriosam quaerat sapiente minima nam minus similique illum architecto et!</li> <li class="item">Incidunt vitae quae facere ducimus nostrum aliquid dolorum veritatis dicta!</li> <li class="item">Tenetur laborum quod cum excepturi recusandae porro sint quas soluta!</li> </ul>