選取器和 @ 規則組合

網頁功能: 容器樣式查詢

問題

我們通常需要結合不同類型的篩選條件,例如選取器 + 媒體查詢、媒體查詢 + 容器查詢等。

舉例來說,將 (prefers-color-scheme: dark) 與指定色彩配置覆寫值的選取器 (例如 :root:has(> head > meta[name="color-scheme"][content="dark"]) 或 :root.dark) 結合,無論色彩配置設定為何,都能在淺色/深色模式下套用特定樣式。

簡單的做法會導致程式碼重複:

/* Light mode styles */
.card.featured {
  font-weight: 400;
}

#logo-dark {
  display: none;
}

@media (prefers-color-scheme: dark) {
  /* Dark mode styles */
  :root:not(.light) {
    .card.featured {
      font-weight: 300;
    }

    #logo-dark {
      display: inline;
    }

    #logo {
      display: none;
    }
  }
}

/* Dark mode styles, again */
:root.dark {
  .card.featured {
    font-weight: 300;
  }

  #logo-dark {
    display: inline;
  }

  #logo {
    display: none;
  }
}

建議做法

將合併篩選器的結果儲存在自訂屬性中,然後使用容器樣式查詢,根據該屬性設定規則。

重要事項:由於容器查詢的運作方式,只有在我們能為必須比對的任何規則設定上層自訂屬性時,這項技術才有效。

1. 將選取邏輯與套用規則分開

:root {
  --color-scheme: light;

  @media (prefers-color-scheme: dark) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="dark"]) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="light"]) {
    --color-scheme: light;
  }
}

2. 套用規則的自訂屬性鍵

@container not style(--color-scheme: dark) {
  .card.featured {
    font-weight: 400;
  }

  #logo-dark {
    display: none;
  }
}

@container style(--color-scheme: dark) {
  .card.featured {
    font-weight: 300;
  }

  #logo {
    display: none;
  }
}

3. 選用:切換顯示設定的公用程式類別

常見的做法是根據條件是否相符,切換顯示設定。公用程式類別必須優先於任意元件樣式 (因此 !important),且其顯示的 display 未知,因此無法使用覆寫,請使用 not style(...) 進行閘道:

@container not style(--color-scheme: dark) {
  .if-dark {
    display: none !important;
  }
}

@container not style(--color-scheme: light) {
  .if-light {
    display: none !important;
  }
}

備用廣告

備用方案分為兩種類型,取決於分支的重要性,以及可接受的備用方案。

  1. 對於關鍵分支,即使不支援樣式查詢,所有狀態也必須正常運作,因此您無法使用樣式查詢。請改用上述基本方法,為每個狀態複製規則。只要公用程式類別也以這種方式定義,就仍可使用。
  2. 對於非關鍵分支,如果可接受預設狀態,您可以在任何 @container 規則之外定義基本樣式,並僅使用樣式查詢做為覆寫。這種做法保留了大部分的精神,主要缺點是覆寫會導致值耦合。
#logo-dark {
  display: none;
}

@container style(--color-scheme: dark) {
  #logo-dark {
    display: inline; /* override */
  }

  #logo {
    display: none;
  }
}