IlmHamroh
JavaScript Full-stack/6-qism. CSS: harakat, zamonaviy CSS va dizayn25/57-dars21 daqiqa
Mundarija (33)

Qorong'i rejim va temalash: to'liq yechim

Qisqacha: To'g'ri qorong'i rejim besh narsadan iborat: tizim sozlamasiga ergashish, foydalanuvchi o'zi tanlashi, tanlovni eslab qolish, sahifa ochilganda "yonib-o'chmaslik" (FOUC) va qorong'ida ham to'g'ri ranglar. Ranglar semantik tokenlarda light-dark() bilan yoziladi, rejimni esa faqat color-scheme hal qiladi: light dark — tizimga ergashadi, [data-tema="qorongi"] da dark — doim qorong'i. Tanlov localStorage da saqlanadi va <head> dagi kichik skript uni sahifa chizilishidan oldin qo'llaydi.

Bu darsda

  • Qorong'i rejimning besh talabini sanaysiz va har biri uchun vositani tanlaysiz.
  • «Bahor» palitrasini yakunlaysiz: --rang-asosiy-toq ning qorong'i qiymati, --rang-yuza va soyalar.
  • Uch holatli tanlovni (tizim, yorug', qorong'i) bitta color-scheme bilan yasaysiz.
  • Sahifa ochilganda yonib-o'chishning sababini tushuntirasiz va uni <head> dagi skript bilan yo'qotasiz.
  • Qorong'i rejimdagi rasm, soya va "sof qora" qoidalarini qo'llaysiz.

Oldin bilishingiz kerak: Dizayn tokenlari, Ranglar 3: light-dark(), Foydalanuvchi afzalliklari, Favicon va color-scheme, Skriptlarni ulash.

1. Nega bu kerak?

«Bahor» Ranglar 3 darsidan beri tizimga ergashadi: telefon qorong'i rejimda bo'lsa, sayt ham qorong'i. Foydalanuvchi afzalliklari darsida rasm va soyalarni ham moslagan edik. Lekin hayot ancha murakkab:

  • Malika telefonini kunduzi yorug' rejimda ishlatadi, lekin kechqurun «Bahor»da menyuni qorong'ida o'qishni xohlaydi — tizimni o'zgartirmasdan.
  • Otabek ishxonadagi kompyuterda qorong'i tizim, lekin bron jadvalini yorug'da ko'rishni afzal ko'radi.
  • Ikkalasi tanlovni bir marta qiladi va keyingi safar sayt uni eslab qolishini kutadi.
  • Tanlov eslab qolingan bo'lsa ham, sahifa ochilganda bir lahzaga yorug' chaqnab, keyin qorong'iga o'tsa — kechasi ko'zga urilib ketadi.

Xarita shu darsni "to'liq yechim" deb ataydi. To'liqlik — mana shu besh talab:

Talab Vosita
Tizimga ergashish color-scheme: light dark + light-dark()
O'zi tanlash [data-tema] atributi → color-scheme
Eslab qolish localStorage (JavaScript)
Yonib-o'chmaslik <head> dagi bloklovchi skript
To'g'ri ranglar Semantik tokenlar, yuza, rasm va soya qoidalari

Favicon va web manifest va Skriptlarni ulash darslarida shu darsga ikki va'da berilgan edi: qorong'i ranglarni o'zimiz berish va "qorong'i rejim tanlovini eng boshida qo'llash". Bugun ikkalasi ham yakunlanadi.

2. Ranglar: palitrani yakunlaymiz

2.1 Tokenlar almashinuvi

Dizayn tokenlari darsida palitrani uch darajaga ajratdik. Qorong'i rejimning butun siri shu tuzilmada: rejim o'zgarganda faqat semantik tokenlar boshqa primitivga ulanadi.

flowchart LR
  S["--rang-fon"] -->|"yorug'"| Q["--qaymoq-50"]
  S -->|"qorong'i"| Y["--yashil-900"]
  S --> K["body, karta, tugma matni"]

Nimaga qarang: komponentlar faqat --rang-fon ni biladi. Rejim almashganda ularning bironta qatori o'zgarmaydi.

2.2 --rang-asosiy-toq ning qorong'i qiymati

