Ringkasan

Dalam artikel teknis mendalam ini, kita mengeksplorasi cara mengimplementasikan pemilih tema (light/dark) tanpa efek berkedip yang tidak menyenangkan yang terjadi saat memuat halaman. Kami menganalisis secara detail siklus rendering browser, penyebab mendalam FOUC (Flash of Unstyled Content), dan menawarkan solusi kuat berbasis pre-chargement sinkron dalam`<head>`. Teknik ini menjamin pengalaman pengguna yang lancar dan profesional.

Masalah: Kedipan Tema yang Sial

Sebuah mimpi buruk untuk pengalaman pengguna

Bayangkan adegan ini: Anda telah menghabiskan jam-jam untuk merancang tema gelap yang indah untuk aplikasi web Anda. Warna-warna seimbang sempurna, kontras optimal, dan pengguna Anda menyukai opsi ini. Tapi ada masalah memalukan: setiap kali halaman dimuat ulang, dalam sekejap, tema terang default muncul sebelum tema gelap menggantikannya.

Flash visual ini, meskipun singkat (kadang kurang dari 100ms), langsung terasa oleh mata manusia dan menciptakan pengalaman yang tidak menyenangkan. Untuk pengguna yang telah memilih tema gelap karena alasan kenyamanan visual atau aksesibilitas, kedipan ini bahkan dapat menyakitkan, terutama dalam lingkungan yang tidak terang.

FOUC: Masalah Web Kuno

Fenomena ini adalah varian dari yang disebut "Flash of Unstyled Content" (FOUC), sebuah masalah klasik dalam pengembangan web yang bermula sejak awal era CSS. FOUC terjadi ketika peramban menampilkan sementara konten HTML tanpa gaya CSS yang diterapkan, menciptakan kilat konten yang tidak terdahului.

Dalam kasus spesifik kita, kita tidak berbicara tentang konten yang tidak diberi gaya sepenuhnya, melainkan tentang sebuahKilat tema salah(FOWT) - Konten tersebut telah diberi gaya, tetapi dengan tema yang salah. Ini sangat menyebalkan karena ini menunjukkan bahwa aplikasi kita "melupakan" preferensi pengguna setiap kali halaman dimuat.

Dampak pada Persepsi Kualitas

Masalah ini, meskipun bersifat teknis, memiliki dampak yang signifikan terhadap persepsi kualitas aplikasi Anda :

Kurang halus: Kedipan memberi kesan bahwa aplikasi belum selesai atau tidak dioptimalkan dengan baik. Pengguna sering mengaitkan cacat visual kecil ini dengan kurangnya profesionalisme secara keseluruhan.

Kehilangan koherensiAplikasi sepertinya "melupakan" preferensi pengguna, menciptakan perasaan tidak sinkron antara antarmuka dan harapan.

Kelelahan visualUntuk pengguna yang sensitif terhadap cahaya atau yang mengalami migrain, cahaya kilat ini bisa menjadi lebih dari sekadar gangguan estetika.

Kinerja yang dirasakanIronis, meski situs Anda dimuat dengan cepat, ketipukan ini dapat memberi kesan aplikasi lambat atau kurang responsif.

Analisis Teknis Masalah

Untuk memahami cara menyelesaikan masalah ini, pertama-tama perlu memahami mengapa hal tersebut terjadi. Kedipan terjadi karena adanya keterlambatan waktu antara tiga peristiwa kritikal dalam siklus hidup sebuah halaman web :

  1. Parsing awal dari HTMLPeramban membaca dan menganalisis struktur halaman Anda.

  2. Penerapan gaya CSSPeramban menerapkan aturan CSS dan menghitung rendering visual

  3. Eksekusi JavaScript: Kode Anda yang mengubah tema berjalan

