定义列表用CSS来插入换行
通过CSS插入换行的情况一般与定义列表有关。通常情况下,采用定义列表是因为我们坚持使用合适的标签、合理的语义——哪怕在视觉上所要呈现的只是一行行的名值对,我们也会认真对待。
举例来说,考虑下面这段结构代码:
<dl> <dt>Name:</dt> <dd>Lea Verou</dd> <dt>Email:</dt> <dd>lea@verou.me</dd> <dt>Location:</dt> <dd>Earth</dd> </dl>
我们希望视觉效果就像下图那样简单。
第一步通常是给它增加一些基本的CSS:
dd{
margin:0;
font-weight:bold;
}
不过,由于这些<dt><dd>
都是块级元素,我们最终得到的往往是所有名和值均独占一行的效果。我们接下来会给这两个元素重新设置一个display
属性值。
dt,dd{
display:inline;
}
如果你不在乎表现型的结构标记,可以请出老套的<br>
元素,就像这样:
<!-- 这样写死的很快 --> <dt>Name:</dt> <dd>Lea Verou<br /></dd> ...
这种方法在可维护性方面很糟糕,而且还污染了结构层的代码。如果我们只要使用生成性内容来增加行,并以此来取代<br>
元素,那么问题就可以解决了!但好像做不到,对吧?又或者,这是可行的?
实际上,Unicode字符有一个专门代表换行符的:0x000A
。在CSS中可以写作“\000A”,或简化为“\A”。我们可以用它来作为::after
伪元素的内容,将它增加到每个<dd>
元素的尾部。
dd::after{
content:"\A";
}
增加后,我们发现好像没什么变化。这并不表示我们思路不对,只是我们还忽略了什么。
这点CSS代码所做的其实只相当于在HTML结构中的所有关闭标签</dd>
之前增加了换行符。而我们编辑HTML源代码时,敲击一个换行符只不过是改变了格式,HTML会把换行符与其相邻的空白符进行合并。这时候,我们希望保留源代码中的这些空白符号和换行应该怎么办呢?
因为<dd>
伪元素里面没有其他的空白符号,我们可以用white-space:pre;
来做。这里面的pre\pre-line\pre-wrap
都可以实现这个效果,我们推荐用pre
是因为它的浏览器支持度更好。
整理下代码,我们亲自测试下,发现它的确有效果:
dt,dd{display:inline;}
dd{
margin:0;
font-weight:bold;
}
dd::after{
content:"\A";
white-space:pre;
}
不过,这种方法还有待改善?假设我们要给定义列表中的这位用户增加第二个邮箱(第二个<dd>
)呢?结果它的第二个邮箱会另起一行,而我们希望它还在同一行里。
在理想情况下,我们只想对<dt>
之后的最后一个<dd>
来插入换行,而不是对所有的<dd>
都这样做。不过,这对于当前CSS选择符的功能来说还是不能的,因为选择符无法做到先在DOM树中选中主体元素,再倒回去查询它之前的元素。我们需要换种方式思考。一个想法就是换行符不用加在<dd>
的后面,而是加在<dt>
的前面:
dt::before{
content:"\A";
white-space:pre;
}
这样会导致第一行变为空行,因为选择符对第一个<dt>
也生效。为了避免这个问题,我们可以尝试使用下列选择符来替换代替单纯的dt:
dt:not(:first-child)
dt ~ dt
dd + dt
我们建议采取最后一种方式,因为这样可以避免一个文档中有多个<dt>
组共同使用的情况。在理想情况下,我们还希望告诉浏览器“只在后面跟着一个<dd>
的<dd>
尾部插入逗号”,但我们又一次遇到的那个限制,眼下的CSS选择器表达不出这种需求。所以,我们可以在每个前面有<dd>
的<dd>
头部插入逗号。最终代码效果如下:
dd+dt::before{
content:'\A';
white-space:pre;
}
dd+dd::before{
content:',';
font-weight:normal;
}