重新认识伪类与伪元素

伪类、伪元素,都是属于CSS选择器的范围。

css 引入伪类和伪元素概念是为了格式化文档树以外的信息。也就是说,伪类和伪元素是用来修饰不在文档树中的部分,比如,一句话中的第一个字母,或者是列表中的第一个元素。

伪类是啥?

伪类是一个选择处于特定状态的元素的选择器。比如::first-child:hover,当元素是当前类型的第一个元素或者鼠标指针悬浮在该元素时,它们表现就像是在该元素上加一个类一样

伪类以开头为单冒号:

简单伪类示例

有人也称这种选择器为 CSS3 结构类。常用的伪类有:

  • E:fist-child:选中父元素的第1个子元素,且该子元素为 E 类型。比如:p:first-child,配置当前元素的父元素下的第一个且类型为 p 的元素。如果第一个元素不是 p,则失效。

  • E:last-child:选中父元素的最后一个子元素,且该子元素为 E 类型。

  • E:nth-child():选中父元素的第 n 个子元素,且该子元素为 E 类型。

  • E:nth-last-child():同上,不过是从后开始查找;

  • E:nth-of-type():选中父元素下第 n 个 E 类型元素。比如:p:nth-of-type(1),在父素元素下查找子元素,直到找到第一个 p 元素。

  • E:nth-last-of-type():同上,不过是从后开始查找;

  • E:first-of-type:选中父元素下第一个 E 类型元素;

  • E:last-of-type:选中父元素下最后一个 E 类型元素;

  • E:only-child:选中父元素下唯一的子元素,且该子元素为 E 类型;

  • E:only-of-type:如果父元素下只有一个 E 类型子元素,则选中该子元素;

  • E:empty:选中不包含子元素和内容的 E 类型元素;

  • :blank:匹配没有子节点、仅有空的文本节点、仅有空白符的文本节点。??

  • :playing:匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“播放”的元素。

  • :paused:匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“暂停”的元素。

  • :root:匹配文档的根元素。除了优先级更高之外,与 html 选择器相同

  • :scope:匹配任何为参考点元素的的元素。

  • :target:匹配当前URL目标的元素(例如如果它有一个匹配当前URL分段的元素)。

  • :is():匹配传入的选择器列表中的任何选择器。

  • :not:匹配作为值传入自身的选择器未匹配的物件。

:nth-child(an+b)

找到所有当前元素的兄弟元素,然后按照位置先后顺序从1开始排序,选择的结果为CSS伪类:nth-child括号中表达式(an+b)匹配到的元素集合(n=0,1,2,3...)。

  • 0n+3 或简单的 3 匹配第三个元素。

  • 1n+0 或简单的 n 匹配每个元素。(兼容性提醒:在 Android 浏览器 4.3 以下的版本 n1n 的匹配方式不一致。1n1n+0 是一致的,可根据喜好任选其一来使用。)

  • 2n+0 或简单的 2n 匹配位置为 2、4、6、8...的元素(n=0时,2n+0=0,第0个元素不存在,因为是从1开始排序)。你可以使用关键字 even 来替换此表达式。

  • 2n+1 匹配位置为 1、3、5、7...的元素。你可以使用关键字 odd 来替换此表达式。

  • 3n+4 匹配位置为 4、7、10、13...的元素。

ab 都必须为整数,并且元素的第一个子元素的下标为 1。换言之就是,该伪类匹配所有下标在集合 { an + b; n = 0, 1, 2, ...} 中的子元素。另外需要特别注意的是,an 必须写在 b 的前面,不能写成 b+an 的形式。

选择器示例:

  • tr:nth-child(2n+1)tr:nth-child(odd):表示HTML表格中的奇数行。

  • tr:nth-child(2n)tr:nth-child(even):表示HTML表格中的偶数行。

  • span:nth-child(0n+1):表示子元素中第一个且为span的元素,与 :first-child 选择器作用相同。

  • span:nth-child(1):表示父元素中子元素为第一的并且名字为span的标签被选中

  • span:nth-child(-n+3):匹配前三个子元素中的span元素。

:scope

当在样式表中使用时,:scope 等效于 :root,因为目前尚无一种方法来显式建立作用域元素。

当从 DOM API 使用,如:querySelector(), querySelectorAll(), matches(), 或 Element.closest():scope 匹配你调用API的元素。??

:target

代表一个唯一的页面元素(目标元素),其id 与当前URL片段匹配 。

