CSS 高级伪类指南::has、:is、:where 等 8 个实用选择器解析

摘要:除了常用的 :hover、:active、:focus,CSS 中还有一些冷门但非常实用的伪类,可以帮助你更优雅地处理各种交互场景。本文整理了 8 个值得掌握的 CSS 伪类,附带代码示例和兼容性说明。

除了常用的 :hover、:active、:focus,CSS 中还有一些冷门但非常实用的伪类,可以帮助你更优雅地处理各种交互场景。本文整理了 8 个值得掌握的 CSS 伪类,附带代码示例和兼容性说明。


1. :has() — 父级选择器

:has() 是 CSS 中一项重要的特性,允许根据子元素的存在与否来选择父元素,一定程度上可以减少对 JavaScript 的依赖。

/* 选择包含错误提示子元素的卡片 */
.card:has(.error) {
  border: 2px solid red;
}

/* 选择包含图片的链接 */
a:has(img) {
  text-decoration: none;
}

/* 选择表单中有无效输入的容器 */
.form-group:has(:invalid) {
  background: #ffeeee;
}

实际应用:

/* 当卡片内没有图片时,调整布局 */
.card:not(:has(img)) {
  grid-template-columns: 1fr;
}

/* 当标题超长时,隐藏描述 */
.card:has(h1.long-title) .description {
  display: none;
}

兼容性:Chrome 105+ | Safari 15.4+ | Firefox 121+


2. :is() 和 :where() — 选择器分组

这两个伪类用于简化复杂选择器的写法,提升代码可读性。

/* 传统写法 */
.card h1,
.card h2,
.card h3 {
  color: #333;
  margin-top: 0;
}

/* :is() 一行搞定 */
.card :is(h1, h2, h3) {
  color: #333;
  margin-top: 0;
}

:is() 与 :where() 的区别

/* :is() 优先级正常 */
.card :is(h1, h2) {
  color: red;   /* 优先级 (0,1,1) */
}

/* :where() 优先级为 0,可被覆盖 */
.card :where(h1, h2) {
  color: blue;  /* 优先级 (0,0,0) */
}

/* 后面的样式可以覆盖 :where() */
.card h1 {
  color: green; /* 覆盖成功 */
}

/* 但不能覆盖 :is() */
.card h1 {
  color: green; /* 无法覆盖 */
}

应用场景:

  • :is():需要保持选择器优先级时使用

  • :where():用于重置样式或降低优先级时使用

兼容性:Chrome 88+ | Firefox 78+ | Safari 14+


3. :not() — 否定选择器

:not() 用于排除特定元素,支持多参数。

/* 选择所有段落,排除 .intro 和 .footer */
p:not(.intro, .footer) {
  margin-bottom: 1rem;
}

/* 选择所有 input,排除 checkbox 和 radio */
input:not([type="checkbox"]):not([type="radio"]) {
  width: 100%;
}

/* 选择所有链接,排除 .external 和 #homepage */
a:not(.external, #homepage) {
  color: blue;
}

实际案例:

/* 隐藏所有元素,除了活动项 */
.list-item:not(.active) {
  display: none;
}

/* 所有按钮加样式,排除禁用的 */
button:not(:disabled) {
  cursor: pointer;
  opacity: 1;
}

/* 非空元素添加边框 */
*:not(:empty) {
  border: 1px solid #eee;
}

兼容性:广泛支持(多参数需 Chrome 88+ | Firefox 84+ | Safari 9+)


4. :target — URL 锚点定位

:target 根据 URL 中的 # 锚点改变样式,可实现无 JavaScript 的页面内跳转高亮。

/* 当用户访问 #section1 时 */
#section1:target {
  background: yellow;
  padding: 20px;
}

/* 当访问任何锚点时 */
:target {
  animation: highlight 2s ease;
}

@keyframes highlight {
  0% { background: yellow; }
  100% { background: transparent; }
}

实际应用:

html
<div id="intro">内容...</div>
<div id="details">内容...</div>
/* 当用户访问 #details 时,显示详情面板 */
#details:target .panel {
  display: block;
  animation: slideIn 0.3s ease;
}