Masalah terjadi ketika peristiwa no.3 (eksekusi JavaScript) tiba setelah browser sudah memulai atau menyelesaikan peristiwa no.2 (penerapan gaya). Saat itu, browser sudah membuat keputusan tentang tema mana yang akan ditampilkan, dan kode Anda terlambat untuk memengaruhinya sebelum rendering pertama.

Mengapa script klasik tidak cukup?

Pendekatan intuitif tetapi tidak efektif

Pendekatan paling natural untuk seorang pengembang akan menempatkan skrip di akhir dari kita.`<body>`yang memeriksa tema favorit pengguna dan menerapkannya. Pendekatan ini mengikuti praktik terbaik tradisional web yang merekomendasikan untuk memuat skrip di akhir halaman agar tidak memblokir rendering.

// À la fin de <body> - L'APPROCHE INSUFFISANTE
document.addEventListener('DOMContentLoaded', () => {
  const theme = localStorage.getItem('preferred-theme');
  if (theme === 'dark') {
    document.documentElement.setAttribute('data-bs-theme', 'dark');
  }
});

Pendekatan ini tampak logis pada pandangan pertama. Kami menunggu hingga DOM siap, lalu kami menerapkan tema. Sederhana, bukan? Sayangnya, kesederhanaan ini menyembunyikan cacat fundamental yang terkait dengan timing siklus rendering peramban.

Memahami Acara DOMContentLoaded

Kejadian`DOMContentLoaded`terpicu ketika dokumen HTML awal telah sepenuhnya dimuat dan dianalisis oleh peramban,tanpa menungguakhir pemuatan stylesheets, gambar, dan subframe. Ini adalah poin penting untuk dipahami.

Berikut adalah urutan tipikal peristiwa:

  1. Peramban mulai mengunduh HTML

  2. Dia menganalisis HTML seiring diterimaannya

  3. Dia menemukan tag`<link>`untuk CSS dan mulai mengunduhnya

  4. Dia menemukan tag`<script>`dan mengeksekusi mereka (sesuai tipe dan atribut mereka)

  5. Dia membangun DOM (Document Object Model)

  6. Peristiwa DOMContentLoaded terpicu

  7. Dia terus menerapkan gaya dan melakukan layout

  8. Pengecatan pertama (tampilan) terjadi

  9. Acara`load`terjadi ketika semua resource telah dimuat

Masalah? Di antara langkah 6 (DOMContentLoaded) dan langkah 8 (paint pertama), peramban telah membuat keputusan tentang cara menampilkan halaman. Jika skrip perubahan tema Anda berjalan di langkah 6, sudah terlambat untuk menghindari tampilan pertama dengan gaya default.

Masalah Render Blocking

Sebenarnya, timing-nya masih lebih kompleks. Penyelancar modern menggunakan teknik optimisasi yang canggih untuk meningkatkan performa yang dirasakan. Mereka mencoba membuat first paint (First Contentful Paint) secepat mungkin agar pengguna melihat sesuatu di layar.

CSS secara default bersifat "render-blocking", artinya browser menunggu sampai stylesheet terunduh dan diparse sebelum melakukan first paint. Itu masuk akal: kita tidak ingin menampilkan konten yang belum diberi gaya.

Tapi ini adalah jebakannya: ketika peramban menerapkan gaya CSS ini untuk pertama kalinya, ia melakukannya berdasarkan keadaan saat ini dari DOM. Jika atribut`data-bs-theme`belum didefinisikan pada tag`<html>`, perambar akan menerapkan gaya default (biasanya tema terang).

Kemudian, ketika skrip Anda berjalan dan mengubah atribut ini, peramban harus:

  1. Menghitung ulang semua gaya yang dipengaruhi oleh perubahan ini

  2. Buat ulang tata letak jika diperlukan

  3. Mengulang cat elemen yang terpengaruh

Proses penghitungan ulang dan penarikan ulang ini yang menyebabkan kedipan yang terlihat.

Visualisasi Masalah

Untuk lebih memahami urutan masalah ini, mari kita periksa diagram urutan terperinci:

