Creating a Dark Mode Toggle with Sass

Even with smaller projects, I try to emphasize modularity. Changing one thing is always better than changing two. After learning more about structuring code with BEM, I decided to learn more about CSS processors, namely Sass.

I implemented the BEM architecture in my HTML and JavaScript code and gave my page a clean, semantic structure. Although my word counter functioned properly, it wasn’t exactly beautiful.

Page counter without any style

Given how simple the page itself was, I decided I wanted the style to be reasonably simple and easy on the eyes as well. I changed the placement of the content using CSS grid and borrowed inspiration for a color palette from CopyPalette. I used the Accessible Color Palette Builder to confirm that there was a large enough contrast between my background color and font color.

Page counter with accessible “dark mode” style

I decided to lighten the colors of the website using the invert() function in CSS. This way, I would maintain the same amount of contrast for accessibility. I added a bit of text at the bottom of that would allow users to toggle between dark and light mode. The JavaScript for the toggle swapped out the dark mode stylesheet for a light mode stylesheet and vice versa.

I created an additional stylesheet for the light mode version, but I didn’t want to copy over all of the CSS from the original stylesheet. Instead, I looked toward two of the modularity features that Sass offers.

I stored my color palette using the variable feature. I referred to colors by only their variable name for the rest of the stylesheet, so I only needed to invert each color once, when I declared its variable. This is a great improvement from searching and replacing for each instance of a color!

Secondly, I created a module to reuse for both the dark and light stylesheets. The only thing that would change in each stylesheet was the color palette. Therefore, I decided to put the rest of the content of the stylesheet into a separate .scss file. I would use the @use rule to load this information into a new dark mode stylesheet and a light mode stylesheet.

I added the !default flag to the variables in the color palette to indicate that they could be configured. As I built the dark mode first, I used those as the default colors. I then used the @use rule and with to configure the inverse colors for the variables.

@use 'style' with(
$dark-color: invert(#001931),
$darker-color: invert(#001529),
$darkest-color: invert(#000e1c),
$mid-color: invert(#002A53),
$accent-color-darker: invert(#003971),
$accent-color-lighter: invert(#007CF7),
$text-color: invert(#ccc)
);

Initially, I tried to reconfiguring the light mode variables by calling the original variables to make the light mode Sass file more modular. Unfortunately, this produced an error, but I would like to find a way to invert the dark mode colors without referencing their actual colors a second time.

Given that the dark mode Sass file was now empty aside from an @use rule, I decided to get rid of it altogether and directly compile the base ‘style’ Sass file to use as the default dark mode stylesheet.

Page counter in inverted “light mode” style

Regular Expression with Japanese Characters

I decided to build a word counter that would give the user the exact number of words and characters and an estimated number of page numbers for text that the user inputs into a textarea. I wanted to make the word counter bilingual and offer instructions to the user in both English and Japanese. Because the Japanese language does not use spaces, users who choose to input text in Japanese would only be able to make use of the character count and the page number estimate.

I decided to count the number of characters inputted by getting the length of the textarea value and retrieve the number of words using a regular expression.

/[\w-']+/g

After testing the code above in Japanese, I realized that it caused an error. In English, a single word would return a length of 1. However, in Japanese there are no “word characters” (or otherwise hyphens or apostrophes), so typing a single word (or character) in Japanese caused an error. The text match returned null, and so the length could not be determined.

In regular express, \w expresses any letter upper or lower case from a to z as well as numbers 0 to 9 and underscores. To add functionality for Japanese, I would need to include unicode characters in this character set, too.

I referenced Regular-Expressions.info for more information about including unicode characters in regular expressions. However, the only way to include unicode in JavaScript appeared to be by including individual unicode characters, and there are far, far too many Japanese characters to try and list all of them in a regular expression.

Initially, I tried to find a solution to this problem by using combinations of \b or \s with, respectively, \B or \S. Instead of looking for words specifically, I could look for something that was certainly not a word and then look for something that might have been a word. Unfortunately, ideas like /[\b\B\b]+/g also yielded null results.

What I wanted was a way to somehow include all possible Japanese unicode characters without having to find the unicode codes for thousands of Japanese characters.

Thankfully, unicode blocks did that work for me. Similarly to [a-z], there were several ranges of unicode codes that covered Japanese characters. So-zou.jp lists several blocks that encompass the Japanese language.

/[\u3041-\u3096\u30A1-\u30FA々〇〻\u3400-\u9FFF\uF900-\uFAFF\uD840-\uD87F\uDC00-\uDFFF\w-']+/g

I combined multiple unicode blocks and tested my counter again using both ASCII characters and Japanese characters. It was fully functionally and finally bilingual!

Relative Sizing in BEM

I am always trying to write cleaner code (although I realize I didn’t always have this philosophy when I look at some of my older projects). Learning about CSS architecture makes me feel one step closer to achieving that goal. After reading about naming conventions in BEM, I decided to test drive my newfound knowledge by creating a simple landing page for my website.

mcksheridan.com landing page concept

The concept was minimalist: a quick paragraph to point visitors to this blog and links to my social media accounts. I made the text larger, changed a few colors, and added responsive styles for visitors on smaller screens. For the most part, I found creating stylesheets with BEM to be a straightforward experience.

My design felt a bit too minimalist, so I decided to indicate that “web development” was a keyword by changing both its font weight and color of the words. The words “web development” were contained within a <p> tag in a <div> tag with a class of .content. According to the standards established by BEM, this text could be in a <b> tag with a class of .content--blue (or some other modifier in place of blue).

Revised mcksheridan.com landing page

I discovered an error in my stylesheet after reviewing the BEM documentation. In addition to the modifier (.content--blue), I would also need to add the block (or element) to the class as well. I changed .content--blue to content content--blue and retained my original stylesheet. This resulted in the relative font size I was using in the .content class increasing again for everything in the .content--blue class.

Error on the mcksheridan.com landing page

I initially fixed this issue by setting the font size for the .content--blue to “inherit”, but adding extra code seemed counterintuitive. I reviewed the style for the .content block and decided that there must be a way to solve this issue by using a different unit of measurement for the font size in .content. Previously, .content--blue inherited its font size from .content, but now the “web development” text both inherited the font size from .content and had it reapplied as part of its own class. This caused the text to appear at 5em of 5em, or 25em relative to the root.

I solved the problem by changing the unit of measurement for the font size in .content from em to rem. By measuring from the root of the document, I did not run the risk of the font size increasing due to the font size of its parent block (or parent element). I look forward to working with BEM again–with different relative units.