结合 CSS :has() 和 HTML <select> 以获得更好的条件样式

207 阅读3分钟

CSS的:has()伪类虽然是一项新兴技术,但众多文章和教程已经充分展示了其根据元素内容进行条件性选择的能力。这一特性特别适合与表单控件结合使用,因为表单控件本质上是条件性的。

<select>元素为例,它允许用户从多个<option>中进行选择。结合:has()伪类,我们能够根据用户选择的<option>来动态改变样式。

<select>
  <option value="1" selected>选项 1</option>
  <option value="2">选项 2</option>
  <option value="3">选项 3</option>
  <option value="4">选项 4</option>
  <option value="5">选项 5</option>
</select>

上述代码创建了一个标准的下拉菜单,其中第一个<option>元素通过selected属性被预设为选中状态。

利用用户的选择来应用样式并非新概念。多年来,我们一直在使用:checked伪类来根据选项的选择来改变元素的样式。在以下示例中,我将展示如何根据所选的<option>来更改元素的颜色和background-color属性。

然而,这种样式的应用仅限于当前元素。如果一个特定的<option>被选中,我们只能针对该选项进行样式设计。虽然可以编写更复杂的选择器来根据选项的选择状态来对子元素进行样式设计,但这种方式无法对更高层级的父元素进行样式设计。

:has()伪类在这里发挥了作用,因为它专门设计用于链式向上选择元素,这也是它常被称为“父选择器”的原因,尽管“家族选择器”可能是一个更准确的描述。

例如,如果我们想根据所选<option>的值来改变<select>元素的background-color,我们可以根据:checked状态选择具有特定值的元素。

这一技术的实际应用非常广泛。例如,我可以为没有有效选择的必选<select>元素设计样式。不是在元素具有:checked状态时应用样式,而是在所需元素不包含:checked状态时应用样式。

我们的使用不必局限于此。既然可以使用:has()来为<select>元素(作为<option>的父元素)设计样式,那么我们同样可以为<select>的父元素、乃至于整个DOM链上的任何元素设计样式,直至:root元素。我们甚至可以使用:has()来检测文档的任何<select>子元素是否选择了特定的<option>

:root:has(select [value="foo"]:checked) {
  /* 如果<option value="foo">被选中,则应用样式 */
}

这在动态设置自定义属性值或为整个页面应用一组样式时非常有用。例如,我们可以创建一个样式选择器来展示如何在整页上设置样式的概念。

或者,我们可以创建一个主题选择器:

在最后一个示例中,我为每个<select>元素添加了一个类,并在:has()选择器中引用了这个类,以避免在页面上存在多个<select>元素时产生不必要的选择。

当然,我们不必总是上溯到:root元素。如果我们正在处理特定组件,我们可以像以下星级评分组件演示中那样,将:has()的作用域限定为该组件。

通过这种方式,:has()伪类提供了一种强大而灵活的方法来根据用户的选择动态改变页面的样式,增强了Web开发中样式设计的深度和复杂性。