@startuml
actor Utilisateur
participant Navigateur
participant "Parser HTML" as Parser
participant "CSSOM" as CSS
participant "Script.js (akhir body)" as Script
participant "Mesin render" as Render

Utilisateur -> Navigateur: Demande la page
activate Navigateur

Navigateur -> Parser: Parse le HTML
activate Parser
Parser -> CSS: Découvre et charge les CSS
activate CSS
Parser -> Parser: Construit le DOM
Parser -> Navigateur: DOM Ready (DOMContentLoaded)
deactivate Parser

CSS -> CSS: Parse les feuilles de style
CSS -> Render: CSSOM Ready
deactivate CSS

activate Render
Render -> Render: Calcule les styles avec data-bs-theme=""note right: Tema default (light)
Render -> Navigateur: Premier Paint (Tema Terang)
note right: Pengguna melihat tema terang
deactivate Render

Navigateur -> Script: Menjalankan skrip
activate Script
Script -> Script: Membaca localStorage
Script -> Navigateur: setAttribute('data-bs-theme', 'dark')
deactivate Script

activate Render
Render -> Render: Menghitung ulang gaya dengan data-bs-theme="dark"
note right: Thème sombre
Render -> Navigateur: Repaint (Thème Sombre)
note right: Clignotement visible
deactivate Render

deactivate Navigateur
@enduml

Diagram ini menggambarkan dengan jelas masalahnya: pertama kali paint terjadi sebelum skrip kami berempatan untuk menentukan tema yang tepat. Repaint yang kemudian menghasilkan berkedip yang terlihat.

Upaya Penyelesaian yang Tidak Efektif

Berbagai pendekatan telah dicoba untuk menyelesaikan masalah ini, tetapi kebanyakan memiliki kelemahan masing-masing :

Pendekatan 1: Menyembunyikan konten sampai pemuatan selesai

body {
  opacity: 0;
  transition: opacity 0.3s;
}

body.loaded {
  opacity: 1;
}

Pendekatan ini menyembunyikan semua konten sampai JavaScript menentukan tema yang tepat. Masalah? Ini menunda secara buatan penampilan konten, memberi kesan situs lebih lambat. Selain itu, jika JavaScript dinonaktifkan, pengguna tidak akan melihat apa-apa sama sekali!

Pendekatan 2 : Menggunakan loader/spinner

Serupa dengan pendekatan 1, tetapi dengan spinner pemuat. Ini menyembunyikan masalah tetapi tidak meningkatkan performa aktual dan menambahkan penundaan yang dirasa tidak perlu.

Pendekatan 3 : Default ke tema gelap

Beberapa developer mengatur tema gelap sebagai default dalam CSS. Ini mencegah kedipan bagi pengguna tema gelap, tetapi menciptakan masalah yang berlawanan bagi pengguna tema terang!

Tidak ada pendekatan ini yang memuaskan karena mereka mengatasi gejala alih-alih akar masalah.

Solusi yang Benar : Bertindak Lebih Awal

Kunci untuk menyelesaikan masalah ini adalah menyadari bahwa kita harus menentukan atribut`data-bs-theme` sebelumbahwa peramban belum mulai menerapkan gaya CSS. Ini berarti bahwa skrip kami harus dieksekusi lebih awal dalam siklus hidup halaman, dan ini persis apa yang akan kita jelajahi di bagian berikutnya.

Solusi: Pemuatan Dini (Early Loading)

Prinsip Dasar

Solusi elegan untuk masalah berkedip kita didasarkan pada prinsip yang sederhana tetapi kuat:Mengsinkronkan status aplikasi dengan proses rendering peramban. Sebagai gantinya menunggu hingga halaman dimuat untuk menentukan tema, kita harus menetapkannyasaatpemuatan, bahkan sebelum gaya CSS diterapkan.