Ranglar 3 darsidan beri palitrada bitta bo'shliq bor edi: --rang-asosiy-toq ning qorong'i qiymati. U uch joyda ishlatiladi: fokus halqasi, .bron-havola ning hover foni va yangi kartaning rangi (CSS o'zgaruvchilari 2).

Yorug' rejimda uning vazifasi — asosiy rangdan kuchliroq ko'rinish: fonga nisbatan asosiy rang 6.1:1, "to'q" varianti 7.7:1. Qorong'i rejimda fon to'q, demak kuchliroq ko'rinish uchun rang yorqinroq bo'lishi kerak. Asosiy rang (--yashil-300) qorong'i fonda 8.0:1. Undan bir pog'ona yorqinroq primitiv qo'shamiz:

css
:root {
  --yashil-200: oklch(88% 0.08 150.8); /* #b2e7bd */
}

Tus o'sha 150.8-bob, yorug'lik 80.3% dan 88% ga ko'tarildi, to'yinganlik biroz pasaydi. Formula bilan hisobladik: qorong'i fonda 10.2:1. Qorong'i rejimdagi tugmada matn fon rangida (--rang-fon), hover'da foni --rang-asosiy-toq bo'ladi — o'sha juftlik, 10.2:1. Yorug' rejimdagidek, hover kontrastni oshiradi.

Dizayn tokenlari darsida aytgan edik: nom "to'q", qorong'i qiymat esa och. Tokenning vazifasi — "asosiydan kuchliroq" — ikkala rejimda bir xil, nomi esa faqat yorug' rejimni tasvirlaydi. Nom 05-qismdan beri ishlatilgani uchun qoladi. Yangi loyihada bunday tokenga vazifa nomi bering, masalan "kuchli".

2.3 Yuza va balandlik

Yorug' rejimda karta fondan soya bilan ajraladi. Qorong'ida soya ko'rinmaydi — to'q fonda qora soya yo'qolib ketadi (Foydalanuvchi afzalliklari). Qorong'i interfeyslarda balandlik boshqacha ko'rsatiladi: baland yuza — yorqinroq. Ochilgan oyna kartadan yorqinroq, karta sahifa fonidan yorqinroq. Material Design shu qoidani qorong'i mavzu uchun asosiy qilgan.

Buning uchun yangi semantik token — --rang-yuza (surface — karta, oyna foni). O'tgan darsdagi background: white xatosining javobi aynan shu:

css
:root {
  --oq: oklch(100% 0 0);
  --rang-yuza: light-dark(
    var(--oq),
    color-mix(in oklch, var(--yashil-900), var(--oq) 7%)
  );
}

Yorug'da karta oq — qaymoq fondan ozgina och. Qorong'ida fonga 7% oq qo'shiladi — Chrome hisoblagan qiymati #2a3c24, fondan biroz yorqin. Kontrastni qayta hisobladik: qaymoq matn yuzada 11.4:1, asosiy yashil 6.7:1, urg'u 5.1:1 — hammasi 4.5:1 dan yuqori.

Soyalar esa qorong'ida shaffof bo'ladi — rangini light-dark() beradi:

css
:root {
  --soya-2:
    0 1px 2px light-dark(oklch(0% 0 0 / 12%), transparent),
    0 4px 12px light-dark(oklch(0% 0 0 / 12%), transparent);
}

light-dark() faqat rang qaytaradi (Ranglar 3), lekin soyaning rangi — rang. Shunday qilib soya ham "rang" orqali o'chadi va buning uchun @media kerak emas.

2.4 Sof qora va o'ta yorqin ranglar

Nega «Bahor»ning qorong'i foni #000 emas, to'q yashil #16301b?

  • Sof qora va sof oq — 21:1 kontrast. Bu juda ko'p: oq harflar qora fonda "yoyilib" ko'rinadi, ayniqsa astigmatizmli (ko'zning keng tarqalgan nuqsoni — tasvir biroz xira ko'rinadi) odamlarda. Uzoq o'qish charchatadi.
  • Qorong'i fonda to'yingan ranglar "titraydi". Yorug' rejimdagi --yashil-600 ni qorong'i fonga qo'ysangiz, u zo'rg'a o'qiladi va ko'zni achishtiradi. Shuning uchun qorong'i qiymatlar yorqinroq va kamroq to'yingan: --yashil-300, --gisht-300.
  • Matn — oq emas, qaymoq. --qaymoq-50 qorong'ida matn bo'ldi: 13.7:1 — yetarli, lekin 21:1 emas.

Bu qoidalar «Bahor» palitrasida Ranglar 3 darsidan beri bor edi. Bugun ularning sababini aytdik.

Tekshirib ko'ring: Dizayner qorong'i rejim uchun --rang-fon ga #000000, --rang-matn ga #ffffff tanladi. Kontrast maksimal — 21:1. Nega bu yaxshi tanlov emas?

Javob

Kontrast "4.5:1 dan yuqori" bo'lishi kerak, "iloji boricha ko'p" emas. 21:1 da oq harflar qora fonda yoyilib ko'rinadi va uzoq o'qish ko'zni charchatadi. Bundan tashqari, sof qora fonda yuzalarni "yorqinroq" qilib ajratish imkoni kamayadi. To'q kulrang yoki brendga yaqin to'q rang va ozgina xiraroq oq matn — 12–15:1 atrofida — qulayroq.

3. Uch holat: tizim, yorug', qorong'i

3.1 Hammasini color-scheme hal qiladi

light-dark() qaysi rangni tanlashini elementning color-scheme i hal qiladi (Ranglar 3):

  • color-scheme: light dark — tizim sozlamasiga qarab;
  • color-scheme: light — doim birinchisi;
  • color-scheme: dark — doim ikkinchisi.

Demak, foydalanuvchi tanlovi uchun ranglarni qayta yozish shart emas. :root ning color-scheme ini almashtirish yetadi. Tanlov HTML'da atribut bilan belgilanadi — <html data-tema="qorongi">:

css
:root {
  color-scheme: light dark; /* tanlov yo'q — tizimga ergash */
}

:root[data-tema="yorug"] {
  color-scheme: light;
}

:root[data-tema="qorongi"] {
  color-scheme: dark;
}

data-tema — Global atributlar darsidagi data-* atributlaridan biri: HTML'ga o'z ma'lumotimizni yozish joyi. Real loyihalarda ko'pincha inglizcha data-theme="dark" yoki class="dark" ni uchratasiz — g'oya bir xil.

Uchta holatni jonli ko'raylik. Bu yerda JavaScript yo'q: tanlovni radio tugmalar qiladi, CSS esa :has() bilan qaysi tugma belgilanganini "ko'radi":

html
<style>
  :root {
    --qaymoq-50: oklch(98.6% 0.014 84.6);
    --yashil-900: oklch(28.2% 0.05 148.6);
    --yashil-600: oklch(47.5% 0.1 147.7);
    --yashil-300: oklch(80.3% 0.098 150.8);
    --kul-900: oklch(27.2% 0.019 161);
    --oq: oklch(100% 0 0);
    color-scheme: light dark;
    --rang-fon: light-dark(var(--qaymoq-50), var(--yashil-900));
    --rang-matn: light-dark(var(--kul-900), var(--qaymoq-50));
    --rang-asosiy: light-dark(var(--yashil-600), var(--yashil-300));
    --rang-yuza: light-dark(var(--oq),
      color-mix(in oklch, var(--yashil-900), var(--oq) 7%));
  }
  :root:has(#tema-yorug:checked) { color-scheme: light; }
  :root:has(#tema-qorongi:checked) { color-scheme: dark; }
  body {
    background: var(--rang-fon);
    color: var(--rang-matn);
    font-family: system-ui, sans-serif;
  }
  fieldset { border-radius: 0.5rem; }
  .taom-karta {
    max-width: 18rem;
    padding: 0.5rem 1rem;
    border-radius: 0.5rem;
    background: var(--rang-yuza);
  }
  .taom-karta h3 { color: var(--rang-asosiy); }
</style>
<fieldset>
  <legend>Mavzu</legend>
  <input type="radio" name="tema" id="tema-tizim" checked>
  <label for="tema-tizim">Tizim</label>
  <input type="radio" name="tema" id="tema-yorug">
  <label for="tema-yorug">Yorug'</label>
  <input type="radio" name="tema" id="tema-qorongi">
  <label for="tema-qorongi">Qorong'i</label>
</fieldset>
<article class="taom-karta">
  <h3>Lag'mon</h3>
  <p>Qo'lda cho'zilgan, 28 000 so'm</p>
</article>

"Qorong'i" ni tanlang. Nimaga qarang: sahifa foni to'q yashil, karta undan biroz yorqinroq, sarlavha och yashil, radio tugmalar va ramka ham qorong'i — bularni color-scheme o'zi qildi. "Yorug'" va "Tizim" natija oynasida bir xil ko'rinadi: sayt bu oynani doim yorug' rejimda ochadi. Qurilmangiz qorong'i bo'lsa ham, "Tizim" bu yerda yorug'.

:has() yo'li sodda, lekin ikki kamchiligi bor: tanlov sahifa yangilanganda yo'qoladi va radio tugmalar har sahifada bo'lishi kerak. Shuning uchun «Bahor»da tanlov data-tema atributida saqlanadi, uni esa JavaScript qo'yadi — pastda ko'ramiz.

3.2 Eski usul bilan solishtirish

light-dark() dan oldin (2024-yilgacha) uch holatli tema shunday yozilardi — eski loyihalarda ko'p uchraydi:

css
:root {
  --rang-fon: #fffaf0;
  --rang-matn: #1f2a24;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-tema="yorug"]) {
    --rang-fon: #16301b;
    --rang-matn: #fffaf0;
  }
}

:root[data-tema="qorongi"] {
  --rang-fon: #16301b;
  --rang-matn: #fffaf0;
}

Nimaga qarang: qorong'i palitra ikki marta yozilgan — biri tizim uchun, biri qo'lda tanlov uchun. Bitta rangni o'zgartirsangiz, ikkinchisini unutish oson. light-dark() bilan har rang bir marta yoziladi, rejimni esa bitta xususiyat hal qiladi.

@media + atribut color-scheme + light-dark()
Qorong'i palitra Ikki marta Bir marta
Bitta bo'lak qorong'i (footer) Qayta yozish color-scheme: dark
Brauzerlar 2020-yildan 2024-yil maydan (yangi Baseline)

3.3 Eski brauzer va meta teg

Ranglar 3 darsida bir savol ochiq qolgan edi. «Bahor»da <meta name="color-scheme" content="light dark"> bor. light-dark() ni tushunmaydigan brauzer esa @supports zaxirasi tufayli yorug' palitrani oladi. Lekin meta teg unga "qorong'i rejimni bilaman" deydi — va u forma maydonlari va skrollbarni qorong'i chizishi mumkin, sahifa esa yorug'.

Qaror: meta teg qoladi, CSS esa uni zaxira holatda bosib ketadi. @supports dan tashqarida :root { color-scheme: light; } yozamiz. CSS'dagi color-scheme meta tegdan kuchli — Chrome'da tekshirdik: meta light dark, CSS'da light, tizim qorong'i — maydon oq chizildi. Yangi brauzer esa @supports ichidagi light dark ni oladi.

Nega meta tegni butunlay olib tashlamaymiz? U CSS yuklanishidan oldin ishlaydi. Qorong'i tizimda brauzer sahifaning bo'sh "kanvas"ini darhol to'q rangda chizadi — CSS kelguncha ekran oppoq chaqnamaydi.

4. Tanlovni eslab qolish va yonib-o'chmaslik

4.1 Muammo: FOUC

Foydalanuvchi "Qorong'i" ni tanladi. Tanlovni brauzer xotirasida saqlash kerak — buning uchun localStorage bor: brauzerdagi kichik "daftar", sahifa yopilsa ham yozuv qoladi. U JavaScript orqali ishlaydi; localStorage darsida to'liq o'rganamiz, hozir bilish shart emas.

Keyingi safar sahifa ochilganda skript yozuvni o'qiydi va <html> ga data-tema="qorongi" qo'yadi. Savol — qachon?

Skriptlarni ulash darsida defer ni tavsiya qilgan edik: skript sahifa tayyor bo'lganda ishlaydi. Lekin brauzer undan oldin sahifani chizib ulguradi — tizim rejimida. Keyin skript atributni qo'yadi va sahifa qorong'iga "sakraydi":

sequenceDiagram
  participant B as Brauzer
  participant E as Ekran
  B->>B: HTML va CSS o'qildi
  B->>E: Chizish: tizim rejimi (yorug')
  B->>B: defer skript: data-tema="qorongi"
  B->>E: Qayta chizish: qorong'i
  Note over E: Ko'z oldida chaqnash

Nimaga qarang: foydalanuvchi bir lahza yorug' sahifani ko'rdi. Bu FOUC (Flash of Unstyled/incorrect Content) — "noto'g'ri ko'rinishning chaqnashi". Kechasi qorong'i xonada bu ayniqsa yoqimsiz.

4.2 Yechim: <head> dagi bloklovchi skript

Skriptlarni ulash darsida aytgan edik: oddiy, atributsiz skript faqat "sahifa chizilishidan oldin albatta ishlashi shart" bo'lganda kerak — va misol qilib aynan shu holatni keltirgan edik. Brauzer bunday skriptni topganda to'xtaydi, uni bajaradi, keyin davom etadi. Skript <head> da tursa, u hali birorta piksel chizilmasdan ishlaydi.

«Bahor»ning har sahifasidagi head:

html
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="light dark">
  <title>Choyxona «Bahor»</title>
  <script src="assets/js/tema.js"></script>
  <link rel="stylesheet" href="assets/css/asosiy.css">
</head>

Ichki sahifalarda yo'l ../assets/js/tema.js — CSS yo'li kabi (CSS nima). Skript alohida faylda, chunki «Bahor» CSP'si HTML ichidagi skriptni ham to'sadi (HTML xavfsizligi).

assets/js/tema.js — to'rtta mazmunli qator:

js
// Sahifa chizilishidan OLDIN ishlaydi: saqlangan tanlovni qo'llaydi
try {
  const tema = localStorage.getItem("tema");
  if (tema === "yorug" || tema === "qorongi") {
    document.documentElement.dataset.tema = tema;
  }
} catch {
  // localStorage yopiq bo'lsa — tizim rejimi qoladi
}

Bu JavaScript — uni 11-qismda o'qiy olasiz, hozir faylni aynan shunday ko'chiring. Mazmuni: "daftardan tema yozuvini o'qi; u yorug yoki qorongi bo'lsa, <html> ga data-tema atributini qo'y". try va catch — xavfsizlik to'ri: ba'zi maxfiy rejimlarda localStorage ishlamaydi, shunda skript jim o'tib ketadi va sayt tizim rejimida ochiladi.

Skript kichik va keshlanadi — kutish sezilmaydi. Katta skriptni bu yerga qo'ymang: u butun sahifani to'xtatadi.

4.3 Tanlash tugmasi

Tanlov qayerda qilinadi? «Bahor»ning footer'ida uch holatli guruh — xuddi yuqoridagi natijadagidek radio tugmalar:

html
<fieldset hidden>
  <legend>Mavzu</legend>
  <input type="radio" name="tema" id="tema-tizim" value="tizim">
  <label for="tema-tizim">Tizim</label>
  <input type="radio" name="tema" id="tema-yorug" value="yorug">
  <label for="tema-yorug">Yorug'</label>
  <input type="radio" name="tema" id="tema-qorongi" value="qorongi">
  <label for="tema-qorongi">Qorong'i</label>
</fieldset>

hidden — ataylab. JavaScript ishlamasa, tugmalar hech narsa qilmaydi — ularni ko'rsatish mehmonni aldash bo'lardi. Ikkinchi skript (assets/js/tema-tanlash.js, defer bilan) guruhni ochadi, joriy tanlovni belgilaydi va o'zgarishni saqlaydi. Uning kodini matchMedia va foydalanuvchi sozlamalari darsida yozamiz — u yerda "Tizim" tanlanganda sahifa tizim o'zgarishini jonli kuzatishini ham qo'shamiz. Hozir CSS tomoni tayyor: data-tema qo'yilishi bilan butun sayt o'zgaradi.

Tekshirib ko'ring: Stajyor tema.js ni <head> dan olib, </body> oldiga defer bilan qo'ydi — "sahifa tezroq ochilsin". Nima buziladi?

Javob

Qorong'i rejimni qo'lda tanlagan mehmon (tizimi yorug') har sahifa ochilganda bir lahza yorug' sahifani ko'radi: brauzer avval tizim rejimida chizadi, keyin skript data-tema ni qo'yadi va sahifa qorong'iga sakraydi — FOUC. Bu skript aynan "chizishdan oldin" ishlashi uchun <head> da va atributsiz turadi.

5. Rangdan boshqa narsalar

5.1 Muammo: @media qo'lda tanlovni bilmaydi

Foydalanuvchi afzalliklari darsida rasmlarni @media (prefers-color-scheme: dark) ichida xiralashtirgan edik. Endi bu yetmaydi: Malika tizimi yorug', lekin qo'lda qorong'ini tanlagan. Media query tizimni so'raydi — rasm yorqin qoladi. Aksincha, Otabek tizimi qorong'i, u yorug'ni tanlagan — rasm keraksiz xiralashadi.

Soya va yuzani light-dark() bilan hal qildik — ular color-scheme ga ergashadi. filter esa rang emas. Uning uchun rejim bayrog'i — bitta token — qilamiz va uni ikkala holatda bir marta hisoblaymiz:

css
:root {
  --rasm-filtr: none;
}

@media screen and (prefers-color-scheme: dark) {
  :root:not([data-tema="yorug"]) {
    --rasm-filtr: brightness(0.85);
  }
}

:root[data-tema="qorongi"] {
  --rasm-filtr: brightness(0.85);
}

asos.css da esa bitta qator: img { filter: var(--rasm-filtr); }. Qoida: "tizim qorong'i va foydalanuvchi yorug'ni tanlamagan" yoki "foydalanuvchi qorong'ini tanlagan". Ikkilanish shu bitta tokenda qoladi, komponentlar uni bilmaydi.

Yangi yo'l ham bor: container style queries — @container style(--tema: qorongi) bilan o'zgaruvchi qiymatini so'rash. Baseline ma'lumotiga ko'ra u 2026-yil maydan beri hamma asosiy brauzerda — juda yangi, eski brauzerlarda ishlamaydi. Keyinchalik bunday bayroqlar uchun qulayroq vosita bo'ladi.

Tekshirib ko'ring: Nega rasm filtrini ham light-dark() bilan yozib qo'ya qolmaymiz?

Javob

light-dark() faqat rang qaytaradi. brightness(0.85) esa rang emas — filtr. Shuning uchun filter uchun alohida token (--rasm-filtr) kerak, uni esa @media va data-tema qoidalari almashtiradi. Soya boshqa gap: uning ichida rang bor, rangni light-dark() bera oladi.

5.2 Chop etish

Qog'oz doim oq — Foydalanuvchi afzalliklari darsidagi qoida. Lekin endi qorong'ilikni color-scheme beradi va u chop etishda ham ishlaydi: qorong'i tanlagan mehmon menyuni chop etsa, printerdan to'q yashil varaq chiqadi. Tuzatish — yordamchi.css dagi chop etish blokiga:

css
@media print {
  :root,
  :root[data-tema] {
    color-scheme: light;
    --rasm-filtr: none;
  }
}

:root[data-tema] ham yozildi: :root[data-tema="qorongi"] ning og'irligi (0,2,0), oddiy :root (0,1,0) uni yenga olmasdi. --rasm-filtr ning @media qoidasiga screen and ham shuning uchun: chop etishda u umuman ishlamaydi.

Tekshiruv: Chrome'da 12 holatni sinadik — tizim yorug' va qorong'i, data-tema yo'q, yorug va qorongi, ekran va chop etish. Ekranda fon, maydon va rasm filtri tanlovga to'g'ri ergashdi; chop etishdagi oltitasida ham sahifa yorug', maydonlar oq, filtr yo'q.

6. «Bahor» temasi: yakuniy ko'rinish

tokenlar.css ning ranglar qismi endi shunday (shrift, masofa va qatlamlar Dizayn tokenlari darsidagidek):

css
:root {
  /* Primitivlar */
  --oq: oklch(100% 0 0);
  --yashil-200: oklch(88% 0.08 150.8); /* #b2e7bd */
  --yashil-300: oklch(80.3% 0.098 150.8); /* #8fd19e */
  --yashil-600: oklch(47.5% 0.1 147.7); /* #2f6b3a */
  --yashil-700: oklch(42.1% 0.12 143.1); /* #1a5d1a */
  --yashil-900: oklch(28.2% 0.05 148.6); /* #16301b */
  --qaymoq-50: oklch(98.6% 0.014 84.6); /* #fffaf0 */
  --gisht-300: oklch(75% 0.13 39.8);
  --gisht-600: oklch(53.7% 0.153 39.8); /* #b4461a */
  --kul-300: oklch(80% 0.016 162);
  --kul-600: oklch(49.9% 0.016 162); /* #5b6660 */
  --kul-900: oklch(27.2% 0.019 161); /* #1f2a24 */

  /* Zaxira: light-dark() yo'q brauzer — faqat yorug'.
     CSS'dagi color-scheme meta tegni ham bosadi. */
  color-scheme: light;
  --rang-fon: var(--qaymoq-50);
  --rang-yuza: var(--oq);
  --rang-matn: var(--kul-900);
  --rang-asosiy: var(--yashil-600);
  --rang-asosiy-toq: var(--yashil-700);
  --rang-urgu: var(--gisht-600);
  --rang-ikkinchi: var(--kul-600);
  --rasm-filtr: none;
}

@supports (color: light-dark(white, black)) {
  :root {
    color-scheme: light dark;
    --rang-fon: light-dark(var(--qaymoq-50), var(--yashil-900));
    --rang-yuza: light-dark(
      var(--oq),
      color-mix(in oklch, var(--yashil-900), var(--oq) 7%)
    );
    --rang-matn: light-dark(var(--kul-900), var(--qaymoq-50));
    --rang-asosiy: light-dark(var(--yashil-600), var(--yashil-300));
    --rang-asosiy-toq: light-dark(
      var(--yashil-700),
      var(--yashil-200)
    );
    --rang-urgu: light-dark(var(--gisht-600), var(--gisht-300));
    --rang-ikkinchi: light-dark(var(--kul-600), var(--kul-300));
  }

  /* Foydalanuvchi tanlovi (assets/js/tema.js qo'yadi) */
  :root[data-tema="yorug"] {
    color-scheme: light;
  }

  :root[data-tema="qorongi"] {
    color-scheme: dark;
    --rasm-filtr: brightness(0.85);
  }

  /* Rangdan boshqa narsa uchun bayroq: tizim qorong'i */
  @media screen and (prefers-color-scheme: dark) {
    :root:not([data-tema="yorug"]) {
      --rasm-filtr: brightness(0.85);
    }
  }
}

Ikki eslatma:

  • --rasm-filtr qoidalari ham @supports ichiga kirdi. Eski brauzer faqat yorug' rejimni ko'radi — unga xiralashtirilgan rasm kerak emas.
  • Soyalar (--soya-*) ikki joyda: Dizayn tokenlari darsidagi oddiy variant :root da qoladi — bu zaxira. @supports ichida esa ular "Yuza va balandlik" bo'limidagidek light-dark() bilan qayta yoziladi. Aks holda eski brauzer light-dark() li qatorni o'qiy olmay, soyasiz qolardi.

Qorong'i rejimdagi kontrastlar (formula bilan): matn 13.7:1, asosiy 8.0:1, urg'u 6.1:1, ikkinchi 7.7:1, --rang-asosiy-toq 10.2:1; yuzada matn 11.4:1. Hammasi 4.5:1 dan yuqori.

next-themes — React'da (kursda keyinroq o'rganamiz, hozir bilish shart emas) shu naqshni tayyor qilib beradigan kutubxona. U ham atribut (yoki class) qo'yadi, tanlovni localStorage da saqlaydi va FOUC'ga qarshi <head> ga skript qo'shadi. Ichida — aynan shu darsdagi uch qism. Tailwind'da esa qorong'i rejim dark: varianti bilan yoziladi — Tailwind CSS 3 darsida uni data-tema ga ulashni ko'ramiz.

7. Ko'p uchraydigan xatolar

7.1 color-scheme siz qorong'i palitra

Ranglar qorong'i, lekin forma maydonlari, skrollbar va select ro'yxati oppoq. Tuzatish: :root da color-scheme — u brauzer chizadigan qismlarni ham moslaydi.

7.2 Tanlov faqat @media da

Qorong'i palitra @media (prefers-color-scheme: dark) ichida, tugma esa data-tema qo'yadi. Tizimi yorug' mehmon "Qorong'i" ni bossa — hech narsa o'zgarmaydi. Tuzatish: ranglar light-dark() da, rejim color-scheme da.

7.3 Skript defer bilan

Tanlov ishlaydi, lekin har sahifada chaqnash bor. Tuzatish: tanlovni qo'llaydigan skript <head> da, atributsiz, CSS link idan oldin. Faqat tugmaning ishini qiladigan skript defer bo'lishi mumkin.

7.4 Butun sahifani filter: invert(1)

"Tez qorong'i rejim" hiylasi: html { filter: invert(1) hue-rotate(180deg); }. Rasmlar negativga aylanadi, brend ranglari buziladi, kontrast nazorat qilinmaydi. Tuzatish: palitrani o'zingiz tanlang.

7.5 Tokenni chetlab o'tgan rang

Qaysidir komponentda color: #1f2a24 qolib ketgan — qorong'ida to'q matn to'q fonda. Tuzatish: Ctrl + F → # va oklch( — rang faqat tokenlar.css da (Yakuniy loyiha darsidagi qoida).

8. Mashqlar

1-mashq (oson): qaysi rang?

:root da «Bahor» palitrasi yuqoridagidek. Har holatda body foni qanday bo'ladi — qaymoq yoki to'q yashil?

  1. Tizim qorong'i, data-tema yo'q.
  2. Tizim qorong'i, data-tema="yorug".
  3. Tizim yorug', data-tema="qorongi", chop etish.
  4. Eski brauzer (light-dark() yo'q), tizim qorong'i.

Ishora: "Hammasini color-scheme hal qiladi", "Chop etish" va "Eski brauzer va meta teg" bo'limlari.

Yechim
  1. To'q yashil — color-scheme: light dark, tizimga ergashdi.
  2. Qaymoq — atribut color-scheme: light qildi.
  3. Qaymoq — chop etishda :root[data-tema] ham light ga qaytadi.
  4. Qaymoq — @supports bloki o'qilmadi, zaxira :root da color-scheme: light va yorug' qiymatlar.

2-mashq (o'rta): eski temani ko'chiring

Eski loyihada qorong'i rejim "Eski usul bilan solishtirish" bo'limidagidek yozilgan — to'rt rang ikki marta: tizim uchun @media da va [data-tema="qorongi"] da. Ranglar: fon #fffaf0 / #16301b, matn #1f2a24 / #fffaf0, havola #2f6b3a / #8fd19e, narx #b4461a / oklch(75% 0.13 39.8).

Uni light-dark() va color-scheme ga ko'chiring. Eski brauzerlar uchun zaxirani unutmang.

Ishora: "«Bahor» temasi: yakuniy ko'rinish" bo'limi; komponentlarga tegmang.

Yechim
css
:root {
  color-scheme: light;
  --rang-fon: #fffaf0;
  --rang-matn: #1f2a24;
  --rang-asosiy: #2f6b3a;
  --rang-urgu: #b4461a;
}

@supports (color: light-dark(white, black)) {
  :root {
    color-scheme: light dark;
    --rang-fon: light-dark(#fffaf0, #16301b);
    --rang-matn: light-dark(#1f2a24, #fffaf0);
    --rang-asosiy: light-dark(#2f6b3a, #8fd19e);
    --rang-urgu: light-dark(#b4461a, oklch(75% 0.13 39.8));
  }

  :root[data-tema="yorug"] {
    color-scheme: light;
  }

  :root[data-tema="qorongi"] {
    color-scheme: dark;
  }
}

Qorong'i qiymatlar endi bir marta yozildi. @media (prefers-color-scheme: dark) bloki ranglar uchun butunlay kerak emas. Primitivlar yo'q — kichik loyihada bu ham to'g'ri; ranglar ko'paysa, Dizayn tokenlari darsidagi uch darajaga o'tasiz.

3-mashq (qiyin): kartaning qorong'i bezagi

«Bahor» menyu kartasi yorug' rejimda --soya-2 soyasi va --rang-yuza foni bilan chiziladi. Qorong'i rejimda soya o'chadi, yuza yorqinroq. Dizayner yana bir narsa so'radi: qorong'ida kartaga ingichka chegara qo'shilsin — fonga 12% qaymoq aralashgan rang, 1 piksel. Yorug'da chegara ko'rinmasin.

  1. Buni @media siz, faqat tokenlar bilan yozing — qo'lda tanlovda ham ishlasin.
  2. Nega chegara rangi uchun transparent ishlatish border: none dan qulayroq?

Ishora: light-dark() rang qaytaradi, chegara rangi — rang. color-mix() — Ranglar 3 darsida.

Yechim
css
/* tokenlar.css, @supports ichida */
:root {
  --karta-chegara: light-dark(
    transparent,
    color-mix(in oklch, var(--qaymoq-50) 12%, var(--yashil-900))
  );
}

/* komponentlar.css */
.taom-karta {
  border: 1px solid var(--karta-chegara);
  background: var(--rang-yuza);
  box-shadow: var(--soya-2);
}

--karta-chegara — portfolio'dagi nom (CSS o'zgaruvchilari 2), «Bahor»da ham shu vazifa uchun.

  1. transparent bilan chegara yorug' rejimda ham bor — faqat ko'rinmaydi. Karta o'lchami ikkala rejimda bir xil qoladi. border: none bilan esa qorong'iga o'tganda karta 2 piksel kattalashib, qo'shnilarini surardi. Va none ni light-dark() bilan berib bo'lmaydi — u rang emas.

4-mashq: Portfolio qadami — light-dark() va qo'lda tanlovga tayyorgarlik

Portfolio'da qorong'i rejim Yakuniy loyiha darsidan beri @media screen and (prefers-color-scheme: dark) ichida yozilgan (endi tokenlar.css oxirida va karta soyasi komponentlar.css da). Mavzu tugmasi portfolio'ga JavaScript qismlarida qo'shiladi. Bugun CSS'ni unga tayyorlaymiz:

  1. Beshta rangni light-dark() ga o'tkazing, @supports va yorug' zaxira bilan.
  2. :root[data-tema="yorug"] va :root[data-tema="qorongi"] qoidalarini qo'shing.
  3. Eski @media screen and (prefers-color-scheme: dark) bloklarini (ranglar va karta soyasi) olib tashlang. Soya qorong'ida --soya-1 ning o'zida o'chsin.
  4. Chop etish doim yorug' bo'lsin.
  5. Tekshiring: DevTools → Elements'da <html> ga qo'lda data-tema="qorongi" yozing — sayt tizim yorug' bo'lsa ham qorong'i bo'ladimi? Keyin yorug ni sinang, tizimni DevTools'da qorong'iga emulyatsiya qilib.

Ishora: --soya-1 dagi color-mix(... var(--rang-matn) 8%, transparent) — yorug' rejimda bu shunchaki --rang-matn ning 8% shaffof varianti; uni light-dark() ichida to'g'ridan-to'g'ri yozish mumkin.

Yechim

tokenlar.css — ranglar qismi:

css
:root {
  /* Zaxira — light-dark() yo'q brauzer: faqat yorug' */
  color-scheme: light;
  --rang-matn: oklch(27.2% 0.019 161);
  --rang-fon: oklch(98.2% 0.004 157.2);
  --rang-asosiy: oklch(48.4% 0.097 158.9);
  --rang-ikkinchi: oklch(49.9% 0.016 162);
  --rang-urgu: oklch(53.7% 0.153 39.8);
  /* --rang-chegara, --rang-fon-och — oldingidek, color-mix() */
}

@supports (color: light-dark(white, black)) {
  :root {
    color-scheme: light dark;
    --rang-matn: light-dark(
      oklch(27.2% 0.019 161), oklch(93% 0.012 160));
    --rang-fon: light-dark(
      oklch(98.2% 0.004 157.2), oklch(21% 0.02 160));
    --rang-asosiy: light-dark(
      oklch(48.4% 0.097 158.9), oklch(80% 0.11 158.9));
    --rang-ikkinchi: light-dark(
      oklch(49.9% 0.016 162), oklch(76% 0.016 162));
    --rang-urgu: light-dark(
      oklch(53.7% 0.153 39.8), oklch(75% 0.13 39.8));
  }

  :root[data-tema="yorug"] {
    color-scheme: light;
  }

  :root[data-tema="qorongi"] {
    color-scheme: dark;
  }
}

@media print {
  :root,
  :root[data-tema] {
    color-scheme: light;
  }
}

Soya tokeni:

css
:root {
  --soya-1:
    0 1px 2px light-dark(oklch(27.2% 0.019 161 / 8%), transparent),
    0 4px 12px light-dark(oklch(27.2% 0.019 161 / 10%), transparent);
}

komponentlar.css dagi box-shadow: none bloki endi kerak emas.

Chrome'da loyihalar sahifasini oldingi holat bilan har element bo'yicha solishtirdik:

  • Yorug' rejim, 360 va 1280 px — bitta ham farq yo'q.
  • Qorong'i rejim — faqat kartalarning box-shadow qiymati: oldin none, endi shaffof soya. Ko'zga farq yo'q.
  • Chop etish, tizim qorong'i — farq bor, va u tuzatish. Eski versiyada maydonlar (input, textarea) qog'ozda ham to'q kulrang chizilardi: color-scheme: light dark chop etishda ham tizimga ergashardi, screen and esa faqat palitrani to'xtatgan edi. Endi chop etishda color-scheme: light — maydonlar oq.

5-banddagi sinov: data-tema="qorongi" bilan sayt tizimga qaramay qorong'i, yorug bilan — qorong'i tizimda ham yorug'. Tugmani esa matchMedia va foydalanuvchi sozlamalari darsida qo'shasiz — CSS tayyor.

9. Real ishda

  • Deyarli har zamonaviy sayt va ilova — GitHub, Telegram Web, YouTube — uch holatli tanlovni beradi: tizim, yorug', qorong'i. Brauzer DevTools'ida <html> ni qarang: ko'pincha data-theme yoki class="dark" ni ko'rasiz.
  • FOUC — kod ko'rigida birinchi tekshiriladigan narsalardan biri: "sahifani qorong'i tanlov bilan yangilab ko'rdingmi?"
  • Dizayn tizimlari qorong'i rejimni alohida palitra emas, semantik tokenlarning ikkinchi to'plami sifatida beradi — Figma Variables'dagi "Light/Dark" rejimlari (Figma dasturchi uchun 2).
  • Intervyuda so'raladi: "Qorong'i rejimni qanday qilasiz?", "Sahifa ochilganda yorug' chaqnashni qanday yo'qotasiz?", "color-scheme nima qiladi?", "Nega sof qora fon ishlatmaslik kerak?"

Xulosa

  • To'liq qorong'i rejim: tizimga ergashish, o'zi tanlash, eslab qolish, FOUC yo'qligi va to'g'ri ranglar.
  • Ranglar semantik tokenlarda light-dark() bilan; rejimni faqat color-scheme hal qiladi: light dark, [data-tema="yorug"] → light, [data-tema="qorongi"] → dark.
  • «Bahor» palitrasi yakunlandi: --rang-asosiy-toq qorong'ida --yashil-200 (10.2:1), yangi --rang-yuza, soyalar qorong'ida shaffof, --rasm-filtr bayrog'i.
  • Tanlov localStorage da; <head> dagi atributsiz tema.js uni CSS'dan oldin qo'llaydi — chaqnash yo'q.
  • Meta teg qoladi (erta to'q kanvas), zaxira :root { color-scheme: light } uni eski brauzerda bosadi; chop etish doim yorug'.

Keyingi dars: Sass/SCSS 1: o'zgaruvchilar, nesting va modullar — CSS'ga kompilyatsiya qilinadigan Sass'ni o'rganamiz va ITCSS'dagi bo'sh "Tools" qatlami nimaga kerakligini ko'ramiz.

Manbalar

  • MDN: "color-scheme", "light-dark()", "prefers-color-scheme", "", "Window.localStorage" — developer.mozilla.org
  • web.dev: "prefers-color-scheme: Hello darkness, my old friend" — web.dev
  • Material Design 3: "Color roles", qorong'i mavzuda yuza va balandlik — m3.material.io
  • web-features (Baseline): "light-dark", "color-scheme", "container-style-queries" — github.com/web-platform-dx/web-features
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Qorong'i rejim va temalash: to'liq yechim — IlmHamroh