如:当前页面URL是 http://www.example.com/index.html#section2hash值为section2:target 指向ID为 section2 的页面元素。

:is()

将选择器列表作为参数,并选择该列表中任意一个选择器可以选择的元素。这对于以更紧凑的形式编写大型选择器非常有用。

/*element_box下所有p元素*/
.element_box :is(p) {
}

/*element_box下所有class为red的p元素*/
.element_box :is(p):is(.red) {
}

/*element_box下所有的b元素和em元素*/
.element_box :is(b, em) {
}

:not

用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中,它也被称为反选伪类(negation pseudo-class)。

/*element_box下所有的非p元素*/
.element_box :not(p) {
}

/*element_box下所有的非p元素和class不为red的元素*/
.element_box :not(p):not(.red) {
}

not不支持复杂选择器:

:not()逻辑伪类出身很早,早到IE9浏览器都支持,不像现在的新出来的逻辑选择器,:not()伪类括号里面并不支持复杂的选择器(虽然新的规范已经让支持了,目前还没有浏览器跟进)。

/*:not()伪类括号里面不能多个选择器:*/
.element_box :not(.green, .red) {}

/*可以写成*/
.element_box :not(.green),
.element_box :not(.red) {}
/*:not()伪类括号里面不支持选择器级联:*/
:not(.element_box .green) {}

/*可以写成*/
:not(.element_box):not(.green) {}

not容易搞不清楚的否定逻辑关系:

  • 匹配既不包含.green类名,又不包含.red类名的元素:

    /*错误*/
    .element_box :not(.green),
    .element_box :not(.red) {}
    
    /*正确*/
    .element_box :not(.green):not(.red) {}

逗号分隔的选择器,表示的是“或”的关系,而不是“与”的关系。:not(.green), :not(.red) 含义是不包含.green类名的元素,或者不包含.red类名的元素。最后导致的结果是.green类名和.red类名元素都会匹配。

动态伪类

一些伪类只会在用户以某种方式和文档交互的时候应用。这些叫做动态伪类,表现得就像是一个类在用户和元素交互的时候加到了元素上一样。

动态伪类包含两种:

  • 锚点伪类。如::link、:visited

  • 用户行为伪类。如::hover、:active、:focus

对于锚点下的四个伪类的设置,有一点需要特别注意,那就是他们的先后顺序,要让他们遵守一个爱恨原则 LVHA(LoVe/HAte) ,也就是 Link--visited--hover--active

  • :link:匹配未曾访问的链接。

  • :visited:匹配已访问链接。

  • :hover:用于当用户把鼠标移动到元素上面时的效果;

  • :active:用于用户点击元素那一下的效果(正发生在点的那一下,松开鼠标左键此动作也就完成了)

  • :focus:用于元素成为焦点,这个经常用在表单元素上。

  • :any-link:匹配一个链接的 :link 和 :visited 状态。

UI元素状态伪类

对于 HTML 中的 Form 元素状态的伪类,称为 UI 元素状态伪类。

主要有:

  • :enabled:可写状态。如:type="text"

  • :disabled:不可写状态。如:type="text"

  • :checked:是否选中状态。如:type="radio"type="checkbox"

  • :optional:匹配不是必填的 form 元素;

  • :placeholder-shown:匹配显示占位文字的 input 元素;

  • read-only:匹配用户不可更改的元素;

  • :read-write:匹配用户可更改的元素;

  • :required:匹配必填的 form 元素。

伪元素是啥?

伪元素用于**创建一些不在文档树中的元素,并为其添加样式,**而不是在现有的元素上加类。比如说,我们可以通过 :before 来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。

伪元素开头为双冒号::

伪元素例表:

  • ::after:匹配出现在原有元素的实际内容之后的一个可样式化元素。

  • ::before:匹配出现在原有元素的实际内容之前的一个可样式化元素。

  • ::first-letter:匹配元素的第一个字母。

  • ::first-line:匹配包含此伪元素的元素的第一行。

  • ::grammar-error:匹配文档中包含了浏览器标记的语法错误的那部分。

  • ::selection:匹配文档中被选择的那部分。

  • ::spelling-error:匹配文档中包含了浏览器标记的拼写错误的那部分。

  • :: cue:匹配所选元素中的WebVTT提示。这可以用于在VTT轨道的媒体中使用字幕和其他线索。

  • ::backdrop:匹配在任何处于 全屏模式 的元素下的即刻渲染的盒子(并且在所有其他在堆中的层级更低的元素之上),比如:video 点击播放,处理全屏状态时。

  • ::marker:匹配如ul li 中项目符号或者数字。它作用在任何设置了 display: list-item 的元素或伪元素。

  • ::placeholder:匹配一个表单元素的占位文本,它允许开发者和设计师自定义占位文本的样式。

  • ::slotted():用于选定那些被放在 HTML模板 中的元素。

