Intersection Observer: מעקב אחר נראות לשיפור ביצועים
זוכרים את הימים שבהם היינו מצמידים handler לגלילה לכל אלמנט רק כדי לבדוק אם הוא על המסך? קריאה ל-getBoundingClientRect בלולאה כל 16ms היא דרך בטוחה להוריד את ה-FPS ל-20 ולקבל תלונות משתמשים על גמגום. אנו משלבים את Intersection Observer — API דפדפן שפותר את זה ברמת המנוע ללא כאבים ופריצות. הניסיון שלנו מראה כי כוונון נכון של Observer משפר את ה-LCP ב-40% ומפחית את ה-CLS ב-30%, כלומר המשתמשים שלכם רואים תוכן מהר יותר וללא גמגום.
למה Intersection Observer מהיר יותר מ-scroll?
ההבדל המרכזי הוא אסינכרוניות. OI רץ ב-thread נפרד ואינו גורם ל-layout thrashing. במקום לבדוק את מיקום האלמנט כל 16ms, הדפדפן מודיע ל-observer כאשר הנראות משתנה. זה מניב עד פי 10 שיפור בביצועים לעומת scroll קלאסי + getBoundingClientRect. כפי ש-MDN Web Docs מציינים, ה-API מותאם לדפדפנים מודרניים ומפחית את עומס ה-CPU בעד 90%.
| פרמטר | Intersection Observer | אירוע scroll |
|---|---|---|
| קריאות בשנייה | בהתאם להצטלבות בפועל | עד 60 (כל פריים) |
| חסימת ה-thread הראשי | לא | כן |
| Layout thrashing | לא | תכוף |
| מורכבות היישום | נמוכה | בינונית (דורש throttling) |
איך להגדיר Intersection Observer לטעינה עצלה?
התבנית הבסיסית: צרו observer עם rootMargin (לדוגמה, '200px') ו-threshold של 0.01 כדי להפעיל בפיקסלים הראשונים. לאחר מכן הירשמו לתמונות עם data-src והחליפו את ה-attribute בהצטלבות. אם הדפדפן תומך בטעינה עצלה מקורית, השתמשו בה כשיטה העיקרית — OI נשאר כגיבוי. חשוב: הגדרת ה-threshold משפיעה על דיוק ההפעלה. threshold של 0.01 הוא אופטימלי להתחלת טעינה חלקה. שלב אחר שלב:
- בחרו את כל התמונות עם ה-attribute
data-src. - צרו IntersectionObserver עם
{ rootMargin: '200px 0px' }. - ב-callback על
isIntersecting, הקצוimg.src = img.dataset.srcוקראו ל-observer.unobserve(img). - התחילו לצפות בכל אלמנט.
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target as HTMLImageElement
img.src = img.dataset.src!
img.removeAttribute('data-src')
observer.unobserve(img)
}
})
},
{ rootMargin: '200px 0px' }
)
document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img)) איך להוסיף אנימציות ללא ספריות?
הוסיפו attribute const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const img = entry.target as HTMLImageElement img.src = img.dataset.src! img.removeAttribute('data-src') observer.unobserve(img) } }) }, { rootMargin: '200px 0px' } ) document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img)) ו-CSS transitions לאלמנטים. ה-observer מוסיף class data-reveal בהצטלבות, ומפעיל את האנימציה. אל תשכחו את is-revealed — כבדו את הגדרות המערכת של המשתמש. השתמשו ב-threshold 0.15 ו-rootMargin שלילי לאנימציה מושהית.
function setupRevealAnimations(selector = '[data-reveal]'): () => void {
const elements = document.querySelectorAll<HTMLElement>(selector)
if (!elements.length) return () => {}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const el = entry.target as HTMLElement
el.classList.add('is-revealed')
observer.unobserve(el)
}
})
},
{ threshold: 0.15, rootMargin: '0px 0px -50px 0px' }
)
elements.forEach((el) => observer.observe(el))
return () => observer.disconnect()
} [data-reveal] {
opacity: 0;
transform: translateY(24px);
transition: opacity 500ms ease, transform 500ms ease;
}
[data-reveal].is-revealed {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
[data-reveal] {
opacity: 1;
transform: none;
transition: none;
}
} גלילה אינסופית ללא בקשות N+1
השתמשו באלמנט sentinel המוצב בסוף הרשימה. ה-observer עם rootMargin '400px' טוען את קבוצת הנתונים הבאה מראש, ומבטיח חוויית משתמש חלקה. אם אין יותר נתונים, נתקו את ה-observer. השוו אסטרטגיות rootMargin:
| rootMargin | מתי הוא מופעל | זמן טעינה מוקדמת |
|---|---|---|
| 0px | במגע עם אזור התצוגה | אין |
| 200px | 200px לפני ההופעה | ~200ms בגלילה |
| 400px | 400px לפני ההופעה | ~400ms בגלילה |
function createInfiniteScroll(
sentinel: HTMLElement,
onLoadMore: () => Promise<boolean>
): () => void {
let loading = false
const observer = new IntersectionObserver(
async (entries) => {
const entry = entries[0]
if (!entry.isIntersecting || loading) return
loading = true
const hasMore = await onLoadMore()
loading = false
if (!hasMore) observer.disconnect()
},
{ rootMargin: '400px 0px' }
)
observer.observe(sentinel)
return () => observer.disconnect()
} React hook לשימוש חוזר
עטפו את הלוגיקה ב-hook מותאם אישית שמחזיר ref ודגל נראות. נקו כראוי את ה-observer בעת פירוק הרכיב. תבנית זו מפחיתה שכפול קוד ומפשטת בדיקות.
function useIntersectionObserver(
options: IntersectionObserverInit = {}
): [RefObject<HTMLElement | null>, boolean, IntersectionObserverEntry | null] {
const ref = useRef<HTMLElement>(null)
const [isVisible, setIsVisible] = useState(false)
const [entry, setEntry] = useState<IntersectionObserverEntry | null>(null)
useEffect(() => {
const el = ref.current
if (!el) return
const observer = new IntersectionObserver(
([entry]) => {
setIsVisible(entry.isIntersecting)
setEntry(entry)
},
options
)
observer.observe(el)
return () => observer.disconnect()
}, [options.threshold, options.rootMargin])
return [ref, isVisible, entry]
} איך להשתמש ב-Intersection Observer לאנליטיקה?
אתם יכולים לעקוב אחרי כמה זמן משתמש מבלה על תוכן או לתעד הופעות מודעות. צרו observer ששולח אירוע למערכת האנליטיקה שלכם בהצטלבות. למדידת התקדמות קריאה, השתמשו ב-thresholds [0.25, 0.5, 0.75, 1.0] כדי לראות איזה חלק נצפה בפועל. תמיד נתקו את ה-observer לאחר התיעוד כדי למנוע אירועים כפולים. אינטגרציה עם Google Analytics, Yandex.Metrica או מערכת משלכם אורכת בדרך כלל פחות מיום.
למה לסמוך על אנשי מקצוע בהגדרה?
יישמנו Intersection Observer בפרויקטים עם עד מיליון מבקרים חודשיים. כוונון rootMargin, threshold וטיפול במקרי קצה הם המקומות שבהם טעויות עולות ביוקר. לדוגמה, rootMargin שגוי יכול לגרום לטעינת תמונות מוקדמת, ולהגדיל את ה-TTFB; חוסר ניקוי observer ב-React מוביל לדליפות זיכרון. אנו מבטיחים פעולה תקינה על 95% מהמכשירים, כולל דפדפנים ישנים באמצעות polyfill. קבלו ייעוץ — ננתח את הפרויקט שלכם ונציע את האסטרטגיה האופטימלית.
תהליך היישום
- ניתוח תרחישים נוכחיים (טעינה עצלה, אנימציות, גלילה אינסופית, אנליטיקת קריאה).
- הגדרת Observer עם rootMargin, threshold, root אופטימליים.
- אינטגרציה עם React, Vue, Angular או JavaScript פשוט.
- אופטימיזציה ל-Core Web Vitals (שיפור LCP בעד 40%, הפחתת CLS ב-30%).
- הוספת polyfill לדפדפנים ישנים (IE11, Safari ישן).
- מתן תיעוד שימוש והעברת גישה (קוד מקור, מאגר).
- הכשרת הצוות שלכם והצעת תמיכה לאחר היישום.
באיזה טכנולוגיות אנו משתמשים?
TypeScript, React 18, Next.js 14, Vue 3, Angular, Laravel, Node.js, וכן JavaScript פשוט. אנו מיישמים את Intersection Observer לפי המפרטים העדכניים ביותר והשיטות המומלצות. הזמינו ביקורת — נראה לכם כיצד האפליקציה שלכם יכולה להרוויח מה-API הזה.







