Perfect dark mode doesn’t have a toggle; it uses the prefers-color-scheme CSS media query to key off your OS theme preference. At that point, there's no problem with Gatsby or Next.
It's definitely simpler to not have a toggle, but I like having the choice. Some websites I frequent often have a dark mode I don't like much, so I switch to light - and vice-versa.
Just because a user generally prefers dark mode, doesn't mean they do everywhere!
On the contrary, this feature has existed for decades. It’s called user-selectable alternative stylesheets: https://developer.mozilla.org/en-US/docs/Web/CSS/Alternative.... But because no one used it, the feature has not been better positioned in more recent browser UI redesigns, so it’s close to inaccessible in most browsers now. No idea if Chrome and related browsers expose it at all, or even if they’ve ripped the functionality out altogether somewhere along the way.
There’s nothing wrong with having a toggle; it just needs to default to a “system” mode. Unfortunately this site doesn’t seem to implement this correctly, as changing the OS theme doesn’t update the site’s theme.
Not necessarily true, I'd argue the "perfect" dark mode uses the system's theme by default like you said, but still allows visitors to manually set light or dark should they wish to view the site a particular way (perhaps they prefer the light mode, etc.)
Agreed. S.O. recently added dark mode and for some reason my eyes couldn't focus on it. No idea why. I run my editors and my terminal in dark themes. Maybe they didn't have enough contrast. Maybe the fonts are too small or too thin. I have my browser set to "prefer dark mode" but I'm really happy S.O. let me opt out.
I think the only reason someone who likes dark theme would opt out of your dark mode is because it's not as nice/readable as your light theme, or vice-versa. You should fix that instead. Once your dark mode support is perfect, or at least as good as your light theme, then the toggle serves no purpose.
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).
CSS variables are the best way to do dark mode, just use the variable everywhere, set it on html or :root, and change it either in .darkmode or a @media for dark mode. They're pretty much supported everywhere dark mode is. Surprisingly simple dark mode support for greenfield sites.
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.
If you read the article, the complexity did not come from React, it came from meeting the author's specific requirements, which are not achievable with CSS alone.
You can totally use CSS variables in React and there’s no difference from native, but you can also add more superpowers by having small areas use the color palette dynamically.
The author had a specific desire for a toggle on a static site, which requires a bit of persistent state that CSS can't really capture. (FWIW, I don't care for a toggle and match the system theme on my website as well. But dismissing the author's work with your "few lines of CSS" fails to account for the fact that this dark mode does something different than yours.)
This doesn't capture all the state correctly even. When you first load the page, if it is dark mode the XKCD loads a black on white (aka light) image. If you toggle to light mode and back to dark the XKCD comic becomes a black on white image. The state of image filters isn't consistent in the current implementation.
Oh, I'm not claiming it does it correctly. (In fact, I have another comment that points out another issue: https://news.ycombinator.com/item?id=22924571). But the claim that I was responding to made incorrect assumptions, and the bugs in the implementation don't change that.
Dark mode shouldn't be harder with SSR apps, you would just send back the dark mode CSS in the initial GET response. Complexity around this might be related to trying to work with out of the box framework settings, but comparing this problem to some advanced image recognition, while admittedly a joke.. is just over-representing the problem imo. I'm sorry gatsby didn't give you an easy way to do this, but if you understand the principles of web applications this should not be an epic quest.
That's the thing with SSR... (i.e. with Next) or with pre-rendering apps before hand. In the initial GET request to the page, you also send a cookie with user preference. Depending on their dark mode preference you can style the page to be in dark mode as part of the server or pre-rendered markup -- no JS required :o. Now.. how difficult that is to do with Gatsby I don't know. But the fact that someone shot themselves in the foot with Gatsby, then learned to hobble along on one foot isn't a cause for celebration imo.
This has nothing to do with Gatsby or SSR. It has to do with storing the user's preference locally and applying it before the page renders. Don't think you understand the principles here.
So with server side rendered code you can render in dark mode and send that back in the html markup of the request -- no latency on seeing the style applied. You don't need to just store the user preference locally and apply it with js. You can even store the user preference on the server as part of their profile (:o) and then NEW browsers will get the dark or light mode styling. If I am very wrong let me know but I still think it is new web devs getting lost in a wilderness of frameworks and not realizing that the escape from the haunted forest is just to walk north for ten paces, because they lack a basic compass.
We have had color schemes on Cryptowatch (https://cryptowat.ch) for years, and since a year ago we even let users create custom color schemes within the web app [1]
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).
The theme toggle button plays a sound when you click it. So not only does this require state for the theme, but also the sound. Also curious is that clicking the button to mute sound plays a sound.
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.
Thanks! I did see this before. Didn't realize it was the same dev. They don't address that Desktop OSes don't do sound for most things and also, I'm not really sure I see sound used a lot in mobile apps, but maybe that's just the apps I use? I think I would personally want more research and discussion on this before I ventured down this path, but it is an interesting idea.
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.
> When you run gatsby build (or whatever your command is to build your site for production), the build system will make all the API calls needed to fetch the data necessary to generate every possible HTML page. It'll use React server-rendering APIs to turn a tree of React components into a big HTML document.
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 :)
> Do a static website, add a little bit of vanilla JS, want to refresh parts of the pages ? It's called Ajax.
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?
> Gatsby is a static website generator that makes bunch of static HTML leaves a bit of vanilla JS, and progressively enhances the site.
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.
The problem mentioned here has nothing to do with React and everything to do with static site generators, which is nothing new as you posit. Keeping that in mind, do you have any comments on how to do this better, other than complaining that the author should have used "old techs"?
> That was exactly my point. We are currently seeing the whole thing looping.
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).
Static site generators are superior to server-side includes/dynamic server frameworks + caching in some aspects (in other aspects, dynamic server frameworks w/caching are better).
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've been thinking about a concept that I'm calling "building up vs buiding down". Building up is adding abstractions. Building down is dropping down to the lower level abstraction to implement something (as opposed to removing functionality altogether to simplify the codebase).
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>).
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.
I like my dark theme implementation which supports the same operations, but a tad lighter, more flexible and not-Reacty: a toggle, falling back to the prefers-color-scheme value if it hasn’t been toggled or if JavaScript is disabled (and I don’t think Josh’s does that), and avoiding a flash of unstyled content. I wrote about it at https://chrismorgan.info/blog/dark-theme-implementation/.
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.
Seriously! Should every Gatsby blog post on HN have this useless 'React is overkill for static sites' talk?
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!
57 comments
[ 3.2 ms ] story [ 121 ms ] threadJust because a user generally prefers dark mode, doesn't mean they do everywhere!
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.
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.
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 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.
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>).
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.
(I’m on mobile so cannot reverse)
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.
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!
https://www.w3schools.com/howto/howto_js_toggle_dark_mode.as...