为什么:before和:after伪元素需要'content'属性?

时间:2013-06-12 14:18:25

标签: css pseudo-element css-content

鉴于以下情况,为什么:after选择器需要内容属性才能运行?

.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>

注意在指定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;
    content:"hi";
}
<div class="test"></div>

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

5 个答案:

答案 0 :(得分:21)

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

Selectors Level 3

  

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

The :before and :after pseudo-elements

  

作者使用:before和:after伪元素指定生成内容的样式和位置。正如其名称所示,:before和:after伪元素指定元素文档树内容之前和之后的内容位置。 'content'属性与这些伪元素一起指定插入的内容。

The content attribute

  

首字母:

     

此属性与:before和:after伪元素一起使用,以在文档中生成内容。值具有以下含义:

     

- 未生成伪元素。


应用于:: before和::之后伪元素的样式会影响生成内容的显示。 content属性这个生成的内容,如果没有它,则会假定默认值为content: none,这意味着没有任何内容可以应用于该样式。

如果你不想多次重复content:'';,你可以简单地通过全局样式化CSS中的所有:: before和:: after伪元素来覆盖它:JSFiddle example)< / p>

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

答案 1 :(得分:7)

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

  

为什么必须在CSS中设置伪类的content属性,如   反对非伪类的内容,可以在其中设置   HTML还是CSS?

原因是:

  • 根据定义,为页面的HTML标记指定的每个元素动态创建伪类
  • 所有页面元素(包括伪类)都必须具有要显示的内容属性。
  • <p>这样的HTML元素也可以,但您可以使用标记(与CSS声明)快速设置其内容属性。
  • 不管怎样,与非伪类元素不同,伪类不能在标记本身中给出值。
    因此,所有伪类都是不可见的(它们的'内容'属性没有值)除非你告诉它们不是(通过用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属性具有值;该值是一个字符串:

"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."; }

这两种将字符串注入<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标记为伪类设置content属性 ∴因此,必须使用CSS声明声明伪元素的content属性才能显示。

答案 2 :(得分:5)

您需要为每个content: ''和/或::before伪元素::after声明的原因是因为content的初始值为normal,在none::before伪元素上计算::after。请参阅spec

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

  1. 在每个元素的开头和结尾都有空的内联内容是相当愚蠢的。请记住,::before::after伪元素的最初目的是在原始元素的主要内容之前和之后插入生成的内容。如果没有要插入的内容,创建一个仅插入任何内容的附加框是没有意义的。因此,none值告诉浏览器不要打扰创建一个额外的框。

    使用空的::before::after伪元素来创建额外的盒子只是为了布局美学的做法相对较新,有些纯粹主义者甚至可能称之为因此而破解。

  2. 在每个元素的开头和结尾都有空的内联内容意味着每个(未替换的)元素 - 包括htmlbody - 默认情况下不会生成一个框,但是最多三个框(如果元素已经生成的不仅仅是主框,那么更多,就像列表样式的元素一样)。您实际使用的每个元素中有多少个额外的盒子?这可能会使布局成本三倍,但收益很少。

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

  3. 所以这些伪元素是选择加入的 - 因为选择它们不仅浪费系统资源,而且仅仅因为它们的原始目的而显得不合逻辑。性能原因也是我建议使用::before, ::after为每个元素生成伪元素的原因。

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

答案 3 :(得分:3)

在添加content: ...之前,伪元素实际上不存在

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

答案 4 :(得分:0)

2020编辑

:before

CSS2的语法是更好的做法,您应该编写CSS3的最新语法,

::before

带有双分号

完整的答案和不同之处可以在这里找到: What is the difference between :before and ::before?