This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Ingo Steinke
Although CSS has added so many features recently, we still have to use JavaScript to detect when an element becomes visible?
It depends:
- We don't need JavaScript for lazy-loading images anymore.
- Scroll-linked animations without JavaScript are coming to CSS.
- But we still need IntersectionObserver to animate images when they first become visible.
- We also need IntersectionObserver to check the visual state of a sticky header element.
As this year's State of CSS survey is open for contributions, we can look back on a year of CSS innovation and better cross-browser support. Extended color space, container queries, and parent/child selectors, top wish list items for years, are now available in modern web browsers.
But we still struggle with visibility detection. There is no :visible
and no :stuck
selector to select elements based on their visibility or sticky state.
Not so simple Use Cases
An apparently simple use case could be a single page portfolio website. We have some pictures, some text, some links, and the contact information. A minimalist website focused on images and visuals, so we want to add some animation. We might also want to shrink or hide the header when scrolling down and make it appear when scrolling up again.
Can we do this without JavaScript?
Both use cases are best solved in JavaScript using IntersectionObserver
, which has a better performance than implementation alternatives based on scroll
event handlers. Scroll detection can waste performance, time, and energy, blocking our main thread and makes websites feel slow and sluggish. IntersectionObserver
is a modern API optimized by browser engines.
But IntersectionObserver
is also an API that requires some boilerplate code which is not easy to understand and learn, especially as a beginner or as a web developer focused on CSS and web design.
I will focus on our animation example in this post, as there are already a lot of blog posts about sticky headers and their complicated details, especially when it comes to compatibility with Safari browsers on iPhones that don't get the latest updates anymore.
Minimal Movement on Visibility Detection
As micro-animations are trending in web design, we want to animate elements when they come into view, like when scrolling down a website, we could make a teaser text move in a subtle way, or make an image enter the viewport.
Animate.css as Animation Library
Simple animations, technically defined as transitions with animation keyframes, don't need to be reinvented. Animate.css (animate.style) is a popular open source CSS animation library that offers a set of predefined animations that can be customized and configured.
Animating a heading or an image becomes quite easy with animate.css
, as we only need to add two class names: animate__animated
, and another animate__*
class to choose an animation effect.
Adding Visibility Detection
But without adding a visibility detection, the animations don't wait for the user to view the element, so they might already have finished when the user scrolls the elements into view. A simple visibility detection using IntersectionObserver
is not that simple after all. We need to
- initialize an observer object,
- tell it what elements to observe,
- make sure we use the correct container element
- adjust the threshold for the visibility trigger
- code a callback function that
- iterates over all triggered element,
- tests the visibility criteria again (why? see below 👇),
- and adds the animation classes to start the actual animation.
Code Example and our animated Website
You can the commented code pen and a real-world use case below.
Notable details:
- The code example is written in classic JavaScript (< ES6) so that we don't need Babel transpilation for older browser support.
- While we might expect the observer only triggering when an intersection happened at the threshold configured in the observer's options object, we still need to ensure every
intersectingEntry
isIntersecting
and itsintersectionRatio
is greater than ourobserverOptions.threshold
.
It seems counter-intuitive that we have to check the intersection criteria in our callback. I would have expect the IntersectionObserver to return only elements that have changed in the entries array. But it seems that initializing an IntersectionObserver causes an intial function call with an array that contains all observable objects, whether they are intersecting or not. See this StackOverflow answer from 2017 for more details.
- We don't initialize the observer until all DOM elements are present (loaded), so that we don't miss any element that we want to animate:
document.addEventListener('DOMContentLoaded'
... - Elements'
data-animationclass
attributes hold the class name for an animation, to be set as an actual class name usingclassList.add
, by our intersection handler callback function, so that each element can have a different class name.
For the actual portfolio website, I added another attribute, data-animationclassincolumn
to be used instead of data-animationclass
when the animated element is displayed within a column (portrait) layout like on a small smartphone screen. So we can use different animation directions to adapt our animations to alternative screen layouts.
As an example of an actual website, check out out the code on GitHub. The actual website is still a work in progress, but you can see the animations at Kleiderordnung-Berlin.de.
Although our websites might often be complex enough to use custom logic and some JavaScript anyway, there are simple situations where we could do without the boilerplate code and just use some CSS to style a website. So this is my conclusion:
Future CSS Visibility Innovation?
Let's keep our eyes open for upcoming CSS innovation. I hope that there will be something like a :visible
selector so we can handle simple use cases like this, without redundant boilerplate JavaScript code, so that it becomes even easier to focus on visual web design in the future.
This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Ingo Steinke
Ingo Steinke | Sciencx (2022-10-24T12:03:05+00:00) Movement and Visibility Detection with CSS and JS đź‘€. Retrieved from https://www.scien.cx/2022/10/24/movement-and-visibility-detection-with-css-and-js-%f0%9f%91%80/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.