/* 高亮当前章节 */
[id]:target {
  border-left: 4px solid #4fd1c5;
  padding-left: 16px;
}

适用场景:

  • 无 JavaScript 的 Tab 切换

  • FAQ 展开/折叠

  • 文档章节高亮

兼容性:所有现代浏览器


5. :focus-within — 子元素获得焦点

当元素自身或子元素获得焦点时触发,适合实现容器级的焦点反馈。

/* 输入框获得焦点时,容器也触发样式 */
.form-control:focus-within {
  border-color: #4fd1c5;
  background: #f0f9ff;
}

/* 当表单内有任何输入框获得焦点时 */
form:focus-within button[type="submit"] {
  background: #4fd1c5;
  transform: scale(1.05);
}

实际案例:

/* 搜索框聚焦时,显示下拉建议 */
.search-container:focus-within .suggestions {
  display: block;
}

/* 模态框内的输入框聚焦时,模态框高亮 */
.modal:focus-within {
  box-shadow: 0 0 0 4px rgba(79, 209, 197, 0.2);
}

/* 导航菜单聚焦时,显示子菜单 */
.nav-item:focus-within .submenu {
  opacity: 1;
  transform: translateY(0);
}

兼容性:Chrome 60+ | Firefox 52+ | Safari 10.1+


6. :checked — 复选框状态

:checked 用于选中状态的复选框或单选框,可实现无 JavaScript 的交互效果。

/* 复选框选中时,改变样式 */
input[type="checkbox"]:checked + label {
  text-decoration: line-through;
  color: #999;
}

/* 实现开关 */
.toggle-switch input[type="checkbox"]:checked + .slider {
  background: #4fd1c5;
}

.toggle-switch input[type="checkbox"]:checked + .slider:before {
  transform: translateX(26px);
}

高级应用:手风琴菜单

.accordion input[type="radio"]:checked ~ .content {
  max-height: 500px;
  padding: 20px;
}

.accordion input[type="radio"]:checked ~ .header .icon {
  transform: rotate(180deg);
}
html
<div class="accordion">
  <input type="radio" name="accordion" id="item1" checked>
  <label class="header" for="item1">
    标题 1 <span class="icon">▼</span>
  </label>
  <div class="content">内容...</div>
</div>

兼容性:所有现代浏览器


7. :placeholder-shown — 占位符显示状态

:placeholder-shown 用于匹配占位符可见的输入框,常用于实现浮动标签效果。

/* 当占位符显示时(空输入框) */
input:placeholder-shown + label {
  position: absolute;
  top: 12px;
  font-size: 16px;
}

/* 当占位符消失时(有内容) */
input:not(:placeholder-shown) + label {
  position: absolute;
  top: -8px;
  font-size: 12px;
  background: white;
  padding: 0 4px;
  color: #4fd1c5;
}

实际案例:浮动标签

.input-group input:placeholder-shown ~ .label {
  transform: translateY(0);
}

.input-group input:not(:placeholder-shown) ~ .label,
.input-group input:focus ~ .label {
  transform: translateY(-24px);
  font-size: 12px;
  color: #4fd1c5;
}

兼容性:Chrome 47+ | Firefox 52+ | Safari 9+


8. :blank — 空内容选择

:blank 用于选择没有内容的元素(包括空白节点),适用于隐藏空元素或显示占位内容。

/* 选择空段落 */
p:blank {
  display: none;
}

/* 空单元格加虚线边框 */
td:blank {
  border: 1px dashed #ccc;
}

实际应用:

/* 空列表项隐藏 */
li:blank {
  display: none;
}

/* 空提示框显示占位文字 */
.message:blank::before {
  content: "暂无消息";
  color: #999;
}

兼容性:实验性特性,目前 Chrome 和 Firefox 部分版本需启用实验性 Web 平台特性才支持


结语

以上 8 个 CSS 伪类在不同场景下各有用途,合理使用可以简化代码结构、减少 JavaScript 依赖。可以根据项目需求逐步尝试引入。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_13502