過去,如要根據元件內容套用不同版面配置,必須在 HTML 範本語言中使用 JavaScript 或條件邏輯,插入修飾符類別 (例如 .card--has-image 或 .card--text-only)。
:has() 虛擬類別可做為父項選取器,因此不需要這麼做。您可以根據特定子系元素是否存在,有條件地設定容器元素的樣式。
使用 :has(),您就能根據元件的實際 DOM 內容,輕鬆在 CSS 中定義不同的版面配置變化版本。您也可以視需要搭配 :not(),明確指定缺少內容,以定義預設版面配置。
實作以內容為基礎的容器樣式
必要:您必須在容器元素上使用 :has() 選取器,偵測是否有特定子項內容。
如要建構會根據內容變更版面配置的元件,請按照下列步驟操作:
- 定義預設樣式:將基本版面配置樣式套用至容器元素 (例如簡單的單欄堆疊)。
- 套用內容覆寫:使用
:has([child-selector])指定容器,並在該內容出現時套用新的版面配置樣式 (例如多欄格線)。
範例:如果圖片存在,資訊卡元件會切換為並排版面配置。
/* 1. Define the default state on the component container */
/* This applies when there is NO image */
.article-card {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1.5rem;
border: 1px solid #ccc;
border-radius: 8px;
}
/* 2. Apply styles when a specific child element is present */
/* MANDATORY: Target the container and use :has() to check for the descendant */
.article-card:has(img) {
/* Change the layout to a row if an image exists */
flex-direction: row;
align-items: center;
}
/* Optional: Style the image itself (no :has() needed here) */
.article-card img {
width: 150px;
height: auto;
border-radius: 4px;
}
/* You can also combine :has() and :not() to explicitly target the ABSENCE of content */
/* This selects a card that DOES NOT have an image */
.article-card:not(:has(img)) {
/* E.g., apply a different background color for text-only cards */
background-color: #f9f9f9;
}
<!-- Assume an <h1> precedes these components in the document layout -->
<!-- A card WITH an image (will use row layout) -->
<article class="article-card">
<img src="thumbnail.jpg" alt="Article thumbnail" />
<div class="content">
<h2>Card With Image</h2>
<p>This card lays out its content horizontally.</p>
</div>
</article>
<!-- A card WITHOUT an image (will use default column layout) -->
<article class="article-card">
<div class="content">
<h2>Text-Only Card</h2>
<p>This card lays out its content vertically, and gets its background color from the :not(:has()) rule.</p>
</div>
</article>
效能提示:使用 :has() 時,請將選取器範圍限定在最明確的元件容器 (例如 .article-card)。如果樣式變更高度局部化,請避免將其錨定在非常高階的元素 (例如 body:has(img)),因為廣泛的 :has() 查詢可能會觸發更多版面配置重新計算。
備用策略
如果內容式版面配置樣式對使用者體驗或網頁設計至關重要,請務必為不支援 :has() 選取器的瀏覽器提供備用方案。如果只是為了裝飾效果,:has() 可做為漸進式增強功能,不需備用。
必要:為重要版面配置導入備用方案時,必須在 CSS 中使用 @supports not selector(:has(*)) 定義傳統的類別型備用方案 (例如 .has-image)。
與互動狀態樣式不同,內容存在與否通常在轉譯時就已知。最穩健的備用方案是,如果資料中存在子元素 (例如圖片),則讓伺服器端範本引擎 (或靜態網站產生器) 將 .has-image 等類別插入容器。
如果無法使用伺服器端轉譯,則必須使用含有 CSS.supports() 的小型指令碼來偵測內容,並在載入時或動態內容插入後附加類別。
/* Fallback CSS for older browsers */
/* We check if the browser DOES NOT support the :has() selector */
@supports not selector(:has(*)) {
/* Define a traditional modifier class that applies the exact same layout overrides */
.article-card.has-image {
flex-direction: row;
align-items: center;
}
.article-card:not(.has-image) {
background-color: #f9f9f9;
}
}
/* Fallback JavaScript for older browsers (if not using SSR to add the class) */
/* Check for support before running the script to avoid unnecessary work in modern browsers */
if (!CSS.supports('selector(:has(*))')) {
// Find all components that need checking
const cards = document.querySelectorAll('.article-card');
cards.forEach(card => {
// If the critical content exists, manually add the fallback class
if (card.querySelector('img')) {
card.classList.add('has-image');
}
});
}