The Quest for the Perfect Dark Mode (Gatsby/React)
joshwcomeau.com
joshwcomeau.com
I don't have the energy to debunk some of these replies, but let me quickly say:
1. The reason that this is a hard problem has nothing to do with React, or Gatsby. It has to do with the strategy of precompiling HTML and not having a runtime server, an approach with many many benefits (described here: https://joshwcomeau.com/gatsby/a-static-future/). If you're wondering why anyone would put up with all this tomfoolery for a dark mode, please read that so you can understand the benefits to this approach.
2. "React is overkill for static sites" is a debate I am not trying to have, but I can say that for my blog (the site that this post is about), React has allowed me to do lots of cool things that would have been much harder otherwise. And using Gatsby means that I have first-meaningful-paint performance that beats a PHP template with no JS, since my site doesn't have to do any database lookups or real-time HTML generation. I am not saying that this is the right approach for every website, but it was 100% the right choice for this one.
4. Many of these replies are making suggestions that are discussed in the article itself. CSS variables are not an alternative to this solution, they _are_ the solution (my solution wouldn't work without them!). Please read the post before forming an opinion about it.
I hope that helps clarify some things! Hope you're all doing alright and staying home.
That's what we're calling "cache" in good ol' backend-code applications. It's used for at least 15 years in e-commerce, blogs and many other "outdated because now we have react-angular-vue.npm.io" CMS.
With "cache" you can store precompiled HTML pages server side, even only parts of it (if you have 50.000 articles like you're explaining in your article).
You can even do that in front of your PHP/Ruby/Python app using HTTP caching proxies such as Squid. Here it's even beyond "blistering fast", it's "ultra blistering fast".
Do a static website, add a little bit of vanilla JS, want to refresh parts of the pages ? It's called Ajax.
The moment I saw ReactJS redering moving server side to "pre-render" stuff I saw that we we just looping again and again.
And again once your HTML is delivered, no one is stopping you to do a few line of JS to add a simple class on top of your page to toggle the Night Mode. Want to do it before the JS is executed (and don't have this ugly delay) ? Use a cookie and set it on render time. If the user is forbidding cookies, well then it's because he don't want to be tracked and don't want all those fancy features. You can fallback to prefers-color-scheme.
Things were done simple, no need to reinvent everything each time :)
Before you become sarcastic, try to check out what Gatsby is. Gatsby is a static website generator that makes bunch of static HTML leaves a bit of vanilla JS, and progressively enhances the site.
> Things were done simple, no need to reinvent everything each time :)
Things are there for a reason, why not just go to the 70s/80s where there was no networking, servers, or bloated JS?
That was exactly my point. We are currently seeing the whole thing looping :)
> Things are there for a reason, why not just go to the 70s/80s where there was no networking, servers, or bloated JS?
React/Angular/Vue can be used for very specific use cases indeed and can be really powerful tools. But lets face it, for most of the websites, you don't need those tools. It's even worst most of the time regarding browser performances, accessibility , SEO, navigation.
Developers are always looking for shinning things. And in the end you end up with really complex architecture.
I'm just saying that in 95% of the cases. You don't need those tools. But only simple "old techs" that are battle tested and works flawlessly.
If Gatsby is exactly the format you like, what's the problem? The fact that it uses React as a dependency? Because... it uses 'npm', the worst package manager of all history?
> But let's face it, for most of the websites, you don't need those tools.
I'm pretty sure asking this is against the guidelines, but I just can't resist - have you ever worked with jQuery/vanilla JS and React?
If you ever, ever worked with them, one can easily see that the component model React provides gives a great productivity boost.
For example, consider this[0] code from the old version of this blog: it defines a 'Code' component that allows live previews of JS code. It would be super tedious to do that every time you embed a JS example in your post.
> It's even worst most of the time regarding browser performances, accessibility , SEO, navigation.
No, it isn't. Gatsby is a 'static site generator', with most of the advantages and disadvantages that they provide. Navigation is faster, not slower if you've turned on JS (due to progressive enhancement) and accessibility has nothing to do with React - it's the matter of proper markup (which React can do pretty well).
[0] https://github.com/joshwcomeau/blog/blob/master/src/componen...
One example: there are security advantages of static site compilation, since it's typically done off-server, on the developer's machine or a CI build machine. This means they can dramatically reduce the attack surface, either by having a server with a single HTTP server running, or (more often) using a service like S3 or Github Pages.
Statically-rendered React pages isn't a recent innovation, even in the context of static site generators. They are just the latest iteration in a long-line of such static site generators, starting most prominently with generators such as Jekyll and Hyde back in the late 2000s.
I've been punting on making a dark/light mode selector on the new TypeScript website for a few months specifically so I don't have to be certain of this route first-hand. This was exactly what I was expecting. Good work.
I think it's interesting to see people complaining about React: it seems people assume we're always building up and that any complexity comes from using whatever tools we're using. What you did here though is _building down_: you're talking about how the browser deals with the order of script loading and painting, which is decidedly not something that is in the React vocabulary at all, and which one absolutely needs to understand and be able to reason about when dealing w/ client-side state to manage FOUC.
The only (minor) complaint I have is that you're framing the knowledge of browser rendering priorities as "tricks" and "tomfoolery". If we want to collectively build better products, it behooves us to understand the technologies we use and when it makes sense to "break" 5 year old dogmas (e.g. the ones saying not to put scripts in <head>).
https://motherfuckingwebsite.com/
It's also worth mentioning that TFA's webpage is broken.
Despite all his dozens of lines of javascript for his "dark background" feature, it totally fails to render (resulting in a blindingly white blank page, ha!) if you have cookies off (it's a static Gatsby site, which does not need and cannot use cookies).
For all his hard work, his site is a blank page.
(Here's why, if you care: https://sneak.berlin/20200211/your-website/)
Guys, you don't need all that JS, seriously. It's slow, it's useless most of the time. And in the end you have to spend hours for something so simple.
Theming the colors of your website is the role of one tech: CSS. That's it, you don't needs layers and layers of Javascript to change that.
Let's go back to server side rendering, a bit of HTML + CSS and JS and we're done.
:root {
color-scheme: light dark;
}
can get you quite far.Dark Mode is pretty easy to do in CSS. I purposely picked jekyll with no javascript for my static site, and despite contributing a plugin for Gatsby, I do not use it these days.
Yet, there is at least some modern applications that can be made thanks to javascript, and React. We do not need to go back, but it is perfectly acceptable to say that not everything is a nail and you do not need a hammer for every single task.
Gatsby is a static site generator!
Running Gatsby does NOT make the whole website run on React. It makes a bunch of HTML pages that are statically served - and some JS progressively enhances it.
The complexity in this blog post has nothing to do with React, it's due to the author's complex requirements that are very beneficial to the user.
Yes, the web is full of bloated pages. No, that's not the topic here. It's so frustrating for people to complain about React on this great post - comment about the post, people!
Just because a user generally prefers dark mode, doesn't mean they do everywhere!
I believe every OS defaults to silent actions for every button. Games, on the other hand, often have sounds for hover/focus and click. I'm not sure what's the better option, but if we're going to default to the OS for theme choice shouldn't we also default to the OS for UI sound choice? I don't know if there's any way to check that via CSS or JS. But I hope that if sites are going to start implementing this more often that browsers at least expose an API with a user preference if not the OS.
The problem as a whole is definitely a tad fiddly, but I still think that trying to do things in React is a substantial part of what’s making it complicated here. I instead used regular stylesheets and the media attribute to control the toggling, and I think that’s the best solution, because it’s what makes it work perfectly with and without JavaScript. (I used external stylesheets, but you could inline them if you wanted; the media attribute works on <style> as well as <link>.)
Josh, I’d be interested in your opinion on it. It took me several iterations to end up where I did (definitely didn’t occur to me to alter the media attribute at first!), and I think it’d apply cleanly to such sites as yours, and be better for the toggling.
Not sure about the dark mode implementation, since it rendered a white screen for me with no content on iOS, but on desktop it worked.
Also the general feel of the website is really nice, a lot of nice little touches from the sounds to the "nonstop confetti party" when you sign up for the newsletter.
We use CSS variables for this. The stylesheet doesn't have any hard-coded colors, it only references a set of several variables and many blends of these variables. This way, you can let a user adjust a variable using a color picker and the entire website adjusts dynamically as they do it. It also lets you render any color scheme properly in your SSR (unlike the approach in this article).
[1] https://guides.cryptowat.ch/real-time-charting-interface/cus...
(I’m on mobile so cannot reverse)