Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Time for intersection observer

557 views

Published on

Lazy loading content, tracking impressions, animation triggers
- for many years we have utilised scroll handlers to detect when
to trigger such actions. Now modern browsers are supporting
IntersectionObserver, a new API that comes with better performance, and results in cleaner code.

In this talk I will show you what Intersection Observer is,
what type of code it replaces and why it is a better alternative.

Slides from talk given at:
- FEL in London on September 28th, 2017
- Paris.js on September 27th, 2017
- BerlinJS on September 21st, 2017

----
Snips are hiring - join us for an amazing adventure working with AI in the heart of Paris (no remote).
Currently looking for one frontend dev, as well as for many other non web roles:
https://snips.ai/jobs

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Time for intersection observer

  1. 1. IntersectionObserver Time for @pocketjoso
  2. 2. Open source, web perf, tooling, React Critical css: Penthouse, criticalcss.com About me @pocketjoso pocketjoso Jonas Ohlsson Aden https://jonassebastianohlsson.com Lead Front end team Using Voice AI to make technology disappear
  3. 3. Today’s talk • What is IntersectionObserver❔ • Why you need it 👊 • How to use it (today) 🚀
  4. 4. What is IntersectionObserver ❔ Default behaviour is in-view monitoring ‘root’ can be changed (advanced use cases)
  5. 5. Some usages areas 🎯 • lazy loading content • in-view tracking • animation triggers
  6. 6. in-view animation trigger
  7. 7. Why is it needed? We’ve been doing these things for years!
  8. 8. Why is it needed? ..without it you end up with • complex code • performance issues more on why: https://github.com/w3c/IntersectionObserver/blob/gh-pages/explainer.md#observing-position
  9. 9. Why complex and badly performing? (historically) • ‘scroll’ fires too often, needs to be throttled useful: https://css-tricks.com/debouncing-throttling-explained-examples/ why getBoundingClientRect is slow https://gist.github.com/paulirish/5d52fb081b3570c81e3a • useful DOM methods are too slow 🐌, f.e. DOMElement.getBoundingClientRect • workarounds requires caching expensive DOM read values, and then cache invalidation..
  10. 10. IntersectionObserver to the rescue! 🎉
  11. 11. const observer = new window.IntersectionObserver(onIntersect) function onIntersect (entries) { entries.forEach(entry => { if (entry.isIntersecting) { console.log('element intersecting!') } }) } observer.observe(DOMElement) 👍 in-view monitoring with IntersectionObserver
  12. 12. Why is it needed? recap • avoid complex code • avoid performance issues more on why: https://github.com/w3c/IntersectionObserver/blob/gh-pages/explainer.md#observing-position ✅
  13. 13. IntersectionObserver performance built in 🏇 • callback doesn’t fire continuously
 - and internally uses requestIdleCallback* • not magic: do keep handler execution quick • no need for getBoundingClientRect()
 - intersection checks handled and optimised by browser *so far only in Chrome
  14. 14. Why is it needed? recap • avoid complex code • avoid performance issues ✅ ✅
  15. 15. IntersectionObserver performance built in 🏇 • callback doesn’t fire continuously
 - and internally uses requestIdleCallback* • not magic: do keep handler execution quick • no need for getBoundingClientRect()
 - intersection checks handled and optimised by browser *so far only in Chrome
  16. 16. IntersectionObserver for animations • don’t use if need continuous updates; tracing scroll position -> Parallax effects ❌ • can use if okay with delayed (async) updates -> enter/exit animation trigger ✅ ✅ Just test your use case
  17. 17. IntersectionObserver what else do we need to know? full API docs: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
  18. 18. in-view detection via entry.isIntersecting const observer = new window.IntersectionObserver(onIntersect) function onIntersect (entries) { entries.forEach(entry => { if (entry.isIntersecting) { console.log('element intersecting!') } }) } observer.observe(DOMElement) In my opinion the easiest way to do this
  19. 19. entry.isIntersecting • Not whether entry is intersecting or not • whether the element now intersects more or less than before ⚠ in earlier version of spec the behaviour was the former; and it’s still the case in polyfills, and early Edge
  20. 20. in view detection via entry.intersectionRatio const observer = new window.IntersectionObserver(onIntersect) function onIntersect (entries) { entries.forEach(entry => { if (entry.intersectionRatio > 0) { console.log('element intersecting!') } }) } observer.observe(DOMElement) (not enough to just use intersectionRatio)
  21. 21. intersectionRatio = 
 area intersecting / total area by default: area in view
  22. 22. Image credit: https://developers.google.com/web/updates/2016/04/intersectionobserver root (Viewport) intersectionRatio = 
 area intersecting / total area
  23. 23. in view detection via intersectionRatio const observer = new IntersectionObserver( onIntersect, {threshold: [0.01]} // default: [0] ) function onIntersect (entries) { entries.forEach(entry => { if (entry.intersectionRatio > 0) { console.log('element intersecting!') } }) } observer.observe(DOMElement) You need to add a custom threshold
  24. 24. in view detection via intersectionRatio const observer = new IntersectionObserver( onIntersect, {threshold: [0.01]} // default: [0] ) function onIntersect (entries) { entries.forEach(entry => { if (entry.intersectionRatio > 0) { console.log('element intersecting!') } }) } observer.observe(DOMElement) threshold + intersectionRatio demo: https://codepen.io/pocketjoso/pen/jGqgPB threshold: array of intersectionRatio values when crossed triggers onIntersect callback
  25. 25. in view detection via intersectionRatio const observer = new IntersectionObserver( onIntersect, {threshold: [0.01]} // Note: above 0 ) function onIntersect (entries) { entries.forEach(entry => { // without 0.01 threshold // we can get false negatives here if (entry.intersectionRatio > 0) { console.log('element intersecting!') } }) } ⚠ To avoid false negatives
  26. 26. thresholds and callbacks • onIntersect also fires when observer.observe() is called • No guarantee of one onIntersect call per threshold -
 callback is ~ throttled, time-overlapping calls omitted • ⚠ Possible to get no callbacks is scrolling past too quickly • ✅ Should not be a problem for most use cases
  27. 27. determine direction • entry.boundingClientRect: static read- only value - we get it for free! 🎉 • together with entry.isIntersecting we can determine direction function onIntersect (entries) { entries.forEach(entry => { // entry.boundingClientRect // entry.isIntersecting
 }
  28. 28. re-use observer const observer = new window.IntersectionObserver(onIntersect) […document.querySelectorAll('.myClass')] .forEach(DOMElement => observer.observe(DOMElement)) also possible using multiple observers,
 if need different observer configuration
  29. 29. observer.unobserve & entry.target const observer = new window.IntersectionObserver(onIntersect) function onIntersect (entries) { entries.forEach(entry => { if (entry.isIntersecting) { // f.e. lazy load image here // then stop observing. // entry.target is the DOMElement // we called observer.observe with observer.unobserve(entry.target) } }) } […document.querySelectorAll(‘.lazy-load’)] .forEach(DOMElement => observer.observe(DOMElement))
  30. 30. disconnect const observer = new window.IntersectionObserver(onIntersect) // later - tears down all observing observer.disconnect() use case: on navigation (leaving page) in Single Page Application
  31. 31. rootMargin px or percent Can use negative margins const observer = new IntersectionObserver( onIntersect, { rootMargin: '0px 0px 0px 0px' } ) observer.observe(DOMElement) rootMargin demo: https://codepen.io/pocketjoso/pen/GMqJYx?editors=0110
  32. 32. rootMargin • Use positive margin to fire onIntersect earlier - for lazy loading logic • Could use negative margin to delay onIntersect, to have more of the element in-view already… ..but better define such “margin” relative to the element:
 
 const observer = new IntersectionObserver( onIntersect, {threshold: [0.2]} // update when 20% in-view instead of 0% )
  33. 33. Support? http://caniuse.com/#feat=intersectionobserver
  34. 34. Support strategies 1. Progressive enhancement 2. Polyfill https://cdn.polyfill.io/v2/polyfill.js?features=IntersectionObserver) Configure polyfill to poll for changes from css (:hover, animations) and other user interactions: https://github.com/w3c/IntersectionObserver/tree/master/polyfill#configuring-the-polyfill
  35. 35. How we use at • React • Declarative code
  36. 36. Declarative (order: Big Mac) vs Imperative (recipe: cut the cucumber, rinse the salad…)
  37. 37. DOM manipulation - imperative const observer = new IntersectionObserver( onIntersect, {threshold: [0.01]} // default: [0] ) function onIntersect (entries) { entries.forEach(entry => { if (entry.intersectionRatio > 0) { console.log('element intersecting!') } }) } observer.observe(DOMElement) We want to avoid repeating this kind of code
  38. 38. <InViewMonitor classNameInView='animated fadeInUp' > <ElementToAnimateIn /> </InViewMonitor> How we use at • “Reveal” animations
  39. 39. <InViewMonitor childPropsInView={{ playVideo: true }} > <VideoPlayer /> </InViewMonitor> How we use at • Auto play/stop video
 - save GPU and mobile battery
  40. 40. <InViewMonitor onInView={() => trackEvent(‘VideoPlayerInView')} > <VideoPlayer /> </InViewMonitor> How we use at • track components coming into view • .. or any other custom functionality
  41. 41. How we use at • declarative & easy to use • Uses IntersectionObserver under the hood Open source! 🎉
 https://snipsco.github.io/react-inview-monitor/ react-inview-monitor
  42. 42. Summary • IntersectionObserver is here -
 ready to use today (with a polyfill) • For in-view detection, it is an easier and better performing alternative than scroll listeners
  43. 43. We’re hiring.. https://snips.ai/jobs
  44. 44. That’s all! 🥂 Thank you! 🙏 @pocketjoso
  45. 45. Resources https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API https://developers.google.com/web/updates/2016/04/intersectionobserver https://github.com/w3c/IntersectionObserver/blob/gh-pages/explainer.md https://davidwalsh.name/intersection-observers http://deanhume.com/home/blogpost/lazy-loading-images-using-intersection- observer/10163 https://www.youtube.com/watch?v=ncYQkOrKTaI&list=PLNYkxOF6rcIBykcJ7bvTpqU7vt- oey72J&index=7 https://corydowdy.com/blog/lazy-loading-images-with-intersection-observer https://alligator.io/js/intersection-observer http://caniuse.com/#feat=intersectionobserver https://developers.google.com/web/updates/2017/09/sticky-headers @pocketjoso

×