Skip to content

Blog Details

Home/Blog Details

SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
Article cover card for: Making a dark mode switch instant, without breaking the page
Performance

Making a dark mode switch instant, without breaking the page

Abdulbasit AbdulalimWritten by Abdulbasit Abdulalim
| 3 min Read

The complaint

The theme toggle on this site felt slow. Not "a little slow" - slow enough that people noticed, and slow enough that the animation became the thing you were waiting for instead of the thing you had asked for.

The interesting part is that nothing about the code looked wrong. There was a button, a class on the root element, a CSS transition on colour properties. A theme switch is not supposed to be difficult.

So the first job was measurement, not intuition.

Measuring the switch

The numbers came from the browser's own instrumentation:

  • 914 transitions started by a single click on the theme toggle.
  • The last one finished 1,177 ms after the click.
  • 92 animations were still running a second and a half later.
  • The main thread was busy for 1,748 ms, but raster work took 5,662 ms.

That last line is the one that mattered. The main thread was not the bottleneck. The raster was - the work of turning the changed styles into pixels.

The cause was structural. The page had a decorative background element - a large, stretched SVG - painted over the whole document. When the theme changed, that element changed too, and repainting a full-page texture is expensive. The work was not in the DOM, the class write, or the framework. It was in the pixels.

Three hypotheses, tested separately

The first instinct is to blame transition: all. It is the usual suspect, and it is usually wrong - transition: all means any property that changes is animated, not all properties are always animated. On a page with hundreds of elements, it multiplies the number of transitions considerably, but it does not by itself explain a raster cost.

So the hypotheses were separated and each was tested on its own:

  • Hypothesis A - the artwork. Remove the background texture entirely, switch the theme, measure. Result: 3,549 ms wall time became 970 ms, p95 frame time went from 283 ms to 17 ms, and frames over 50 ms went from 42 to 2.
  • Hypothesis B - blur and filters. Turn off every blur and backdrop filter, measure. Result: 3,324 ms - a large effect, and a symptom of the same thing, because filters force expensive raster work on the same large surfaces.
  • Hypothesis C - animations generally. Pause every animation, measure. Result: 4,456 ms - worse, which is the useful answer. Animations were not the cause; removing them made the page do more work per frame.

The artwork was the cause. It was also nearly invisible: a pixel diff of the texture against the flat background showed it contributed 0.11% to 0.18% of the visible pixels, with a mean difference of 0.14 out of 255. A decoration nobody could see was costing 2.5 seconds.

What the fix actually was

Two changes, both small:

  1. The texture was removed. The reference design the site is built on has a flat ground colour. The texture was our own addition, and it was paying a real cost for an effect that was invisible.
  2. The circular wipe was removed. The theme change used the View Transitions API with a clip-path circle expanding from the button. It was a nice effect. It was also 520 ms of clip-path animation on the root element, and it made the change feel like a transition rather than a switch.

What was left: the toggle writes one class on the root element, and the page changes. Measured after the fix:

  • Class write: 1 ms.
  • Transitions started: 8, down from 914.
  • Settled: 178 ms, down from 1,177 ms.
  • Style recalculation: 0.048 s, down from 0.22 s.

The whole thing is now a single atomic swap. There is no in-between state, and the page goes from light to dark in the same frame.

The rule about transitions

There is a temptation to solve this by declaring transition: none everywhere. Do not. It removes the symptom and the rest of the page with it - hover states, panel entrances, the small transitions that make an interface feel considered.

The rule that came out of this is narrower and more useful:

A transition belongs to the element that changes, and only to the property that changes.

Most of the 914 transitions were incidental: an element's background changed because the theme changed, and a blanket transition rule caught it. Animating a theme change is a design decision, and it should be a deliberate one on the elements you chose - not an accident that happens to every element with a background.

How to tell what is slow

The technique matters more than the fix, because the same method applies to any performance problem:

  • Measure the phases separately. Main thread, style, layout, paint, raster. One of them was three times bigger than the rest; that is where the time was.
  • Change one thing at a time. Removing the artwork, removing the filters and pausing the animations were three separate experiments. Any two of them together would have produced a number that pointed at the wrong cause - the third one increased the time, which is exactly the sort of thing you would never guess.
  • Compare against a real baseline, not against a feeling. "It feels slower" is a symptom. "3,549 ms of raster work for a theme change" is a bug you can close.
  • Check what the decoration is actually worth. A pixel diff is cheap and decisive. If a full-page texture contributes 0.14 out of 255, it is not worth 2.5 seconds.

What I would keep

The theme switch is now the fastest interaction on this site, and it is faster because of something that looks like a regression in the design: a flat background instead of a textured one, and a hard cut instead of a wipe. Sometimes the decorative layer is the bug.

If you take one thing from this: profile the paint, not the DOM. The DOM was never where the time was.

Contact Me

Let's Talk for Your
Next Projects

0 / 4000

Or email olaleke2004@gmail.com

Where

Based in Lagos, Nigeria
Working with clients worldwide

Contact

Email : olaleke2004@gmail.com

Time

within 24 hours

Stay Connected

SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers
SaaS Platforms
Marketplaces
Mobile Apps
AI Integration
Admin Dashboards
API Development
Automation
Takeovers