具代表性的面試主題

前端面試題:CSS Anchor Positioning 的佈局模型與核心原語

前端困難
Offer.cc 編輯團隊發佈 更新

題幹

請解釋 CSS Anchor Positioning 的佈局模型,並用一個跟隨卡片的標註說明錨點命名、位置關聯、位置函式、尺寸函式與作用域。

1. 題目與適用場景

頁面中的價格標註需要跟隨商品卡片:標註的起點對齊卡片內容起點,寬度等於卡片寬度;切換由左至右、由右至左或垂直書寫時,關係仍保持正確。同一列表會重複渲染多組卡片與標註,部分頁面還要讓一個範圍條同時參考兩個端點。

這道題討論 CSS Anchor Positioning 的佈局模型。重點是元素如何成為錨點、絕對定位元素如何找到預設錨點、位置與尺寸函式如何解析,以及名稱作用域和包含區塊如何限制關係。視口避讓與浮動元件互動屬於另一類實作問題。

2. 面試官考察點

  • 是否理解 anchor-name 宣告可被引用的錨點,position-anchor 為定位元素選擇預設錨點。
  • 是否能區分 anchor() 回傳位置、anchor-size() 回傳長度。
  • 是否會用邏輯 inset 與邏輯尺寸適配書寫方向,而非固定寫 leftright
  • 是否知道同名錨點的匹配受原始碼順序、樹作用域與 anchor-scope 影響。
  • 是否會先確認絕對定位元素的包含區塊,因為函式值最終仍參與一般定位計算。

3. 回答前需要釐清的問題

  1. 目標元素使用 position: absolute 還是 position: fixed?它的包含區塊是誰?
  2. 關係是「一對一」、多個目標共用一個錨點,還是一個目標參考多個錨點?
  3. 頁面是否重複渲染同名元件,或跨越 Shadow DOM 等樹作用域?
  4. 是否支援 RTL 與垂直書寫模式?需要同步的是物理寬度,還是邏輯 inline size?
  5. 錨點缺失或在目前上下文不可接受時,目標元素要回到哪一個一般定位值?

4. 30 秒回答框架

先用 anchor-name 給來源元素一個虛線識別符,再讓絕對或固定定位的目標透過 position-anchor 選中它。位置用 anchor() 讀取錨點邊緣,尺寸用 anchor-size() 讀取錨點寬高或邏輯尺寸;目標的 inset 仍相對自己的包含區塊計算。支援不同書寫方向時使用 inset-inline-*inset-block-*inline-size。重複元件用 anchor-scope 限制同名錨點,多錨點關係則在不同屬性中明確寫出錨點名稱。

5. 從錨點到最終佈局

第一步:建立明確的錨點關係

來源元素透過 anchor-name 宣告一個或多個名稱。目標必須先進入絕對定位或固定定位,再透過 position-anchor 指定預設錨點:

css
.product-card {
  anchor-name: --product-card;
}

.price-note {
  position: absolute;
  position-anchor: --product-card;
}

position-anchor 只建立預設引用關係。它不會自動替目標設定 inset,也不會改變目標的包含區塊。若名稱找不到可接受錨點,依賴該錨點的函式會使用其回退值或成為無效值,因此基礎定位仍要可預期。

第二步:用 anchor() 讀取位置

anchor() 產生一個長度,用在 inset 屬性中,把目標的一條邊連到錨點的一條邊。邏輯 inset 可以讓同一條規則適用不同書寫方向:

css
.price-note {
  position: absolute;
  position-anchor: --product-card;
  inset-block-start: anchor(end);
  inset-inline-start: anchor(start);
}

這裡的 startend 會結合目前軸向解析。若要引用非預設錨點,可以把名稱直接寫入函式,例如 anchor(--sidebar end)。明確名稱適合一個目標在不同屬性中引用不同來源。

第三步:用 anchor-size() 建立尺寸關係

anchor-size() 回傳錨點的物理或邏輯尺寸,而非座標。讓標註與卡片維持相同邏輯寬度,可以寫:

css
.price-note {
  inline-size: anchor-size(inline);
  max-inline-size: min(32rem, anchor-size(inline));
}

widthheight 適合明確的物理尺寸;inlineblock 適合需要隨書寫模式改變的元件。函式也能放進 calc(),例如把間距設為錨點 inline size 的一部分。它只提供長度,元素位置仍遵循絕對定位規則。

第四步:同時引用多個錨點

範圍條可以把起點設為預設關聯錨點,同時在另一個 inset 明確引用終點:

