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

Dav*_*e C 18 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;
}
Run Code Online (Sandbox Code Playgroud)
<div class="test"></div>
Run Code Online (Sandbox Code Playgroud)

注意在指定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";
}
Run Code Online (Sandbox Code Playgroud)
<div class="test"></div>
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*lly 22

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

选择者等级3

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

:之前和:之后的伪元素

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

内容属性

首字母:

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

none - 不生成伪元素.


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

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

::before, ::after {
    content:'';
}
Run Code Online (Sandbox Code Playgroud)

  • display:none on :: before和:: after与content:none具有完全相同的效果在任何情况下都包括计数器.如果您更习惯使用display属性来隐藏伪元素,那么您可以这样做.如果特异性是个问题,切换到其他属性也很有用. (3认同)

JAG*_*AGP 8

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

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

原因是:

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

拿这个简单的页面:

<body>
<p> </p>
</body>
Run Code Online (Sandbox Code Playgroud)

我们知道此页面不会显示任何内容,因为该<p>元素没有文本.重新表述这方面的一个更准确的方法,就是<p>元素的内容属性没有值.

我们可以通过在HTML标记中设置h1元素的content属性来轻松更改它:

<body>
<p>This sentence is the content of the p element.</p>
</body>
Run Code Online (Sandbox Code Playgroud)

现在将在加载时显示,因为<p>元素的content属性具有值; 该值是一个字符串:

"This sentence is the content of the p element."
Run Code Online (Sandbox Code Playgroud)

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

p { content: "This sentence is the content of the p element set in the CSS."; }
Run Code Online (Sandbox Code Playgroud)

这两种将字符串注入<p>元素的方法是相同的.

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

HTML:
  <body>
      <p class="text-placeholder">P</p>
  </body>

CSS:
  p:before { content: "BEFORE... " ; }
  p:after { content: " ...and AFTER"; }
Run Code Online (Sandbox Code Playgroud)

结果:

BEFORE...  P ...and AFTER
Run Code Online (Sandbox Code Playgroud)

最后,想象一下如何在使用CSS的情况下完成此示例.这是不可能的,因为无法在HTML标记中设置伪类的内容.

你可能很有创意,想象这样的事情可能有用:

<p:before>BEFORE... </p>
<p> P </p>
<p:after> ...and AFTER</p>
Run Code Online (Sandbox Code Playgroud)

但是,这不,因为<p:before><p:after> 没有HTML元素.

结论:

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


SLa*_*aks 5

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

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


Bol*_*ock 5

你需要一个原因content: ''为每个声明::before和/或::after伪元素是因为初始值content就是normal,它计算到none::before::after伪元素.请参阅规格.

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

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

    使用空元素::before::after伪元素来创建用于布局美学的唯一目的的附加框的做法相对较新,并且一些纯粹主义者甚至可能因为这个原因而将其称为黑客.

  2. 具有每个元素的开始和结束时清空联内容意味着每一个(非替代)元素-包括htmlbody默认会生成没有一个盒子,但到- 3盒(和更多在已经产生多种元素的情况下,而不仅仅是主要的盒子,就像列表样式的元素一样).你实际使用的每个元素中有多少个额外的盒子?这可能会使布局成本增加三倍而获得的收益微乎其微.

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

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

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

  • @Michael_B:我猜他们计划让内容与真实元素一起工作,然后最终将其推迟到CSS3(propdef说“在元素上,总是计算为‘正常’。”即使该属性不适用于一开始的元素)。将初始值设置为 none 意味着整个页面都会消失...直到您添加 `html, body, body * { content: normal }` 因此,为了允许 CSS3 的定义,将初始值设置为正常更有意义,这然后计算 ::before、::after 为 none,因为“通常”根本不需要伪类。 (2认同)