放置工具提示或下拉式選單時,您通常會想將其放置在頁面上的另一個元素旁邊。雖然過去可使用絕對定位來達成此效果,但如果需求較複雜,通常會使用 JavaScript 定位項目。
CSS 錨點定位功能可讓您以宣告方式,將元素定位在另一個元素的相對位置。
繫結元素
如要將元素設為錨點,請為其提供以兩個破折號開頭的任何字串 anchor-name
值。這是定位元素用來尋找錨點的 ID,建議您為其提供描述性名稱。如果元素會以不同方式做為錨點使用,您甚至可以為元素提供多個錨點名稱。
您需要在定位元素上設定幾個屬性,才能繫結該元素。首先,您需要將元素從文件的流程中拉出,方法是設定 position: absolute
或 position: fixed
,讓元素浮動。
接著,您需要設定要繫結的錨點,方法是將 position-anchor
設為您在錨點上設定的錨點名稱。
最後,您需要設定錨點的放置位置。本單元稍後會進一步說明 position-area
。
#anchor {
anchor-name: --my-anchor;
}
#positionedElement {
position: absolute;
position-anchor: --my-anchor;
position-area: end;
}
隱含繫結
Popover 的繫結方式更簡單。使用含有 popovertarget
的按鈕開啟浮動視窗,或透過 showPopover({source})
設定 source
時,浮動視窗已設定「隱含錨點」。由於彈出式視窗預設會隨著 position: fixed
浮動,因此如要設定彈出式視窗的位置,您只需要設定位置即可。
#anchor{}
#positionedElement {
position-area: end;
margin: unset;
}
設定潛在錨點的範圍
您可以在元件中實作錨點定位,以便在多個位置使用下拉式選單等模式。如果您多次使用相同的 anchor-name
,如何確保每個定位元素都能找到正確的錨點?
JavaScript 解決方案需要為每個錨點新增專屬 ID,然後從定位元素參照該 ID。這樣做很麻煩,而 CSS 提供了更簡單的解決方案 anchor-scope
。
anchor-scope
屬性會設定要比對的錨點名稱,僅限元素及其後代。這個屬性接受一或多個錨點名稱的清單,或 all
關鍵字,以限制所有已定義錨點名稱的範圍。
理想情況下,anchor-scope
會新增至定位元素和錨點元素的祖先,且該祖先不得包含其他同名的錨點元素。通常位於可重複使用的元件根目錄。
以下範例顯示套用至具有相同 anchor-name
的重複元素時,anchor-scope
的差異。在本例中,所有 <img>
元素和圖片橫幅都會參照 --image
錨點名稱。將 anchor-scope
套用至 <li>
元素時,position-anchor: --image
只會比對與橫幅位於同一 <li>
元素中的 <img>
元素,否則會比對最後一個算繪的 <img>
。
位置
現在您已將元素繫結至錨點,接下來請放置元素。錨點定位提供兩種定位方法:position-area
和 anchor()
函式。
position-area
position-area
屬性可讓您指定一或兩個關鍵字,將元素放置在錨點周圍。這涵蓋許多常見用途,通常是良好的起點。
position-area
的運作方式
position-area
的運作方式是,在錨點和定位元素原始包含區塊的邊緣所產生的區域中,為定位元素建立新的包含區塊。
雖然 position-area
有許多關鍵字,但可以細分成幾個類別,方便瞭解。Anchor-tool.com 是探索語法的絕佳工具。
實體關鍵字
您可以使用實體關鍵字 top
、left
、bottom
、right
和 center
。舉例來說,position-area: top right
會將定位元素放在錨點上方和右側。這些關鍵字也有對應的實體軸,分別是 y-start
、x-start
、y-end
和 x-end
。
邏輯關鍵字
您也可以使用邏輯關鍵字 block-start
、block-end
、inline-start
和 inline-end
。舉例來說,在英文等語言中,position-area: block-end inline-start
會將定位元素放在錨點下方和左側;在文件的書寫模式中,則會將定位元素放在錨點的區塊軸上,以及錨點的內嵌軸上。center
也可以搭配邏輯關鍵字使用。
如果您指定邏輯關鍵字,也可以省略軸,但必須先指定區塊軸,再指定行內軸。position-area: start end
與 position-area: block-start inline-end
相同,甚至與 position-area: inline-end block-start
相同。
跨越多個格線區域
到目前為止,您可能已注意到這些選項只允許您將定位元素放在單一格線空間內。在實體或邏輯屬性中新增 span
前置字串,即可新增相鄰的中央格線空間。position-area: span-top right
會位於錨點右側,且從錨點底部到定位元素原始的包含區塊頂端。
下拉式選單的常見位置區域是 position-area: block-end span-inline-end
。
span-all
關鍵字會跨越 3 列或 3 欄。
單一關鍵字
如果您只設定一個關鍵字,系統會自動設定另一個軸。這項功能大致上會如您預期運作,但瞭解運作方式可能會有幫助。
如果提供的關鍵字清楚指出軸,系統會將另一個軸計算為 span-all
。這表示 position-area: bottom
等於 position-area: bottom span-all
,定位元素會位於錨點下方,並佔用整個可用寬度的包含區塊。
另一方面,如果關鍵字未明確指出軸,則會重複。position-area: start
等同於 start start
,且會放置在錨點的左上角 (適用於從左至右書寫的語言)。
anchor()
函式
對於更進階的使用案例,position-area
可能無法滿足您的需求。anchor()
函式可讓您根據另一個元素的位置設定個別插邊屬性。這會解析為 CSS 長度,因此您可以在計算中使用,也可以搭配其他 CSS 函式使用。此外,您也可以將不同側邊繫結至不同錨點。
anchor()
函式會採用錨點名稱和錨點側邊。如果元素有預設錨點 (透過 position-anchor
設定或隱含設定,例如使用快顯視窗),則可省略錨點名稱。
.positionedElement {
block-start: anchor(--my-anchor start);
/* OR */
position-anchor: --my-anchor;
block-start: anchor(start);
}
備用值
如果找不到 anchor()
函式的錨點,整個宣告就會無效。如果錨點是在定位元素之後轉譯,或是沒有相符 anchor-name
的元素,就可能發生這種情況。如要處理這項問題,你可以設定備用長度或百分比。
.positionedElement {
block-start: anchor(--my-anchor, 100px)
}
在上述範例中,定位元素的左值會錨定至 --focused-anchor
,但只有在懸停或聚焦於第一個按鈕時,anchor-name
才會存在。由於 anchor()
函式會解析為長度,因此您可以使用另一個錨點做為備援。如果我們沒有提供備用值,定位元素就不會定位。
錨定側邊關鍵字
錨定側值會選擇要對齊的錨定邊緣。與 position-area
類似,錨點側邊值支援多種不同類型的語法。
類型 | 值 | 說明 |
---|---|---|
實體 | top 、left 、bottom 、right |
實體關鍵字對應錨點的特定側邊,但只能用於與您要設定的位置元素插邊相同的軸。 舉例來說, |
側邊 | inside 、outside |
舉例來說, |
邏輯 | start 、end 、self-start 、self-end |
邏輯關鍵字會根據定位元素的書寫模式 (使用 |
百分比 | 0% - 100% |
百分比值會沿著指定軸,將定位元素從錨點的起點到終點放置在軸上。 |
這個範例顯示百分比值一律會從指定軸的開頭到結尾:
使用anchor()
由於 anchor()
是長度,因此非常靈活。您可以使用 max()
和 calc()
等 CSS 函式操控值。
其中一項限制是,您只能在插邊屬性上使用 anchor()
函式。
上例會在開啟的詳細資料面板後方新增背景,並在開啟不同面板時順暢地產生動畫效果,且會延展以納入懸停的詳細資料面板。為達成此目的,它會使用 min()
在兩個錨點之間挑選較短的長度。
#indicator{
/* Use the smaller of the 2 values: */
inset-block-start: min(
/* 1. The start side of the default anchor, which is the open `<details>` element */
anchor(start),
/* 2. The start side of the hovered `<details>` element. */
anchor(--hovered start,
/* If no `<details>` element is hovered, this falls back to infinity px, so that the other value is smaller, and therefore used. */
var(calc(1px * infinity)))
);
}
這個範例也使用 calc()
在開啟的面板周圍新增內嵌空間。
使用錨點的大小
您也可以使用 anchor-size()
函式,將錨點的尺寸用於定位元素的尺寸、位置或邊界。
anchor-size()
會採用錨點名稱,或使用預設錨點。根據預設,系統會使用軸上錨點的大小,因此 width: anchor-size()
會傳回錨點的寬度。您也可以使用其他軸,指定所需長度,方法是使用實體關鍵字 width
和 height
,或是邏輯關鍵字 block
、inline
、self-block
和 self-inline
。
處理溢位
您已建立下拉式選單元件,並使用錨點定位將下拉式選單放在所需位置。但隨後您將選單移至畫面另一側,或將選單用於使用者選單,而使用者名稱過長。突然間,下拉式選單消失在螢幕外。現在該怎麼辦?
CSS 錨點定位內建系統,可讓您在定位元素超出其包含區塊時,快速建構一組強大的備援。
備用選項
position-try-fallbacks
規則會採用備援選項清單。如果預設位置溢位,系統會依序嘗試每個選項,直到找到不會溢位的位置為止。
您可以使用任何 position-area
值做為備援選項。在這個範例中,在英文等從左到右的書寫模式中,定位元素會嘗試定位在錨點底部,跨越中央和右側欄。如果溢位,系統會嘗試將其放置在錨點底部,並跨越左欄和中間欄。如果該位置也溢位,即使溢位,位置也會還原為預設位置。
.positioned-element {
position-area: block-end span-inline-end;
position-try-fallbacks: block-end span-inline-start;
}
此外,還有幾個 flip-
關鍵字可處理常見的回退情況。flip-block
和 flip-inline
嘗試在區塊和內嵌軸上翻轉元素。也可以與 flip-block flip-inline
結合使用,同時翻轉兩個軸。flip-start
值會將定位元素翻轉到錨點的起點和終點角落之間的對角線上。
您也可以使用 @position-try
建立自訂備援選項,設定邊界、對齊方式,甚至變更錨點。
@position-try --menu-below {
position-area: bottom span-right;
margin-top: 1em;
}
#positioned-element {
position-try: --menu-below;
}
flip-block
和 flip-inline
可新增至 @position-try
備用選項,以建立變化版本。
#positioned-element {
position-try: --menu-below, flip-inline --menu-below;
}
在上述範例中,瀏覽器會依序執行這些步驟,並在找到不會溢位的解決方案後立即停止。
- 元素會放置在錨點右下方的
position-area: end
。 - 如果溢位,系統會使用名為
--bottom-span-right
的自訂備援選項放置元素,也就是使用position-area: bottom span-right
放置元素,並在下方加上額外邊界。 - 如果溢位,系統會使用
flip-inline --bottom-span-right
放置元素,將自訂備用選項與flip-inline
合併,這基本上就是position-area: bottom span-left
。 - 如果溢位,系統會使用
--use-alternate
自訂備援選項放置元素,也就是將元素放在完全不同的錨點下方。 - 如果溢位,元素會還原為原始位置,並顯示
position-area: end
,即使溢位是已知問題也一樣。
備用順序
根據預設,如果初始位置溢位,瀏覽器會嘗試 position-try-fallbacks
中的每個選項,直到找到不會溢位的位置為止。您可以使用 position-try-order
覆寫這項行為,測試每個備用選項,並使用在指定軸上空間最大的選項。
您可以使用邏輯關鍵字 most-block-size
和 most-inline-size
,或實體關鍵字 most-height
和 most-width
指定軸。
position-try-order
和 position-try-fallbacks
可與 position-try
簡寫組合,順序在前。
捲動
使用者捲動頁面時,會希望頁面流暢移動。為達成此目的,瀏覽器會限制捲動時錨點定位的使用方式。
雖然您可以將已定位的元素繫結至不同捲動容器中的錨點,但元素只會因其中一個錨點捲動而移動。這會是預設錨點,也就是來自快顯視窗的隱含錨點,或是 position-anchor
的值。
請注意,即使錨點捲動到檢視區塊外,定位元素仍會保持顯示。如要在錨點隱藏時隱藏定位元素,請設定 position-visibility: anchors-visible
。這不僅適用於錨點過度捲動的情況,也適用於以其他方式隱藏錨點的情況,例如使用 visibility: hidden
。
隨堂測驗
anchor()
中側邊的有效值為何?
inside
25%
25px
25px
等長度可用做備用值,但只有百分比可用於側邊。block-start
start
哪些是 position-area
的有效值?
top
block-end inline-end
block-start block-end
哪些屬性支援 anchor()
函式?
top
margin-left
inset-block-start
transform
如果有多個錨點具有相同的 anchor-name
,會發生什麼情況?