使用 CSS 遮罩和已註冊的自訂屬性,為網站加入高效能的互動式揭露效果。只要使用放射狀漸層做為遮罩,並註冊其停止值,就能順暢地轉換進入和離開效果,同時以最少的 JavaScript 追蹤使用者的指標。
導入作業
1. 註冊自訂屬性
如要啟用漸層停靠點值的平滑內插,您必須使用 @property 註冊變數。這會告知瀏覽器引擎資料類型,讓瀏覽器在更新期間轉換值。
/* Register the spotlight inner and outer sizes to enable interpolation */
@property --inner-size{
syntax: "<length-percentage>";
inherits: true;
initial-value: 0px;
}
@property --outer-size{
syntax: "<length-percentage>";
inherits: true;
initial-value: 0px;
}
追蹤指標位置的自訂屬性不需要轉換,因此不必註冊。
2. 定義遮罩層
將 mask-image 套用至要顯示的元素。使用參照已註冊屬性的 radial-gradient。
.reveal-layer {
/* Only transition the size properties, NOT the position variables */
transition: --inner-size 0.2s ease-in-out, --outer-size 0.2s ease-in-out;
/* The spotlight is defined by the transparent center of the mask */
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
black var(--inner-size, 0%),
transparent var(--outer-size, 0%)
);
/* Ensure the mask doesn't repeat if the element is large */
mask-repeat: no-repeat;
/* Make the mask layer non-interactive */
pointer-events: none;
}
/* Update the gradients stops on interaction */
.reveal-layer:hover {
--inner-size: 100px;
--outer-size: 120px;
}
3. 使用 JavaScript 更新座標
追蹤指標位置並更新 CSS 變數。由於屬性已註冊且已定義 transition,因此即使指標事件不常發生,聚光燈也會順暢移動。
const container = document.querySelector('.container');
// Store the container's bounding rect
let rect = container.getBoundingClientRect();
// Update the rect when the container is resized
const resizeObserver = new ResizeObserver(()=>{
rect = container.getBoundingClientRect();
})
resizeObserver.observe(container);
container.addEventListener('pointermove', (e) => {
// Calculate position as a percentage of the container.
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
// Update the registered properties
container.style.setProperty('--mouse-x', `${x}%`);
container.style.setProperty('--mouse-y', `${y}%`);
});
4. 無障礙功能和互動
強制無障礙保證:這個模式需要透過指標互動,才能顯示視覺焦點。您必須確保所有基礎內容在基礎版面配置中,預設仍完全可見、可讀,且可透過鍵盤獨立存取,並僅將焦點層做為指標使用者的非必要視覺強化功能。請勿使用這項效果,遮蓋或阻擋僅使用鍵盤或輔助技術的使用者所需的重要內容。
- 指標事件:在遮罩疊加層上設定
pointer-events: none,允許標準點擊和觸控互動傳遞至下方的控制項。 - 覆寫減少動態效果:為要求減少動態效果的使用者,停用流暢轉場內插。
/* MANDATORY Copy-Paste Safety: Disable transition scaling for motion-sensitive users */
@media (prefers-reduced-motion: reduce) {
.reveal-layer {
transition: none !important;
}
}
備用策略
未註冊資源備用廣告
如果瀏覽器支援 mask-image,但不支援 @property,仍會顯示聚光燈,但由於無法在 radial-gradient 內插補值,因此動作會在開啟和關閉狀態之間跳動。使用 var() 時,請提供備用值。
.reveal-layer {
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
/* Use fallback values when using the `var()` function for browsers that don't get an initial value from the @property registration. */
black var(--inner-size, 0%),
transparent var(--outer-size, 0%)
);
}
基本遮罩支援
如果瀏覽器完全不支援 CSS 遮罩:
- 前置屬性:使用
-webkit-mask-image前置屬性,可支援更多瀏覽器。 - 漸進增強:設計 UI 的基本狀態,確保在沒有揭露效果的情況下,仍能正常運作且易於閱讀。如果效果只是增加視覺效果,而非閱讀內容的必要條件,這項功能就非常實用。