Pendekatan ini disebut "Early Loading" atau "Synchronous Preloading" dalam jargon pengembangan web. Ideanya adalah menjalankan logika deteksi tema kita secepat mungkin dalam siklus hidup halaman, idealnya dalam tag`<head>`, bahkan sebelum peramban mulai mengunduh file CSS.

Mengapa <head> adalah tempat yang ideal

Le `<head>`Sebuah elemen dari dokumen HTML diproses secara berurutan oleh peramban, dari atas ke bawah. Setiap elemen diproses dalam urutan tempat ia muncul. Karakteristik ini krusial untuk solusi kita.

Ketika peramban menemui sebuah tag`<script>`dalam`<head>`tanpa atribut-atribut`async` ou defer, il :

  1. Menginterupsi parsing HTML

  2. Unduh skrip(jika eksternal) atau tempat tidur (jika inline)

  3. Jalankan skrip segera

  4. Melanjutkan parsing HTML

Perilaku ini, yang sering dianggap sebagai masalah performa (sebab itu rekomendasi biasa adalah meletakkan script di akhir halaman), menjadi sekutu kita dalam kasus spesifik ini. Dengan menempatkan script deteksi tema kita di awal du`<head>`, kami menjamin bahwa dieksekusi sebelum browser bertemu dengan tag`<link>`dari lembar gaya kami.

Arsitektur Solusi dalam Tiga Lapisan

Solusi lengkap kami terdiri dari tiga lapisan yang saling terkait, masing-masing berperan secara spesifik :

Lapisan 1 : Persistensi (localStorage) Lapisan ini bertanggung jawab atas penyimpanan dan pemulihan pilihan pengguna antar sesi

Lapisan 2 : Sinkronisasi Dini (script inline dalam <head>) Lapisan ini mensinkronkan keadaan aplikasi dengan DOM sebelum rendering awal

Lapisan 3 : Gaya Responsif (CSS dengan selektor atribut) Lapisan ini menentukan gaya visual berdasarkan keadaan yang ditentukan oleh lapisan 2.

Mari kita jelajahi setiap lapisan secara detail sekarang

Langkah 1: Menyimpan Pilihan Pengguna

localStorage : Memori Persisten Anda

Le localStorage`adalah API Web Storage yang memungkinkan penyimpanan pasangan kunci-nilai dalam browser secara persisten. Berbeda dengan cookies, data`localStorage:

  • Tidak pernah dikirim ke server secara otomatis

  • Mempunyai kapasitas penyimpanan yang lebih besar (biasanya 5-10 MB)

  • Tidak memiliki tanggal kedaluwarsa (bertahan sampai dihapus secara eksplisit)

  • Dibatasi pada protokol dan domain (Same-Origin Policy)

Untuk kasus penggunaan kita, yang`localStorage`adalah sempurna karena :

  1. Kami tidak perlu berbagi informasi ini dengan server

  2. Kami ingin preferensi tersebut tetap bertahan selamanya

  3. Ukuran penyimpanan yang diperlukan sangat kecil (beberapa byte)

Implementasi Cadangan Tema

Berikut cara kami menyimpan pilihan pengguna saat ia mengubah tema :

// Fonction complète pour changer le thème
function setTheme(newTheme) {
  // Validation de l'entrée
  if (!['light', 'dark', 'auto'].includes(newTheme)) {
    console.error('Thème invalide:', newTheme);
    return;
  }

  try {
    // Sauvegarde dans localStorage
    localStorage.setItem('preferred-theme', newTheme);

    // Application immédiate dans le DOM
    document.documentElement.setAttribute('data-bs-theme', newTheme);

    // Dispatch d'un événement personnalisé pour notifier d'autres composants
    window.dispatchEvent(new CustomEvent('theme-changed', {
      detail: { theme: newTheme }
    }));

    console.log('Thème changé:', newTheme);
  } catch (error) {
    console.error('Erreur lors de la sauvegarde du thème:', error);
    // Fallback : on applique quand même le thème visuellement
    document.documentElement.setAttribute('data-bs-theme', newTheme);
  }
}

