Inject CSS with webextension

I’m injecting CSS using somethings like that:

const CSS = `
body * {
  /*CSS transition*/
  transition: none !important;
  /*CSS animations*/
  animation: none !important;
 }
`;

browser.tabs.insertCSS(tab.id, { code: CSS, cssOrigin: 'user' });

(full code on https://github.com/gagarine/no-transition/blob/master/background.js )

The problem is insertCSS doesn’t seem to take !important into account. At least some animation are still playing because it seem the website CSS can overwrite the CSS I’m injecting.

Is their a better approach to inject CSS? I like insertCSS because you can remove the CSS easely without reloading with browser.tabs.removeCSS. It’s also works from background.js.

The add-on is published, so you can quickly install if if you want https://addons.mozilla.org/en-US/firefox/addon/no-transition/

Add your css file to the page head after pageload.

You should only do that if you find no other way. Messing with the DOM on every page is generally not a good idea.


browser.webNavigation.onCommitted would be the event you want. Also, you only apply to top frames, you ignore <iframe>s.

He could also use a mutation observer if the css adjustment from website is finished he can apply his css changes if the observer fires.

Yeah, one could do that. But while there are good use cases for MutationObservers and they are supposedly much faster than DOM mutation events, they, and the logic they fire, are still performance burdens.

I think in this case, CSS is all you need. And the above CSS itself looks fine to me. If applied to a document, it should prevent all CSS animations/transitions. But:

  • It is currently not properly applied to all document.
  • It won’t prevent manual JavaScript powered “animations”, where a script simply changes the CSS every frame. I don’t think there even is a way to get rid of these.
  • Animated GIFs, videos and the like will also still play.

I was ignoring iframe on purpose until the addon is stable. But now I’m going to inject in iframe too (it’s one argument change in insertCSS).

I will change to browser.webNavigation.onCommitted but was is the difference with browser.tabs.onUpdated.addListener ? I read the doc but don’t really understand what it will change in my case. I opened the issue to not forget… https://github.com/gagarine/no-transition/issues/7

FYI I’m going to support some JS library https://github.com/gagarine/no-transition/issues/5

Video and gif are out of scope, the purpose is stopping useless decorative animation.

Thanks a lot for you help.

onCommitted will fire for all frames in a tab and also fire only once per load as early as it is possible to use insertCSS on that frame. tabs.onUpdated pretty much fires whenever a property on a tabs.Tab property would change (url, title, loading, …) and is not what you want here. It doesn’t handle frames and will fire more than once per tab load.

1 Like

Thanks a lot for those precision. I will change that ASAP and add frame support :).