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. 접근성 및 상호작용
필수 접근성 보장: 이 패턴은 포인터 상호작용을 사용하여 시각적 스포트라이트를 표시합니다. 스포트라이트 레이어를 포인터 사용자를 위한 비필수적인 시각적 개선 기능으로만 사용하여 기본 레이아웃에서 모든 기본 콘텐츠가 기본적으로 완전히 표시되고, 읽을 수 있고, 키보드로 독립적으로 접근할 수 있도록 보장해야 합니다(MUST). 키보드 전용 또는 보조 기술 사용자에게 필수 콘텐츠를 가리거나 차단하는 데 이 효과를 사용해서는 안 됩니다.
- 포인터 이벤트: 마스크 오버레이 레이어에
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의 기본 상태를 표시 효과 없이도 완전히 작동하고 읽을 수 있도록 디자인합니다. 이는 효과가 시각적 감각만 더하고 콘텐츠를 읽는 데 필요하지 않은 경우에 유용합니다.