Tambahkan efek pengungkapan interaktif yang berperforma tinggi ke situs Anda dengan mask CSS dan properti kustom terdaftar. Dengan menggunakan gradien radial sebagai mask dan mendaftarkan nilai perhentiannya, kita dapat mentransisikan masuk dan keluar dengan lancar, sekaligus mengikuti pointer pengguna dengan JavaScript minimal.
Penerapan
1. Mendaftarkan Properti Kustom
Untuk mengaktifkan interpolasi halus nilai perhentian gradien, Anda harus mendaftarkan variabel menggunakan @property. Hal ini memberi tahu mesin browser tentang jenis data, sehingga memungkinkan transisi antar-nilai selama update.
/* 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;
}
Properti kustom yang melacak posisi kursor tidak perlu ditransisikan, sehingga tidak perlu didaftarkan.
2. Menentukan Lapisan Masking
Terapkan mask-image ke elemen yang ingin Anda tampilkan. Gunakan radial-gradient yang mereferensikan properti terdaftar.
.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. Memperbarui Koordinat dengan JavaScript
Lacak posisi pointer dan perbarui variabel CSS. Karena properti didaftarkan dan memiliki transition yang ditentukan, sorotan akan bergerak dengan lancar meskipun peristiwa pointer jarang terjadi.
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. Aksesibilitas dan Interaksi
Jaminan Aksesibilitas WAJIB: Pola ini mengandalkan interaksi pointer untuk menampilkan sorotan visual. Anda HARUS menjamin bahwa semua konten yang mendasarinya tetap terlihat sepenuhnya, dapat dibaca, dan dapat dijangkau secara independen oleh keyboard secara default dalam tata letak yang mendasarinya, dengan menggunakan lapisan sorotan murni sebagai peningkatan visual yang tidak penting bagi pengguna pointer. Jangan pernah menggunakan efek ini untuk menyembunyikan atau membatasi konten penting dari pengguna khusus keyboard atau teknologi pendukung.
- Peristiwa Pointer: Tetapkan
pointer-events: nonepada lapisan overlay mask untuk memungkinkan interaksi klik dan sentuh standar diteruskan ke kontrol di bawahnya. - Penggantian Pengurangan Gerakan: Menonaktifkan interpolasi transisi yang mulus untuk pengguna yang meminta pengurangan gerakan.
/* MANDATORY Copy-Paste Safety: Disable transition scaling for motion-sensitive users */
@media (prefers-reduced-motion: reduce) {
.reveal-layer {
transition: none !important;
}
}
Strategi penggantian
Penggantian Properti yang Tidak Terdaftar
Browser yang mendukung mask-image, tetapi tidak mendukung @property, akan tetap menampilkan sorotan, tetapi gerakannya akan melompat antara status aktif dan nonaktif karena tidak dapat menginterpolasi nilai di dalam radial-gradient. Berikan nilai penggantian saat menggunakan 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%)
);
}
Dukungan Masker Dasar
Untuk browser yang sama sekali tidak mendukung penyamaran CSS:
- Properti dengan awalan: Gunakan properti dengan awalan
-webkit-mask-imageuntuk dukungan browser yang lebih luas. - Progressive Enhancement: Desain status dasar UI agar berfungsi penuh dan dapat dibaca tanpa efek pengungkapan. Hal ini berguna jika efeknya hanya menambahkan gaya visual, dan bukan persyaratan untuk membaca konten.