// Exemple d'utilisation avec un bouton
document.getElementById('theme-toggle').addEventListener('click', () => {
  const currentTheme = document.documentElement.getAttribute('data-bs-theme') || 'light';
  const newTheme = currentTheme === 'light' ? 'dark' : 'light';
  setTheme(newTheme);
});

Manajemen Kasus Kesalahan

Penting untuk mengelola kasus di mana`localStorage`Tidak tersedia atau tidak dapat diakses. Beberapa skenario dapat mencegah akses ke`localStorage` :

Navigasi pribadi ketatSafari dalam mode penelusuran pribadi menimbulkan pengecualian`QuotaExceededError`saat percobaan menulis dalam`localStorage`.

Pengaturan privasi: Beberapa peramban atau ekstensi privasi dapat memblokir akses ke`localStorage`.

Keterbatasan domain : Le `localStorage`tidak dapat diakses pada protokol`file://`di beberapa peramban.

Ruang penyimpanan penuhMeskipun jarang, ruang penyimpanan dapat sepenuhnya terisi.

Karena itu kode kita menggunakan sebuah blok`try…​catch`Untuk menangani kasus-kasus ini dengan anggun, sambil terus menawarkan fungsionalitas perubahan tema meskipun persistensi tidak tersedia.

Strategi Persistensi Lanjutan

Untuk aplikasi yang lebih canggih, Anda dapat mempertimbangkan strategi tambahan:

Sinkronisasi server (opsional)

async function setTheme(newTheme) {
  // Sauvegarde locale immédiate
  localStorage.setItem('preferred-theme', newTheme);
  document.documentElement.setAttribute('data-bs-theme', newTheme);

  // Synchronisation serveur en arrière-plan (si l'utilisateur est connecté)
  if (userIsAuthenticated()) {
    try {
      await fetch('/api/user/preferences', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ theme: newTheme })
      });
    } catch (error) {
      console.warn('Échec de la synchronisation serveur:', error);
      // L'échec n'est pas critique car la préférence est déjà sauvegardée localement
    }
  }
}

Pendekatan ini memungkinkan sinkronisasi preferensi antar perangkat untuk pengguna yang terhubung, sambil tetap menjaga responsivitas lokal yang langsung.