生成带有::before和::after的内容

这是一组特别的伪元素,它们和 content 属性一同使用,使用CSS将内容插入到你的文档中中。

.element_box::after {
    display: inline-block;
    width: 400px;
    content: '我是一个伪元素';
    color: blue;
    font-size: 24px;
    font-weight: bold;
}

content 可以为以下值:

  • none:不会产生伪类元素;

  • normal::before:after 伪类元素中会被视为 none

  • <string>:文本内容;

  • <uri> url():URI 值会指定一个外部资源(比如图片)。如果该资源或图片不能显示,它就会被忽略或显示一些占位(比如无图片标志);

  • <counter>:计数器可以指定两种不同的函数:counter()counters()

  • attr(X):将元素的X属性以字符串形式返回。如果该元素没有 X 属性,则返回一个空字符串。区分大小写的属性返回值依赖文挡的语言设定。

伪类和伪元素的区别?

  • 表示方法

    CSS2 中伪类、伪元素都是以单冒号:表示,CSS2.1 后规定伪类用单冒号表示,伪元素用双冒号::表示,浏览器同样接受 CSS2 时代已经存在的伪元素的单冒号写法。

    对于 CSS2 之后所有新增的伪元素(如:::selection),应该采用双冒号的写法。

    单冒号和双冒号兼容的伪元素:

    • :after、::after;

    • :before、::before;

    • :cue 、::cue;

    • :first-letter、::first-letter;

    • :first-line、::first-line。

  • 定义不同

    伪类即假的类,通常可以添加类来达到效果;伪元素即假元素,需要通过添加元素才能达到效果。

    <section class="box box_01">
        <p>江南可采莲,莲叶何田田。</p>
        <p>鱼戏莲叶间。</p>
        <p>鱼戏莲叶东,鱼戏莲叶西,鱼戏莲叶南,鱼戏莲叶北。</p>
    
        <span>玉炉香,红蜡泪,偏照画堂秋思。眉翠薄,鬓云残,夜长衾枕寒。</span>
        <span>梧桐树,三更雨,不道离情正苦。一叶叶,一声声,空阶滴到明。</span>
        <em>杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭?</em>
        <p>自君之出矣,明镜暗不治。思君如流水,何有穷已时。</p>
        <b>心的春陌,有一朵是为我绽放,不求开的多么盛世;只愿让我感受:春,真的来过,我,没有被光阴遗落,便足矣。</b>
    </section>

    伪类实现:

    要修改第一个p元素的样式,我们可以通过伪元素 :first-child 实现:

    .box_01 p:first-child {
        font-size: 30px;
        font-weight: bold;
        color: green;
    }

    查看DEMO

    除此之外,我们可以直接给这个p元素加类来实现:

    .first_child {
        font-size: 30px;
        font-weight: bold;
        color: red;
    }
    <section class="box">
        <p class="first_child">江南可采莲,莲叶何田田。</p>
        ...
    </section>

    查看DEMO

    伪元素实现:

    要修改第一行的首字的样式,我们可以通过伪元素 ::first-letter 实现:

    .box_03::first-letter {
        font-size: 30px;
        font-weight: bold;
        color: green;
    }

    查看DEMO

    除此之外,要实现这个效果,就要为首字母创建一个元素,再添加样式:

    .first_letter {
        font-size: 30px;
        font-weight: bold;
        color: red;
    }
    <section class="box">
        <p><span class="first_letter">江</span>南可采莲,莲叶何田田。</p>
        ...
    </section>

    查看DEMO

常见问题

CSS3 新增伪类有那些?

上文常见伪类列表中大多都是 CSS3 新增。

CSS2 的伪类有 ::first-child:link:visited:hover:active:focuslang

CSS3 新增伪元素有那些?

上文常见伪元素列表中大多都是 CSS3 新增的。

CSS2 的元素有 ::first-line:first-letter:before:after

参考链接

MDN 伪类和伪元素

CSS :not伪类可能错误的认识

最后更新于