为什么:之前和之后:伪元素需要“内容”属性?

鉴于以下情况,为什么afterselect器需要content属性才能运行?

.test { width: 20px; height: 20px; background: blue; position:relative; } .test:after { width: 20px; height: 20px; background: red; display: block; position: absolute; top: 0px; left: 20px; } 
 <div class="test"></div> 

请注意,除非指定内容属性,否则不会看到伪元素:

 .test { width: 20px; height: 20px; background: blue; position:relative; } .test:after { width: 20px; height: 20px; background: red; display: block; position: absolute; top: 0px; left: 20px; content:"hi"; } 
 <div class="test"></div> 

为什么这是预期的function? 你会认为显示块会强制显示元素。 奇怪的是,你实际上可以看到webdebugging器中的样式; 但是,它们不会显示在页面上。

以下是对各种W3C规范和草案的参考:

select器3级

可以使用':before'和'after'伪元素在元素的内容之前或之后插入生成的内容。

:之前和之后:伪元素

作者使用:before和:after伪元素指定生成内容的样式和位置。 正如它们的名字所表示的那样:before和之后:伪元素指定元素的文档树内容之前和之后的内容的位置。 'content'属性与这些伪元素一起指定了什么被插入。

内容属性

初始:

该属性与:before和之后的:伪元素一起用于在文档中生成内容。 值有以下含义:

none没有生成伪元素。


应用于:: before和:: after伪元素的样式会影响生成内容的显示。 content属性就是这个生成的内容,如果没有它,就会默认content: none的默认值,这意味着没有什么东西可以应用。

如果你不想重复的content:''; 多次,你可以简单地通过在你的CSS( JSFiddle示例 )中全局设置所有:: before和::之后的伪元素来覆盖它:

 ::before, ::after { content:''; } 

根据你对他人答案的评论,我相信你的问题实际上是:

为什么必须在CSS中设置伪类的内容属性,而不是非伪类的内容,这可以在HTML或CSS中设置?

原因是:

  • 根据定义,伪类是为页面的HTML标记指定的每个单元dynamic创build的
  • 所有页面元素(包括伪类)都必须具有要显示的内容属性。
  • <p>这样的HTML元素也可以,但是您可以使用标记( 使用CSS声明)快速设置其内容属性。
  • 不pipe怎样, 与非伪类元素不同 ,伪类本身不能被赋予值。
    所以, 除非你告诉他们不要 (通过用CSS声明给他们赋值), 否则 所有伪类都是不可见的 (他们的“内容”属性没有价值)。

拿这个简单的页面:

 <body> <p> </p> </body> 

我们知道这个页面什么也不显示,因为<p>元素没有文本。 一个更准确的方法来重写这个,是<p>元素的内容属性没有价值

通过在HTML标记中设置h1元素的content属性,我们可以很容易地改变它:

 <body> <p>This sentence is the content of the p element.</p> </body> 

这会在加载时显示,因为<p>元素的content属性有一个值; 该值是一个string:

 "This sentence is the content of the p element." 

或者,我们可以通过在CSS中设置<p>元素的content属性来显示<p>元素:

 p { content: "This sentence is the content of the p element set in the CSS."; } 

这两种将string注入<p>元素的方法是相同的。

现在,考虑用伪类来做同样的事情:

 HTML: <body> <p class="text-placeholder">P</p> </body> CSS: p:before { content: "BEFORE... " ; } p:after { content: " ...and AFTER"; } 

结果:

 BEFORE... P ...and AFTER 

最后,想象一下如何在使用CSS的情况下完成这个例子。 这是不可能的,因为没有办法在HTML标记中设置伪类的内容。

你可能很有创意,想像这样的事情可能会起作用:

 <p:before>BEFORE... </p> <p> P </p> <p:after> ...and AFTER</p> 

但是,它并不是,因为<p:before><p:after> 不是HTML元素

结论是:

  • 每个标记元素都存在伪类。
  • 它们默认是不可见的,因为它们没有内容属性被初始化。
  • 您不能使用HTML标记设置伪类的内容属性。
    因此,伪元素的内容属性必须用CSS声明声明才能被显示。

你需要一个content: ''的原因是content: ''每个::before和/或::after伪元素的声明是因为content的初始值是normal ,在::before::after伪元素上计算为none 。 看规格 。

content的初始值不是空string,而是对::before::after伪元素计算为none的值的原因是双重的:

  1. 在每个元素的开始和结尾都有空的内联内容是相当愚蠢的。 请记住::before::after伪元素的最初目的是在源元素的主要内容之前和之后插入生成的内容。 当没有内容可以插入时,创build一个额外的盒子来插入任何东西都是毫无意义的。 所以none价值是告诉浏览器不要打扰创build一个额外的盒子。

    使用empty ::before::after伪元素为布局美学的唯一目的创build附加框的做法是相对较新的,有些纯粹主义者甚至可能因为这个原因而称之为黑客行为。

  2. 在每个元素的开始和结尾处都有空的内联内容意味着每个(未被replace的)元素(包括htmlbody默认情况下不会生成一个框,而是最多三个框(对于已经包含元素的元素,生成的不仅仅是主体框,就像列表样式的元素一样)。 每个元素的两个额外框会有多less个实际使用? 这可能会使布局成本增加三倍 ,收益甚微。

    实际上,即使在这十年中,页面上的元素的不到10%仍然需要::before布局的伪元素::before::after

因此,这些伪元素是可选的,因为使它们退出不仅浪费了系统资源,而且在原来的目的下显然是不合逻辑的。 性能原因也是为什么我build议使用::before, ::after为每个元素生成伪元素。

但是你可能会问:为什么不把display属性默认为none ::before, ::after ? 简单:因为display的初始值不是none ; 它是inlineinline计算在::before, ::after不是一个选项,因为那么你永远不能显示他们内联。 display的初始值在::before, ::after::before, ::after不是一个选项,因为一个属性只能有一个初始值。 (这就是为什么content的初始值总是normal并且它简单地定义为在::before, ::after计算为none )。

在添加content: ... ,psuedo元素实际上不存在

设置其他样式属性不足以强制浏览器创build元素。