In this post, I'm going to talk about how Bulma and Gatsby can be used to create a professional blog. Diving into this topic is interesting considering these are the technologies which were used to build the website this article is hosted on, so this website is in itself an example of the ideas expressed in this article.
Introduction: Why Bulma and Gatsby are a Great Combination for Building Professional Blogs
Bulma and Gatsby are a great combination for the development of professional blogs, as they provide the perfect blend of modern web development technologies to create a visually appealing and fast-loading site. Bulma is a modern CSS framework based on Flexbox, which makes it easy to create responsive and mobile-friendly layouts. It has a wide array of components and utilities to build custom interfaces, and its easy to learn syntax makes it a great choice for web developers. Gatsby, on the other hand, is a static site generator, built on React and JavaScript, and is used to create modern websites and applications. It provides a fast and reliable build process, and its performance-focused architecture makes it ideal for creating high-performance websites.
When combined, Bulma and Gatsby provide developers with the perfect toolkit for building professional blogs. Bulma's easy-to-use components and utilities can be used to create custom-branded interfaces for the blog, while Gatsby's powerful static site generator can be used to quickly build out the blog's pages. Additionally, Gatsby's performance-focused architecture ensures that the blog will load quickly and reliably, even under heavy load. This makes Bulma and Gatsby a great combination for building professional blogs, as it provides developers with the tools to both quickly create a visually appealing interface and ensure that the blog runs fast and reliably.
Using Gatsby to Set up the Project
A great way for getting started with Gatsby for blogging is to use the official blog starter. In fact, that's how this website was started! However, keep the following in mind when considering whether to use the starter:
- The starter uses the latest version of Gatsby and its plugins, which could cause problems if you're on an older version of NodeJS. We'll revisit this later.
- If you're following along with this article, you'll be writing your own CSS. The CSS which ships with the starter is fine, but it will have to be removed when Bulma is introduced.
Even though we're going to change the appearance and some other elements, the starter ships with GraphQL already setup for generating the homepage and blog post URLs. It comes with remark plugins installed as well, which means all the blog posts can be written in Markdown. In my opinion, that's the biggest time saver of the blog starter.
You can install the starter blog as follows:
npx gatsby new gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blog
Be sure to replace gatsby-starter-blog
after the new
keyword with the name of your project.
Introducing Dark Mode: Why It's Important
Dark mode has become an increasingly popular trend in recent years, and for good reason. In fact, it's more than just a trend - it's an important accessibility feature that can make your website or application more usable for a wide range of users. Here are a few reasons why dark mode is important:
- Reduced Eye Strain: One of the primary benefits of dark mode is that it can reduce eye strain. When you're looking at a bright screen for extended periods of time, it can cause eye fatigue and discomfort. Dark mode uses a black or dark gray background with light text, which can be easier on the eyes and reduce eye strain.
- Improved Readability: In addition to reducing eye strain, dark mode can also improve readability. When text is displayed on a dark background, it can be easier to read, especially in low-light conditions. This can be particularly beneficial for users with visual impairments or dyslexia.
- Energy Savings: Dark mode can also help prolong battery life on mobile devices. OLED screens, which are becoming increasingly popular, use less power to display black pixels than they do to display white pixels. This means that using dark mode can reduce battery consumption and help users get more out of their devices.
- Aesthetic Appeal: Finally, it's worth noting dark mode simply looks cool. Many users prefer the sleek, modern look of dark mode, and offering it is an option which can help make your website or application more appealing to a wider audience.
Overall, dark mode is an important feature that can improve usability and accessibility for many users. By incorporating dark mode into your website or application, you can help make it more user-friendly and appealing to a wider range of users.
Dynamic Dark Mode Switching: How to Implement a User-Friendly Toggle with Gatsby
Finding a Starting Point
A good place to start for understanding how to implement dark mode with Gatsby is this blog post by Victor Zhou. In it, Victor describes an algorithm for theme selection as follows:
The first question we have to answer is: when a user starts loading your site, what theme (light or dark) will you show them initially? Here’s how we’ll do it:
- Do we have a saved theme preference for this user from a previous visit? If so, use it.
- Does the user have an operating system preference for dark mode? If so, use it.
- Default to Light mode.
Throughout the rest of the article, Victor provides useful code examples for how to implement this algorithm.
Using those examples, this is the head component script I ended up using:
(function() {
function setTheme(theme) {
if (theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
window.__theme = theme
}
window.__setPreferredTheme = function(theme) {
setTheme(theme)
try {
localStorage.setItem('preferred-theme', theme)
} catch (e) {}
}
var preferredTheme
try {
preferredTheme = localStorage.getItem('preferred-theme')
} catch (e) {}
window.__themeListeners = []
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
darkQuery.addListener(function(e) {
window.__setPreferredTheme(e.matches ? 'dark' : 'light')
window.__themeListeners.forEach(function(listener) {
listener()
})
})
setTheme(preferredTheme || (darkQuery.matches ? 'dark' : 'light'))
})()
Next, I created a style sheet called style.scss
(basically a rename of style.css
from the starter after deleting that file's contents) and entered some code like this:
:root {
// . . .
}
:root.dark {
// . . .
}
These selectors will be used to set CSS variables which are in turn used to customize Bulma on-the-fly based on what theme the user wants.
Lastly, we are going to need to create a dark mode toggle component and here's where this site's implementation diverges from Victor's example because we're not going to be able to follow Victor's example all that closely. Here's the component I ended up writing:
import React, { useCallback, useState, useEffect } from 'react'
const DarkModeToggle = () => {
const [theme, setTheme] = useState(typeof window === 'undefined' ? null : window.__theme)
const onChange = useCallback(e => {
window.__setPreferredTheme(e.target.checked ? 'dark' : 'light')
setTheme(window.__theme)
},
[setTheme])
useEffect(() => {
window.__themeListeners.push(() => {
document.getElementById('dark-mode-toggle').checked = window.__theme === 'dark'
})
}, [theme])
if (theme === null) {
return null
}
return <div id="dark-mode-toggle-wrapper" className="field">
<input id="dark-mode-toggle"
type="checkbox"
name="dark-mode-toggle"
className="switch is-rounded is-success is-rtl"
onChange={onChange}
checked={theme === 'dark'}
/>
<label id="dark-mode-toggle-label" htmlFor="dark-mode-toggle">Dark Mode</label>
</div>
}
export default DarkModeToggle
Notice how this doesn't return null
immediately if the window object is undefined. This is because React Hooks must be called in the exact same order in every render (there's an error that specifically mentions that). I'm also not using a boolean called checked
, but rather a string called theme
representing the theme. You may also notice the absence of react-toggle
and might wonder what some of those class names are. Don't worry, that will be covered in the next section.
Since we can't have an early return, the workaround is to first set a variable based on the content of the window.__theme
field. If the window's undefined, it will be null
. If the window's there, then we get the user preferred theme.
If the theme is null
, we don't render the component by returning null
.
Additionally, I introduce the useEffect
function to add a theme listener which will be executed if the user changes their theme in their system preferences. If the user switches to dark mode, the toggle will be checked. If the user switches to light mode, the toggle will be unchecked.
Using a Bulma Toggle Switch
The toggle switch uses bulma-switch which is an official Bulma extension that adds styling to create toggles. One of the styles is even similar to that of react-toggle
!
To get started with this, first we need to install Bulma:
npm install bulma
Then we can install the extension:
npm install bulma-switch
In the component, you can see it looks very similar to the right-justified example from the bulma-switch
docs.
Styling Your Blog for Dark Mode with Bulma
Before starting, make sure Bulma is installed. See the previous section for more information on how that is done.
Now comes the interesting part. We need to customize Bulma to integrate with the toggle setup we implemented in the previous section. To do this, we can use the bulma-dark.sass example file provided in the Bulma docs on GitHub. This example file isn't referenced anywhere else in the documentation or the official website, so it's a bit hidden. We can use that file to guide us in crafting our own SCSS file which will define the light and dark themes of the site.
Most importantly, the dark mode edits for Bulma are going to need to work with the head component script and :root
/:root.dark
selectors.
Here's what I ended up writing:
@import "bulma/sass/utilities/initial-variables.sass";
:root {
--scheme-main: #{$white};
--scheme-main-bis: #{$white-bis};
--scheme-main-ter: #{$white-ter};
--scheme-invert: #{$black};
--scheme-invert-bis: #{$black-bis};
--scheme-invert-ter: #{$black-ter};
--background: #{$white-ter};
--border: #{$grey-lighter};
--border-hover: #{$grey-light};
--border-light: #{$grey-lightest};
--border-light-hover: #{$grey-light};
--text: #{$grey-dark};
--text-invert: #{$grey-light};
--text-light: #{$grey};
--text-strong: #{$grey-darker};
--link-hover: #{$grey-darker};
--link-hover-border: #{$grey-light};
--link-active: #{$grey-darker};
--link-active-border: #{$grey-dark};
}
:root.dark {
--scheme-main: #{$black};
--scheme-main-bis: #{$black-bis};
--scheme-main-ter: #{$black-ter};
--scheme-invert: #{$white};
--scheme-invert-bis: #{$white-bis};
--scheme-invert-ter: #{$white-ter};
--background: #{$black-ter};
--border: #{$grey-darker};
--border-hover: #{$grey-dark};
--border-light: #{$grey-darker};
--border-light-hover: #{$grey-dark};
--text: #{$grey-light};
--text-invert: #{$grey-darker};
--text-light: #{$grey};
--text-strong: #{$white};
--link-hover: #{$white};
--link-hover-border: #{$grey-dark};
--link-focus: #{$white};
--link-focus-border: #{$blue};
--link-active: #{$white};
--link-active-border: #{$grey-light};
}
$scheme-main: var(--scheme-main);
$scheme-main-bis: var(--scheme-main-bis);
$scheme-main-ter: var(--scheme-main-ter);
$scheme-invert: var(--scheme-invert);
$scheme-invert-bis: var(--scheme-invert-bis);
$scheme-invert-ter: var(--scheme-invert-ter);
$border: var(--border);
$border-hover: var(--border-hover);
$border-light: var(--border-light);
$border-light-hover: var(--border-light-hover);
$text: var(--text);
$text-invert: var(--text-invert);
$text-light: var(--text-light);
$text-strong: var(--text-strong);
$link-hover: var(--link-hover);
$link-hover-border: var(--link-hover-border);
$link-focus: var(--link-focus);
$link-focus-border: var(--link-focus-border);
$link-active: var(--link-active);
$link-active-border: var(--link-active-border);
$body-background-color: var(--background);
@import "bulma/bulma.sass";
@import "bulma-switch/src/sass/index.sass";
The idea here is to set CSS variables based on which selector is triggered. When dark mode is active, the :root.dark
selector will set the variable values to the dark mode ones, and then those will be used to override Bulma's variable values.
Once these pieces are in place, the dark mode toggle switch will allow users to switch the theme of the site to whatever works best for them.
Conclusion: Unlocking the Power of Dark Mode with Bulma and Gatsby
In this blog post, we explored how to use Bulma and Gatsby to create professional blogs that are visually appealing and fast-loading. I have highlighted the advantages of combining Bulma's easy-to-use components and utilities with Gatsby's performance-focused architecture. I also discussed the importance of incorporating a dark mode theme into your website or application to improve usability and accessibility for users.
Furthermore, I have provided step-by-step guidance on implementing dynamic dark mode switching with Gatsby and I have reviewed a method for dynamically toggling between light and dark mode with a user-friendly switch. I also showed how to switch themes based on the user's system preferences using the React hooks.
In conclusion, Bulma and Gatsby provide an excellent toolkit for building professional blogs, and the addition of dynamic dark mode switching can help improve user experience and accessibility. By using the content of this post as an example, developers can create stunning blogs that are not only visually appealing but also fast and accessible to a wide range of users.