Avoid universal selector (`*`) for theme-switch transitions in `dark-mode.sass`
- Dominant language
- HTML
- Stars
- 46
- Forks
- 222
- PR merge metrics
- No merged PRs in 30d
Description
## Problem
`assets/sass/dark-mode.sass` (lines 387, 396) applies transitions to `background-color`, `color`, and `border-color` using the universal selector `*`:
```sass
[data-theme="dark"],
[data-theme="light"]
transition: background-color 0.3s ease, color 0.3s ease
*
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease
```
This forces the browser to compute transition logic for **every DOM node** on theme toggle, including elements that never change color (wrappers, spans, hidden elements, SVGs). This is a known CSS performance anti-pattern and can cause jank/frame drops on complex pages or low-end devices.
## Proposed fix
Replace `*` with an explicit list of elements/classes that actually change color on theme switch:
```sass
body, .navbar, .navbar-menu, .navbar-dropdown, .navbar-item, .navbar-link, .navbar-burger span, .footer, .hero, .card, .card-content, .button, code, pre, .content, a, .table, th, tr, td, .menu-list a, .tag, .modal-content, hr, input.input, #search-bar, .section, .column, .list-item, h1, h2, h3, h4, h5, h6, .title, .subtitle
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease
```
Same change applies to the `prefers-reduced-motion` block using `*`.
## Why this matters
- **Performance cost scales with page size.** The `*` selector doesn't just target visible, styled elements — it matches *every* node in the DOM, including deeply nested wrappers, hidden elements, SVG internals, and third-party embeds. On content-heavy pages, this can mean thousands of elements being touched on a single toggle.
- **Real, measurable jank.** Applying transitions to `background-color`, `color`, and `border-color` on every element forces the browser to run style recalculation and repaint across the full render tree. On low-end/mobile devices this is visible as stutter or dropped frames during what should be an instant, lightweight UI action.
- **It defeats the purpose of `prefers-reduced-motion`.** Users who've explicitly opted out of animations still get transitions computed for the entire DOM under this rule — the accessibility intent is currently undermined by the same anti-pattern.
- **It grows silently over time.** As the site adds more components, sections, or third-party widgets, this selector automatically absorbs all of them into the transition — meaning the performance cost increases without any recognition, and without appearing in any diff as a red flag.
- **Low effort, high payoff fix.** This isn't a rearchitecture — it's a scoped selector swap. The visual behavior (smooth theme transition) is fully preserved; only the unnecessary browser workload is removed. It's a quick, safe win for site responsiveness with virtually no downside or regression risk.
- **Best-practice alignment.** Scoping transitions to only the elements that actually change is standard CSS performance guidance (avoid `*` in transition/animation rules), and adopting it here brings the codebase in line with that convention going forward.
## Impact
Eliminates unnecessary style recalculation overhead across the entire DOM on every theme switch, scoping transitions only to elements that need them.
Happy to open a PR with this fix if it looks good.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in assets/sass/dark-mode.sass around lines 387 and 396, then inspect both the theme-switch rules and the prefers-reduced-motion block. Replace the universal-selector transition rules with the scoped elements listed in the issue, and confirm that theme transitions remain covered while no `*` transition selector remains.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sass
- Domain
- frontend, performance
- Issue type
- Refactor
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100