:has() 实战

真实项目中的 :has() 应用案例

实战应用场景

:has() 伪类在实际项目中有着广泛的应用场景。 通过根据子元素的状态来改变父元素的样式,我们可以实现许多以前需要 JavaScript 才能完成的功能。

本页面展示了 4 个真实的应用案例,涵盖了表单验证、卡片状态管理、导航菜单和购物车等常见场景。 这些案例都是可以直接应用到实际项目中的实用技巧。

  • 表单验证 - 根据输入框状态改变表单容器样式
  • 卡片状态 - 根据内容和选中状态调整卡片布局
  • 导航菜单 - 智能高亮和子菜单指示
  • 购物车 - 根据商品数量显示不同状态

案例 1: 表单验证状态

使用 :has() 根据表单内输入框的验证状态,动态改变表单容器的样式,提供实时的视觉反馈。

效果预览 - 尝试填写表单

用户注册

✓ 表单填写完整,可以提交
用户名必须至少包含 3 个字符
请输入有效的电子邮箱地址
密码必须至少包含 6 个字符

💡 尝试填写表单,观察表单容器的边框和背景色变化

/* 表单包含无效输入时显示错误样式 */
.validation-form:has(input:invalid) {
  border-color: red;
  background: #fee;
}

/* 显示错误提示 */
.validation-form:has(input:invalid) .form-status.error {
  display: block;
}

/* 表单全部有效时显示成功样式 */
.validation-form:has(input:valid):not(:has(input:placeholder-shown)) {
  border-color: green;
  background: #efe;
}

/* 显示成功提示 */
.validation-form:has(input:valid):not(:has(input:placeholder-shown)) .form-status.success {
  display: block;
}

/* 优势:无需 JavaScript 即可实现实时验证反馈 */

案例 2: 卡片状态管理

根据卡片内容和选中状态,动态调整卡片的样式和布局。这在任务列表、商品列表等场景中非常实用。

效果预览 - 点击复选框查看效果

智能手机

最新款旗舰手机,性能强劲

¥4,999

无线耳机

降噪耳机,音质出色(无图片)

¥1,299

笔记本电脑

轻薄便携,适合办公

¥6,999

智能手表

健康监测,运动追踪(无图片)

¥2,499

💡 点击卡片右上角的复选框,观察卡片样式变化。有图片的卡片布局也不同。

/* 卡片包含选中复选框时高亮 */
.product-card:has(input[type="checkbox"]:checked) {
  background: lightgreen;
  border-color: green;
  box-shadow: 0 4px 12px rgba(0, 255, 0, 0.2);
  transform: scale(1.02);
}

/* 显示选中标签 */
.product-card:has(input:checked)::before {
  content: '✓ 已选中';
  position: absolute;
  top: 15px;
  left: 15px;
  background: green;
  color: white;
  padding: 4px 12px;
  border-radius: 20px;
}

/* 卡片包含图片时调整布局 */
.product-card:has(img) {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 15px;
}

/* 多种状态组合:根据内容和选中状态动态调整 */

案例 3: 导航菜单高亮

使用 :has() 实现智能导航菜单,根据当前页面链接自动高亮父级导航项,并为包含子菜单的项显示箭头。

效果预览 - 点击链接查看效果

💡 "产品中心"包含当前激活的子链接,因此自动高亮并展开。有子菜单的项显示箭头。

/* 包含当前页面链接的导航项高亮 */
.smart-nav li:has(a.active) {
  background: lightgreen;
  border-radius: 8px;
  padding: 8px;
}

/* 包含子菜单的导航项显示箭头 */
.smart-nav li:has(ul) > a::after {
  content: '▼';
  float: right;
  transition: transform 0.3s;
}

/* 展开包含激活链接的子菜单 */
.smart-nav li:has(a.active) ul {
  max-height: 500px;
}

/* 旋转箭头 */
.smart-nav li:has(a.active) > a::after {
  transform: rotate(180deg);
}

/* 优势:父级导航自动感知子链接状态,无需手动添加类 */

案例 4: 购物车状态

根据购物车中是否有商品,动态显示不同的状态和操作按钮。这是电商网站中非常常见的场景。

效果预览 - 点击按钮添加/移除商品

购物车

0 件商品

购物车是空的

快去添加一些商品吧!

测试功能:添加商品到购物车

💡 添加商品到购物车,观察空状态和有商品状态的切换。结算按钮只在有商品时显示。

/* 购物车为空时显示提示 */
.shopping-cart:not(:has(.cart-item)) .empty-message {
  display: block;
}

/* 隐藏空购物车的商品列表 */
.shopping-cart:not(:has(.cart-item)) .cart-items {
  display: none;
}

/* 隐藏空购物车的数量标签 */
.shopping-cart:not(:has(.cart-item)) .cart-count {
  display: none;
}

/* 购物车有商品时显示结算按钮 */
.shopping-cart:has(.cart-item) .cart-actions {
  display: flex;
}

/* 优势:根据商品数量自动切换状态,无需手动管理类名 */

浏览器兼容性

:has() 是一个相对较新的 CSS 特性,主流现代浏览器已经支持。

浏览器 版本 支持状态
Chrome / Edge 105+ ✓ 完全支持
Firefox 121+ ✓ 完全支持
Safari 15.4+ ✓ 完全支持
Opera 91+ ✓ 完全支持
IE 11 - ✗ 不支持
⚠️ 兼容性建议

如果需要支持旧版浏览器,可以使用 @supports 检测 :has() 支持情况, 并提供降级方案(如使用 JavaScript 或传统的类名管理)。

/* 检测 :has() 支持 */
@supports selector(:has(*)) {
  .card:has(input:checked) {
    /* 支持 :has() 的样式 */
  }
}

@supports not selector(:has(*)) {
  .card.selected {
    /* 降级方案:使用类名 */
  }
}

更多兼容性信息请访问: Can I Use - :has()

实战总结

通过这 4 个实战案例,我们看到了 :has() 在真实项目中的强大应用:

  • 表单验证 - 无需 JavaScript 即可实现实时验证反馈
  • 卡片管理 - 根据内容和状态自动调整样式和布局
  • 智能导航 - 父级菜单自动感知子链接状态
  • 购物车 - 根据商品数量动态切换空/非空状态

:has() 让我们能够用纯 CSS 实现许多以前需要 JavaScript 才能完成的功能, 大大简化了代码,提升了性能和可维护性。在支持的浏览器中,它是一个非常值得使用的现代特性。