定义列表用CSS来插入换行

 2016-10-05 09:39

通过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来插入换行

第一步通常是给它增加一些基本的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;
}


作者头像

作者:紫铜炉

自由博主,网页设计师。我关注科技产品和个人博客发展,注重用户体验和界面优化。

 发表评论: