【问题标题】:How is ::first-letter different from :first-child (pseudo-class vs pseudo-element)::first-letter 与 :first-child 有何不同(伪类与伪元素)
【发布时间】:2019-03-01 00:29:18
【问题描述】:

来自 W3C 标准对伪元素的定义https://www.w3.org/TR/selectors-3/#pseudo-elements

伪元素创建关于文档树的抽象,超出了文档语言指定的那些。例如,文档语言不提供访问第一个字母或元素内容的第一行的机制。伪元素允许作者引用这些否则无法访问的信息。

(我的重点。)

为什么文档语言允许检测第一个子元素(所以:first-child 是一个css 伪)但不是的第一个字母(所以::first-letter 是一个css 伪元素)?这个“文档语言”应该怎么理解?

本质上,问题是:为什么选择第一个元素与第一个字母有区别?为什么文档语言可以检索其中一个而不能检索另一个?

我不是在询问伪类和伪元素之间的一般区别,而是我具体询问为什么第一个字母在概念上与第一个子元素不同。其他伪元素不那么令人困惑:例如 ::after::before 是伪元素是相当明显的,因为它们与 html 结构中未定义的“空间”相关。但是第一个字母,所以为什么这样的第一个字母仍然被区别对待的问题。

【问题讨论】:

  • 如果您认为标记的欺骗的最佳答案(或任何进一步的答案)没有回答您的问题,或者如果它提出了进一步的问题,请在您的答案的编辑中详细说明,我'很乐意相应地重新提出问题。
  • @TylerH 我真的不认为这是重复的。我知道伪类和伪元素之间的区别,但我特别询问为什么第一个字母在概念上与第一个子元素不同。为什么 ::after::before 例如是伪元素是相当明显的,因为它们与 html 结构中未定义的“空间”相关。但是第一个字母,因此我的问题。
  • 不,::first-letter 未在结构中定义。换句话说,你没有标签环绕第一个字母(除非你这样做,那么你不需要::first-letter)。这就是伪类和伪元素之间的区别。如果您可以使用简单的选择器(如类或元素选择器)来定位它,那么它就不是伪元素。你不能用一个简单的选择器来定位第一个字母,因为它就像试图定位一个部分内部文本片段...... CSS 不能做到这一点。这个问题被称为“裸文本”(谷歌搜索时要小心......)

标签: css css-selectors standards w3c


【解决方案1】:

在最典型的 CSS 用例中,文档语言指的是 HTML。文档树(在整个选择器中都提到)指的是从标记构造的 DOM 树。

伪元素是基于现有布局生成的东西。也就是说,必须首先基于应用于 DOM 树中元素的 CSS 构建和呈现布局。这不能仅靠文档语言、标记来完成。

例如,您会注意到 ::first-letter 伪元素仅适用于块容器框。没有办法知道一个元素(或其后代)是否会有 ::first-letter 伪元素,直到它被确定为块容器框(唯一可以直接包含内联内容流的框),并且由 CSS 决定,而不是由 HTML 决定。举个更具体的例子:

<p>Hello world!

默认情况下,p 元素是display: block。这产生了一个块盒,它是一种块容器盒。但即便如此,这个默认值还是使用 CSS 实现的。如果您要使用以下 CSS 规则覆盖该默认值:

p {
  display: inline;
}

然后这个元素变成一个内联框,p::first-letter 将不再对其产生任何影响。

直观地说,与块框(或任何其他类型的框)相比,确定内联框的第一个字母似乎仍然是微不足道的,但是一旦您在同一个内联格式化上下文中拥有多个内联框,事情就会变得相当复杂互相交流。

::first-line 更加明确:在您格式化该行之前,不仅不可能知道元素文本的第一个格式化行有多长,而且它的内容和长度当您调整和/或重排元素及其内容时,此行也可以更改

相比之下,像:first-child 这样的树结构伪类与布局的DOM 中的元素独立 匹配。无需渲染任何内容,浏览器就可以立即分辨出哪个元素是其父元素的第一个子元素。您所需要的只是元素的 DOM 树,这意味着您需要的所有信息都可以从文档语言、标记中检索到。例如,以下片段中ol 的第一个孩子总是相同的无论你应用什么CSS

<ol>
  <li>First
  <li>Second
  <li>Third
</ol>

【讨论】:

  • 我不相信这完全回答了 OP 的问题。你说::first-line的内容在页面调整大小时会发生变化,但这不是问题;元素本身及其子元素的许多属性,如clientHeight,也会在页面调整大小时发生变化。所以原则上没有区别。 OP(和我)想知道为什么您可以检索querySelector(':first-child').clientHeight,但不能检索querySelector('::first-line').clientHeight,而这两个属性都是浏览器已知的。唯一的区别是 ::first-line 不在 DOM 中。
  • @Mr Lister:问题问为什么 ::first-line 不在 DOM 中 - 答案是 DOM 是标记的反映,而不是呈现的布局。甚至 CSSOM 也没有提供渲染布局的完整抽象。布局是基于两个对象模型呈现的,而不是相反,伪元素又基于这个呈现的布局生成。
猜你喜欢
  • 2014-05-21
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 1970-01-01
  • 2012-08-14
相关资源
最近更新 更多