CSS `Selector `:is() / :where()`:简化复杂选择器与特异性控制

各位观众老爷们,晚上好!今天咱们聊点CSS里的小技巧,保证让你的代码更优雅,生活更美好(至少写CSS的时候)。今天的主题是 :is():where(),这两个家伙能帮你简化复杂的选择器,还能控制特异性,听起来是不是有点意思?

好,废话不多说,咱们直接上干货!

一、 啥是:is():where()

简单来说,:is():where() 都是CSS中的伪类函数选择器。它们的作用是:把一堆选择器打包在一起,让你的CSS代码看起来更简洁,可读性更高。

  • :is(): 可以理解为“是…或者…或者…”。它会匹配括号内任意一个选择器匹配的元素。它的特异性是括号内最高的那个选择器的特异性。

  • :where()::is() 差不多,也是“是…或者…或者…”。区别在于,:where() 的特异性永远是 0!这意味着它不会影响最终样式的优先级。

二、 :is() 的用法

先看一个简单的例子:

/* 传统写法 */
header h1,
header h2,
header h3 {
  color: red;
}

/* 使用 :is() */
header :is(h1, h2, h3) {
  color: red;
}

看到没?:is()h1, h2, h3 塞到一起了,代码瞬间清爽了很多。 这个例子可能不太明显,但是当选择器更复杂的时候,:is() 的威力就显现出来了。

再来一个稍微复杂点的例子:

<article>
  <h1>文章标题</h1>
  <p>文章内容</p>
  <aside>
    <h2>侧边栏标题</h2>
    <ul>
      <li>列表项1</li>
      <li>列表项2</li>
    </ul>
  </aside>
</article>

<footer>
  <h1>页脚标题</h1>
  <p>页脚内容</p>
</footer>
/* 传统写法 */
article h1,
article h2,
article h3,
article p,
article ul,
article ol,
article li {
  font-family: "Arial", sans-serif;
  line-height: 1.5;
}

/* 使用 :is() */
article :is(h1, h2, h3, p, ul, ol, li) {
  font-family: "Arial", sans-serif;
  line-height: 1.5;
}

还是那句话,:is() 让代码更简洁了。

:is() 的特异性:

重点来了!:is() 的特异性取决于括号内最高特异性的选择器。 啥意思呢?看下面的例子:

<div class="container">
  <p id="my-paragraph" class="highlight">这是一段文字。</p>
</div>
/* 使用 :is() */
:is(#my-paragraph, .highlight, p) {
  color: blue;
}

在这个例子中,:is() 包含三个选择器:#my-paragraph (ID选择器), .highlight (类选择器), p (标签选择器)。它们的特异性分别是:

  • #my-paragraph: 100
  • .highlight: 10
  • p: 1

所以,:is() 的特异性是 100 (和 #my-paragraph 一样),因为它是里面最高的。

记住: :is() 的特异性会影响样式的优先级!

三、 :where() 的用法

:where() 的用法和 :is() 基本一样,区别在于它的特异性永远是 0。这意味着 :where() 不会影响样式的优先级。

/* 使用 :where() */
:where(h1, h2, h3) {
  color: green;
}

这个例子中,:where(h1, h2, h3) 的特异性是 0。

:where() 的特异性为 0 的意义:

:where() 非常适合用来设置一些默认样式,或者在不希望影响样式优先级的情况下应用一些样式。

举个例子:

<button class="primary">主要按钮</button>
<button>普通按钮</button>
/* 设置按钮的默认样式,不影响优先级 */
:where(button) {
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

/* 主要按钮的样式 */
.primary {
  background-color: blue;
  color: white;
}

在这个例子中,:where(button) 设置了按钮的默认样式(padding, border, border-radius, cursor)。由于 :where() 的特异性是 0,所以 .primary 的样式会覆盖默认样式。

如果没有 :where(),你需要这样写:

button {
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.primary {
  background-color: blue;
  color: white;
  padding: 10px 20px; /* 需要重复写一遍 */
  border: none;         /* 需要重复写一遍 */
  border-radius: 5px;   /* 需要重复写一遍 */
  cursor: pointer;     /* 需要重复写一遍 */
}

看到了吧? :where() 避免了重复写默认样式,让代码更简洁。

四、 :is():where() 的区别总结

为了更清晰地对比 :is():where(),咱们来个表格:

特性 :is() :where()
作用 将多个选择器组合在一起,匹配其中任意一个选择器匹配的元素。 将多个选择器组合在一起,匹配其中任意一个选择器匹配的元素。
特异性 等于括号内最高特异性的选择器的特异性。 永远是 0。
适用场景 需要简化复杂的选择器,并且希望样式的优先级根据选择器的特异性来决定。 需要简化复杂的选择器,并且不希望影响样式的优先级(例如,设置默认样式)。
举例 :is(h1, h2, .title) 如果 .title 的特异性最高,则整个 :is() 的特异性等于 .title 的特异性。 :where(h1, h2, .title) 整个 :where() 的特异性永远是 0。
适用情况 需要根据选择器类型的不同,来区分样式优先级的情况。比如标题需要优先样式,而默认样式优先级低一些。 需要统一设置一些样式,但是这些样式不应该影响到其他选择器的优先级,比如全局的reset样式,或者一些组件的默认样式。

五、 实际应用场景

  1. 主题切换:

    假设你的网站支持多种主题,你可以使用 :is() 根据不同的主题应用不同的样式。

    <body data-theme="light">
      <h1>这是一个标题</h1>
      <p>这是一段文字。</p>
    </body>
    
    <body data-theme="dark">
      <h1>这是一个标题</h1>
      <p>这是一段文字。</p>
    </body>
    /* 默认主题 */
    h1 {
      color: black;
    }
    
    p {
      color: gray;
    }
    
    /* 深色主题 */
    body[data-theme="dark"] :is(h1) {
      color: white;
    }
    
    body[data-theme="dark"] :is(p) {
      color: lightgray;
    }

    这里,:is() 简化了深色主题的样式,让代码更易读。

  2. 组件库:

    在构建组件库时,可以使用 :where() 来设置组件的默认样式,避免影响使用者自定义样式。

    <my-button>点击我</my-button>
    /* 组件库样式 */
    :where(my-button) {
      padding: 10px 20px;
      background-color: lightblue;
      border: none;
      border-radius: 5px;
      cursor: pointer;
    }
    
    /* 使用者自定义样式 */
    my-button {
      background-color: red;
      color: white;
    }

    由于 :where() 的特异性是 0,所以使用者自定义的 background-colorcolor 会覆盖组件库的默认样式。

  3. 表单样式:

    统一设置表单元素的默认样式,例如 input, textarea, select 等。

    :where(input, textarea, select) {
      padding: 8px;
      border: 1px solid #ccc;
      border-radius: 4px;
      box-sizing: border-box; /* 避免 padding 影响元素尺寸 */
    }
  4. Resetting/Normalizing CSS:

    :where()在reset CSS或Normalize CSS中非常有用,因为它允许你设置默认样式,而不会意外地覆盖其他更具体的样式。

    /* Reset some basic styles */
    :where(html, body, div, span, applet, object, iframe,
            h1, h2, h3, h4, h5, h6, p, blockquote, pre,
            a, abbr, acronym, address, big, cite, code,
            del, dfn, em, img, ins, kbd, q, s, samp,
            small, strike, strong, sub, sup, tt, var,
            b, u, i, center,
            dl, dt, dd, ol, ul, li,
            fieldset, form, label, legend,
            table, caption, tbody, tfoot, thead, tr, th, td,
            article, aside, canvas, details, embed,
            figure, figcaption, footer, header, hgroup,
            menu, nav, output, ruby, section, summary,
            time, mark, audio, video) {
        margin: 0;
        padding: 0;
        border: 0;
        font-size: 100%;
        font: inherit;
        vertical-align: baseline;
    }

    这个例子展示了一个简化的CSS重置,使用:where()确保这些基本样式不会与你之后定义的更具体的样式冲突。

六、 注意事项

  • :is():where() 的括号内可以包含多个选择器,用逗号分隔。

  • :is():where() 可以嵌套使用。

  • :is():where() 可以与其他伪类选择器(例如 :hover, :active)组合使用。

  • :is():where() 在一些老版本的浏览器中可能不支持,需要进行兼容性处理(可以使用 PostCSS 插件)。

  • 虽然 :is():where() 可以简化代码,但是也要注意不要过度使用,以免降低代码的可读性。

七、 总结

:is():where() 是CSS中非常实用的两个伪类函数选择器。它们可以简化复杂的选择器,提高代码的可读性,还可以控制特异性,让你的样式更灵活。

  • :is() 简化选择器,特异性取决于括号内最高的选择器。
  • :where() 简化选择器,特异性永远是 0,适合设置默认样式。

掌握了这两个家伙,你的CSS代码水平绝对能提升一个档次!以后写CSS的时候,不妨试试它们,你会发现新大陆的!

好了,今天的讲座就到这里。希望大家有所收获! 散会!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注