N1 Nex1on

Tamsi tema be blyksnio: jungiklis, kuris įsimena pasirinkimą

Tamsios temos mygtukas, kuris perkraunant nesužybsi baltai: trumpas scenarijus head dalyje, light-dark() ir color-scheme. Visas kodas, ekrano nuotraukos telefone, planšetėje ir kompiuteryje bei patikra, kad blyksnio nėra.

Įjungėte tamsią temą, o kiekvieną kartą perkraunant puslapis akimirką sužybsi baltai ir tik tada patamsėja. Tai dažniausia temos jungiklio klaida, ir ji ištaisoma vienu mažyčiu scenarijumi tinkamoje vietoje. Toliau – visas receptas: kodas, kurį galima nukopijuoti, paaiškinimas, kaip tai veikia, ir būdas patiems patikrinti rezultatą.

Ką gausite #

  • Numatytai tema atitinka sistemos temą (šviesią arba tamsią) ir veikia net išjungus JavaScript.
  • Mygtukas perjungia temą, o pasirinkimas įsimenamas naršyklėje.
  • Išsaugotas pasirinkimas pritaikomas dar prieš pirmą piešimą: perkraunant jokio balto blyksnio.
Tamsi tema telefone, 390 pločio: antraštė su mygtuku „Tamsi“ ir kortelė
Tamsi tema telefone, 390 pločio: antraštė su mygtuku „Tamsi“ ir kortelė
Tamsi tema planšetėje, 768 pločio
Tamsi tema planšetėje, 768 pločio
Tamsi tema kompiuteryje, 1280 pločio: kortelė centre, nieko nereikalingo
Tamsi tema kompiuteryje, 1280 pločio: kortelė centre, nieko nereikalingo

Kodėl puslapis sužybsi #

Naršyklė piešia puslapį skaitydama HTML. Jei naudotojo pasirinkimą pritaiko scenarijus puslapio pabaigoje arba po įkėlimo, naršyklė spėja nupiešti šviesųjį variantą ir tik tada jį perpiešia. Pasirinkimas turi būti žinomas dar prieš pasirodant pirmam taškui, todėl scenarijus turi stovėti pačioje puslapio pradžioje, head dalyje.

1 žingsnis. Praneškite, kad svetainė turi abi temas #

Į head įdėkite meta eilutę, o iškart po jos – mažytį scenarijų. Jis perskaito išsaugotą pasirinkimą ir, jei toks yra, įrašo jį į šakninio elemento atributą data-theme:
headHTML
<meta name="color-scheme" content="light dark">
<script>
(function () {
  var saved = null;
  try { saved = localStorage.getItem('theme'); } catch (e) {}
  if (saved === 'light' || saved === 'dark') {
    document.documentElement.dataset.theme = saved;
  }
})();
</script>
Scenarijus trumpas ir nelaukia, kol puslapis įsikels. Blokas try reikalingas todėl, kad privačiame režime arba užblokavus saugyklą naršyklė meta klaidą, ir be jo visas puslapis liktų be temos.

2 žingsnis. Aprašykite spalvas vieną kartą #

