סקירה כללית
כדי לשפר את חוויית המשתמש של לחצנים צפים, כמו קישור "חזרה לראש הדף", כדאי להציג אותם רק כשהם שימושיים. במדריך הזה מוסבר איך ליצור את הרכיבים האלה באמצעות CSS container-scroll-state-queries, שמאפשר לעצב רכיבים על סמך מיקום הגלילה של מאגר התגים שלהם בלי להסתמך על מאזינים או משקיפים של גלילה ב-JavaScript.
הטמעה
1. הגדרת מאגר הגלילה
צריך להצהיר על מאגר הגלילה כמאגר שאילתות של מצב גלילה.
.scroller {
overflow-y: auto;
/* Establish this element as a scroll-state query container */
container-type: scroll-state;
}
2. עיצוב הרכיב הצף
ממקמים את הרכיב בתוך הקונטיינר ומעצבים אותו. כברירת מחדל, הוא אמור להיות מוסתר.
.back-to-top {
position: sticky;
bottom: 20px;
visibility: hidden;
opacity: 0;
translate: 0 20px;
transition:
visibility 0.3s,
opacity 0.3s ease,
translate 0.3s ease;
}
3. תגובה למצב הגלילה
משתמשים בכלל @container עם הפונקציה scroll-state. כדי לבדוק אם המשתמש גלל למטה, בודקים אם אפשר לגלול את הקונטיינר למעלה.
/* When the container can be scrolled toward the top, it means the user has scrolled down */
@container scroll-state(scrollable: top) {
.back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
}
אסטרטגיות חלופיות
גיבוי בסיסי
אם אין תמיכה ב-container-scroll-state-queries, הרכיב הצף יישאר בלתי נראה בגלל ברירת המחדל של visibility: hidden. כדי לוודא שהרכיב יפעל, אתם יכולים לבחור שהוא תמיד יהיה גלוי בדפדפנים לא נתמכים.
/* Fallback for browsers that do not support the feature */
.back-to-top {
visibility: visible; /* Always visible */
opacity: 1;
}
/* Override for supported browsers to handle dynamic visibility */
@supports (container-type: scroll-state) {
.back-to-top {
visibility: hidden;
opacity: 0;
}
@container scroll-state(scrollable: top) {
.back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
}
}
חלופה מתקדמת (Intersection Observer)
אם נדרשת חשיפה דינמית, צריך להשתמש ב-IntersectionObserver כדי להחליף מחלקה כשאלמנט sentinel בחלק העליון של הגלילה יוצא מהתצוגה.
<!-- Sentinel element placed at the top of the scroller -->
<div class="scroll-sentinel"></div>
/* Marker styling to ensure it does not affect layout */
.scroll-sentinel {
height: 0;
width: 0;
visibility: hidden;
}
.scrolled .back-to-top {
visibility: visible;
opacity: 1;
translate: 0 0;
}
if (!CSS.supports('container-type', 'scroll-state')) {
const sentinel = document.querySelector('.scroll-sentinel');
const scroller = document.querySelector('.scroller');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// If the sentinel is NOT intersecting, it means the user has scrolled down
if (!entry.isIntersecting) {
scroller.classList.add('scrolled');
} else {
scroller.classList.remove('scrolled');
}
});
}, { root: scroller });
observer.observe(sentinel);
}