Style Observer

npm npm bundle size

A robust, production-ready library to observe CSS property changes on any element. Detects browser bugs and works around them, so you don't have to.

Chrome 117+ Safari 17.4+ Firefox 129

Same compat as transition-behavior i.e. ~90% of global users

Install

The quickest way is to just include straight from the Netlify CDN:

import StyleObserver from 'https://observe.style/index.js';

This will always point to the latest version, so it may be a good idea to eventually switch to a local version that you can control. E.g. you can use npm:

npm install style-observer

and then, if you use a bundler like Rollup or Webpack:

import StyleObserver from 'style-observer';

and if you don’t, you can just include the file from node_modules/style-observer/dist/index.js.

Usage

You can first create the observer instance and then observe, like a MutationObserver:

import StyleObserver from 'style-observer';

const observer = new StyleObserver(callback);
const properties = ['color', '--my-custom-property'];
const targets = document.querySelectorAll('.my-element');
observer.observe(targets, properties);

Alternatively, you can provide both targets and properties when creating the observer, which will also call observe() for you:

import StyleObserver from 'style-observer';

const observer = new StyleObserver(callback, {
	targets: document.querySelectorAll('.my-element'),
	properties: ['color', '--my-custom-property'],
});

Both targets and properties can be either a single value or an iterable.

Note that the observer will not fire immediately for the initial state of the elements.

Future Work

Prior Art

This is not a fork of either. It was written from scratch and has several differences, including:

Read the blog post for more details.

Limitations & Caveats

Transitions & Animations

Observing display

Observing display is inconsistent across browsers (see relevant tests):

Rule Chrome Firefox Safari Safari (iOS) Samsung Internet
From display: none
To display: none
From not none to not none

Changing transition properties after observing

If you change the transition/transition-* properties dynamically on elements you are observing after you start observing them, you need to call observer.updateTransition(targets) to regenerate the transition property the observer uses to detect changes. Or just tuck , var(--style-observer-transition, all) at the end of your transition property, and then you don’t need to worry about it.