Movement and Visibility Detection with CSS and JS

Although CSS has added a lot of features recently, we still have to use JavaScript to detect when an element is visible?

depends on:

As this year’s State of CSS survey is open for contributions, we can look back on a year of CSS innovation and improved 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 detecting visibility. nobody is here :visible no more :stuck Selectors 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 contact information. A minimalist website focused on images and visuals, so we want to add some animation. We may also want to shrink or hide the header when scrolling down and reveal it when scrolling again.

can we do this without javascript?

Both use cases are best solved using JavaScript IntersectionObserverwhich has better performance than the implementation alternatives scroll event handlers. Scroll detection can waste performance, time and energy by blocking our main thread and making websites feel slow and sluggish. IntersectionObserver There is a modern API optimized by the browser engine.

but IntersectionObserver There is also an API that requires some boilerplate code that is not easy to understand and learn, especially as a beginner or as a web developer focused on CSS and web design.

I’ll focus on my animation example in this post, as there are already a lot of blog posts about sticky headers and their intricate details, especially when it comes to compatibility with the Safari browser on the iPhone, which is no longer the latest update. see you.

Minimum movement on detection visibility

As micro-animations are a trend in web design, we want to animate elements when they are in front of them, such as when scrolling down a website, we can micro-move a teaser text, or move an image to the viewport. can enter.

Animate.css as Animation Library

Simple animations, which are technically defined as transitions with animation keyframes, do not need to be recreated. Animate.css ( is a popular open source CSS animation library that provides a set of predefined animations that can be customized and configured.

Animating the title or image becomes quite easy animate.cssBecause we only need to add two class names: animate__animatedand the other animate__* Class to choose animation effect.

add visibility check

But without visibility detection, animations don’t wait for the user to see the element, so they’re already finished when the user scrolls through the elements into view. using a simple visibility detection IntersectionObserver It’s not that easy after all. we need to

  • initialize an observer object,
  • Explain which elements to follow,
  • Make sure we use the correct container element
  • Adjust the range for the visibility trigger
  • code a callback function that
    • iterate over all triggered elements,
    • re-tests the visibility criteria (Why? see below),
    • and adds animation classes to start the actual animation.

Code examples and our animated website

You can comment below code pen and real world use case.

Notable details:

  • Code Example Classic Javascript (
  • Although we might expect that the Observer can only be triggered when an intersection occurs at the threshold configured in the Observer’s Options object, we still need to ensure every intersectingEntry isIntersecting And its intersectionRatiobigger than us observerOptions.threshold,

It seems counter-intuitive that we have to check the intersection criterion in our callback. I would expect the IntersectionObserver to return only the elements that have changed in the entries array. But it seems that initializing an IntersectionObserver with an array 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 elements we want to animate:
  • Element’ data-animationclass Attributes hold the class name for an animation, which can be set as the actual class name using classList.addby our intersection handler callback function, so that each element can have a different class name.

For the actual portfolio website, I added one more feature, data-animationclassincolumn to be used instead data-animationclass When the animated element is displayed within a column (portrait) layout on a small smartphone screen. So we can use different animation directions to adapt our animations to alternate screen layouts.

As an example of a real website, see the code on GitHub. The actual website is still a work in progress, but you can watch the animations at

While our websites can often be complex enough to use custom logic and some JavaScript, there are simple situations where we can do without boilerplate code and just use some CSS to style the website. . So this is my conclusion:

Future CSS Visibility Innovation?

Let’s keep our eyes open for upcoming CSS innovations. I hope a. something like :visible Selectors so that we can handle simple use cases like this without unnecessary boilerplate JavaScript code, making it even easier to focus on Visual Web Design in the future.

Leave a Comment