CSS 伪元素和伪类
1.为什么要引入伪元素和伪类?
在 CSS 的官方文档中,是这样描述的:
CSS introduces the concepts of pseudo-elements and pseudo-classes to permit formatting based on
information that lies outside the document tree.
意思是:CSS 引入伪类和伪元素概念是为了格式化文档树以外的信息。即,伪类和伪元素是用来修饰不在文档树种的部分。CSS 中没有比如:"段落的第一行"、"文章首字母"之类的选择器,而这些部分在一些业务场景中又是需要控制的,这时候就需要用到伪元素和伪类了。
2.伪类和伪元素的概念以及作用
2.1 伪类
伪类是为处于某一状态的已有元素添加相应的样式,而这个状态是根据用户的行为而动态改变的。
伪类一般用于以下场景:
- 设置鼠标悬停在元素上的样式
- 为已访问和未访问链接设置不同的样式
- 设置元素获得焦点时的样式
- 为一串元素中的某些特定元素设置样式
- ...
2.2 伪元素
伪元素是用于创建一些不存在于文档树中的元素,并为其添加指定的样式。即,虽然用户可以看到这些元素,但是这些元素实际上并不存在于文档树中!这一点也是伪元素与伪类之间的本质区别!
伪元素一般用于以下场景:
- 设置文本元素首字母、首行的样式
- 在元素内容之前或之后插入内容
- 设置滚动元素的滚动条样式
- ...
3.伪类
CSS 中的常用伪类可以分为以下几类:
- 状态伪类
- 结构性伪类
- 表单相关
- 语言相关
- 其他
如下图:
3.1 状态伪类
状态伪类,即元素的样式会根据其状态的不同而呈现不同的样式,当元素处于某一状态时,应用该状态对应的样式,而进入另一状态后,该样式也不再生效。
常见的状态伪类有:
:link
应用于未被访问过的链接;:hover
应用于鼠标悬停到的元素;:active
应用于被激活的元素;:visited
应用于被访问过的链接 ,是一种与:link
状态互斥的状态!:focus
应用于拥有键盘输入焦点的元素。
需要注意的是,**这几个伪类同时出现在一个元素的操作上,顺序是固定的,否则很大程度上会产生紊乱,造成效果失效!**具体来说,:hover
必须在 CSS 定义中的 :link
和 :visited
之后,才能生效。:active
必须在 CSS 定义中的 :hover
之后才能生效。
3.2 结构性伪类
结构性伪类是 CSS3 中新加入的元素选择器,它通过对 DOM 树进行元素过滤,用文档结构的相互关系来匹配元素,能够减少 class
和 id
属性的定义,使得文档结构更加简洁!
常见的结构性伪类:
:first-child
选择某个元素的第一个子元素:last-child
选择某个元素的最后一个子元素;:nth-child(n)
匹配属于其父元素的第 n 个子元素,不论元素的类型;:nth-last-child()
从这个元素的最后一个子元素开始算,选匹配属于其父元素的第 n 个子元素,不论元素的类型;:nth-of-type()
规定属于其父元素的第 n 个指定类型元素;:nth-last-of-type()
从元素的最后一个开始计算,规定属于其父元素的指定类型元素;:first-of-type
选择一个上级元素下的第一个同类子元素;:last-of-type
选择一个上级元素的最后一个同类子元素;:only-child
选择它的父元素的唯一一个子元素;:only-of-type
选择一个元素是它的上级元素的唯一一个相同类型的子元素;:checked
匹配被选中的input
元素 ,这个input元素包括radio
和checkbox
。:empty
选择的元素里面没有任何内容。:disabled
匹配禁用的表单元素。:enabled
匹配没有设置disabled属性的表单元素。:valid
匹配条件验证正确的表单元素。:in-range
选择具有指定范围内的值 的<input>
元素。:optional
选择不带required
属性 的<input>
元素。:focus
选择获得焦点 的<input>
元素。
3.3 表单相关
有些伪类的使用常常与表单向关联:
3.3.1 :checked
:checked
--- 匹配被选中的 input 元素,这个 input 元素包括 radio 和 checkbox。
例:当复选框被选中时,与其相邻的<label>
元素的背景会变化
HTML
html
<input type="checkbox"/>
<label>agree</label>
CSS
css
/* 匹配选中状态input元素的相邻label元素 */
input:checked + label {
background: yellow;
}
3.3.2 :default
:default
--- 匹配默认选中的元素
3.3.3 :disabled
:disabled
--- 匹配禁用的表单元素
例如这里,我们将禁用的 input 元素置为红色
HTML
html
<input type="text" disabled/>
CSS
css
input:disabled {
background-color: red;
}
3.3.4 :empty
:empty
--- 匹配没有子元素 的元素。但凡元素中含有文本节点、HTML 元素或者一个空格,:empty
都不能匹配这个元素。
例:
HTML
html
<div>这个容器里的背景是橙色的</div>
<div> </div>
<div></div>
<div><!-- 注释不会被视作内容 --></div>
CSS
css
div {
background: red;
height: 30px;
width: 200px;
}
div:empty {
background: blue;
}
效果如下:
可以看到,第一个元素中有文本节点,所以其背景不会变成蓝色;第二个元素中有一个空格,有空格则该元素不为空,所以其背景不会变成蓝色;第三个元素中没有任何内容,所以其背景会变成蓝色;第四个元素中只有一个注释,此时该元素是空的,所以其背景会变成蓝色;
3.3.5 :enabled
与:disabled
相反,:enabled
匹配没有设置 disabled 属性的表单元素。
3.3.6 :in-range
:in-range
匹配在指定区域内元素。
例如:
HTML
html
<input type="number" min="5" max="10">
CSS
css
input[type=number] {
border: 5px solid orange;
}
input[type=number]:in-range {
border: 5px solid green;
}
效果如下:
可以看到,当输入的数字在我们设定的范围 5 ~ 10 之间时,边框变为绿色。
3.3.7 :out-of-range
:out-of-range
与 in-range
相反,其用于匹配不在指定区域内的元素。
3.3.8 :indeterminate
indeterminate 的英文意思是" 不确定的"。当某组中的单选框或复选框还没有选取状态时,:indeterminate
可以匹配到该组中所有的单选框或复选框。
例:
HTML
html
<ul>
<li>
<input type="radio" name="list" id="option1">
<label for="option1">Option 1</label>
</li>
<li>
<input type="radio" name="list" id="option2">
<label for="option2">Option 2</label>
</li>
<li>
<input type="radio" name="list" id="option3">
<label for="option3">Option 3</label>
</li>
</ul>
CSS
css
:indeterminate + label {
background: red;
}
效果如下:
可以看到,当组中没有一个单选被选中时,所有的单选都处于不确定的状态,因此它们的label背景都为红色;而当有一项被选中后,所有单选的状态都确定了!所以它们的背景都不会被设置为红色。
3.3.9 :valid
:valid
匹配条件验证正确的表单元素。
3.3.10 :invalid
:invalid
与:valid
相反,匹配条件验证错误的表单元素。
3.3.11 :optional
:optional
匹配是具有 optional 属性的表单元素。当表单元素没有设置为 required 时,即为 optional 属性。
3.3.12 :required
:required
与 :optional
相反,匹配设置了 required 属性的表单元素。
3.3.13 :read-only
:read-only
匹配设置了只读属性 的元素,表单元素可以通过设置 readonly
属性来定义元素只读。
3.3.14 :read-write
:read-write
可以匹配处于编辑状态 的元素。input,textarea 和设置了 contenteditable
的HTML元素获取焦点时即处于编辑状态。
例:
HTML
html
<input type="text" value="获取焦点时背景变黄"/>
<div class="editable" contenteditable>
<h1>点击这里可以编辑</h1>
<p>获取焦点时背景变黄</p>
</div>
CSS
css
:read-write:focus {
background: yellow;
}
效果如下:
可以看到,在 input 框获取焦点时,样式作用到了其身上。同时,我们为div设置 contenteditable 属性后,使其获取焦点时,同样可以将样式作用到其身上。
3.3.15 :scope
(处于试验阶段)
:scope
匹配处于 style 作用域下的元素。当 style 没有设置 scope 属性时,style 内的样式会对整个 html 起作用。
以上就是常用的三类伪类,至于其他两类,在实际开发中的使用并不多,这里就不作介绍了,需要使用时,可以查阅官方文档。
4.伪元素
常用的伪元素如下:
::after
--- 在元素之后插入内容。::before
--- 在元素之前插入内容。::first-letter
--- 选择元素的首字母,只能作用于块级元素!::first-line
--- 选择元素的首行,只能作用于块级元素!::selection
--- 选择用户选择的元素部分。::placeholder
--- 匹配占位符的文本,只有元素设置了 placeholder 属性时,该伪元素才能生效。但需要注意的是,该伪元素不是 CSS 的标准,它的实现可能在将来会有所改变,所以要决定使用时必须谨慎。
下面就拿最为常用的两个伪元素 ::after
和 ::before
来举个例子:
vue
<style lang="less" scoped>
.btn_block {
position: relative;
.block {
position: absolute;
bottom: 55px;
left: -40px;
width: 200px;
height: 200px;
background: skyblue;
}
.block::after {
content: '这里是after伪元素';
position: absolute;
top: 100%;
left: 18%;
// background: orange;
border-width: 10px;
border-style: solid;
border-color: orange transparent transparent transparent;
}
}
/* 这里用了iview组件库的Modal组件,其类名为 ivu-modal */
:deep(.ivu-modal::before) {
content: '1111111111111';
background: skyblue;
}
:deep(.ivu-modal::after) {
content: url(../../assets/icons/uploadBtn.png);
}
</style>
<template>
<div class="btn_block">
<button @mouseenter="isShowBlock = true" @mouseleave="isShowBlock = false">
hover to show block
</button>
<div class="block" v-show="true">this is a block!</div>
</div>
<div class="btn_modal">
<button>click to show modal</button>
<Modal v-model="isShowModal"> 11111 </Modal>
</div>
</template>
<script>
export default {
data() {
return {
isShowBlock: false,
isShowModal: false,
}
}
}
</script>
效果如下:
可以看到,我们在这里通过::after
和 ::before
能够为元素的前方、后方添加原本不存在于文档流中的元素。另外,需要注意的是,虽然通过这样的方式在元素前后方添加元素很方便,且的确能够向伪元素身上添加事件,但是仍然是比较麻烦的,如果要添加的元素与交互相关,那么尽量还是通过实际元素来实现!而伪元素则用来做一些修饰性的工作。