:hover 的工作原理
:hover 是一个伪类,当鼠标指针停在元素上时匹配该元素。把它加到任意选择器后面,再写出悬停状态的样式:
只有 :hover 规则里的声明会改变,其余样式都沿用 .btn 的。指针移开后,元素恢复到正常样式。
用 transition 实现平滑的悬停效果
悬停时的变化是瞬间完成的,除非你把 transition 加在普通规则上(而不是 :hover 规则上),这样移入和移出都会有动画:
transform 和 opacity 是做动画开销最小的属性;它们不会挤动周围的元素。给 width、height 或 margin 做动画,会让页面在每一帧都重新排版。时长、延迟和缓动曲线见 CSS transition 一页。
链接颜色::link、:visited、:hover、:active
链接有四个经典状态,外加键盘焦点,而且规则的顺序很重要:
| 伪类 | 何时生效 |
|---|---|
:link | 链接还没有被访问过 |
:visited | 该 URL 在浏览器历史记录中 |
:hover | 指针停在链接上 |
:active | 链接正在被按下 |
:focus-visible | 链接获得了键盘焦点 |
这些伪类的优先级都相同,所以两条规则同时匹配时,后写的胜出。一个被悬停的已访问链接会同时匹配 :visited 和 :hover;如果 :visited 写在最后,悬停颜色就永远不会显示。安全的顺序是 Link、Visited、Hover、Active(LVHA):
为了防止网页读取你的浏览历史,浏览器限制了 :visited 能修改的内容。只有与颜色相关的属性(color、background-color、border-color、outline-color 等少数几个)会生效,而脚本读到的始终是未访问时的值。
:active:按下状态
:active 在元素被按下时匹配。加一点位移,就能让按钮有真实的按压感:
悬停父元素来设置子元素样式
悬停状态属于指针下方的元素及其所有祖先元素。所以 .card:hover .title 会在卡片的任何部分被悬停时为标题设置样式,同样的思路也能用来显示隐藏的元素:
:focus-within 这一行很重要:没有它,用 Tab 键移到 Delete 按钮的键盘用户就会按下一个看不见的按钮。每个靠悬停显示的元素都要配一条焦点规则。
触摸屏上的悬停
手机和平板没有可以停在元素上的指针。大多数移动浏览器会在第一次点击时应用 :hover,并一直保持到你点击别处,所以悬停样式可能看起来“卡住”了。两条规则可以控制住这个问题:
- 永远不要让
:hover成为访问某些内容的唯一途径。悬停时打开的菜单,点击时也必须能打开。 - 把纯装饰性的悬停效果包进一个检测真实悬停设备的媒体查询里:
@media (hover: hover) {
.card:hover { transform: translateY(-4px); }
}
常见错误
- 冒号前面多了一个空格。
.btn :hover的意思是“.btn里面一个被悬停的元素”。应写成.btn:hover。 - 只在
:hover规则上写transition。 这样移入时有动画,移出时却会直接跳回去。把它写在普通规则上。 - 链接伪类顺序错误。 保持
:link、:visited、:hover、:active的顺序。 - 有悬停样式却没有焦点样式。 键盘用户永远不会触发
:hover;也要给可交互元素设置:focus-visible样式。 - 悬停的元素被别的元素盖住了。 一个看不见的遮罩层(通常是绝对定位的伪元素)可能会截获指针。给遮罩层加上
pointer-events: none即可解决。
常见问题
CSS 中怎么添加悬停效果?
在选择器后面加上 :hover 写一条规则:.btn:hover { background: #1d4ed8; }。指针停在元素上时,这些声明就会生效。在普通规则里加上 transition: background 0.2s;,变化就会带有动画。
:hover 和 :active 有什么区别?
:hover 在指针停在元素上时生效。:active 在元素被按下时生效,从按下鼠标键到松开为止。一个被按下的按钮通常同时处于悬停和激活状态。
链接伪类应该按什么顺序写?
:link、:visited、:hover、:active(记作 LVHA,英文口诀是 "LoVe HAte")。它们的优先级相同,所以后写的规则胜出;换成其他顺序,visited 或 hover 的样式可能会把 hover 或 active 的样式盖住。
CSS 中怎么修改链接颜色?
给 a 元素设置样式:a { color: #2563eb; },再用 a:visited { color: #7c3aed; } 和 a:hover { color: #1d4ed8; } 设置其他状态。在 a 上设置 color 会同时作用于未访问和已访问的链接。
hover 在手机上有效吗?
触摸屏没有可以停在元素上的指针。大多数移动浏览器会在点击时应用 :hover,并一直保持到你点击别处,这可能让悬停样式“卡住”。把仅用于悬停的效果包进 @media (hover: hover),并且绝不要把关键内容藏在悬停之后。