Voeg interactieve onthullingseffecten met goede prestaties toe aan je site met CSS-maskers en geregistreerde aangepaste eigenschappen. Door een radiale kleurovergang als masker te gebruiken en de stopwaarden te registreren, kunnen we de overgang van de invoer en uitstappunt soepel laten verlopen, terwijl we de aanwijzer van een gebruiker volgen met minimale JavaScript.
Implementatie
1. Aangepaste eigenschappen registreren
Als je vloeiende interpolatie van waarden voor kleurverloopstops wilt aanzetten, moet je de variabelen registreren met @property. Dit informeert de engine van de browser over het gegevenstype, zodat deze tijdens updates tussen waarden kan overschakelen.
/* 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;
}
De aangepaste eigenschappen die de positie van de aanwijzer bijhouden, hoeven niet te worden overgezet. Je hoeft ze dus niet te registreren.
2. De maskerlaag definiëren
Pas de mask-image toe op het element dat u wilt onthullen. Gebruik een radial-gradient die verwijst naar de geregistreerde property's.
.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. Coördinaten updaten met JavaScript
De positie van de aanwijzer bijhouden en de CSS-variabelen updaten. Omdat de properties zijn geregistreerd en er een transition is gedefinieerd, beweegt de spotlight soepel, zelfs als de aanwijzergebeurtenissen onregelmatig zijn.
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. Toegankelijkheid en interactie
VERPLICHTE toegankelijkheidsgarantie: Dit patroon is afhankelijk van aanwijzerinteracties om een visuele spotlight te tonen. Je MOET garanderen dat alle onderliggende content standaard volledig zichtbaar, leesbaar en onafhankelijk bereikbaar blijft via het toetsenbord in de onderliggende vormgeving. Gebruik de spotlightlaag uitsluitend als een niet-essentiële visuele verbetering voor gebruikers van een aanwijzer. Gebruik dit effect nooit om essentiële content te verbergen of te blokkeren voor gebruikers die alleen een toetsenbord of ondersteunende technologie gebruiken.
- Pointergebeurtenissen: Stel
pointer-events: nonein op de maskeroverlaylaag zodat standaard klik- en aanraakinteracties kunnen worden doorgegeven aan de onderliggende bedieningselementen. - Overschrijving voor minder beweging: Zet interpolatie van vloeiende overgangen uit voor gebruikers die minder beweging aanvragen.
/* MANDATORY Copy-Paste Safety: Disable transition scaling for motion-sensitive users */
@media (prefers-reduced-motion: reduce) {
.reveal-layer {
transition: none !important;
}
}
Reservestrategieën
Fallback voor niet-geregistreerde property
Browsers die mask-image ondersteunen maar niet @property, tonen de spotlight nog steeds, maar de beweging springt tussen de aan- en uit-status omdat ze geen waarden kunnen interpoleren binnen een radial-gradient. Voer reservewaarden in als u var() gebruikt.
.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%)
);
}
Ondersteuning voor basismaskers
Voor browsers die CSS-maskering helemaal niet ondersteunen:
- Property met voorvoegsel: Gebruik de property met het voorvoegsel
-webkit-mask-imagevoor bredere browserondersteuning. - Progressive enhancement: Ontwerp de basisstatus van de UI zo dat deze volledig functioneel en leesbaar is zonder het onthullingseffect. Dit is handig als het effect alleen visuele flair toevoegt en niet vereist is om content te lezen.