Dark tema artık bir "ekstra özellik" değil, kullanıcıların beklediği temel bir UX standardı. Doğru yapmak; sistemin tercihine saygı duymak, her iki temada da tutarlı görünmek ve hydration sorunlarına düşmemekten geçiyor.
Kurulum: tailwind.config + next-themes
// tailwind.config.ts
export default {
darkMode: 'class', // 'media' değil — kullanıcı kontrolü için
// ...
}// app/layout.tsx
import { ThemeProvider } from 'next-themes'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html suppressHydrationWarning> {/* Flash önlemek için şart */}
<body>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem={false} // sistem tercihini ignore etmek için
>
{children}
</ThemeProvider>
</body>
</html>
)
}⚠️ Dikkat
suppressHydrationWarning olmadan "Text content did not match" hydration hatası alırsınız çünkü sunucu hangi temayı seçeceğini bilmez.
CSS Değişkenleri ile Tutarlı Renk Sistemi
Her rengi dark: prefixi ile ikiye katlamak yerine CSS değişkenleri kurmak çok daha ölçeklenebilir.
/* globals.css */
:root {
--bg: 255 255 255;
--surface: 248 250 252;
--text: 15 23 42;
--muted: 100 116 139;
--border: 226 232 240;
--accent: 99 102 241;
}
.dark {
--bg: 5 8 16;
--surface: 15 18 28;
--text: 241 245 249;
--muted: 100 116 139;
--border: 30 41 59;
--accent: 129 140 248;
}
/* tailwind.config'de: */
/* colors: { bg: 'rgb(var(--bg) / <alpha-value>)' } */Hydration Flash Sorununu Çözmek
next-themes kullanan bileşenler ilk render'da temayı bilmez. mounted state ile çözülür.
'use client'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return <div className="w-8 h-8" /> // placeholder, layout shift önler
return (
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? <SunIcon /> : <MoonIcon />}
</button>
)
}Glassmorphism: Her İki Temada Çalışan Kart
/* Dark varsayılan, light override */
.glass {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
}
html:not(.dark) .glass {
background: rgba(255, 255, 255, 0.75);
border: 1px solid rgba(0, 0, 0, 0.07);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}💡 İpucu
Glassmorphism backdrop-filter'ı desteklemez tarayıcılarda için @supports ile fallback verin: @supports not (backdrop-filter: blur(1px)) { .glass { background: rgb(var(--surface)); } }