Kiekvienos temos spalvos yra reikšmių pora funkcijoje light-dark(): pirmoji šviesiai temai, antroji tamsiai. Tinkamą parenka savybė color-scheme:
style.cssCSS
:root {
  color-scheme: light dark;
  --bg: light-dark(#ffffff, #14161a);
  --text: light-dark(#1b1f24, #e6e8eb);
  --card: light-dark(#f3f5f8, #1e2228);
  --line: light-dark(#d8dee6, #2c333c);
  --accent: light-dark(#1a56db, #7aa7ff);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
body { background: var(--bg); color: var(--text); }
Kol data-theme nėra, veikia color-scheme: light dark: puslapis perima sistemos temą be jokios JavaScript eilutės. Kai scenarijus įrašo naudotojo pasirinkimą, dvi paskutinės eilutės priverstinai įjungia reikiamą temą.

3 žingsnis. Pridėkite mygtuką #

bodyHTML
<button id="theme-toggle" type="button" aria-pressed="false"></button>
Dviejų būsenų mygtukas paprastesnis nei trijų („šviesi, tamsi, kaip sistemoje“): aišku, kas paspausta, ir nereikia aiškinti trečio varianto. Kol žmogus jo nepaspaudė, svetainė vis tiek seka sistemą.
theme.jsJavaScript
(function () {
  var root = document.documentElement;
  var button = document.getElementById('theme-toggle');
  var names = { dark: 'Dark', light: 'Light' };

  function current() {
    return root.dataset.theme ||
      (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  }
  function show() {
    var now = current();
    button.textContent = names[now];
    button.setAttribute('aria-pressed', now === 'dark');
  }

  button.addEventListener('click', function () {
    var next = current() === 'dark' ? 'light' : 'dark';
    root.dataset.theme = next;
    try { localStorage.setItem('theme', next); } catch (e) {}
    show();
  });
  show();
})();
Šį scenarijų galima įkelti puslapio pabaigoje: jam nereikia suveikti prieš pirmą piešimą, jis tik užrašo mygtuko tekstą ir išsaugo pasirinkimą.

Patikrinkite patys #

Receptą išbandėme naršyklėje puslapyje su lėtu (dviejų sekundžių) scenarijumi prieš pabaigą, kai saugykloje išsaugotas pasirinkimas „tamsi“, o sistemos tema šviesi. Praėjus 0,8 sekundės nuo įkėlimo pradžios: kai scenarijus head dalyje, puslapis jau tamsus, kai scenarijus pabaigoje – baltas ir toks lieka, kol puslapis perskaitomas iki galo. Štai ką žmogus mato tą akimirką:
Scenarijus puslapio pabaigoje: pasirinkimas „tamsi“ išsaugotas, bet puslapis šviesus – tai ir yra blyksnis
Scenarijus puslapio pabaigoje: pasirinkimas „tamsi“ išsaugotas, bet puslapis šviesus – tai ir yra blyksnis
Scenarijus head dalyje: ta pati įkėlimo akimirka, puslapis iškart tamsus
Scenarijus head dalyje: ta pati įkėlimo akimirka, puslapis iškart tamsus

Patikrinta ir visa kita: be JavaScript puslapis perima sistemos temą, paspaudus mygtuką ir perkrovus pasirinkimas išlieka, o esant 390, 768 ir 1280 taškų pločiui horizontalios slinkties nėra.
Pakartoti galite taip:

  1. Atidarykite puslapį, paspauskite mygtuką ir pasirinkite tamsią temą.
  2. Kūrėjo įrankiuose įjunkite tinklo lėtinimą ir perkraukite puslapį: fonas lieka tamsus nuo pirmo kadro.
  3. Išjunkite JavaScript ir išvalykite saugyklą: puslapis vėl seka sistemos temą.

Dažnos klaidos #

  • Scenarijus puslapio pabaigoje. Blyksnis grįžta: pasirinkimas sužinomas per vėlai.
  • Nėra color-scheme ant :root. Be jo light-dark() nežino, kurią reikšmę imti.
  • Nėra try aplink localStorage. Privačiame režime kai kuriose naršyklėse puslapis sugenda.
  • Tema tik JavaScript. Be scenarijaus lankytojas neturi tamsios temos, net jei sistemoje ji įjungta. Receptas tai išsprendžia su color-scheme.
  • Nepatikrintas kontrastas. Tekstas ir fonas turi duoti bent 4,5 su 1 – tai WCAG AA prieinamumo taisyklė. Patikrinkite abi temas, ne vieną.
Dalintis: Telegram WhatsApp

Skaitykite taip pat

Diskusija

Komentarai

Diskusija dar neprasidėjo

Dar niekas nepakomentavo. Būkite pirmi.

Pranešti apie šį įrašą