Created: February 10, 2019

Last modified: February 5, 2023

In search of “functional” CSS

What is “functional” CSS?

A while back I came across this post on Hacker News. As with any programming paradigm, people quickly become opinionated, but CSS is strange because it isn’t a programming language or a markup language, its a styling language. I’m not really a webdev export and frankly I find it exhausting just how quickly the “best practices” for web development change. So mostly I’ve just tried to avoid whatever the current hype is and stick to HTML+CSS with the occasional Javascript. But plain CSS can be painful as I learned when trying to rewrite cmuhl.org which is why that post, and especially one of the linked articles within it which does a better job of explaining “functional” CSS, really made me think about how to write better CSS. The idea of of decoupling styles from structure really helps make CSS be less brittle when the HTML structure changes so I definitely think its best to keep CSS “flat”.

Making this website’s CSS more “functional”

I previously wrote about how org-publish generates the CSS for this website. This is already somewhat functional as it does a good job of decoupling styles from structure. However each HTML element only gets a single class instead of a more functional set of css component classes. Even worse there as a lot of redundancy since most of the .org- classes only set color while the others only additionally set background-color, font-weight, font-style, text-decoration, and font-size. This is since that’s basically all that can be set in an Emacs Face Attributes. It would be nice if there were an org-html-htmlize-output-type option to use css component classes for each face attribute. Then the .org- css classes would essentially resemble the color definitions for an Emacs theme package. But since that isn’t possible without essentially rewriting htmlize.el, I’ll just have to compromise for the time being.1

CSS Variables and Emacs Themes

I really like the Spacemacs dark and light themes and it’s my current Emacs theme (after all I am using Spacemacs). So I thought I try to add a fun little feature that allows this site’s theme to be toggled between the two, including all the syntax highlighting. It’s relatively easy to do this using CSS Variables by pulling all the hex colors from spacemacs-theme out into CSS variable definitions:

:root {
  /* generic */
  --act1          : #222226;
  --act2          : #5d4d7a;
  --base          : #b2b2b2;
  --base-dim      : #686868;
  --bg1           : #292b2e;
  --bg2           : #212026;
  --bg3           : #100a14;
  --bg4           : #0a0814;
  --border        : #5d4d7a;
  --cblk          : #cbc1d5;
  --cblk-bg       : #2f2b33;
  --cblk-ln       : #827591;
  --cblk-ln-bg    : #373040;
  --cursor        : #e3dedd;
  --const         : #a45bad;
  --comment       : #2aa1ae;
  --comment-light : #2aa1ae;
  --comment-bg    : #292e34;
  --comp          : #c56ec3;
  --err           : #e0211d;
  --func          : #bc6ec5;
  --head1         : #4f97d7;
  --head1-bg      : #293239;
  --head2         : #2d9574;
  --head2-bg      : #293235;
  --head3         : #67b11d;
  --head3-bg      : #293235;
  --head4         : #b1951d;
  --head4-bg      : #32322c;
  --highlight     : #444155;
  --highlight-dim : #3b314d;
  --keyword       : #4f97d7;
  --lnum          : #44505c;
  --mat           : #86dc2f;
  --meta          : #9f8766;
  --str           : #2d9574;
  --suc           : #86dc2f;
  --ttip          : #9a9aba;
  --ttip-sl       : #5e5079;
  --ttip-bg       : #34323e;
  --type          : #ce537a;
  --var           : #7590db;
  --war           : #dc752f;
  /* colors */
  --aqua          : #2d9574;
  --aqua-bg       : #293235;
  --green         : #67b11d;
  --green-bg      : #293235;
  --green-bg-s    : #29422d;
  --cyan          : #28def0;
  --red           : #f2241f;
  --red-bg        : #3c2a2c;
  --red-bg-s      : #512e31;
  --blue          : #4f97d7;
  --blue-bg       : #293239;
  --blue-bg-s     : #2d4252;
  --magenta       : #a31db1;
  --yellow        : #b1951d;
  --yellow-bg     : #32322c;
}

Then the tedious part is combing through the existing CSS and replacing all colors with its var(--color) reference.

I’ve defined the dark theme on :root since I want it to be the default. I put the light theme in its own .light class. Then I just throw up some buttons to toggle the theme:

<button class="menu-btn" style="display: none" id="toggle-theme-light">Light Theme</button>
<button class="menu-btn" style="display: none" id="toggle-theme-dark" >Dark Theme</button>

And some Javascript to switch out the CSS classes and make the selected theme persist across pages:

document.addEventListener('DOMContentLoaded', function() {
  let toggle_theme_light = document.querySelector('#toggle-theme-light')
  let toggle_theme_dark = document.querySelector('#toggle-theme-dark')

  function lights_on(e) {
    if (e) { e.preventDefault(); }
    document.body.classList.add('light');
    toggle_theme_dark.style.display = null;
    toggle_theme_light.style.display = "none";
    localStorage.setItem('light', true);
  }

  function lights_off(e) {
    if (e) { e.preventDefault(); }
    document.body.classList.remove('light');
    toggle_theme_dark.style.display = "none";
    toggle_theme_light.style.display = null;
    localStorage.removeItem('light');
  }

  if (localStorage.getItem('light')) { lights_on(null); }
  else { lights_off(null); }

  toggle_theme_light.addEventListener('click', lights_on);
  toggle_theme_dark.addEventListener('click', lights_off);
}, false);

The great thing about this implementation is that it gracefully fails on browsers with Javascript disabled and does not affect the content or usability of the site.

CSS Variables and SVGs

The one hiccup with my theme toggling feature was the SVG logo on my about page didn’t change color while the text over it did, making it unreadable. Luckily SVGs embedded inside HTML can be styled with CSS.

Org CSS themes

I should also mention that there are some quite nice CSS themes for org export already out there:

My favorite for technical documentation is definitely ReadTheOrg.2

Backlinks:

Footnotes:

1

If I wanted the easy way, I would’ve just used Jekyll…

2

which I used here