前端面試:如何用 CSS sibling-index() 和 sibling-count() 產生自適應序號?
題幹與適用場景
一個響應式卡片列表由 CMS 動態增刪。設計要求每張卡依兄弟總數計算寬度,並按目前位置延遲動畫,同時保留真實的可及性序號。請說明 sibling-index()、sibling-count() 的語意、使用邊界、降級和驗證。
面試官考察點
- 是否知道兩個函式回傳整數,位置從 1 開始,作用於 flat tree。
- 是否區分 CSS 視覺順序與 DOM/輔助技術順序。
- 是否考慮函式尚未 Baseline、
@supports、靜態回退和效能。 - 是否能說明 Shadow DOM、偽元素、隱藏節點和動態列表的影響。
回答前需要釐清的問題
- 目標是視覺寬度、動畫延遲,還是使用者必須讀到的序號?降級不同。
- 列表是否包含隱藏、模板或虛擬化節點?它們是否仍在 flat tree?
- 支援的瀏覽器範圍和是否允許 JavaScript 回退是什麼?
- 是否使用 Shadow DOM、slot 或 CSS counter?這會改變驗證方式。
30 秒回答框架
sibling-count() 回傳父級直接子元素總數,sibling-index() 回傳目前元素在兄弟中的 1-based 位置,規範按 flat tree 計算。它們適合把數量和位置用於 calc()、網格寬度或動畫延遲,但不是可靠的可及性文字來源。先用固定 CSS 回退,再以 @supports 啟用新函式;序號交給語意 HTML 或可驗證的 counter。測試動態增刪、slot、隱藏項目、瀏覽器不支援和 prefers-reduced-motion。
分步驟深入解答
1. 先確認函式回傳什麼
兩個函式都回傳整數。sibling-count() 包含元素自身;sibling-index() 從 1 計數。它們統計父元素的直接子元素,規範描述的是 flat tree,因此不能把任意後代或視覺排列順序當成兄弟位置。
2. 用於尺寸和動畫
卡片可以按兄弟數量分攤寬度,動畫延遲可以按目前位置遞增:
.card {
--count: sibling-count();
--index: sibling-index();
flex-basis: calc(100% / var(--count));
animation-delay: calc((var(--index) - 1) * 60ms);
}這是視覺計算,不應取代 DOM 順序或業務編號。對空列表、單項和很大數量設定邊界,避免除零或過長延遲。
3. 處理不支援與降級
MDN 將這些函式標為 Limited availability,不能假定所有生產瀏覽器支援。先提供固定寬度或 flex 回退,再用 @supports (width: calc(100% / sibling-count())) 漸進增強。不支援時,JavaScript 只在業務確實需要動態值時更新 CSS 自訂屬性,不要讓首屏依賴腳本才能可用。
4. flat tree、slot 與隱藏節點
規範以 flat tree 定義兄弟關係;Shadow DOM 的 slot 分發會影響可見樹和測試結果。display: none、模板節點、虛擬列表佔位符是否成為直接子元素必須用實際 DOM 驗證。不要憑視覺順序推斷函式結果,也不要把 order 改變當成索引改變。
5. 可及性與語意
視覺延遲和寬度不會產生可讀序號。列表應使用 ol、li 或明確的 aria-posinset 與 aria-setsize,並確保螢幕閱讀器順序與 DOM 一致。若 CSS 只用於裝飾,停用動畫或函式不應影響內容理解。
6. 動態更新與效能
兄弟增刪會改變計算值,瀏覽器需要重新計算受影響的樣式。數千節點的列表應測量樣式重算、版面和動畫,而不是只看單一 demo。虛擬化列表可限制 DOM 數量,但此時函式只看得到視窗內兄弟,不能代表總資料集。
高品質示範回答
我會把 sibling-index() 和 sibling-count() 當作視覺計算能力:前者回傳 flat tree 中從 1 開始的位置,後者回傳直接子元素總數。卡片寬度和動畫延遲可用它們增強,但語意序號仍由 ol、li 或 ARIA 提供。生產 CSS 先有固定版面回退,再用 @supports 檢測函式;對 Shadow DOM、slot、隱藏節點和虛擬化列表做真實 DOM 測試。動態增刪和大列表要測樣式重算與版面;不支援時保證內容可讀,並遵守 prefers-reduced-motion。
常見錯誤
- 把函式當成普遍可用 → 舊瀏覽器樣式失效 → 提供固定版面和
@supports回退。 - 用視覺
order推斷索引 → CSS 順序不等於 flat tree 順序 → 以 DOM 和 slot 分發測試。 - 用 CSS 計算取代可及性序號 → 螢幕閱讀器得不到位置 → 保留 HTML 語意或 ARIA。
- 虛擬列表直接代表總數量 → 函式只看到目前 DOM 視窗 → 由業務資料提供總數。
- 大列表無限遞增動畫延遲 → 等待時間和重算成本失控 → 設上限並按 reduced motion 關閉。
追問及應對
sibling-count() 會把後代元素也算進去嗎?
不會。它統計父元素的直接子元素,並包含目前元素;後代節點不參與。
元素透過 slot 投影時,應按哪個順序驗證?
同時檢查 Shadow DOM 的 light tree、slot 分發後的 flat tree 和輔助技術讀取順序。用瀏覽器實際 DOM 與可及性樹驗證,不能只看原始碼排列。
舊瀏覽器完全不支援時,可以只用 JavaScript 嗎?
可以作為漸進增強,但基礎版面和內容不能依賴腳本。腳本更新 CSS 變數時還要處理增刪、SSR 首屏、停用腳本和 reduced-motion。