How to stop dark mode transition animation from showing on every page load?

I’ve got the following css to ensure you get a nice transition when switching/toggling from light to dark mode on a project we’re creating at work.
* {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}
* {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}
The problem I’m having is that our project has some pretty neat ways of using a mix of our client’s “media:prefers-color-scheme-dark” but with an ability to let our users override this and persist the settings through some state in a global store and saving the preference to local storage for future visits. The issue is, on page load, our calculations run (very quickly) but asynchronously after the DOM is rendered to the browser to determine whether or not to attach a “dark” class to a top level parent node on the DOM which allows the dark styling to take hold. Because of this, the page renders initially in light mode, and then immediately begins a 150ms transition to dark mode if it’s the setting you’re using. It’s kind of like the problem people used to have with a FOUC (flash of unstyled content) when the html would deliver before the CSS only this is a more of a “flash of wrong color setting content”. I want to know if there is a clever way in my <link> tag, or with a script to load a separate stylesheet with just the above CSS to come in after the dark or light mode preference is established? The transition style really only needs to be there for when the user toggles to the other mode so they can see the smooth transition from one to the other but it’s annoying to navigate to a bright page that then darkens immediately in front of you rather than just looking correct.
3 Replies
Rowe2ry
Rowe2ryOP2y ago
To give a little more code example here is a faux example of how we’re changing the styles. HTML:
<div class=“{{ darkMode ? “dark” : “”}}”>
<header>
Hello World
</header>
</div>
<div class=“{{ darkMode ? “dark” : “”}}”>
<header>
Hello World
</header>
</div>
CSS:
* {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}

header {
background-color: #eee;
color: #111;
}

.dark header {
background-color: #000;
color: #f5f5f7;
}
* {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}

header {
background-color: #eee;
color: #111;
}

.dark header {
background-color: #000;
color: #f5f5f7;
}
And the programmatic function is not written in JS because we’re using web assembly but it’s essentially On component render, go into local storage and find out if we should be using dark mode or not and then set the darkMode Boolean to true. Then the ternary operator in the parent div will apply the dark class or use an empty string.
Coder_Carl
Coder_Carl2y ago
In JS I would normally add a temporary class that has the transition on it when someone toggles it. Then do a set timeout and remove that class after the 150ms/transition time. Otherwise the initial class has a transition time of 0. Unsure how to do that with your stack
Rowe2ry
Rowe2ryOP2y ago
That’s a great idea! I could programmatically attach the transition styles to the same parent level where I’m deciding to attach the dark class or not and use a promise to ensure it happens at the right time! Something like:
.smooth-change,
.smooth-change * {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}
.smooth-change,
.smooth-change * {
transition: color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
}
And end up with:
<div class=“dark smooth-change”>
<div class=“dark smooth-change”>
Or just
<div class=“smooth-change”>
<div class=“smooth-change”>
But start off without the smooth change class in either scenario on page load so the user sees the immediate calculated UI for them! I just read your answer again. What I wrote above might be even more complicated than I needed it to be. I could do what you said by essentially writing (in C#):
private string _transitionClass = string.Empty;

private void OnDarkModeToggle()
{
_transitionClass = “smooth-change”;
_darkMode = !_darkMode;
Task.Delay(200); // 200ms
_transitionClass = string.Empty;
}
private string _transitionClass = string.Empty;

private void OnDarkModeToggle()
{
_transitionClass = “smooth-change”;
_darkMode = !_darkMode;
Task.Delay(200); // 200ms
_transitionClass = string.Empty;
}
And then just bind the class list on the parent container in the HTML to be 2 variables. The computed light or dark, the the temp class which updates from the empty string to the stylesheet-linked transition and back to an empty string on any toggle event triggering.
Want results from more Discord servers?
Add your server