您目前如何連結元素?您可以嘗試追蹤廣告的位置,或使用某種形式的包裝函式元素。
<!-- index.html -->
<div class="container">
<a href="/link" class="anchor">I’m the anchor</a>
<div class="anchored">I’m the anchored thing</div>
</div>
/* styles.css */
.container {
position: relative;
}
.anchored {
position: absolute;
}
這類解決方案通常並不理想。需要使用 JavaScript 或導入額外標記。為此,CSS 錨點定位 API 是透過提供網路共用元素的 CSS API 來解決這個問題。它可讓您根據其他元素的位置和大小,決定元素的位置和大小。
瀏覽器支援
您可以在 Chrome Canary 中試用「實驗性 Web Platform 功能」的 CSS Anchoring API旗標。如要啟用該標記,請開啟 Chrome Canary 並前往 chrome://flags
。然後啟用「實驗性網頁平台功能」旗標。
Oddbird 團隊也提供開發中的 polyfill。請務必前往 github.com/oddbird/css-anchor-positioning 查看存放區。
您可以使用以下功能檢查錨定支援功能:
@supports(anchor-name: --foo) {
/* Styles... */
}
請注意,這個 API 目前仍在實驗階段,可能會有所變動。本文將概略介紹這些重要部分。此外,目前的導入方式也並未與 CSS 工作群組規格完全同步。
問題
為什麼要這麼做?其中一種顯著的應用實例是建立工具提示或類似工具提示的體驗。在這種情況下,建議您為工具提示參照的內容建立網路共用功能。您通常需要用某種方法將元素與另一個元素共用。您也會預期與頁面互動並不會對共用網路造成破壞,例如當使用者捲動畫面或調整使用者介面大小時。
另一個問題是,如何確保網路共用元素持續顯示在畫面上,例如當您開啟工具提示,導致圖片遭到可視區域邊界裁剪時。這可能無法為使用者提供良好的體驗。你想讓工具提示進行調整。
目前的解決方案
目前您可以透過幾種方式解決這個問題。
第一個是基本「包裝錨點」。您要將兩個元素納入容器中,接著,您就能使用 position
來設定相對於錨點的工具提示。
<div class="containing-block">
<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
</div>
.containing-block {
position: relative;
}
.tooltip {
position: absolute;
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%);
}
您可以移動容器,讓所有元素固定落在您想要的位置。
另一個方法:如果您知道錨點的位置,或者還可以追蹤定位,您可透過自訂屬性,將該屬性傳送至工具提示。
<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
:root {
--anchor-width: 120px;
--anchor-top: 40vh;
--anchor-left: 20vmin;
}
.anchor {
position: absolute;
top: var(--anchor-top);
left: var(--anchor-left);
width: var(--anchor-width);
}
.tooltip {
position: absolute;
top: calc(var(--anchor-top));
left: calc((var(--anchor-width) * 0.5) + var(--anchor-left));
transform: translate(-50%, calc(-100% - 10px));
}
但是,不知道錨定位置怎麼辦?您可能需要與 JavaScript 介入處理。您可以執行類似以下的程式碼,但現在代表您的樣式會開始從 CSS 外洩到 JavaScript 中。
const setAnchorPosition = (anchored, anchor) => {
const bounds = anchor.getBoundingClientRect().toJSON();
for (const [key, value] of Object.entries(bounds)) {
anchored.style.setProperty(`--${key}`, value);
}
};
const update = () => {
setAnchorPosition(
document.querySelector('.tooltip'),
document.querySelector('.anchor')
);
};
window.addEventListener('resize', update);
document.addEventListener('DOMContentLoaded', update);
因此請先提出一些問題:
- 何時要計算樣式?
- 如何計算樣式?
- 我多久計算一次樣式?
這個方法能解開謎題嗎?這可能適用於您的用途,但有一個問題:我們的解決方案無法配合調整。操作無回應。如果我的錨定元素遭到可視區域截斷,該怎麼辦?
現在,您必須決定是否回應這種情況以及處理方式。需要思考的問題和決策數量已經開始成長。你只想將一個元素固定在另一個元素上,在理想情況下,您的解決方案會根據周遭環境進行調整並做出回應。
如要解決這個問題,不妨洽詢 JavaScript 解決方案來協助您。這種做法會產生在專案中新增依附元件的費用,也可能因使用方式而異。舉例來說,某些套件會使用 requestAnimationFrame
讓位置保持正確。這代表您和您的團隊需要熟悉套件內容及設定選項。因此,您的問題和決策可能不會減少,而是改變。這是「原因」的一部分以供 CSS 錨定位置使用這樣一來,在計算排名時,就不會想到效能問題。
使用「floating-ui」這項問題常用套件的程式碼看起來會像這樣:
import {computePosition, flip, offset, autoUpdate} from 'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1/+esm';
const anchor = document.querySelector('.anchor')
const tooltip = document.querySelector('.tooltip')
const updatePosition = () => {
computePosition(anchor, tooltip, {
placement: 'top',
middleware: [offset(10), flip()]
})
.then(({x, y}) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`
})
})
};
const clean = autoUpdate(anchor, tooltip, updatePosition);
在這個示範中,請嘗試將該程式碼重新定位錨點。
「工具提示」可能無法如預期般運作會因應可視區域在 Y 軸上移動的情形,而非 X 軸。參閱說明文件,即可找到適合您的解決方案。
不過,要尋找適合您專案的套件,可能需要不少時間。這個購物決定是件上的額外決定,如果未能做到這一點,可能會感到困擾。
使用錨定位置
輸入 CSS 錨定定位 API。這麼做的用意是將樣式保留在 CSS 中,並減少您需要做出的決定。希望也能達到相同結果,但這麼做的用意是改善開發人員體驗。
- 不需要 JavaScript。
- 讓瀏覽器按照您的指示找出最佳位置。
- 不再需要使用任何第三方依附元件
- 沒有任何包裝函式元素。
- 適用於頂層元素。
讓我們重新建立並解決上述問題。不過,我們會改用具有錨點的船型比喻。這些代表錨定的元素和錨定標記。水代表包含的塊。
首先,您必須選擇如何定義錨定標記。只要在 CSS 中設定錨定元素上的 anchor-name
屬性即可。可接受虛線值。
.anchor {
anchor-name: --my-anchor;
}
或者,您也可以使用 anchor
屬性在 HTML 中定義錨定廣告。屬性值是錨定元素的 ID。這會建立隱含錨點。
<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>
定義錨點後,您可以使用 anchor
函式。anchor
函式使用 3 個引數:
- 錨點元素:要使用的錨點
anchor-name
;或者,您可以省略該值,使用implicit
錨點。可透過 HTML 關係或具有anchor-name
值的anchor-default
屬性定義。 - 錨定側:所要使用位置的關鍵字。可以是
top
、right
、bottom
、left
、center
等等,也可以傳遞百分比。例如,50% 就是center
。 - 備用值:這是選填的備用值,可接受長度或百分比。
您可以使用 anchor
函式做為錨定元素的插邊屬性 (top
、right
、bottom
、left
或其邏輯的同等元素) 的值。您也可以在 calc
中使用 anchor
函式:
.boat {
bottom: anchor(--my-anchor top);
left: calc(anchor(--my-anchor center) - (var(--boat-size) * 0.5));
}
/* alternative with anchor-default */
.boat {
anchor-default: --my-anchor;
bottom: anchor(top);
left: calc(anchor(center) - (var(--boat-size) * 0.5));
}
由於沒有 center
插邊屬性,因此如果您知道錨定元素的大小,就可以選擇使用 calc
。為什麼不使用 translate
?這時您可以:
.boat {
anchor-default: --my-anchor;
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}
但瀏覽器不會考慮錨定元素的轉換位置,您會清楚瞭解為什麼在考慮排名備用和自動定位時,這一點非常重要。
您可能已經注意到,使用上述自訂屬性 --boat-size
。但如果想根據錨定標記設定固定的元素大小,也可以設定該大小。您可以使用 anchor-size
函式,不必自行計算。舉例來說,假設要乘船是錨定標記寬度的四倍:
.boat {
width: calc(4 * anchor-size(--my-anchor width));
}
你也可以使用 anchor-size(--my-anchor height)
查看高度。而且可以設定軸的大小,也可以同時設定兩者。
如果想將固定位置固定在採用 absolute
位置的元素,該怎麼做?這項規則是元素不能為同層級元素。在此情況下,您可以將錨定標記納入具有 relative
位置的容器。然後錨定在頂端。
<div class="anchor-wrapper">
<a id="my-anchor" class="anchor"></a>
</div>
<div class="boat">I’m a boat!</div>
歡迎觀看這個示範影片,你可以拖曳錨定標記,之後船隻會跟著移動。
追蹤捲動位置
在某些情況下,錨定元素可能會位於捲動容器中。但錨定元素可能在該容器外面。由於捲動作業發生在與版面配置的其他執行緒,因此您必須透過方法追蹤。anchor-scroll
屬性可進行這項操作。只要將這類設定設為在錨定元素上,並為其指定要追蹤的錨定值即可。
.boat { anchor-scroll: --my-anchor; }
歡迎嘗試這個示範模式,使用角落的核取方塊切換「anchor-scroll
」。
但比喻來說,這裡有點平坦的,因為在理想世界中,你的船隻和錨點都放在水中。此外,Popover API 之類的功能還能讓相關元素保持關閉狀態。不過,錨點位置適用於位在頂層圖層的元素。這是 API 背後的一大優點:能夠在不同的流程中共用元素。
請考慮以下示範,其中,捲動容器的錨點有工具提示。彈出式視窗的工具提示元素無法與錨點一起位置:
不過,您會看到彈出式視窗如何追蹤各自錨定連結。您可以調整捲動容器的大小,讓系統更新位置。
排名備用和自動定位
也就是錨定定位能力提升的等級。position-fallback
可根據您提供的一組備用選項調整錨定元素的位置。你將能引導瀏覽器調整樣式,交由瀏覽器找出你偏好的位置。
這裡的常見用途是工具提示,切換為顯示在錨定標記上方或下方。實際行為則取決於工具提示是否由容器裁剪。這個容器通常是可視區域。
如果深入分析上一個示範的程式碼,會發現系統有使用中的 position-fallback
屬性。如果捲動容器,您可能會注意到錨定彈出式視窗跳動。當各自的錨點在可視區域邊界附近時,就會發生這種情況。目前,為了保持可視區域,彈出式視窗會設法調整。
建立明確的 position-fallback
之前,錨定位置也提供自動定位功能。您可以在錨定函式和相反的插邊屬性中使用 auto
的值,免費取得翻轉。舉例來說,如果您針對 bottom
使用 anchor
,請將 top
設為 auto
。
.tooltip {
position: absolute;
bottom: anchor(--my-anchor auto);
top: auto;
}
除了自動定位之外,您也可以使用明確的 position-fallback
。您必須定義排名備用組合。瀏覽器會逐一檢查這些指令,直到找出可以使用的標記,然後再套用該定位。如果找不到有效的聯絡方式,系統會預設使用您定義的第一個參數。
嘗試顯示上述工具提示的 position-fallback
可能如下所示:
@position-fallback --top-to-bottom {
@try {
bottom: anchor(top);
left: anchor(center);
}
@try {
top: anchor(bottom);
left: anchor(center);
}
}
套用至工具提示後,畫面如下所示:
.tooltip {
anchor-default: --my-anchor;
position-fallback: --top-to-bottom;
}
使用 anchor-default
表示您可以將 position-fallback
重複用於其他元素。您也可以使用範圍自訂屬性來設定 anchor-default
。
再看一次使用船隻的示範。已設定 position-fallback
。當你變更錨點的位置時,船隻會隨之調整,直到控制在容器內。請嘗試變更邊框間距值,進而調整主體邊框間距。請注意瀏覽器的修正位置。變更容器的格線對齊方式,即可變更位置。
這次嘗試依順時針方向移動位置時,position-fallback
會比較詳細。
.boat {
anchor-default: --my-anchor;
position-fallback: --compass;
}
@position-fallback --compass {
@try {
bottom: anchor(top);
right: anchor(left);
}
@try {
bottom: anchor(top);
left: anchor(right);
}
@try {
top: anchor(bottom);
right: anchor(left);
}
@try {
top: anchor(bottom);
left: anchor(right);
}
}
範例
現在,您已瞭解錨定位置的主要功能,我們來看看除了工具提示之外,還有一些有趣的範例。這些範例旨在幫助你發想點子,思考如何使用錨點位置。因此,最好的方法就是參考真實使用者的寶貴意見。
內容選單
首先,使用 Popover API 的內容選單。概念是在點選 V 形標記按鈕後,顯示內容選單。而且選單具有專屬的展開選單
標記並不是重要的部分。不過,每個使用 popovertarget
都有三個按鈕。接著,有三個元素使用 popover
屬性。如此一來,您無需使用任何 JavaScript 也能開啟內容選單。如下所示:
<button popovertarget="context">
Toggle Menu
</button>
<div popover="auto" id="context">
<ul>
<li><button>Save to your Liked Songs</button></li>
<li>
<button popovertarget="playlist">
Add to Playlist
</button>
</li>
<li>
<button popovertarget="share">
Share
</button>
</li>
</ul>
</div>
<div popover="auto" id="share">...</div>
<div popover="auto" id="playlist">...</div>
現在,您可以定義 position-fallback
,並在內容選單之間共用。此外,也請務必取消設定彈出式視窗的任何 inset
樣式。
[popovertarget="share"] {
anchor-name: --share;
}
[popovertarget="playlist"] {
anchor-name: --playlist;
}
[popovertarget="context"] {
anchor-name: --context;
}
#share {
anchor-default: --share;
position-fallback: --aligned;
}
#playlist {
anchor-default: --playlist;
position-fallback: --aligned;
}
#context {
anchor-default: --context;
position-fallback: --flip;
}
@position-fallback --aligned {
@try {
top: anchor(top);
left: anchor(right);
}
@try {
top: anchor(bottom);
left: anchor(right);
}
@try {
top: anchor(top);
right: anchor(left);
}
@try {
bottom: anchor(bottom);
left: anchor(right);
}
@try {
right: anchor(left);
bottom: anchor(bottom);
}
}
@position-fallback --flip {
@try {
bottom: anchor(top);
left: anchor(left);
}
@try {
right: anchor(right);
bottom: anchor(top);
}
@try {
top: anchor(bottom);
left: anchor(left);
}
@try {
top: anchor(bottom);
right: anchor(right);
}
}
這樣您就能取得自動調整式巢狀內容選單 UI。請嘗試透過選取項目變更內容位置。您選擇的選項會更新格線對齊方式。這會影響錨定廣告的位置。
聚焦與追蹤
此示範影片結合了 CSS 基本功能,加入了 :has()。概念是為已聚焦的 input
轉換視覺指標。
方法是在執行階段設定新的錨定標記。在這個示範中,限定範圍的自訂屬性會更新輸入焦點。
#email {
anchor-name: --email;
}
#name {
anchor-name: --name;
}
#password {
anchor-name: --password;
}
:root:has(#email:focus) {
--active-anchor: --email;
}
:root:has(#name:focus) {
--active-anchor: --name;
}
:root:has(#password:focus) {
--active-anchor: --password;
}
:root {
--active-anchor: --name;
--active-left: anchor(var(--active-anchor) right);
--active-top: calc(
anchor(var(--active-anchor) top) +
(
(
anchor(var(--active-anchor) bottom) -
anchor(var(--active-anchor) top)
) * 0.5
)
);
}
.form-indicator {
left: var(--active-left);
top: var(--active-top);
transition: all 0.2s;
}
但該如何進一步發展呢?您可以用它做為某種形式的教學疊加層。工具提示可在搜尋點之間移動並更新內容。您可以將內容交叉淡出。獨立的動畫可讓你為 display
或 View Transitions 建立動畫。
長條圖計算
錨定位置的另一個有趣功能,就是結合 calc
。假設在圖表中,您加入了部分彈出式視窗為圖表加上註解,
您可以使用 CSS min
和 max
追蹤最高和最低的值。的 CSS 程式碼可能如下所示:
.chart__tooltip--max {
left: anchor(--chart right);
bottom: max(
anchor(--anchor-1 top),
anchor(--anchor-2 top),
anchor(--anchor-3 top)
);
translate: 0 50%;
}
系統會執行一些 JavaScript 來更新圖表值,並使用一些 CSS 設定圖表樣式。但錨點位置會負責更新版面配置。
大小調整控點
不只能固定在一個元素上。元素可以有多個錨點。您可能已經注意到,在長條圖範例中,工具提示會固定在圖表上,然後會選在對應的長條上。如果您進一步使用這個概念,可以使用此概念調整元素大小。
您可以將錨點視為自訂大小調整控點,並採用 inset
值。
.container {
position: absolute;
inset:
anchor(--handle-1 top)
anchor(--handle-2 right)
anchor(--handle-2 bottom)
anchor(--handle-1 left);
}
在這個示範中,GreenSock Draggable 使其成為可拖曳的控點。不過,<img>
元素會調整大小來填滿容器,配合控制控點之間的間距。
選擇選單?
相信你們最後再跟幾個消息有關。但是,您可以建立可聚焦的彈出式視窗,而現在您已設定錨點的位置。您可以建立可設定樣式的 <select>
元素基礎。
<div class="select-menu">
<button popovertarget="listbox">
Select option
<svg>...</svg>
</button>
<div popover="auto" id="listbox">
<option>A</option>
<option>Styled</option>
<option>Select</option>
</div>
</div>
隱含的 anchor
可以簡化這項作業。但基本起點的 CSS 可能如下所示:
[popovertarget] {
anchor-name: --select-button;
}
[popover] {
anchor-default: --select-button;
top: anchor(bottom);
width: anchor-size(width);
left: anchor(left);
}
結合 Popover API 的功能與 CSS 錨定位置,就大功告成了!
當您開始介紹 :has()
等項目時,這個方法非常實用。你可以在開啟時旋轉標記:
.select-menu:has(:open) svg {
rotate: 180deg;
}
接下來該怎麼做?我們還需要採取哪些行動,才能使 select
順利運作?我們會將此名稱儲存在下一篇文章中。請放心,我們即將推出可設定樣式的精選元素。敬請持續鎖定!
就是這麼簡單!
網路平台不斷演進,CSS 錨定位置是改善 UI 控制項開發方式的重要關鍵。這樣一來,您就不會錯過某些棘手的決定。此外,這項工具也能讓您執行前所未有的功能。例如設定 <select>
元素的樣式!請提供您寶貴的意見。
相片來源:CHUTTERSNAP,來源為 Unsplash