28

鉴于以下场景,为什么: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 调试器中看到样式;但是,它们不会显示在页面上。

4

5 回答 5

27

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

选择器级别 3

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

:before:after元素

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

内容属性

初始:

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

none -不生成伪元素。


应用于伪元素的样式会影响生成内容的显示::before。属性::after这个生成的内容,如果没有它,默认值是假定的,这意味着没有要应用的样式。contentcontent: none

如果您不想重复content:'';多次,您可以简单地通过全局样式化 CSS 中的所有元素::before::after伪元素来覆盖它(JSFiddle 示例):

::before, ::after {
    content:'';
}
于 2013-06-12T14:55:55.423 回答
20

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

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

  1. 在每个元素的开头和结尾都有空的内联内容是相当愚蠢的。请记住,伪元素::before::after伪元素的最初目的是在原始元素的主要内容之前和之后插入生成的内容。当没有要插入的内容时,创建一个额外的框只是为了不插入任何内容是没有意义的。所以none价值是告诉浏览器不要费心创建一个额外的盒子。

    仅出于布局美学的目的而使用空元素::before::after伪元素来创建附加框的做法相对较新,一些纯粹主义者甚至可能因此将其称为 hack。

  2. 在每个元素的开头和结尾都有空的内联内容意味着每个(非替换)元素(包括html和)body默认情况下不会生成一个框,而是最多三个框(如果元素已经生成更多框,则更多不仅仅是主框,比如带有列表样式的元素)。您将实际使用每个元素的两个额外框中的多少?这可能会使布局成本增加三倍而收益很小。

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

所以这些伪元素被选择加入——因为让它们选择退出不仅浪费系统资源,而且考虑到它们的原始目的,这完全不合逻辑。性能原因也是为什么我建议使用::before, ::after.

但是你可能会问:为什么不让display属性默认为noneon ::before, ::after?简单:因为的初始值display不是none; 它是inline。开启inline计算不是一种选择,因为那样你就永远无法内联显示它们none::before, ::after具有displaybe noneon的初始值::before, ::after不是一种选择,因为属性只能具有一个初始值。(这就是为什么 的初始值content总是normal并且它被简单地定义为计算到noneon ::before, ::after。)

于 2017-03-07T16:21:06.943 回答
9

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

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

原因是:

  • 根据定义,伪类是为页面的 HTML 标记指定的每个元素动态创建的
  • 所有页面元素,包括伪类,都必须具有要显示的内容属性。
  • HTML 元素<p>也可以,但您可以使用标记(使用 CSS 声明)快速设置它们的内容属性。
  • 但是,与非伪类元素不同,伪类不能在标记本身中赋予值。
    因此,所有伪类都是不可见的(它们的“内容”属性没有值),除非你告诉它们不可见(通过 CSS 声明赋予它们值)。

拿这个简单的页面:

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

我们知道这个页面不会显示任何内容,因为该<p>元素没有文本。更准确的表述方式是元素<p>的 content 属性没有 value

我们可以通过在 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 属性。
    因此,伪元素的 content 属性必须用 CSS 声明,才能显示。
于 2014-02-14T20:15:02.080 回答
5

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

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

于 2013-06-12T14:20:03.990 回答
1

2020 编辑

:before

是来自 CSS2 的语法以获得更好的实践,您应该编写来自 CSS3 的最新语法,即

::before

带双分号

完整的答案和区别可以在这里找到 ::before 和 ::before 有什么区别?

于 2020-10-23T10:39:20.333 回答