css
.range-start { anchor-name: --range-start; }
.range-end { anchor-name: --range-end; }

.range-band {
  position: absolute;
  position-anchor: --range-start;
  inset-inline-start: anchor(--range-start center);
  inset-inline-end: anchor(--range-end center);
}

定位元素仍只透過 position-anchor 關聯一個預設錨點;其他名稱可以在 anchor() 中參與位置計算。預設關聯也會影響捲動關聯等行為。兩個 inset 都會進入目標包含區塊的定位方程式,設計時要確保起點與終點順序有效,並替錨點缺失、交叉或不可接受的情況準備回退。

第五步:限制同名錨點的作用域

重複元件若都宣告 --item,未設作用域時,定位元素可能匹配到原始碼順序中最後一個可接受錨點。anchor-scope 可以把同名關係限制在元件子樹內:

css
.result-row {
  anchor-scope: --item;
}

.result-row__value { anchor-name: --item; }
.result-row__note {
  position: absolute;
  position-anchor: --item;
  inset-inline-start: anchor(end);
}

它解決的是名稱可見範圍,不能跨越樹作用域強制引用,也不會建立新的包含區塊。元件仍需明確指定哪個祖先負責定位上下文。

第六步:把包含區塊納入計算

anchor() 回傳的錨點位置會轉換成目標 inset 可用的長度,目標最終仍由自己的絕對定位包含區塊佈局。改變 position: absolutefixed、移動目標 DOM、在祖先建立新的定位上下文,都可能改變結果。排查錯位時先檢查目標包含區塊,再檢查錨點匹配與函式值;只盯著錨點座標,常會漏掉真正的參照系。

6. 高品質示範回答

Anchor Positioning 先建立「來源元素」與「定位元素」的關係。來源用 anchor-name 宣告名稱,絕對或固定定位的目標用 position-anchor 選擇預設錨點。anchor() 為 inset 提供錨點位置,anchor-size() 為寬高或邏輯尺寸提供長度。元件支援 RTL 或垂直書寫時,我會用邏輯 inset 與 inline-size。一個目標需要兩個來源時,先選一個預設關聯,再在各個 anchor() 中寫明名稱;列表重複元件則用 anchor-scope 限制同名錨點。最後檢查目標的包含區塊,因為錨點函式沒有繞過絕對定位模型。

7. 常見錯誤

  • 只寫 anchor-name 就等待元素移動 → 尚未建立定位關係 → 給目標設定絕對或固定定位,並用 position-anchor 或函式中的明確名稱引用。
  • anchor() 當尺寸函式 → 位置與長度職責混淆 → 座標用 anchor(),錨點寬高用 anchor-size()
  • 固定使用 leftwidth → RTL 或垂直書寫關係反轉 → 依元件語意改用邏輯 inset 與邏輯尺寸。
  • 重複列表共用同一個名稱卻未設作用域 → 多個目標跟到最後一個同名錨點 → 在元件容器設定 anchor-scope
  • anchor-scope 當包含區塊 → 名稱匹配正確但座標仍錯 → 單獨檢查負責絕對定位的祖先。
  • 多錨點只寫一個預設 position-anchor → 其他屬性仍錯誤引用預設來源 → 在對應 anchor() 中明確寫出名稱。

8. 追問及應對

追問一:anchor() 與 position-area 有什麼差別?

anchor() 把某個錨點邊緣轉換成 inset 使用的長度,適合精確建立邊對邊關係。position-area 把目標放入以錨點為中心的區域網格,適合表達整體方位。兩者屬於同一佈局體系,但思考層級不同。

追問二:anchor-size() 會讓目標自動跟隨錨點移動嗎?

不會。它只計算一個長度。目標是否跟隨位置變化取決於 anchor()position-area 或其他定位規則;只把 inline-size 設為 anchor-size(inline),只會同步邏輯尺寸。

追問三:多個元素使用同一個 anchor-name 會怎樣?

目標會按可接受錨點的匹配規則選擇來源,同名重複元件很容易全部指向原始碼順序靠後的錨點。對可重複模式,應在每個元件容器用 anchor-scope 限制名稱,或產生明確的獨立名稱。

追問四:為什麼錨點正確,目標仍可能偏移?

目標的 inset 仍屬於絕對定位計算,包含區塊、書寫模式、margin 與自身尺寸都會參與最終位置。先在開發工具中確認目標的 containing block,再檢查預設錨點與每個函式的解析結果。

公開來源

同類題目