[CSS] Efficient CSS
keywords: css, refactor
:is() 和 :where
:is() @ MDN
範例一
/* 原本的寫法 */
article h2,
article h3,
article h4,
article h5 {
  font-weight: bold;
  font-family: sans-serif;
}
使用 :is()(過去曾經稱作 :matches() 或 :any())來改寫:
/* 更好的寫法 */
article :is(h2, h3, h4, h5) {
  font-weight: bold;
  font-family: sans-serif;
}
範例二
/* CREDIT: https://developer.mozilla.org/en-US/docs/Web/CSS/:is */
/* 原本的寫法 */
header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}
可以優化成:
:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
提示
:is() 和 :where() 的作用相同,差別只在於它們的 specificity 不同。
:not()
:not() @ MDN
:not()前面有空格和沒空格的意思 不同p:not(.foo):找到元素是<p>,但 class 不為.foo的元素p :not(.foo):<p>元素中,class 不為.foo的「所有」元素
:not(.foo, .bar)的作用等同於:not(.foo):not(.bar)
/* CREDIT: https://developer.mozilla.org/en-US/docs/Web/CSS/:not */
/* 除了 class 是 .fancy 的其他所有 <p> */
p:not(.fancy) {
  color: green;
}
/* <body> 中除了 <p> 之外的所有元素 */
body :not(p) {
  text-decoration: underline;
}
/* <body> 中除了 <div> 或 <span> 的所有元素 */
body :not(div):not(span) {
  font-weight: bold;
}
/* 等同於上面的寫法 */
body :not(div, span) {
  font-weight: bold;
}
也可以搭配其他 selector 做組合技:
/* article 中所有 h2, h4, h5,以及「所有不是在 aside 裡的 h3」 */
article :is(h2, h3:not(aside h3), h4, h5) {
  /* rules */
}
:has():如果有...則
:has() @ MDN
透過 :has() 可以用來「檢驗某個條件是否符合」,如果符合的話才套用特定的 CSS:
/* CREDIT: https://developer.mozilla.org/en-US/docs/Web/CSS/:has */
/* 如果 a 裡直接有 img,則套用特定樣式到 a 上 */
a:has(> img) {
  /* rules */
}
/* 如果 h1 後面直接跟著 p,則套用特定樣式在 h1 上面 */
h1:has(+ p) {
  color: red;
}
/* 如果 ul 中 li 有第 6 個 child,則以兩欄的方式顯示 */
ul:has(li:nth-child(6)) {
  columns: 2;
}
/* 如果 ul 中 li 有第 11 個 child,則以三欄的方式顯示 */
ul:has(li:nth-child(6)) {
  columns: 3;
}
參考資料
- Intermediate HTML and CSS @ Frontend Masters
 - CSS @ MDN