注意双冒号 ::before
与单冒号 :before
。 哪个是正确的?
从技术上讲,正确答案是 ::before
。 但这并不意味着您应该自动使用它。
情况是
- 双冒号选择器是伪元素。
- 单冒号选择器是伪选择器。
::before
绝对是伪元素,因此应该使用双冒号。
伪元素和伪选择器之间的区别已经很令人困惑。 幸运的是,::after
和 ::before
相当简单明了。 它们实际上在页面中添加了一些新内容,一个元素。
但是,像 ::first-letter
这样的东西也是伪元素。 我在脑子里是这样推断的,它正在选择一个没有现有 HTML 元素的部分。 目标的第一个字母周围没有 <span>
,因此该第一个字母几乎就像您在页面中添加的新元素。 这与伪选择器不同,伪选择器选择已经存在的元素,例如 :nth-child(2)
或其他。
即使 ::before
是一个伪元素,并且双冒号是使用伪元素的正确方法,您应该这样做吗?
有一种论点认为您也许应该使用 :before
,其论据如下
- Internet Explorer 8 及更低版本只支持
:before
,不支持::before
- 所有现代浏览器都以这两种方式支持它,因为大量网站使用
:before
,并且浏览器非常重视向后兼容性。 - 嘿,它少了一个字符,这算是一个额外的好处。
我听说有人说他们的 CSS 规范器要求(或自动执行)它们为单冒号。 就个人而言,我不介意人们这样做。 似乎还不错。 我更重视一致性,而不是您选择哪种方式。
另一方面,也有一个论点支持使用 ::before
,其论据如下
- 单冒号伪元素是一个错误。 将不会再有使用单冒号的伪元素。
- 如果您在脑海中明确区分了它们,不妨训练您的手指以正确的方式使用它们。
- 这已经足够令人困惑了,所以我们不妨遵循规范的方式。
我已经将我的规范器设置为强制我使用双冒号。 我反正不支持 Internet Explorer 8,而且以“正确”的方式做事感觉很好。
我认为经验已经表明我们可以坚持使用单冒号。 为什么不放弃双冒号,结束这种困惑呢?
我同意! 为什么不完全取消这种区分呢? 即使这是一个错误,它也比根据如此抽象的概念更改语法更容易记忆。
完全同意 - 显然,如果它们是可互换的,那么一个冒号就足够了。 为什么让事情变得比必要的更难?
一些有趣的(?)笔记
content: 'some string'
CSS 规则只适用于::before
和::after
,不适用于任何其他伪元素。至少在 Chrome 上,
::first-letter
选择了包括第一个字母在内的所有内容,例如,kbd::first-letter { color: red }
在<kbd>#!/usr/bin/python</kbd> 上会突出显示
#!/u`。当
kbd
显示为“block
”元素时有效(::first-letter
的一个小限制)kbd {
display: inline-block; /* display: block */
}
根据 Mozilla,“在第一个字母之前或紧随其后的标点符号包含在匹配项中。 标点符号包括在打开 (Ps)、关闭 (Pe)、初始引号 (Pi)、最终引号 (Pf) 和其他标点符号 (Po) 类中定义的任何 Unicode 字符。” (https://mdn.org.cn/en-US/docs/Web/CSS/::first-letter)
这是一个典型的例子,似乎有一种明显正确的方法来编写它(::before,为了规范正确性/面向未来)并部署它(:before,支持和宝贵的字符计数),并且它们是相反的。
构建工具和部署流程使在 CSS8 最终弃用单冒号语法时轻松切换开关:)
伪类是基于状态的选择器,伪元素是基于内容的选择器。 当某些东西是伪类时,实际上更容易记住,并假设如果它不符合该定义,那么它一定是一个伪元素。
伪类可以根据用户操作(或交互)而改变。
:hover
是一个简单的例子。 它只在用户将鼠标悬停在元素上时才会采用该样式。 一个更棘手的例子可能是:valid
,因为内容是有效的还是无效的,但预计这将作为用户输入的一部分而改变。 输入元素本身并不无效,它只是有一个无效的值,因此它处于无效状态(并且会应用样式)。我不确定为什么
::first-letter
会令人困惑,但同样,可以通过思考“这是否会根据用户操作而改变”来确定它不是伪类。 当然,可能有一些有趣的 JavaScript 代码会在用户单击按钮时创建一个新段落,但这并没有改变“第一个字母”的状态,它只是使其他内容成为第一个字母。 由于它听起来不像伪类,因此它是一个伪元素。嗯……你的类比在大多数情况下都有效,但是
:first-child
呢?它并不真正是一个基于状态的选择器。 除非是某种动态内容,否则用户无法更改第一个子元素是什么。
双冒号从技术上讲是正确的方法,但是我通常会使用单冒号来尝试扩展支持。 不是说我积极地试图支持 IE8,但不会造成伤害。
顺便说一句,伪元素和伪类之间的区别在大多数情况下非常清楚,但有些情况比较复杂。 甚至浏览器开发人员似乎也无法达成一致。
例如,请考虑占位符。 Webkit 浏览器使用
::-webkit-input-placeholder
,因此它们认为它是一个伪元素。 Trident 运行:-ms-input-placeholder
,这意味着它们认为它是一个伪类。 实际上,Gecko 在 Firefox 19 中将他们的伪类:-moz-placeholder
切换到了伪元素::-moz-placeholder
……你最后一句话是最好的
当您使用
::before
,然后 gulp-sass 将其转换为/before
时,真正让您头疼的是 - 但仅在构建服务器上,而不是在任何人的本地开发环境中(所有版本都匹配)。 我们不得不改回单冒号以避免此错误也许我生活在一个梦幻世界,但肯定,肯定我们不必担心 IE8 支持?
微软多年来一直没有支持任何版本的 IE,除了 IE 11。
此外,IE 8 已经超过 10 年了。 这意味着它早于(例如)整个漫威电影宇宙。
我们的主要产品涉及处理机密信息。 我们不支持任何低于 IE 11 的版本(并且我们正在逐步淘汰该版本),因为它们隐式地不安全,并且只能在已过期的操作系统上使用。
我真的想不出保留一个功能以支持十年前的软件的理由,因为我无法想象使用它的合理理由。 有人能给出理由吗?
我们应该将其写为双冒号,因为这是正确的 - 如果我们需要支持单冒号,那么应该使用例如 autoprefixer 添加它(一个严肃的问题 - autoprefixer 是否支持向不支持双冒号版本的浏览器添加单冒号?)- 与渐变发生的情况相同 - 我们有三种语法,但我们应该只使用一种(正确的) - 新的和让 autoprefixer 在需要时添加中间和旧的语法。
Autoprefixer 不会添加
:before
。 它不是前缀,它们对该规则非常严格,以防止范围蔓延。即使它添加了,您也必须在配置文件中明确声明您要支持 IE8,以便它包含在您的输出 CSS 中。
你可以这样想:你有一个伪元素
::before
,这也就是你在 Chrome 开发者工具中看到的代码。在 CSS 中,你使用伪**选择器**:before
来**选择**伪元素::before
。所以只有一个冒号…它们不都是叫做伪选择器吗?并且被分成伪元素(双冒号,::before ::after)和伪**类**(单冒号,比如 :hover, :focus :disabled 等)吗?
我最近为我的公司制作了一个关于这方面的视频(尚未公开发布)。与你 Chris 一样,我得出的结论是,如果浏览器需要“添加东西”才能渲染样式,那么它就是一个伪元素(浏览器需要“将第一个字母包裹在某物中”,以便我们可以应用
::first-letter
)。如果样式被添加到现有的元素中,那么它就是一个伪类。我一直主张使用规范,但直到制作了那个视频,我才对伪元素之间的差异有了有效的定义。
现在有一些伪元素,比如
::placeholder
,需要两个冒号。因此,为了保持一致,所有伪元素(包括::before
)也应该有两个冒号。规范与实际使用之间的永恒斗争
当使用双冒号 ::before 时,我遇到了浏览器兼容性问题,从那以后,我从未使用过双冒号。
我对区别并不困惑,只是不明白为什么需要这个区别。双冒号对我来说一直像是浪费一个按键。
我的 CSS 代码校验器要求(或自动)将它们设置为单冒号。那么,我该怎么办?