It's difficult to transition between themes smoothly. Adding a CSS transition
to every element negatively impacts rendering performance, and it also won't work for images, icons, and CSS properties that don't support transitions.
Instead, we can temporarily remove transitions from all elements so that toggling themes feels snappy and consistent. We'll manually create a stylesheet that disables transitions:
const css = document.createElement('style')
css.type = 'text/css'
css.appendChild(
document.createTextNode(
`* {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}`
)
)
document.head.appendChild(css)
Note that we need to manually specify browser prefixes, as this CSS isn't run through any preprocessing.
After changing the theme (usually this involves toggling a class on <body>
), we force a browser repaint and remove the stylesheet:
// Toggle the theme here...
// Calling getComputedStyle forces the browser to redraw
const _ = window.getComputedStyle(css).opacity
document.head.removeChild(css)
Calling requestAnimationFrame
before removing the stylesheet seemed to work at first, but it was unreliable and elements still transitioned. Using getComputedStyle
works reliably on every major browser, because it forcibly applies all active stylesheets.
Before:
After:
Thanks to Guillermo for the idea!