Aggiungi effetti di rivelazione interattivi e ad alte prestazioni al tuo sito con maschere CSS e proprietà personalizzate registrate. Utilizzando una sfumatura radiale come maschera e registrando i suoi valori di interruzione, possiamo eseguire una transizione fluida dell'entrata e dell'uscita, seguendo il puntatore di un utente con un codice JavaScript minimo.
Implementazione
1. Registra proprietà personalizzate
Per attivare l'interpolazione uniforme dei valori dei punti di interruzione del gradiente, devi registrare le variabili utilizzando @property. In questo modo, il motore del browser viene informato sul tipo di dati, consentendogli di passare da un valore all'altro durante gli aggiornamenti.
/* 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;
}
Le proprietà personalizzate che monitorano la posizione del puntatore non devono essere sottoposte a transizione, quindi non è necessario registrarle.
2. Definisci il livello di mascheramento
Applica mask-image all'elemento che vuoi mostrare. Utilizza un radial-gradient che faccia riferimento alle proprietà registrate.
.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. Aggiorna le coordinate con JavaScript
Monitora la posizione del puntatore e aggiorna le variabili CSS. Poiché le proprietà sono registrate e hanno un transition definito, il faretto si sposterà in modo fluido anche se gli eventi del puntatore sono rari.
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. Accessibilità e interazione
Garanzia di accessibilità OBBLIGATORIA: questo pattern si basa sulle interazioni con il puntatore per mostrare un elemento visivo in evidenza. DEVI garantire che tutti i contenuti sottostanti rimangano completamente visibili, leggibili e raggiungibili in modo indipendente dalla tastiera per impostazione predefinita nel layout sottostante, utilizzando il livello di evidenziazione esclusivamente come miglioramento visivo non essenziale per gli utenti che utilizzano il puntatore. Non utilizzare mai questo effetto per oscurare o nascondere contenuti essenziali agli utenti che utilizzano solo la tastiera o tecnologie per la disabilità.
- Eventi puntatore: imposta
pointer-events: nonesul livello di overlay della maschera per consentire alle interazioni standard di clic e tocco di passare ai controlli sottostanti. - Override del movimento ridotto: disattiva l'interpolazione della transizione fluida per gli utenti che richiedono un movimento ridotto.
/* MANDATORY Copy-Paste Safety: Disable transition scaling for motion-sensitive users */
@media (prefers-reduced-motion: reduce) {
.reveal-layer {
transition: none !important;
}
}
Strategie di riserva
Procedimento di riserva per proprietà non registrata
I browser che supportano mask-image, ma non @property, mostreranno comunque il faretto, ma il movimento passerà da uno stato attivo a uno non attivo perché non possono interpolare i valori all'interno di un radial-gradient. Fornisci valori di riserva quando utilizzi 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%)
);
}
Supporto di base per le maschere
Per i browser che non supportano affatto il mascheramento CSS:
- Proprietà con prefisso: utilizza la proprietà con prefisso
-webkit-mask-imageper un supporto più ampio del browser. - Potenziamento progressivo: progetta lo stato di base della UI in modo che sia completamente funzionale e leggibile senza l'effetto di visualizzazione. Questo è utile quando l'effetto aggiunge solo un tocco visivo e non è un requisito per la lettura dei contenuti.