主题
伪类
:hover
选择鼠标指针浮动在其上的元素
1. 延时触发
通过 transition 实现
css/* 鼠标浮动在其上一秒后,才变红 */ div:hover { color: red; transition: all 0s 1s; }
显隐延时使用 display 是无效的,但 visibility 是有效的
2. 非子元素的 :hover
使用兄弟选择器实现
css/* 经过按钮时,显示图片。在图片上时,也显示图片 */ button:hover + img, img:hover { display: inline; }
若中间有间隔,导致还未移动到图片上,图片就隐藏了,就可以通过延时来解决
cssimg { margin-top: 20px; visibility: hidden; transition: visibility .2s; } button:hover + img, img:hover { visibility: visible; }
:active
选择激活的元素
1. 兼容性问题
- 在 IE 浏览器下,
<html>
、<body>
应用 :active 设置背景色后,背景色无法还原 - 移动端 Safari 浏览器下,:active 默认无效,可以使用 -webkit-tap-highlight-color 实现触摸高亮
2. CSS 数据上报
如果想知道按钮的点击率,CSS 可以实现埋点
cssbutton:active::after { content: url(xxx); }
:focus
选择获得焦点的元素
1. 只匹配特定元素
- 非 disabled 状态的表单元素
- 包含 href 属性的 a 标签
- area 元素
- HTML5 中的 summary 元素
- 设置了 contenteditable 属性的普通元素
- 设置了 tabindex 属性的普通元素
- tabindex="0":可以点击触发,也可以被 Tab 键索引
- tabindex="-1":只可以点击触发
2. 任何元素点击显示
html
<div tabindex="0">点击显示</div>
<img src="xxx.png" />
css
img { display: none; }
:focus + img { display: inline; }
但存在问题,在 iOS Safari 浏览器下,元素一旦处于 focus 状态,除非点击其他可聚焦元素来转移焦点,否则会一直保持,可通过给祖先容器设置 tabindex="-1",同时取消 outline 样式解决
html<body> <div class="App" tbaindex="-1"></div> </body>
css.App { /* focus 状态,外边框不高亮 */ outline: 0 none; }
:focus-within
匹配元素自身或者它的某个后代匹配 :focus 的元素
css
/* 仅当 form 处于聚焦状态 */
form:focus {}
/* form 自身,或者 form 内部的任意子元素处于聚焦状态时 */
form:focus-within {}
:focus-visible
匹配使用键盘访问时聚焦的元素
css
/* 去除鼠标点击时候的 outline,保留键盘访问时的 outline */
:focus:not(:focus-visible) {
outline: 0;
}
解释:
- 现代浏览器,点击时不应该有焦点轮廓,但使用键盘访问时,应该出现焦点轮廓,因为用户需要知道当前焦点聚焦的元素
- 但 Chrome 浏览器点击时,以下三个场景也会出现焦点轮廓
- 设置了背景的 button
- HTML5 中的 summary
- 设置了 tabindex 的元素
- Chrome 的行为不是开发者想看到的,但仅仅通过 outline: none 来处理,键盘访问时就会去掉焦点轮廓
- :focus-visible 正是为此而生,浏览器认为使用键盘访问时才会触发 :focus-visible 的聚焦,换句话说,:focus-visible 可以知道元素的聚焦行为时鼠标触发,还是键盘触发
:any-link
匹配每一个有 href 属性的 <a>
、<area>
、<link>
元素
:disabled
匹配任何被禁用的元素
:read-only
一般用于匹配有 readonly 属性的 <input>
<textarea>
元素
:placeholder-shown
匹配显示 placeholder text 时的 <input>
<textarea>
元素
1. 实现 Material Design 占位符交互效果
html
<div class="input-container">
<input placeholder="邮箱">
<label>邮箱</label>
</div>
首相让文本框的 placeholder 不可见
cssinput:placeholder-shown::placeholder { color: transparent; }
label 使用绝对定位,来代替文本框原生的 placeholder
csslabel { position: absolute; left: 3px; top: 2px; pointer-events: none; }
在聚焦文本框时,对 label 进行重新定位
cssinput:not(:placeholder-shown) + label, input:focus + label { transform: scale(0.75) t r anslate(O, -32px); }
总体
css.input-container { position: relative; } input:placeholder-shown::placeholder { color: transparent; } label { position: absolute; left: 3px; top: 2px; font-size: 12px; color: #a2a9b6; background: #fff; pointer-events: none; transform-origin: 0 0; transition: all .25s; } input:focus + label { color: #2486ff; transform: scale(0.75) translate(0px, -10px); }
2. 空值判断
借助 :placeholdershown 伪类来判断一个输入框中是否有值
css
input:placeholder-shown + div::after {
content: "不能为空";
}
:default
匹配表单元素中的默认元素
1. 推荐标记
css
input:default + label::after {
content: "(推荐)";
}
:checked
匹配任何处于选中状态的 radio、checkbox、option 元素
1. 实现 Switch 按钮
html
<input type="checkbox" id="switch" hidden />
<label for="switch"></label>
css
[for=switch] {
display: inline-block;
width: 44px;
height: 26px;
border-radius: 26px;
box-sizing: border-box;
border: 2px solid;
background-color: currentColor;
color: silver;
transition: all 0.2s;
cursor: pointer;
}
[for=switch]::after {
content: "";
display: block;
width: 22px;
height: 22px;
border-radius: 50%;
background-color: #fff;
transition: margin-left 0.2s;
}
:checked + [for=switch] {
color: skyblue;
}
:checked + [for=switch]::after {
margin-left: 18px;
}
2. 实现多选择标签
html
<input type="checkbox" id="checkbox1" hidden />
<label for="checkbox1">科技</label>
<input type="checkbox" id="checkbox2" hidden />
<label for="checkbox2">体育</label>
...
css
[for^=checkbox] {
padding: 5px;
border: 1px solid silver;
}
:checked + [for^=checkbox] {
border-color: deepskyblue;
background-color: azure;
}
javascript
// 获取选中的
Array.from(document.querySelectorAll('input')).filter(item => item.checked)
通过 CSS 显示已选中的复选框数量
html<input type="checkbox" id="checkbox2" hidden /> <label for="checkbox2">体育</label> <p></p>
cssbody { /* 重置 */ counter-reset: topicCounter; } :checked + [for^=checkbox] { /* 选中加一 */ counter-increment: topicCounter; } p::before { /* 显示*/ content: counter(topicCounter); }
:valid 和 :invalid
:valid 匹配验证正确的表单元素
:invalid 匹配验证错误的表单元素
1. 局限性
- 页面一加载,此两个伪类就会触发,不符合用户使用习惯
- 可通过 JS 消除隐患
2. 控制表单校验
html
<form id="form" novalidate>
<p>
验证码:<input placeholder=" " required pattern="\w{4,6}">
<span class="valid-tips"></span>
</p>
<input type="submit" value="提交">
</form>
css
.valid input:invalid {
border-color: red;
}
.valid input:valid + .valid-tips::before {
content: "√";
color: green;
}
.valid input:invalid + .valid-tips::before {
content: "不符合要求";
color: red;
}
.valid input:placeholder-shown + .valid-tips::before {
content: "尚未输入值";
}
javascript
// 提交时验证
form.addEventListener('submit', function (event) {
event.preventDefault();
// 页面一加载不开启验证,当用户提交表单后,通过添加特定类名,触发验证
this.classList.add('valid');
// 判断表单全部验证通过
if (this.checkValidity?.()) {
console.log('验证通过')
}
});
// 实时验证
form.addEventListener('input', function (event) {
event.target.classList.add('valid');
})
当输入框有 min 和 max 校验时,可以加入 :out-of-range 伪类细化提示
html<input placeholder=" " required pattern="\w{4,6}" min="0000" max="9999">
css.valid input:out-of-range + .valid-tips::before { content: "超出范围限制"; color: red; }
:not()
匹配当前元素与括号里面的选择器不匹配的元素
1. 可以不断级联
css
/* 不禁用,且不处于只读状态的 input 元素 */
input:not(:disabled):not(:read-only) {}