Skip to content

Commit 2e2dee0

Browse files
committed
Replace CPU color transitions with GPU View Transitions for dark mode
The dark mode toggle previously animated background-color, color, and border-color on every element via a wildcard CSS rule, causing full-page CPU repaints for 0.8 seconds. On weaker browser engines this was visibly choppy. Now uses the View Transitions API: the browser takes a GPU-composited screenshot, swaps the theme instantly, then crossfades between old and new states in 0.4s using only opacity (compositor-only). Falls back to instant swap on unsupported browsers. Removed all 0.8s color transitions from body, sections, sidebar, and mobile top bar that existed solely for the dark mode toggle.
1 parent ba00265 commit 2e2dee0

1 file changed

Lines changed: 17 additions & 11 deletions

File tree

index.html

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,6 @@
140140
font-family: 'Geist Mono';
141141
color: var(--text-dark);
142142
line-height: 1.6;
143-
transition: background-color 0.8s ease-in-out, color 0.8s ease-in-out;
144-
}
145-
146-
*, *::before, *::after {
147-
transition: background-color 0.8s ease-in-out, color 0.8s ease-in-out, border-color 0.8s ease-in-out;
148143
}
149144

150145
a {
@@ -280,7 +275,6 @@
280275
padding: 24px var(--spacing) var(--spacing);
281276
background-color: var(--bg-light);
282277
z-index: 100;
283-
transition: background-color 0.8s ease-in-out;
284278
}
285279

286280
.profile-photo {
@@ -340,7 +334,7 @@
340334
flex-direction: column;
341335
opacity: 0;
342336
visibility: hidden;
343-
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out, background-color 0.8s ease-in-out, color 0.8s ease-in-out;
337+
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
344338
will-change: opacity;
345339
overflow-y: auto;
346340
scroll-behavior: smooth;
@@ -823,6 +817,12 @@
823817
--line-color: #3d3d3d;
824818
}
825819

820+
::view-transition-old(root),
821+
::view-transition-new(root) {
822+
animation-duration: 0.4s;
823+
animation-timing-function: ease-in-out;
824+
}
825+
826826

827827
/* ============================================
828828
12. LOADING SCREEN
@@ -997,7 +997,6 @@
997997
top: 0;
998998
right: 0;
999999
z-index: 10020;
1000-
transition: background-color 0.8s ease-in-out;
10011000
}
10021001

10031002
.mobile-top-bar .theme-toggle {
@@ -1033,13 +1032,12 @@
10331032
padding: 60px var(--spacing);
10341033
opacity: 0;
10351034
visibility: hidden;
1036-
transition: background-color 0.8s ease-in-out;
10371035
}
10381036

10391037
.sidebar.menu-open {
10401038
opacity: 1;
10411039
visibility: visible;
1042-
transition: opacity 0.3s ease, visibility 0.3s ease, background-color 0.8s ease-in-out;
1040+
transition: opacity 0.3s ease, visibility 0.3s ease;
10431041
}
10441042

10451043
.nav-links {
@@ -2560,12 +2558,20 @@
25602558
/* ============================================
25612559
10. THEME TOGGLE
25622560
============================================ */
2563-
function toggleTheme() {
2561+
function applyThemeToggle() {
25642562
const isDark = document.body.classList.toggle('dark-mode');
25652563
document.documentElement.classList.toggle('dark-mode', isDark);
25662564
localStorage.setItem('theme', isDark ? 'dark' : 'light');
25672565
}
25682566

2567+
function toggleTheme() {
2568+
if (document.startViewTransition) {
2569+
document.startViewTransition(applyThemeToggle);
2570+
} else {
2571+
applyThemeToggle();
2572+
}
2573+
}
2574+
25692575
if (localStorage.getItem('theme') === 'dark') {
25702576
document.body.classList.add('dark-mode');
25712577
document.documentElement.classList.add('dark-mode');

0 commit comments

Comments
 (0)