Langkah 2: Skrip Preload di `<head>

Inti Solusi

Ini adalah tempat di mana sihir tersebut benar-benar berfungsi. Kami akan menempatkan sebuah skrip kecil.secara langsunglangsung di dalam kita`<head>`, sebelum semua tag kami`<link>`de lembar gaya. Skrip ini sengaja dibuat minimalis, mandiri, dan dirancang untuk berjalan secepat mungkin.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mon Site Incroyable</title>

    <!-- ==========================================
         NOTRE SCRIPT MAGIQUE DE PRÉ-CHARGEMENT
         Ce script DOIT être le premier élément
         dans le <head> après les meta tags
         ========================================== -->
    <script>
      // IIFE pour ne pas polluer le scope global
      (function() {
        'use strict';

        try {
          // Lecture de la préférence sauvegardée
          const savedTheme = localStorage.getItem('preferred-theme');

          // Si une préférence existe, on l'applique immédiatement
          if (savedTheme) {
            document.documentElement.setAttribute('data-bs-theme', savedTheme);
          }
          // Optionnel : Détecter la préférence système si aucune sauvegarde
          else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
            document.documentElement.setAttribute('data-bs-theme', 'dark');
          }
          // Sinon, le thème par défaut du CSS sera utilisé (généralement 'light')

        } catch (error) {
          // En cas d'erreur (localStorage bloqué, etc.), on log discrètement
          // et on laisse le thème par défaut s'appliquer
          console.warn('Impossible de charger la préférence de thème:', error);
        }
      })();
    </script>
    <!-- FIN DU SCRIPT MAGIQUE -->

    <!-- Les feuilles de style sont chargées APRÈS le script -->
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/styles.css">

    <!-- Autres ressources du head -->
    <link rel="icon" href="favicon.ico">
</head>
<body>
    <!-- Contenu de la page -->
</body>
</html>

Anatomi Skrip : Setiap Baris Penting

Mari kita pecah skrip ini baris demi baris untuk memahami setiap keputusan desain:

IIFE (fungsi yang segera dipanggil)

(function() {
  // ...
})();

Struktur ini membuat sebuah fungsi yang dieksekusi segera. Mengapa? Untuk mengisolasi variabel kita dalam cakupan lokal dan menghindari pencemaran cakupan global. Meskipun kita hanya menggunakan`const`(yang memiliki scope blok), IIFE adalah praktik yang baik yang membuat niat kita jelas dan melindungi dari konflik nama yang mungkin.

Mode Ketat

'use strict';

Directive ini mengaktifkan mode ketat JavaScript, yang : - Melarang penggunaan variabel yang tidak dideklarasikan - Menghasilkan kesalahan untuk operasi berbahaya - Meningkatkan performa di beberapa mesin JavaScript

Untuk skrip kritis seperti ini, kami ingin keamanan maksimal.

Blok try…​catch

try {
  // Code principal
} catch (error) {
  console.warn('Impossible de charger la préférence de thème:', error);
}

Blok ini sangat penting. Ia menjamin bahwa jika terjadi sesuatu yang salah (localStorage terblokir, kesalahan sintaks improbable, dsb.), skrip kita tidak akan menghambat pemuatan seluruh halaman. Penggunaan`console.warn`daripada`console.error`mengindikasikan bahwa ini bukan masalah kritis

Pembacaan localStorage

const savedTheme = localStorage.getItem('preferred-theme');

Baris ini dapat menimbulkan pengecualian dalam beberapa konteks (privatisasi Safari yang ketat). Itu sebabnya ia berada dalam blok try…​catch.

Aplikasi bersyarat

if (savedTheme) {
  document.documentElement.setAttribute('data-bs-theme', savedTheme);
}

Kami menerapkan tema hanya jika kami menemukan tema yang telah disimpan. Jika tidak, kita membiarkan CSS menggunakan tema default-nya. Pendekatan ini lebih robust daripada nilai default yang di-hardcode dalam JavaScript.

Deteksi Preferensi Sistem (Bonus)

Penambahan yang opsional namun elegan adalah mendeteksi preferensi tema sistem operasi pengguna jika mereka belum membuat pilihan eksplisit dalam aplikasi Anda :

else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  document.documentElement.setAttribute('data-bs-theme', 'dark');
}

Fitur ini menggunakan Media Query`prefers-color-scheme`untuk menanyakan sistem. Pada macOS, Windows 10+, iOS, dan Android modern, permintaan ini mengembalikan preferensi sistem pengguna.

Keuntungan : - Pengalaman yang dipersonalisasi sejak pertama kali berkunjung - Konsistensi dengan lingkungan sistem pengguna - Tidak perlu penyimpanan untuk kunjungan pertama

Pertimbangan: - Tidak semua browser mendukung fitur ini (tapi dukungannya sangat baik sejak 2020) - Verifikasi`window.matchMedia`memastikan kompatibilitas - Pengguna selalu dapat mengganti pilihan ini

Kinerja : Mengapa skrip ini cepat

Skrip pre-load kami dirancang untuk sangat cepat:

Ukuran minimumKira-kira 300 byte yang tidak dipersempit, 200 byte yang dipersempit. Itu dianggap tidak signifikan dibandingkan dengan gambar atau pustaka JavaScript apa pun.

secara langsungTidak ada permintaan HTTP tambahan. Skrip ada di dalam HTML, sehingga ia langsung tersedia.

Operasi sinkron sederhana: Membaca sebuah kunci dalam localStorage (operasi sangat cepat) dan modifikasi sebuah atribut DOM (operasi bawaan peramban).

Tidak ada ketergantungan: Tidak ada framework, tidak ada perpustakaan, hanya JavaScript vanilla. Tidak ada waktu pemuatan, tidak ada parsing dependensi.

Eksekusi tunggal: Skrip ini dijalankan hanya sekali saat dimuat. Tidak ada listener peristiwa, tidak ada perulangan, tidak ada perhitungan kompleks.

Dalam praktiknya, pada perangkat modern, skrip ini berjalan dalam kurang dari 1 milidetik, waktu yang tidak terasa yang tidak memiliki dampak apa pun pada kinerja pemuatan halaman.

Penempatan optimal di `<head>

