חשיפת תוכן אינטראקטיבי

הוספת אפקטים אינטראקטיביים של חשיפה לאתר באמצעות מסכות 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. נגישות ואינטראקציה

התחייבות חובה לנגישות: התבנית הזו מסתמכת על אינטראקציות עם הסמן כדי לחשוף את ה-Spotlight החזותי. אתם חייבים לוודא שכל התוכן שמתחת לשכבה נשאר גלוי וקריא לחלוטין, ושאפשר להגיע אליו באמצעות המקלדת כברירת מחדל בפריסה שמתחת לשכבה. השכבה של ה-Spotlight צריכה לשמש רק כשיפור חזותי לא חיוני למשתמשים שמשתמשים בסמן. אסור להשתמש באפקט הזה כדי להסתיר או לחסום תוכן חיוני ממשתמשים שמשתמשים רק במקלדת או בטכנולוגיה מסייעת.

  • אירועי סמן: מגדירים את 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:

  1. מאפיין עם קידומת: השתמשו במאפיין עם הקידומת -webkit-mask-image כדי לקבל תמיכה רחבה יותר בדפדפנים.
  2. שיפור הדרגתי (progressive enhancement): עצבו את מצב הבסיס של ממשק המשתמש כך שיהיה פונקציונלי וקריא לחלוטין בלי אפקט החשיפה. זה שימושי כשהאפקט רק מוסיף סגנון חזותי, ולא נדרש לקריאת התוכן.