Journal tags: dark



Dark mode revisited

I added a dark mode to my website a while back. It was a fun thing to do during Indie Web Camp Amsterdam last year.

I tied the colour scheme to the operating system level. If you choose a dark mode in your OS, my website will adjust automatically thanks to the prefers-color-scheme: dark media query.

But I’ve seen notes from a few friends, not about my site specifically, but about how they like having an explicit toggle for dark mode (as well as the media query). Whenever I read those remarks, I’d think “I’m really not sure I’ve got time to deal with adding that kind of toggle to my site.”

But then I realised, “Jeremy, you absolute muffin! You’ve had a theme switcher on your website for almost two decades now!”

Doh! I had forgotten about that theme switcher. It dates back to the early days of CSS. I wanted my site to be a demonstration of how you could apply different styles to the same underlying markup (this was before the CSS Zen Garden came along). Those themes are very dated now, but if you like you can view my site with a Zeldman theme or a sci-fi theme.

To offer a dark-mode theme for my site, all I had to do was take the default stylesheet, pull out the custom properties from the prefers-color-scheme: dark media query, and done. It took less than five minutes.

So if you want to view my site in dark mode, it’s one of the options in the “Customise” dropdown on every page of the website.

Programming CSS to perform Sass colour functions

I wrote recently about moving away from Sass to using native CSS features. I had this to say on the topic of mixins in Sass:

These can be very useful, but now there’s a lot that you can do just in CSS with calc(). The built-in darken() and lighten() mixins are handy though when it comes to colours.

I know we will be getting these in the future but we’re not there yet with CSS.

Anyway, I had all this in the back of my mind when I was reading Lea’s excellent feature in this month’s Increment: A user’s guide to CSS variables. She’s written about a really clever technique of combining custom properites with hsl() colour values for creating colour palettes. (See also: Una’s post on dynamic colour theming with pure CSS.)

As so often happens when I’m reading something written by Lea—or seeing her give a talk—light bulbs started popping over my head (my usual response to Lea’s knowledge bombs is either “I didn’t know you could do that!” or “I never thought of doing that!”).

I immediately set about implementing this technique over on The Session. The trick here is to use separate custom properties for the hue, saturation, and lightness parts of hsl() colour values. Then, when you want to lighten or darken the colour—say, on hover—you can update the lightness part.

I’ve made a Codepen to show what I’m doing.

Let’s say I’m styling a button element. I make custom propertes for hsl() values:

button {
  --button-colour-hue: 19;
  --button-colour-saturation: 82%;
  --button-colour-lightness: 38%;
  background-color: hsl(

For my buttons, I want the borders to be slightly darker than the background colour. When I was using Sass, I used the darken() function to this. Now I use calc(). Here’s how I make the borders 10% darker:

border-color: hsl(
  calc(var(--button-colour-lightness) - 10%)

That calc() function is substracting a percentage from a percentage: 38% minus 10% in this case. The borders will have a lightness of 28%.

I make the bottom border even darker and the top border lighter to give a feeling of depth.

On The Session there’s a “cancel” button style that’s deep red.

Here’s how I set its colour:

.cancel {
  --button-colour-hue: 0;
  --button-colour-saturation: 100%;
  --button-colour-lightness: 40%;

That’s it. The existing button declarations take care of assigning the right shades for the border colours.

Here’s another example. Site admins see buttons for some actions only available to them. I want those buttons to have their own colour:

.admin {
  --button-colour-hue: 45;
  --button-colour-saturation: 100%;
  --button-colour-lightness: 40%;

You get the idea. It doesn’t matter how many differently-coloured buttons I create, the effect of darkening or lightening their borders is all taken care of.

So it turns out that the lighten() and darken() functions from Sass are available to us in CSS by using a combination of custom properties, hsl(), and calc().

I’m also using this combination to lighten or darken background and border colours on :hover. You can poke around the Codepen if you want to see that in action.

I love seeing the combinatorial power of these different bits of CSS coming together. It really is a remarkably powerful programming language.

Dark mode

I had a very productive time at Indie Web Camp Amsterdam. The format really lends itself to getting the most of a weekend—one day of discussions followed by one day of hands-on making and doing. You should definitely come along to Indie Web Camp Brighton on October 19th and 20th to experience it for yourself.

By the end of the “doing” day, I had something fun to demo—a dark mode for my website.

Y’know, when I first heard about Apple adding dark mode to their OS—and also to CSS—I thought, “Oh, great, Apple are making shit up again!” But then I realised that, like user style sheets, this is one more reminder to designers and developers that they don’t get the last word—users do.

Applying the dark mode styles is pretty straightforward in theory. You put the styles inside this media query:

@media (prefers-color-scheme: dark) {

Rather than over-riding every instance of a colour in my style sheet, I decided I’d do a little bit of refactoring first and switch to using CSS custom properties (or variables, if you will).

:root {
  --background-color: #fff;
  --text-color: #333;
  --link-color: #b52;
body {
  background-color: var(--background-color);
  color: var(--text-color);
a {
  color: var(--link-color);

Then I can over-ride the custom properties without having to touch the already-declared styles:

@media (prefers-color-scheme: dark) {
  :root {
    --background-color: #111416
    --text-color: #ccc;
    --link-color: #f96;

All in all, I have about a dozen custom properties for colours—variations for text, backgrounds, and interface elements like links and buttons.

By using custom properties and the prefers-color-scheme media query, I was 90% of the way there. But the devil is in the details.

I have SVGs of sparklines on my homepage. The SVG has a hard-coded colour value in the stroke attribute of the path element that draws the sparkline. Fortunately, this can be over-ridden in the style sheet:

svg.activity-sparkline path {
  stroke: var(--text-color);

The real challenge came with the images I use in the headers of my pages. They’re JPEGs with white corners on one side and white gradients on the other.

header images

I could make them PNGs to get transparency, but the file size would shoot up—they’re photographic images (with a little bit of scan-line treatment) so JPEGs (or WEBPs) are the better format. Then I realised I could use CSS to recreate the two effects:

  1. For the cut-out triangle in the top corner, there’s clip-path.
  2. For the gradient, there’s …gradients!
background-image: linear-gradient(
  to right,
  transparent 50%,
  var(—background-color) 100%

Oh, and I noticed that when I applied the clip-path for the corners, it had no effect in Safari. It turns out that after half a decade of support, it still only exists with -webkit prefix. That’s just ridiculous. At this point we should be burning vendor prefixes with fire. I can’t believe that Apple still ships standardised CSS properties that only work with a prefix.

In order to apply the CSS clip-path and gradient, I needed to save out the images again, this time without the effects baked in. I found the original Photoshop file I used to export the images. But I don’t have a copy of Photoshop any more. I haven’t had a copy of Photoshop since Adobe switched to their Mafia model of pricing. A quick bit of searching turned up Photopea, which is pretty much an entire recreation of Photoshop in the browser. I was able to open my old PSD file and re-export my images.

LEGO clone trooper Brighton bandstand Scaffolding Tokyo Florence

Let’s just take a moment here to pause and reflect on the fact that we can now use CSS to create all sorts of effects that previously required a graphic design tool like Photoshop. I could probably do those raster scan lines with CSS if I were smart enough.

dark mode

This is what I demo’d at the end of Indie Web Camp Amsterdam, and I was pleased with the results. But fate had an extra bit of good timing in store for me.

The very next day at the View Source conference, Melanie Richards gave a fantastic talk called The Tailored Web: Effectively Honoring Visual Preferences (seriously, conference organisers, you want this talk on your line-up). It was packed with great insights and advice on impementing dark mode, like this little gem for adjusting images:

@media (prefers-color-scheme: dark) {
  img {
    filter: brightness(.8) contrast(1.2);

Melanie also pointed out that you can indicate the presence of dark mode styles to browsers, although the mechanism is yet to shake out. You can do it in CSS:

:root {
  color-scheme: light dark;

But you can also do it in HTML:

That allows browsers to swap out replaced content; interface elements like form fields and dropdowns.

Oh, and one other addition I added after the fact was swapping out map imagery by using the picture element to point to darker map tiles:

<source media="(prefers-color-scheme: dark)" srcset="">
<img src="" alt="map">

light map dark map

So now I’ve got a dark mode for my website. Admittedly, it’s for just one of the eight style sheets. I’ve decided that, while I’ll update my default styles at every opportunity, I’m going to preservethe other skins as they are, like the historical museum pieces they are.

If you’re on the latest version of iOS, go ahead and toggle the light and dark options in your system preferences to flip between this site’s colour schemes.

Movie Knight

I mentioned how much I enjoyed Mike Hill’s talk at Beyond Tellerrand in Düsseldorf:

Mike gave a talk called The Power of Metaphor and it’s absolutely brilliant. It covers the monomyth (the hero’s journey) and Jungian archetypes, illustrated with the examples Star Wars, The Dark Knight, and Jurassic Park.

At Clearleft, I’m planning to reprise the workshop I did a few years ago about narrative structure—very handy for anyone preparing a conference talk, blog post, case study, or anything really:

Ellen and I have been enjoying some great philosophical discussions about exactly what a story is, and how does it differ from a narrative structure, or a plot. I really love Ellen’s working definition: Narrative. In Space. Over Time.

This led me to think that there’s a lot that we can borrow from the world of storytelling—films, novels, fairy tales—not necessarily about the stories themselves, but the kind of narrative structures we could use to tell those stories. After all, the story itself is often the same one that’s been told time and time again—The Hero’s Journey, or some variation thereof.

I realised that Mike’s monomyth talk aligns nicely with my workshop. So I decided to prep my fellow Clearlefties for the workshop with a movie night.

Popcorn was popped, pizza was ordered, and comfy chairs were suitably arranged. Then we watched Mike’s talk. Everyone loved it. Then it was decision time. Which of three films covered in the talk would we watch? We put it to a vote.

It came out as an equal tie between Jurassic Park and The Dark Knight. How would we resolve this? A coin toss!

The toss went to The Dark Knight. In retrospect, a coin toss was a supremely fitting way to decide to watch that film.

It was fun to watch it again, particularly through the lens of Mike’s analyis of its Jungian archetypes.

But I still think the film is about game theory.

Hooked and booked

At, they do a lot of A/B testing.

At, they’ve got a lot of dark patterns.

I think there might be a connection.

A/B testing is a great way of finding out what happens when you introduce a change. But it can’t tell you why.

The problem is that, in a data-driven environment, decisions ultimately come down to whether something works or not. But just because something works, doesn’t mean it’s a good thing.

If I were trying to convince you to buy a product, or use a service, one way I could accomplish that would be to literally put a gun to your head. It would work. Except it’s not exactly a good solution, is it? But if we were to judge by the numbers (100% of people threatened with a gun did what we wanted), it would appear to be the right solution.

When speaking about A/B testing at, Stuart Frisby emphasised why it’s so central to their way of working:

One of the core principles of our organisation is that we want to be very customer-focused. And A/B testing is really a way for us to institutionalise that customer focus.

I’m not so sure. I think A/B testing is a way to institutionalise a focus on business goals—increasing sales, growth, conversion, and all of that. Now, ideally, those goals would align completely with the customer’s goals; happy customers should mean more sales …but more sales doesn’t necessarily mean happy customers. Using business metrics (sales, growth, conversion) as a proxy for customer satisfaction might not always work …and is clearly not the case with many of these kinds of sites. Whatever the company values might say, a company’s true focus is on whatever they’re measuring as success criteria. If that’s customer satisfaction, then the company is indeed customer-focused. But if the measurements are entirely about what works for sales and conversions, then that’s the real focus of the company.

I’m not saying A/B testing is bad—far from it! (although it can sometimes be taken to the extreme). I feel it’s best wielded in combination with usability testing with real users—seeing their faces, feeling their frustration, sharing their joy.

In short, I think that A/B testing needs to be counterbalanced. There should be some kind of mechanism for getting the answer to “why?” whenever A/B testing provides to the answer to “what?” In-person testing could be one way of providing that balance. Or it could be somebody’s job to always ask “why?” and determine if a solution is qualitatively—and not just quantitatively—good. (And if you look around at your company and don’t see anyone doing that, maybe that’s a role for you.)

If there really is a connection between having a data-driven culture of A/B testing, and a product that’s filled with dark patterns, then the disturbing conclusion is that dark patterns work …at least in the short term.

Connections: Weak Signals

Tuesday evening saw the inaugural Connections event at 68 Middle Street, home to Clearleft. It was a rousing success—much fun was had by all.

There was a great turn-out. Normally I’d expect a fairly significant no-show rate for a free event (they’re often oversubscribed to account for this very reason), but I was amazed how many people braved the dreadful weather to come along. We greeted them all with free beer, courtesy of Clearleft.

The talks had a nice yin and yang quality to them. Honor talked about darkness. Justin talked about light. More specifically, Honor talked about dark matter and Justin talked about Solarpunk.

Honor made plentiful use of sound during her presentation. Or rather, plentiful use of electromagnetic signals converted into sound: asteroseismology from the sun; transient luminous events in the Earth’s upper atmosphere; the hailstorm as Cassini pirouettes through Saturn’s rings; subatomic particle collisions sonified. They all combined to eerie effect.

Justin’s talk was more down to Earth, despite sounding like a near-future science-fiction scenario: individuals and communities harnessing the power of the photovoltaic solar panel to achieve energy-independence.

There was a beer break between the talks and we had a joint discussion afterwards, with questions from the audience. I was leading the discussion, and to a certain extent, I played devil’s advocate to Justin’s ideas, countering his solar energy enthusiasm with nuclear energy enthusiasm—I’m on Team Thorium. (Actually, I wasn’t really playing devil’s advocate. I genuinely believe that nuclear energy is the cleanest, safest source of energy available to us and that an anti-nuclear environmentalist is a contradiction in terms—but that’s a discussion for another day.)

There was a bittersweet tinge to the evening. The first Connections event was also Honor’s last public speaking engagement in Brighton for a while. She is bidding farewell to Lighthouse Arts and winging her way to a new life in Singapore. We wish her well. We will miss her.

The evening finished with a facetious rhetorical question from the audience for Honor. It was related to the sonification of particle collisions like the ones that produced evidence for “the God particle”, the Higgs boson. “Given that the music produced is so unmusical”, went the question, “does that mean it’s proof that God doesn’t exist?”

We all had a laugh and then we all went to the pub. But I’ve been thinking about that question, and while I don’t have an answer, I do have a connection to make between both of the talks and algorithmically-generated music. Here goes…

Justin talked about the photovoltaic work done at Bell Labs. An uncle of Ray Kurzweil worked at Bell Labs and taught the young Kurzweil the basics of computer science. Soon after, Ray Kurzweil wrote his first computer program, one that analysed works of classical music and then generated its own music. Here it is.

The email notification anti-pattern: a response

Quite quickly after I wrote my email to Findings about their email notification anti-pattern, I got a response back from Lauren Leto:

Give it to us. I applaud you shouting at us from a rooftop. I also hate defaulting to all notifications and agree that it was a douchebag startup move but can assure it was one made accidentally - a horrible oversight that the entire team feels bad about and will work to amend for you and the rest of our users.

We try to be a site for the common user - nothing like Facebook taking cheap shots wherever they can. I hope we haven’t forever turned you off from our site. Relaunches are hard and mistakes were made but nothing like this will happen again.

Apart from the use of the passive voice (“mistakes were made” rather than “we made mistakes”), that’s a pretty damn good response. She didn’t try to defend or justify the behaviour. That’s good.

She also asked if there was anything they could do to make it up to me. I asked if I could publish their response here. “Yeah, feel free to post”, she said.

I think it’s important that situations like this get documented. It could be especially useful for new start-ups who might be thinking about indulging in a bit of “growth hacking” (spit!) under the impression that this kind of behaviour is acceptable just because other start-ups—like Findings—implemented the email notification anti-pattern.

As Lauren said:

I think every startup manages to mess up one of these at some point in their life, either willingly or unwillingly. A clear listing of all offenses could be useful to everyone.

That’s where Harry’s Dark Patterns wiki comes in:

The purpose of this pattern library is to “name and shame” Dark Patterns and the companies that use them.

  • For consumers, forewarned is fore-armed.
  • For brand-owners, the bad-press associated with being named as an offender should discourage usage.
  • For designers, this site provides ammunition to refuse unethical requests by our clients / bosses. (e.g. “I won’t implement opt-out defaults for the insurance upsells because that practice is considered unethical and it will get you unwanted bad press.”)

The email notification anti-pattern isn’t yet listed on the wiki. I’ll see if I can get Harry to add it.

A dark star is born

At Clearleft towers, we’ve been having semi-regular movie nights, based around a connecting theme. Previous themes include car chases (The French Connection, Bullitt and Ronin) and films set at Christmas that aren’t about Christmas (Gremlins and Die Hard).

Last week’s movie night’s theme was near-future science fiction. We didn’t get around to watching Minority Report but we did watch Children of Men and Sunshine.

is one of those films that gets better with each viewing. Little by little, it’s edging up my list of all-time favourites. It has a sense of awe, wonder and humility in the face of science that’s genuinely Clarkeian.

It also has plenty of loving references to those other films featuring the trifecta of sci-fi elements: a ship, a crew, a signal. The nods to 2001 and Alien are clear, but something I didn’t catch until just the other day was that the character of Pinbacker was named for Sergeant Pinback from .

I know this because, instead of our usual Thursday evening pub gathering and book swapping, the Brighton Speculative Fiction Group this week hosted a puppet show. Paul and Richard recreated all of Dark Star using cardboard, some string, a few dolls and some strategic lighting.

It was one of the best things I’ve ever seen. Here’s the highlight reel.

A Scanner Darkly

The Clearleft office was empty on Wednesday afternoon. The bodies that normally inhabit that space were to be found sitting in a cinematheque.

By unanimous agreement, we decided to see A Scanner Darkly. Having read and thoroughly enjoyed the book, I was looking forward to seeing this. I wasn’t disappointed. I can’t say the same for the other people who saw the film with me.

I loved it, Richard liked it, Andy, Paul, Aral and Jessica were distinctly underwhelmed. I can understand their reaction, even if I don’t share it. This isn’t a film for everyone.

Personally, I really enjoyed the experience of being immersed in an off-kilter drug-fueled world. But I can see why this world might not seem like the most inviting place to spend two hours of your life. The same dialogue that I found so hysterical (in every sense of the word) could also come across as just plain annoying.

The casting is inspired. It sounds like something a sketch show writer would put together: “So, Winona Ryder, Keanu Reeves, Woody Harrelson, and Robert Downey Jr. are all sitting around getting stoned…”

Oh, and using Thom Yorke and Radiohead songs for the soundtrack? Also inspired.

The roto-scoping worked wonderfully for the scramble suit. I’m not sure whether it was entirely necessarily for everything else, but it did add to the otherworldly atmosphere to have everything nestled in the uncanny valley. It would be interesting the compare the finished film with the pre-roto-scoped footage to see how much of a difference it makes to the emotional impact of each scene. The film’s style is an interesting way of trying to nail down the right medium for telling this story. It struck me that a graphic novel might actually be the ideal medium: exactly halfway between the novel and the film.

The film is, by and large, very faithful to the book. It is by far the most faithful adaptation of a Philip K. Dick story to date. But then, A Scanner Darkly, for all its quesy strangeness is one of the more coherent and down-to-earth of Dick’s works. While this film worked wonderfully, I doubt that even Richard Linklater could pull off an adaptation of Ubik or The Three Stigmata of Palmer Eldritch. On the other hand, there’s Flow My Tears, the Policeman Said… now there’s a great film just waiting to happen.

So maybe it was a relatively easy target, but the film of A Scanner Darkly really captures the essence of a classic Philip K. Dick book. Bladerunner is a wonderful, wonderful movie on its own terms, but it bears little resemblance to the existentialist heart of Do Androids Dream Of Electric Sheep?

There is a wonderful moment in A Scanner Darkly when subjective and objective reality collide in the playback of a recording captured by a scanner of the film’s title. It’s the quintessential Philip K. Dick coup. Just as you think you have a handle on the world you have entered, the rug is pulled from under your feet. I’ll never forget the corresponding moment from Time Out Of Joint with its Truman Show-esque plot, in which a hot-dog stand winks out of existence to be replaced by a piece of paper reading “hot-dog stand.”

There’s a short story by Philip K. Dick called The Electric Ant which can be read as a version of Kafka’s Metamorphosis. The comparison is apt. Dick writes Kafka-esque stories: funny, paranoid, and unsettling.

Richard Linklater’s A Scanner Darkly captures that Dickian feeling. That’s no mean feat.

As much as I loved this film, I’m hesitant to recommend it for your next outing to the cinema. It’s not the most cinematic of films. Wait for the DVD. I have the feeling that the film’s visual style will suit that medium very well indeed.

Gather some friends on the sofa. Pop the disc into your player and compare the anti-piracy warnings that precede the film to the pointless crusade against Substance D.