Keyboard shortcuts

T
Switch light / dark theme
P
Jump to projects
E
Jump to experience
C
Jump to contact
N
Open notes
H
Back to the top
?
Show these shortcuts
All notes
· 4 min read

A sunrise and sunset theme switch

Light rises from the bottom, night comes down from the top. How I built it with the View Transitions API, and the three bugs I hit on the way.

  • CSS
  • View Transitions
  • UX

This site has a light and a dark theme. I wanted switching between them to feel intentional, so the toggle plays a little sunrise or sunset: the light theme rises up from the bottom of the screen, and dark mode comes down from the top.

Attempt one: fade every colour

My first version added a short colour transition to every element while the theme changed. It flickered. Text inherits its colour from its parent, so a child was animating toward its parent's in-between colours, which were themselves still changing. My name in the hero visibly jumped through two colours.

Attempt two: View Transitions

document.startViewTransition() takes a snapshot of the page, lets you change the DOM, then animates from the old snapshot to the new one. Nothing fades element by element, so there's nothing to flicker. I mask the new snapshot with a soft gradient and move the mask up for sunrise or down for sunset.

root.dataset.themeTransition = theme === "light" ? "sunrise" : "sunset";
const transition = document.startViewTransition(() => {
  root.dataset.theme = theme;
});

Bugs worth knowing about

  • Clicks didn't register mid-transition. While a view transition runs, the browser sends clicks to the root element, not to the button under your cursor. I catch document clicks inside the toggle's rectangle so the button always responds.
  • Rapid clicks had to wait. A new click now calls skipTransition() on the running one and starts the next straight away.
  • Skipping a transition rejects its ready promise, which showed up as a console error. That rejection is expected, so it is handled quietly.

With reduced motion turned on, or in a browser without View Transitions, the theme simply switches instantly.