Skip to content

伪类

:hover

选择鼠标指针浮动在其上的元素

1. 延时触发
  • 通过 transition 实现

    css
    /* 鼠标浮动在其上一秒后,才变红 */
    div:hover {
      color: red;
      transition: all 0s 1s;
    }

    显隐延时使用 display 是无效的,但 visibility 是有效的

2. 非子元素的 :hover
  • 使用兄弟选择器实现

    css
    /* 经过按钮时,显示图片。在图片上时,也显示图片 */
    button:hover + img,
    img:hover {
      display: inline;
    }
  • 若中间有间隔,导致还未移动到图片上,图片就隐藏了,就可以通过延时来解决

    css
    img {
      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 可以实现埋点

    css
    button: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 可以知道元素的聚焦行为时鼠标触发,还是键盘触发

匹配每一个有 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>
  1. 首相让文本框的 placeholder 不可见

    css
    input:placeholder-shown::placeholder {
      color: transparent;
    }
  2. label 使用绝对定位,来代替文本框原生的 placeholder

    css
    label {
      position: absolute;
      left: 3px;
      top: 2px;
      pointer-events: none;
    }
  3. 在聚焦文本框时,对 label 进行重新定位

    css
    input:not(:placeholder-shown) + label,
    input:focus + label {
      transform: scale(0.75) t r anslate(O, -32px);
    }
  4. 总体

    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>
css
body {
  /* 重置 */
    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');
})

当输入框有 minmax 校验时,可以加入 :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) {}