Web前端技术 · 第8课16 / 18 | 编码:L08-90
进阶观察 · 从本课知识向前一步

关系伪类 :has():根据勾选状态改变卡片样式

勾选“参加唱腔赏析”,观察整张卡片的边框和背景;再取消勾选,看看它们怎样变化。

1 · 先看效果

单独打开演示(新标签页)

2 · 再看代码:怎样让整张卡片变色?

<style>
.choice {
  padding: 22px;
  border: 3px solid #aebfc2;
}
.choice:has(input:checked) {
  border-color: teal; /* 青绿色 */
  background: #def3e9; /* 浅绿色 */
}
</style>

<article class="choice">
  <label>
    <input type="checkbox"> 参加唱腔赏析
  </label>
  <p>周三 14:00 · A208</p>
</article>

先有卡片和复选框

<article class="choice"> 是整张卡片;内部的 input 是复选框。label 包裹复选框和文字,因此点击“参加唱腔赏析”也能切换选中状态。

.choice 设置卡片的默认样式:padding 留出内边距,border 设置灰色实线边框。

再判断:内部是否有已勾选的控件

input:checked 匹配当前已勾选的复选框。.choice:has(input:checked) 可以读作:“选中内部包含已勾选复选框的 .choice 卡片”。

样式作用于整张卡片,不是复选框。:has(...) 中的内容是筛选条件,外面的 .choice 才是本例的样式目标。

最后改变边框和背景

勾选后,第二条规则匹配卡片:border-color: teal 把边框改为青绿色,background: #def3e9 把背景改为浅绿色。

取消勾选后,第二条规则不再匹配,卡片恢复默认的灰色边框和原背景。这项变色效果由 CSS 完成,不需要 JavaScript 处理点击事件。

思考

把规则改成 .choice input:checked { background: teal; },是否仍会让整张卡片变色?

展开参考分析

不会。后代选择器直接匹配 input,:has() 则在筛选外层 .choice。样式施加在哪个元素上,要看整个选择器的匹配目标,而不是只看条件中出现了谁。

现代关系选择器::has()。它扩展匹配条件,不负责保存报名或提交数据。

完整源码:展开、修改与运行
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>关系伪类 :has():根据勾选状态改变卡片样式</title>
  <style>
body { margin:16px; color:#183347; background:white; font:20px/1.5 "Times New Roman",SimSun,serif; }
h1,h2 { font-family:"Times New Roman",SimHei,sans-serif; }
button,input,select { font:inherit; max-width:100%; }
button { margin:4px 0; cursor:pointer; }
pre { white-space:pre-wrap; overflow-wrap:anywhere; font:18px/1.5 Consolas,SimSun,monospace; }
:focus-visible { outline:3px solid #b56220; outline-offset:3px; }
.choice { padding:22px; border:3px solid #aebfc2; }
.choice:has(input:checked) { border-color:teal; background:#def3e9; }
  </style>
</head>
<body>
<article class="choice">
<label>
<input type="checkbox"> 参加唱腔赏析</label>
<p>周三 14:00 · A208</p>
</article>
<p id="support">
</p>
  <script>
document.querySelector('#support').textContent = CSS.supports('selector(:has(*))') ? '当前浏览器支持 :has()。' : '当前浏览器不支持 :has(),复选框仍可选择。';
  </script>
</body>
</html>