这里有一个包含一些子元素的容器
<div class="container">
<div>item</div>
<div>item</div>
<div>item</div>
</div>
如果我这样做
.container::before {
content: "x"
}
我本质上是在做
<div class="container">
[[[ ::before psuedo-element here ]]]
<div>item</div>
<div>item</div>
<div>item</div>
</div>
这将像子元素一样工作,大多数时候。 一个棘手的事情是,除了用于创建它的那个选择器(或类似的选择器,实际上是::before
或::after
,最终出现在同一个位置),没有其他选择器可以选择它。
为了说明,假设我将该容器设置为 2×3 网格,并将每个项目设置为某种药盒设计
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 0.5rem;
}
.container > * {
background: darkgray;
border-radius: 4px;
padding: 0.5rem;
}
没有伪元素,它将是这样的

如果我像上面那样添加那个伪元素选择器,我将得到这个

这很有道理,但它也可能让人感到意外。 伪元素通常是装饰性的(它们几乎应该只用于装饰),因此让它参与内容网格感觉很奇怪。
请注意,.container > *
选择器没有选择它并将其设为darkgray
,因为你无法以这种方式选择伪元素。 这是另一个小问题。
在我的日常工作中,我发现伪元素通常是绝对定位的,用于做一些装饰性的工作 - 所以,如果你有
.container::before {
content: "";
position: absolute;
/* Do something decorative */
}
…你可能根本不会注意到。 从技术上讲,伪元素仍然是子元素,所以它仍然在那里发挥作用,但没有参与网格。 这也不仅仅是 CSS 网格独有的。 例如,你会发现通过使用 flexbox,你的伪元素会成为一个 flex 项目。 你也可以自由地浮动你的伪元素或用它做任何其他类型的布局。
DevTools 很清楚地表明它在 DOM 中就像子元素一样

还有几个需要注意的地方!
一个是:nth-child()
。 你会认为如果伪元素实际上是子元素,它们会影响:nth-child()
计算,但事实并非如此。 这意味着像这样
.container > :nth-child(2) {
background: red;
}
…无论是否存在::before
伪元素,它都会选择同一个元素。 ::after
和:nth-last-child
及其朋友也是如此。 这就是我在标题中加上“有点像”的原因。 如果伪元素完全像子元素一样,它们会影响这些选择器。
另一个需要注意的地方是,你不能像选择普通子元素一样在 JavaScript 中选择伪元素。 document.querySelector(".container::before");
将返回null
。 如果你在 JavaScript 中尝试获取伪元素的原因是为了查看它的样式,你可以使用一些CSSOM魔法来实现这一点。
const styles = window.getComputedStyle(
document.querySelector('.container'),
'::before'
);
console.log(styles.content); // "x"
console.log(styles.color); // rgb(255, 0, 0)
console.log(styles.getPropertyValue('color'); // rgb(255, 0, 0)
你遇到过伪元素的任何问题吗?
这种行为比较有用的一点是,你可以通过在父元素中添加
display: flex;
来轻松地将你的伪元素居中(或更一般地说,定位)。 例如,在向<li>
元素添加自定义标记时。 如果列表项是一个 flexbox,那么它的::before
伪元素和文本内容将像预期的那样对齐。这也是值得一提的一点:那些在网格和 flexbox 中的伪元素,它们的处理方式与文本节点完全相同。 毕竟,你可以有一个像这样的结构
Text node Another text node