Urutan elemen di dalam`<head>`penting. Berikut urutan yang disarankan :

<head>
    <!-- 1. Métadonnées critiques -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- 2. Notre script de pré-chargement (IMMÉDIATEMENT après les meta) -->
    <script>
      (function() { /* notre code */ })();
    </script>

    <!-- 3. Titre de la page -->
    <title>Mon Site</title>

    <!-- 4. Feuilles de style -->
    <link rel="stylesheet" href="styles.css">

    <!-- 5. Autres ressources (fonts, favicons, etc.) -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="icon" href="favicon.ico">

    <!-- 6. Autres scripts avec defer ou async -->
    <script src="app.js" defer></script>
</head>

Perintah ini memastikan bahwa :

  1. Charset ditentukan sebelum apa pun pemrosesan teks

  2. Skrip kita dieksekusi sebelum CSS dimuat

  3. CSS kemudian dimuat dan langsung menerapkan tema yang tepat

  4. Sumber daya non-kritis lainnya dimuat terakhir

Langkah 3: Kekuatan Selektor Atribut CSS

Sistem Tema Bootstrap 5

Bootstrap 5 telah memperkenalkan sistem tema yang elegan berbasis custom properties CSS (variabel CSS) dan selector atribut. Sistem ini menggunakan atribut`data-bs-theme`pada elemen`<html>`untuk menentukan kumpulan variabel warna yang akan diterapkan.

Keindahan sistem ini terletak pada kesederhanaannya: alih-alih memuat berbagai stylesheet atau mengalihkan kelas pada ribuan elemen, kita hanya mengubah satu atribut pada satu elemen, dan CSS melakukan sisa dengan menggunakan kaskad.

Struktur CSS untuk sebuah Sistem Tema

Berikut adalah struktur CSS lengkap untuk mengimplementasikan sistem tema yang kuat :

/**
 * SYSTÈME DE THÈME COMPLET
 * Utilise les Custom Properties CSS pour une maintenance facile
 */

/* ============================================
   THÈME PAR DÉFAUT (LIGHT)
   Défini sur :root pour être le fallback
   ============================================ */
:root {
  /* Couleurs de base */
  --color-primary: #0d6efd;
  --color-secondary: #6c757d;
  --color-success: #198754;
  --color-danger: #dc3545;
  --color-warning: #ffc107;
  --color-info: #0dcaf0;

  /* Couleurs de fond */
  --bg-primary: #ffffff;
  --bg-secondary: #f8f9fa;
  --bg-tertiary: #e9ecef;

  /* Couleurs de texte */
  --text-primary: #212529;
  --text-secondary: #6c757d;
  --text-tertiary: #adb5bd;

  /* Couleurs de bordure */
  --border-color: #dee2e6;
  --border-color-subtle: #e9ecef;

  /* Couleurs d'ombre */
  --shadow-sm: rgba(0, 0, 0, 0.075);
  --shadow-md: rgba(0, 0, 0, 0.15);
  --shadow-lg: rgba(0, 0, 0, 0.25

Artikel terkait