IlmHamroh
JavaScript Full-stack/6-qism. CSS: harakat, zamonaviy CSS va dizayn48/57-dars29 daqiqa
Mundarija (39)

CSS tugmalar tizimi: variantlar, o'lchamlar, holatlar va yuklanish

Qisqacha: Tugmalar tizimi — saytdagi hamma tugma bitta asos class'dan (.tugma) chiqadi, farqi faqat bir necha ichki o'zgaruvchida: fon, matn va chegara rangi. Variant (asosiy, ikkinchi, shaffof, xavfli) va o'lcham (kichik, o'rta, katta) shu o'zgaruvchilarni almashtiradi, holatlar (hover, bosilgan, fokus, nofaol, yuklanmoqda) esa hamma variant uchun bitta qoidada yoziladi. Harakat qilsa — <button>, boshqa sahifaga olib borsa — <a>; ko'rinish bir xil, teg har xil.

Bu darsda

  • <button> va <a> ni vazifasiga qarab tanlaysiz va ikkalasini piksel-ma-piksel bir xil ko'rinishga keltirasiz.
  • Tugma reset'ini va to'rt variantni ichki o'zgaruvchilar bilan yozasiz.
  • O'lcham tokenlari, hover, bosilgan, fokus va nofaol holatlarni hamma variant uchun bir marta yozasiz.
  • Ikonkali tugma va faqat ikonkadan iborat tugmani accessible qilasiz.
  • Yuklanish holatini tugma eni sakramaydigan qilib chizasiz va tugmalarni guruhlaysiz.

Oldin bilishingiz kerak: Tugma yoki havola: to'g'ri tanlov, UI/UX asoslari, Micro-interaktsiyalar, Dizayn tokenlari.

1. Nega bu kerak?

O'tgan darsda SVG va ikonka tizimi bilan tanishdik. Bugun ikonkalar birinchi marta ishga tushadi — tugma ichida. Bu dars bilan 06-qismning "komponentlar" bo'limi boshlanadi: o'rganganlarni real interfeys bo'laklariga yig'amiz.

Jasur aka «Bahor» saytiga yangi stajyor oldi. Bir oydan keyin sahifalarda yettita har xil "tugma" topdik. Bron sahifasida button yashil, burchagi 8 piksel; bosh sahifadagi .bron-havola biroz balandroq; menyuda kimdir border-radius: 20px yozgan; "Bronni bekor qilish" oddiy qizil matn. Hover faqat ikkitasida bor, fokus halqasi esa bittasida ham yo'q.

Har tugma alohida yozilgan: dizayner "burchaklarni 6 piksel qiling" desa, yettita joyni o'zgartirish kerak — bittasi albatta esdan chiqadi.

Bugun bunga yakun yasaymiz. Oldingi darslarda uchta va'da bergan edik:

  1. Tugma yoki havola darsida: havola vazifasidagi "Buyurtma berish" a bilan yoziladi va CSS bilan tugmaga o'xshatiladi.
  2. UI/UX asoslari darsida: yuklanishda tugma eni sakramasin.
  3. Micro-interaktsiyalar darsida: aria-disabled va yuklanish holati bilan tugmalar tizimi.

Bu darsda bitta komponent (component) quramiz — saytda qayta-qayta ishlatiladigan, o'z qoidalariga ega interfeys bo'lagi. Xuddi LEGO g'ishtchasi kabi: rangi va o'lchami har xil, lekin hammasi bir-biriga mos tushadi.

2. <button> yoki <a>: avval teg

2.1 Qoida

Tugma yoki havola darsidagi qoidani eslaymiz:

Nima qiladi Teg «Bahor»da misol
Boshqa sahifaga yoki joyga olib boradi <a href> "Stolni band qilish" (bron sahifasiga)
Shu sahifada harakat qiladi <button type="button"> "Menyuni ochish", "Yopish"
Formani yuboradi <button type="submit"> "Yuborish"

CSS bu qoidani o'zgartira olmaydi — u faqat ko'rinishni beradi. Ko'rinish bir xil bo'lishi mumkin, lekin klaviatura xulqi har xil. Chrome'da tekshirdik: button Enter bilan ham, Space bilan ham bosiladi; havola esa faqat Enter bilan. Ekran o'quvchi ham ularni boshqacha e'lon qiladi — "tugma" va "havola". Malika (NVDA) shu so'zga qarab nima bo'lishini kutadi.

2.2 Bir xil ko'rinish: birinchi urinish

Stajyor ikkalasiga bitta class berdi:

html
<style>
  body { font-family: system-ui, sans-serif; }
  .tugma {
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    padding: 0.5em 1.25em;
    border: 2px solid transparent;
    border-radius: 0.5rem;
    background: #2f6b3a;
    color: #fffaf0;
    text-decoration: none;
  }
</style>
<p>
  <button type="button">Oddiy button</button>
  <a href="#bron">Oddiy havola</a>
</p>
<p>
  <button class="tugma" type="button">Band qilish</button>
  <a class="tugma" href="#bron">Band qilish</a>
</p>

Nimaga qarang: pastki qatorda ikki "tugma" bir xil emas. Chapdagisi (button) past va kichik shriftli, o'ngdagisi (a) baland va shrifti kattaroq.

Chrome'da o'lchadik — ikkita sabab chiqdi:

  • Shrift. Brauzer button ga o'zining shriftini beradi: 13.33 piksel, Arial. Havola esa sahifa shriftini meros oladi — 16 piksel. Meros darsida aytgan edik: forma elementlari shriftni meros olmaydi. Tuzatish — font: inherit.
  • Balandlik. button 44 piksel, a esa 64 piksel. Brauzer button ga box-sizing: border-box beradi, havola esa content-box da. min-block-size: 2.75rem havolada faqat ichki qismga tegdi, ustiga padding va border qo'shildi: 44 + 16 + 4 = 64. box-sizing darsidagi tuzoqning o'zi.

«Bahor»da reset hamma elementga border-box beradi (CSS reset), shuning uchun u yerda ikkinchi muammo ko'rinmaydi. Lekin komponent reset'ga tayanmasligi yaxshi: uni boshqa loyihaga ko'chirsangiz, u yerda reset boshqacha bo'lishi mumkin. Shuning uchun box-sizing ni tugmaning o'zida ham yozamiz.

Tekshirib ko'ring: Havolada href yo'q: <a class="tugma">Band qilish</a>. Ko'rinishi tugmadek. Nima yetishmaydi?

Javob

Deyarli hammasi. Chrome'da tekshirdik: href siz a ga Tab bilan borib bo'lmaydi va ekran o'quvchi uni havola ham, tugma ham demaydi — oddiy matn. Ko'rinish "bosing" deydi, element esa bosilmaydi. Havola bo'lsa — href shart; harakat bo'lsa — button.

3. Asos: reset va ichki o'zgaruvchilar

3.1 Tugma asosi

Endi tizimning yuragi — asos class'i. Unda ikki guruh qoida bor: reset (brauzer farqlarini yo'qotish) va ichki o'zgaruvchilar (variantlar almashtiradigan joy).

css
.tugma {
  /* Ichki o'zgaruvchilar: variantlar shularni almashtiradi */
  --_fon: var(--rang-asosiy);
  --_matn: var(--rang-fon);
  --_chegara: var(--_fon);
  --_balandlik: 2.75rem;

  /* Reset: button ham, a ham bir xil boshlansin */
  box-sizing: border-box;
  appearance: none;
  font: inherit;
  text-decoration: none;
  cursor: pointer;

  /* Ko'rinish */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-block-size: var(--_balandlik);
  padding: 0.25em 1.25em;
  border: 2px solid var(--_chegara);
  border-radius: var(--burchak-m);
  background: var(--_fon);
  color: var(--_matn);
  font-weight: 600;
  line-height: 1.2;
}

Qatorma-qator:

  • --_fon, --_matn, --_chegara — pastki chiziqli ichki o'zgaruvchilar (CSS o'zgaruvchilari 2 darsidagi uslub). Tashqaridan ularga tegilmaydi, faqat variantlar almashtiradi.
  • --_chegara: var(--_fon) — sukut bo'yicha chegara fon bilan bir xil, ya'ni ko'rinmaydi. Lekin u bor — bu keyinroq muhim bo'ladi.
  • appearance: none — brauzerning "mahalliy" tugma ko'rinishini o'chiradi (Forma elementlarini stillash). Chrome'da fon berishning o'zi yetadi, lekin eski iPhone Safari'da input type="submit" o'z gradientini chizardi. appearance Baseline, 2024-yil sentabridan keng tarqalgan.
  • inline-flex + gap — ikonka va matn yonma-yon, orasi shriftga qarab (Flex'da tekislash).
  • min-block-size, height emas — matn ikki qatorga o'tsa, tugma o'sadi, matn toshib chiqmaydi.
  • padding em da — ataylab. Tugma shrifti kattalashsa, ichki masofa ham u bilan o'sadi. Spacing tizimi darsida maydonlar uchun xuddi shunday "ongli istisno" qilgan edik.
  • cursor: pointer — button ustida brauzer strelka ko'rsatadi, havola ustida esa qo'l. Bir xil bo'lsin deb qo'l tanladik. Baseline ma'lumotiga ko'ra cursor Baseline emas — telefon brauzerlarida sichqoncha kursori umuman yo'q. Zaxira kerak emas: qoida ishlamasa, shunchaki kursor o'zgarmaydi.

3.2 Variantlar

Variant (variant) — bir komponentning vazifasiga qarab farq qiladigan ko'rinishi. Sahifada bitta asosiy harakat va bir nechta ikkinchi darajali harakat bo'ladi (Vizual ierarxiya). Variantlar shu ierarxiyani ko'rsatadi:

Variant «Bahor»da Qachon
Asosiy (primary) "Stolni band qilish" Sahifadagi eng muhim harakat — bitta
Ikkinchi (secondary) "Menyuni ko'rish" Muhim, lekin asosiy emas
Shaffof (ghost) "Bekor qilish" Past darajali harakat
Xavfli (destructive) "Bronni o'chirish" Qaytarib bo'lmaydigan amal

Asos class'ida hamma narsa bor, variant faqat uchta o'zgaruvchini almashtiradi:

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
    --rang-xato: oklch(52% 0.19 27);
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
    --_chegara: var(--_fon);
    box-sizing: border-box;
    appearance: none;
    font: inherit;
    text-decoration: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    min-block-size: 2.75rem;
    padding: 0.25em 1.25em;
    border: 2px solid var(--_chegara);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
    line-height: 1.2;
  }
  .tugma.ikkinchi {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: var(--rang-asosiy);
  }
  .tugma.shaffof {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: transparent;
  }
  .tugma.xavfli {
    --_fon: var(--rang-xato);
  }
</style>
<p>
  <a class="tugma" href="#bron">Stolni band qilish</a>
  <a class="tugma ikkinchi" href="#menyu">Menyuni ko'rish</a>
</p>
<p>
  <button class="tugma shaffof" type="button">Bekor qilish</button>
  <button class="tugma xavfli" type="button">Bronni o'chirish</button>
</p>

Nimaga qarang: to'rt tugma to'rt xil ko'rinishda, lekin balandligi, burchagi, shrifti va ichki masofasi bir xil — ular bir oilaga tegishli ekani ko'rinib turibdi. Birinchi ikkitasi havola (a), keyingi ikkitasi button — farqini ko'z sezmaydi. Chrome'da o'lchadik: to'rttasining ham balandligi 44 piksel.

Kontrast (formula bilan, qaymoq fonda): asosiy tugmada qaymoq matn yashil fonda — 6.1:1, ikkinchi va shaffof tugmada yashil matn — 6.1:1, xavfli tugmada qaymoq matn qizil fonda — 5.8:1. Hammasi 4.5 dan yuqori (Rang nazariyasi). --rang-xato — o'sha darsdagi semantik xato rangi.

«Bahor» class uslubi — blok va qisqa holat so'zi (CSS metodologiyalari): class="tugma ikkinchi". BEM'da bu tugma tugma--ikkinchi bo'lardi.

Tekshirib ko'ring: Xavfli variantda faqat --_fon yozildi. Nega chegara ham qizil bo'ldi?

Javob

Asosda --_chegara: var(--_fon) yozilgan. O'zgaruvchi ichidagi var() elementning o'zida hisoblanadi — o'sha elementdagi --_fon qiymati bilan. .tugma.xavfli da --_fon qizil, demak --_chegara ham qizil. Shuning uchun asosiy va xavfli variantga chegarani alohida yozish shart emas.

4. O'lchamlar

Tugma har joyda bir xil kattalikda bo'lmaydi: jadval qatoridagi "Tahrirlash" kichik, bosh sahifadagi "Stolni band qilish" katta. O'lcham modifikatori ikki narsani almashtiradi — shrift va minimal balandlik. padding em da bo'lgani uchun o'zi moslashadi:

css
.tugma.kichik {
  --_balandlik: 2rem;
  font-size: var(--step--1);
}

.tugma.katta {
  --_balandlik: 3.25rem;
  font-size: var(--step-1);
}

Chrome'da telefon enida (360 piksel) o'lchadik: kichik — 32, o'rta — 44, katta — 52 piksel balandlik. Bosish maydoni qoidasi (UI/UX asoslari): talab — 24, maqsad — 44. Kichik tugma talabdan o'tadi, lekin maqsadga yetmaydi. Shuning uchun kichik tugma faqat sichqoncha bilan ishlanadigan zich joylarda (jadval, admin panel) va hech qachon telefondagi asosiy harakat uchun emas.

Nega height emas, --_balandlik? Sababi — ikonkali tugma. U kvadrat bo'lishi uchun o'z enini ham shu o'zgaruvchidan oladi (keyingi bo'limlarda ko'ramiz). O'lcham bitta joyda, ikki xususiyat undan foydalanadi.

Tekshirib ko'ring: Kichik tugmaning shrifti 14 piksel bo'lsin. padding: 0.25em 1.25em gorizontal tomonda necha piksel bo'ladi? piksel.

Javob

1.25 × 14 = 17.5 piksel. em — elementning o'z shrifti (O'lcham birliklari). O'rta tugmada (16–18 piksel) esa 20–22.5 piksel. Ichki masofa shrift bilan birga o'sadi va kichrayadi — nisbat saqlanadi.

5. Holatlar: hamma variant uchun bir marta

5.1 Muammo

UI/UX asoslari darsida tugmaning olti holatini ko'rgan edik. To'rt variant × olti holat = 24 ta kombinatsiya. Har biriga alohida rang yozsak, tizim yana tartibsizlikka aylanadi.

Yechim — holatni nisbiy yozish: "hozirgi fonga biroz matn rangini aralashtir". color-mix() (Ranglar 3) har qanday fon bilan ishlaydi:

  • yashil fon + 15% to'q matn rangi → to'qroq yashil;
  • qizil fon + 15% → to'qroq qizil;
  • shaffof fon + 15% → matn rangining 15% li "soyasi" — och yashil-kulrang dog'.

Bitta qoida — to'rt variant. Qorong'i rejimda esa --rang-matn och bo'ladi, shuning uchun hover ochroq chiqadi. Rang nazariyasi darsida aytilgan "qorong'ida teskarisi" o'z-o'zidan bajariladi.

5.2 Holatlar kodi

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-matn: #1f2a24;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
    --rang-ikkinchi: #5b6660;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
    --_chegara: var(--_fon);
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    padding: 0.25em 1.25em;
    border: 2px solid var(--_chegara);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
  }
  .tugma.ikkinchi {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: var(--rang-asosiy);
  }
  @media (hover: hover) {
    .tugma:not(:disabled, [aria-disabled="true"]):hover {
      background: color-mix(in oklch, var(--_fon),
        var(--rang-matn) 15%);
    }
  }
  .tugma:not(:disabled, [aria-disabled="true"]):active {
    background: color-mix(in oklch, var(--_fon),
      var(--rang-matn) 25%);
  }
  .tugma:focus-visible {
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  .tugma:is(:disabled, [aria-disabled="true"]) {
    --_fon: oklch(90% 0.01 162);
    --_matn: var(--rang-ikkinchi);
    --_chegara: var(--_fon);
    cursor: not-allowed;
  }
  @media (prefers-reduced-motion: no-preference) {
    .tugma {
      transition: background-color 0.15s, scale 0.1s ease-out;
    }
    .tugma:not(:disabled, [aria-disabled="true"]):active {
      scale: 0.97;
    }
  }
</style>
<p>
  <button class="tugma" type="button">Band qilish</button>
  <button class="tugma ikkinchi" type="button">Menyu</button>
</p>
<p>
  <button class="tugma" type="button" disabled>disabled</button>
  <button class="tugma" type="button" aria-disabled="true">
    aria-disabled
  </button>
</p>

Nimaga qarang: sichqonchani yuqoridagi ikki tugma ustiga olib boring — yashil tugma to'qlashadi, ramkali tugma ichida och yashil-kulrang dog' paydo bo'ladi. Bosib turing — yana to'qroq va 3% kichrayadi. Tab bosing: fokus halqasi tugmadan 2 piksel narida, 3 piksel qalinlikda. Pastki ikkita tugma kulrang, hover va bosilishga javob bermaydi, sichqoncha ustida "taqiq" kursori.

Endi Tab bilan yurib ko'ring. Chrome'da tekshirdik: fokus "Band qilish" → "Menyu" → "aria-disabled" ga o'tadi. disabled tugma o'tkazib yuboriladi.

5.3 disabled va aria-disabled farqi

disabled aria-disabled="true"
Tab bilan boriladimi Yo'q Ha
Ekran o'quvchi "tugma, mavjud emas" "tugma, mavjud emas"
Bosilsa Hech narsa bo'lmaydi Bosiladi — skript to'xtatishi kerak
CSS selektor :disabled [aria-disabled="true"]

disabled tugmani Malika umuman topmasligi mumkin: u Tab bilan sahifani aylanadi va tugma ro'yxatda yo'q. aria-disabled esa tugmani joyida qoldiradi — Malika "Yuborish, mavjud emas" ni eshitadi va yonidagi sababni o'qiydi ("Avval sanani tanlang"). Lekin aria-disabled bosishni to'xtatmaydi: buni JavaScript qiladi — tilni 08-qismdan, bosish hodisasini ushlashni 09-qismdan o'rganasiz. CSS tomoni esa tayyor: :is(:disabled, [aria-disabled="true"]) ikkalasini bir xil chizadi.

Tekshirib ko'ring: Bron formasida "Yuborish" tugmasi sana tanlanmaguncha ishlamasligi kerak, yonida "Avval sanani tanlang" yozuvi bor. disabled yoki aria-disabled — qaysi biri?

Javob

aria-disabled="true". Malika Tab bilan tugmaga yetib, "mavjud emas" ni eshitadi va yonidagi sababni o'qiydi. disabled bo'lsa, tugma Tab ro'yxatidan tushib qoladi — Malika uni umuman topmaydi va nega yuborib bo'lmasligini bilmaydi.

Havolani (a) "nofaol" qilib bo'lmaydi — unda disabled atributi yo'q. Havola hozir ishlamasa, href ni olib tashlang yoki uni oddiy matnga almashtiring.

5.4 Kodni o'qiymiz

  • :not(:disabled, [aria-disabled="true"]) — hover va bosilish faqat faol tugmada. Busiz nofaol tugma ham hover'da to'qlashardi — "meni bosish mumkin" degan yolg'on signal.
  • Hover @media (hover: hover) ichida — telefonda "yopishib qoladigan" hover bo'lmasin (Mobil qurilma tuzoqlari). :active esa tashqarida: bosilish telefonda ham bor.
  • transition va scale — no-preference ichida. Harakat kamaytirilganda tugma kichraymaydi, lekin rang baribir o'zgaradi — harakat etikasi darsidagi "o'chirish emas, almashtirish". transition: all emas — faqat kerakli xususiyatlar (Rendering pipeline).
  • Fokus halqasi — ikki rangli (CSS'da accessibility): tashqi to'q outline va tugma bilan halqa orasidagi qaymoq chiziq (box-shadow). Halqa tugmadan tashqarida, shuning uchun yashil ham, qizil tugmada ham bir xil ko'rinadi — foydalanuvchi uni bir qarashda taniydi. «Bahor»da bu qoida asos.css da hamma element uchun bitta; natijalarda u faqat namoyish uchun takrorlangan.

Diqqat: Hover va bosilish qoidalarining og'irligi bir xil — (0,3,0). Sichqoncha bilan bosganda ikkalasi birga ishlaydi va keyin yozilgani yutadi (Kaskad). Shuning uchun hover bloki :active dan oldin turibdi. Tartibni almashtirsangiz, bosilgan tugma hover rangida qoladi — portfolio'da UI/UX asoslari darsida xuddi shu tartibni tanlagan edik.

5.5 Majburiy ranglar rejimi

CSS'da accessibility darsida ko'rdik: majburiy ranglar rejimida (Windows'dagi "Contrast themes") brauzer fonlarni o'chiradi va faqat fon bilan yasalgan tugma oddiy yozuvga aylanadi. O'sha darsda ikki yechim bor edi: doimiy shaffof chegara yoki @media (forced-colors: active) ichida chegara.

Tugmalar tizimida birinchisini — doimiy chegarani — tanladik. Sabab: ramkali "ikkinchi" variantda chegara baribir bor. Hamma variant bir xil o'lchamda bo'lishi uchun asosda ham 2 piksel chegara turadi: --_chegara: var(--_fon), shaffof variantda transparent. Chrome'da rejimni emulyatsiya qilib tekshirdik: chegarasiz tugmadan qora fonda faqat oq so'z qoldi, bizning tugmalar esa oq ramka ichida — tugmadek ko'rinadi.

6. Ikonkali tugmalar

6.1 Ikonka va matn

SVG va ikonka tizimi darsidagi ikonka — sprite'dagi symbol va .ikonka class'li <svg><use></svg> — tugmaga o'zgarishsiz kiradi. currentColor bilan u tugma matni rangini oladi, 1.25em o'lcham bilan shriftga qarab o'sadi. Faqat bitta shart — u bezak, shuning uchun aria-hidden="true".

6.2 Faqat ikonka

Qidiruv, yopish, menyu tugmalarida ko'pincha so'z yo'q, faqat belgi. Ko'zi ko'radigan odam belgini taniydi. Ekran o'quvchi esa belgini o'qiy olmaydi — tugmaning nomi bo'sh qoladi. Nom aria-label bilan beriladi (ARIA asoslari):

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
    --_chegara: var(--_fon);
    --_balandlik: 2.75rem;
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    min-block-size: var(--_balandlik);
    padding: 0.25em 1.25em;
    border: 2px solid var(--_chegara);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
    text-decoration: none;
  }
  .tugma.ikkinchi {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: var(--rang-asosiy);
  }
  .sprite { display: none; }
  .ikonka {
    flex: none;
    inline-size: 1.25em;
    block-size: 1.25em;
    fill: currentColor;
  }
  .tugma.belgi {
    inline-size: var(--_balandlik);
    padding: 0;
  }
  .tugma:focus-visible {
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
</style>
<svg class="sprite">
  <symbol id="i-strelka" viewBox="0 0 24 24" fill="none"
    stroke="currentColor" stroke-width="2">
    <path d="M5 12h14M13 6l6 6-6 6" />
  </symbol>
  <symbol id="i-qidiruv" viewBox="0 0 24 24" fill="none"
    stroke="currentColor" stroke-width="2">
    <circle cx="11" cy="11" r="7" />
    <path d="M20 20l-4-4" />
  </symbol>
  <symbol id="i-yopish" viewBox="0 0 24 24" fill="none"
    stroke="currentColor" stroke-width="2">
    <path d="M6 6l12 12M18 6 6 18" />
  </symbol>
</svg>
<p>
  <a class="tugma" href="#bron">
    <svg class="ikonka" aria-hidden="true">
      <use href="#i-strelka"/></svg>
    Band qilish
  </a>
  <button class="tugma ikkinchi belgi" type="button"
    aria-label="Qidirish">
    <svg class="ikonka" aria-hidden="true">
      <use href="#i-qidiruv"/></svg>
  </button>
  <button class="tugma ikkinchi belgi" type="button"
    aria-label="Yopish">
    <svg class="ikonka" aria-hidden="true">
      <use href="#i-yopish"/></svg>
  </button>
</p>

Nimaga qarang: birinchi tugmada strelka va so'z yonma-yon, strelka qaymoq rangda — tugma matni bilan bir xil. Keyingi ikkitasi kvadrat, 44 × 44 piksel, ichida faqat belgi. Chrome'ning accessibility daraxtida tekshirdik: ular "Qidirish, tugma" va "Yopish, tugma" deb nomlanadi — aria-label ishladi.

Bir necha nozik joy:

  • .ikonka dagi flex: none — uzun matnli tor tugmada ikonka siqilib qolmasin (flex algoritmi). Chiziqli belgilar uchun fill="none" va stroke atributlari symbol ga yozilgan: .ikonka ning fill: currentColor i meros bo'lib keladi, symbol dagi atribut esa undan ustun.
  • .belgi eni = --_balandlik — o'lcham bitta joyda, kvadrat har o'lchamda saqlanadi: class="tugma kichik belgi" — 32 × 32.
  • aria-label yoki ko'rinmas matn. Ikkinchi yo'l: tugma ichiga <span class="korinmas">Qidirish</span>. Ikkalasi ham to'g'ri — farqini CSS'da accessibility darsida ko'rgan edik.
  • Ko'rish orqali ishlaydigan foydalanuvchiga ham belgi har doim tushunarli emas. Belgining ma'nosini sichqoncha ustida ko'rsatadigan tooltip — Tooltip, dropdown va toast darsida.

Tekshirib ko'ring: Faqat ikonkali "Yopish" tugmasidan aria-label o'chirib yuborildi. Ekran o'quvchi nima deydi va nega?

Javob

Faqat "tugma" — nomsiz. Ichidagi svg aria-hidden="true", ya'ni ekran o'quvchi uchun yo'q. Boshqa matn ham yo'q. Malika tugma borligini biladi, lekin nima qilishini bilmaydi.

7. Yuklanish holati: tugma sakramasin

7.1 Muammo

Mehmon "Yuborish" ni bosdi. So'rov serverga ketdi, javob 2 soniyadan keyin keladi. Shu vaqtda tugma ikki narsani aytishi kerak: "ishlayapman" va "qayta bosmang".

Micro-interaktsiyalar darsida matnni "Yuborilmoqda…" ga almashtirgan edik. Muammo: yangi matn uzunroq. Chrome'da o'lchadik — "Yuborish" tugmasi 107, "Yuborilmoqda…" 159 piksel. Tugma 52 pikselga kengayadi va yonidagi tugmani suradi. Mehmon "Bekor qilish" ni bosmoqchi edi — u joyidan qochib ketdi.

7.2 Yechim: matn joyida, lekin ko'rinmas

Matnni almashtirmaymiz. Uni shaffof qilamiz — joyi saqlanadi — va ustiga aylanuvchi halqa chizamiz:

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    padding: 0.25em 1.25em;
    border: 2px solid var(--_fon);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
  }
  .tugma[aria-busy="true"] {
    position: relative;
    color: transparent;
    cursor: progress;
  }
  .tugma[aria-busy="true"]::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    inline-size: 1.25em;
    block-size: 1.25em;
    box-sizing: border-box;
    border: 2px solid var(--_matn);
    border-inline-end-color: transparent;
    border-radius: 50%;
    animation: miltilla 1s ease-in-out infinite alternate;
  }
  @media (prefers-reduced-motion: no-preference) {
    .tugma[aria-busy="true"]::after {
      animation: aylan 0.8s linear infinite;
    }
  }
  @keyframes aylan {
    to { rotate: 1turn; }
  }
  @keyframes miltilla {
    to { opacity: 0.3; }
  }
</style>
<p>
  <button class="tugma" type="submit">Yuborish</button>
  <button class="tugma" type="submit" aria-busy="true">
    Yuborish
  </button>
</p>

Nimaga qarang: ikki tugma bir xil enda. O'ngdagisining yozuvi ko'rinmaydi, o'rtasida qaymoq rangli halqa aylanadi. Chrome'da o'lchadik: ikkalasining eni aynan 107 piksel — sakrash yo'q.

Qanday ishlaydi:

  • color: transparent — matn chiziladi, lekin rangsiz. Tugma eni matnga qarab qoladi.
  • Halqa ::after da — position: absolute; inset: 0; margin: auto va aniq o'lcham — position darsidagi markazlash. Halqa rangi var(--_matn), currentColor emas: currentColor endi shaffof.
  • Nega visibility: hidden emas? U ham joyni saqlaydi, lekin matnni accessibility daraxtidan ham olib tashlaydi — tugma nomsiz qoladi. color: transparent da Chrome tugmani baribir "Yuborish, tugma" deb nomlaydi — tekshirdik.
  • Harakat kamaytirilganda halqa aylanmaydi, miltillaydi — shaffofligi 1 dan 0.3 gacha o'zgaradi. Shaffoflik joy o'zgartirmaydi, bosh aylantirmaydi (harakat etikasi). Harakatsiz halqa esa "qotib qoldi" degan taassurot berardi.
  • aria-busy="true" — "bu element yangilanmoqda" degan standart atribut. Uni so'rov boshlanganda JavaScript qo'yadi va javob kelganda olib tashlaydi. Tilni 08-qismdan, atributni sahifada qo'yishni 09-qismdan o'rganasiz; CSS tomoni tayyor — atribut paydo bo'lishi bilan tugma o'zgaradi.

Maslahat: Yuklanish holatida ikkinchi bosishni ham to'xtatish kerak — buni ham skript qiladi. pointer-events: none ni qo'shib qo'yish vasvasasi bo'ladi, lekin u Enter bosishni to'xtatmaydi — klaviatura foydalanuvchisi baribir ikkinchi so'rovni yuboradi.

Tekshirib ko'ring: Ikonkali tugma ("→ Band qilish") yuklanish holatiga o'tdi. Strelka nima bo'ladi?

Javob

U ham yo'qoladi. Strelka stroke="currentColor" bilan chizilgan, currentColor esa endi transparent. Faqat halqa qoladi — aynan kerakli natija, alohida qoida yozish shart emas.

8. Tugmalar guruhi

8.1 Harakatlar qatori

Oyna yoki forma oxirida bir nechta tugma yonma-yon turadi: "Bekor qilish" va "Saqlash". Ular uchun flex + gap + flex-wrap yetadi — tor ekranda ikkinchi qatorga o'tadi (Flex naqshlari). Qoida: asosiy harakat oxirida. Ko'zimiz chapdan o'ngga yuradi va oxirgi tugma "keyingi qadam" bo'lib qabul qilinadi.

8.2 Birlashgan guruh

Ba'zan tugmalar bitta tanlovning variantlari: menyu sahifasida "Ro'yxat" va "Jadval" ko'rinishlari. Ular yopishib turadi, faqat tashqi burchaklari yumaloq:

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    min-block-size: 2.75rem;
    padding: 0.25em 1.25em;
    border: 2px solid var(--rang-asosiy);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
  }
  .tugma[aria-pressed="true"] {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
  }
  .tugma:focus-visible {
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  .tugma-guruh {
    display: inline-flex;
  }
  .tugma-guruh > .tugma:not(:first-child) {
    margin-inline-start: -2px;
    border-start-start-radius: 0;
    border-end-start-radius: 0;
  }
  .tugma-guruh > .tugma:not(:last-child) {
    border-start-end-radius: 0;
    border-end-end-radius: 0;
  }
  .tugma-guruh > .tugma:focus-visible {
    z-index: 1;
  }
</style>
<div class="tugma-guruh" role="group" aria-label="Menyu ko'rinishi">
  <button class="tugma" type="button" aria-pressed="true">
    Ro'yxat
  </button>
  <button class="tugma" type="button" aria-pressed="false">
    Jadval
  </button>
  <button class="tugma" type="button" aria-pressed="false">
    Rasmlar
  </button>
</div>

Nimaga qarang: uchta tugma bitta "tasma" bo'lib turibdi, faqat chetki burchaklar yumaloq. Tanlangani ("Ro'yxat") yashil fonli. Tugmalar orasidagi chiziq qalin emas — 2 piksel. Tab bilan o'rtadagi tugmaga boring: fokus halqasi qo'shnilarning ostida qolmay, to'liq ko'rinadi.

  • margin-inline-start: -2px — qo'shni chegaralar ustma-ust tushadi, ikki barobar qalin chiziq bo'lmaydi (Margin sirlari).
  • Mantiqiy burchak xususiyatlari (border-start-start-radius) — o'ngdan chapga yoziladigan tilda ham to'g'ri chetlar yumaloq (Mantiqiy xususiyatlar).
  • z-index: 1 fokusda — flex elementida z-index position siz ham ishlaydi (z-index). Busiz o'ng qo'shni halqaning bir qismini yopib qo'yardi.
  • role="group" + aria-label — ekran o'quvchi "Menyu ko'rinishi, guruh" deydi.
  • aria-pressed — "bosilgan/bosilmagan" holatli tugma. Uni almashtirish — yana JavaScript ishi (09-qismda). Agar tanlov formada yuborilsa, tugma emas, radio tugmalar kerak — ularni shunday ko'rinishga keltirishni Forma komponentlari darsida ko'ramiz.

9. «Bahor»ning komponentlar.css iga

Hammasini bir joyga yig'amiz. «Bahor»da tokenlar allaqachon bor (Dizayn tokenlari), shuning uchun xom qiymat deyarli yo'q:

css
/* === Tugma (Tugmalar tizimi darsi) === */
.tugma {
  --_fon: var(--rang-asosiy);
  --_matn: var(--rang-fon);
  --_chegara: var(--_fon);
  --_balandlik: 2.75rem;

  box-sizing: border-box;
  appearance: none;
  font: inherit;
  text-decoration: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-block-size: var(--_balandlik);
  padding: 0.25em 1.25em; /* shrift bilan o'sadi — ataylab em */
  border: 2px solid var(--_chegara); /* forced colors uchun */
  border-radius: var(--burchak-m);
  background: var(--_fon);
  color: var(--_matn);
  font-weight: 600;
  line-height: 1.2;
}

/* Variantlar */
.tugma.ikkinchi {
  --_fon: transparent;
  --_matn: var(--rang-asosiy);
  --_chegara: var(--rang-asosiy);
}

.tugma.shaffof {
  --_fon: transparent;
  --_matn: var(--rang-asosiy);
  --_chegara: transparent;
}

.tugma.xavfli {
  --_fon: var(--rang-xato);
}

/* O'lchamlar */
.tugma.kichik {
  --_balandlik: 2rem;
  font-size: var(--step--1);
}

.tugma.katta {
  --_balandlik: 3.25rem;
  font-size: var(--step-1);
}

/* Faqat ikonka (.ikonka o'lchami — SVG darsidan) */
.tugma.belgi {
  inline-size: var(--_balandlik);
  padding: 0;
}

/* Holatlar: hover bosilgandan oldin */
@media (hover: hover) {
  .tugma:not(:disabled, [aria-disabled="true"]):hover {
    background: color-mix(in oklch, var(--_fon),
      var(--rang-matn) 15%);
  }
}

.tugma:not(:disabled, [aria-disabled="true"]):active {
  background: color-mix(in oklch, var(--_fon),
    var(--rang-matn) 25%);
}

/* Fokus — asos.css dagi umumiy ikki rangli halqa (CSS'da
   accessibility darsi), bu yerda alohida yozilmaydi */

.tugma:is(:disabled, [aria-disabled="true"]) {
  --_fon: color-mix(in oklch, var(--rang-ikkinchi) 20%,
    var(--rang-fon));
  --_matn: var(--rang-ikkinchi);
  --_chegara: var(--_fon);
  cursor: not-allowed;
}

/* Yuklanmoqda: en saqlanadi */
.tugma[aria-busy="true"] {
  position: relative;
  color: transparent;
  cursor: progress;
}

.tugma[aria-busy="true"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  inline-size: 1.25em;
  block-size: 1.25em;
  box-sizing: border-box;
  border: 2px solid var(--_matn);
  border-inline-end-color: transparent;
  border-radius: 50%;
  animation: miltilla 1s ease-in-out infinite alternate;
}

@keyframes aylan {
  to {
    rotate: 1turn;
  }
}

@keyframes miltilla {
  to {
    opacity: 0.3;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .tugma {
    transition:
      background-color 0.15s,
      scale 0.1s ease-out;
  }

  .tugma:not(:disabled, [aria-disabled="true"]):active {
    scale: 0.97;
  }

  .tugma[aria-busy="true"]::after {
    animation: aylan 0.8s linear infinite;
  }
}

/* Guruhlar */
.tugma-guruh {
  display: inline-flex;
}

.tugma-guruh > .tugma:not(:first-child) {
  margin-inline-start: -2px;
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

.tugma-guruh > .tugma:not(:last-child) {
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

.tugma-guruh > .tugma:focus-visible {
  z-index: 1;
}

Uch izoh:

  • Nofaol fon endi tokenlardan: --rang-ikkinchi ning 20% i qaymoq fonga aralashtirilgan. Qorong'i rejimda ikkalasi o'zgaradi — nofaol tugma ham moslashadi. Namoyishdagi xom oklch(90% 0.01 162) faqat yorug' rejim uchun edi.
  • Eski .bron-havola o'rniga HTML'da class="tugma katta". CSS nesting darsida "qayta ishlatiladigan komponent o'z tashqi selektori bilan yoziladi" degan edik — .tugma karta ichida ham, oyna ichida ham bir xil ishlaydi.
  • Qatlam — komponentlar (Kaskadni boshqarish). Reset'dagi :where(button) qoidalari qatlamda oldinroq — .tugma ularni og'irlik jangisiz yutadi.

Maslahat: Bitta "tugmalar sahifasi" yarating: hamma variant × o'lcham × holat bir joyda — UI/UX asoslari darsidagi holat matritsasi. Har o'zgarishdan keyin uni ochib, hammasini bir qarashda tekshirasiz.

10. Ko'p uchraydigan xatolar

10.1 div tugma

<div class="tugma" onclick="..."> — ko'rinishi to'g'ri, lekin Tab bilan borilmaydi, Enter bilan bosilmaydi, ekran o'quvchi "tugma" demaydi. Tuzatish: button. CSS ko'rinishni beradi, teg — xulqni.

10.2 outline: none

Dizayner "brauzerning ko'k chizig'i xunuk" dedi va stajyor fokusni o'chirdi. Bobur endi qaysi tugmada turganini bilmaydi. Tuzatish: o'chirmang — :focus-visible ga o'z halqangizni bering. U faqat klaviaturada ko'rinadi, sichqoncha bilan bosganda chiqmaydi.

10.3 Har variantga alohida hover rangi

.tugma:hover { background: #1a5d1a; } — endi ikkinchi va xavfli tugma ham hover'da yashil bo'lib qoladi. Tuzatish: hover'ni nisbiy yozing (color-mix() bilan hozirgi --_fon dan) yoki har variant o'z hover o'zgaruvchisini bersin.

10.4 Yuklanishda matnni almashtirish

Tugma kengayadi, qo'shnilar suriladi. Tuzatish: color: transparent va halqa ("Yuklanish holati" bo'limi); visibility: hidden emas — u tugma nomini o'chiradi.

10.5 Chegarasiz tugma

border: 0 + fon — majburiy ranglar rejimida tugma oddiy matnga aylanadi. Tuzatish: border: 2px solid fon rangida yoki transparent.

11. Mashqlar

Mashqlarni kurs/mashqlar/06/ papkasida bajaring.

1-mashq (oson): «Bahor» urg'u varianti

Aksiya sahifasi uchun beshinchi variant kerak: g'isht rangli (--rang-urgu) to'la tugma, matni qaymoq. Uni .tugma.urgu deb yozing. Hover va bosilgan holatlar uchun alohida qoida yozish kerakmi?

Ishora: variant faqat ichki o'zgaruvchilarni almashtiradi — «Variantlar» bo'limidagi xavfli variantga qarang.

Yechim
css
.tugma.urgu {
  --_fon: var(--rang-urgu);
}

Bitta qator. --_matn asosdan (qaymoq), --_chegara — var(--_fon) orqali g'isht rangida. Hover va bosilgan holat uchun hech narsa yozish shart emas: umumiy qoida color-mix() bilan hozirgi --_fon ni to'qlashtiradi. Kontrast: qaymoq matn g'isht fonda — 5.3:1 (CSS o'zgaruvchilari 1).

2-mashq (o'rta): kichik kvadrat tugmalar

Menyu jadvalida har qatorda ikkita kichik ikonkali tugma bor: "Tahrirlash" (qalam) va "O'chirish" (xoch, xavfli). Talablar:

  1. Ikkalasi 32 × 32 piksel, faqat belgi.
  2. Ekran o'quvchi ularni "Tahrirlash: Osh" va "O'chirish: Osh" deb o'qisin.
  3. O'chirish tugmasi shaffof fonli, lekin matni (belgisi) xato rangida.

Ishora: o'lcham — .kichik va .belgi birga. Qizil belgi uchun --_matn ni almashtiring. Belgilar — sprite'dagi symbol lar (SVG va ikonka tizimi); qalam uchun oddiy yo'l: M4 20h4L20 8l-4-4L4 16z.

Yechim
html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
    --rang-xato: oklch(52% 0.19 27);
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: transparent;
    --_balandlik: 2.75rem;
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--_balandlik);
    border: 2px solid var(--_chegara);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
  }
  .tugma.kichik { --_balandlik: 2rem; font-size: 0.875rem; }
  .tugma.belgi { inline-size: var(--_balandlik); padding: 0; }
  .tugma.xato-belgi { --_matn: var(--rang-xato); }
  .sprite { display: none; }
  .ikonka {
    inline-size: 1.25em;
    block-size: 1.25em;
    fill: currentColor;
  }
  .tugma:focus-visible {
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  td { padding: 0.25rem 0.5rem; }
</style>
<svg class="sprite">
  <symbol id="i-qalam" viewBox="0 0 24 24" fill="none"
    stroke="currentColor" stroke-width="2">
    <path d="M4 20h4L20 8l-4-4L4 16z" />
  </symbol>
  <symbol id="i-yopish" viewBox="0 0 24 24" fill="none"
    stroke="currentColor" stroke-width="2">
    <path d="M6 6l12 12M18 6 6 18" />
  </symbol>
</svg>
<table>
  <tr>
    <td>Osh</td>
    <td>35 000 so'm</td>
    <td>
      <button class="tugma kichik belgi" type="button"
        aria-label="Tahrirlash: Osh">
        <svg class="ikonka" aria-hidden="true">
          <use href="#i-qalam"/></svg>
      </button>
      <button class="tugma kichik belgi xato-belgi" type="button"
        aria-label="O'chirish: Osh">
        <svg class="ikonka" aria-hidden="true">
          <use href="#i-yopish"/></svg>
      </button>
    </td>
  </tr>
</table>

xato-belgi — mashq uchun namoyish class'i. Nega aria-label da taom nomi ham bor? Jadvalda o'nta "O'chirish" tugmasi bo'lsa, ekran o'quvchi ro'yxatida ular bir xil eshitiladi — qaysi taom ekanini bilib bo'lmaydi. Qizil xoch — 5.8:1, ikonka uchun talab (3:1) bilan ham, matn talabi bilan ham o'tadi. Esda tuting: 32 piksel — faqat zich jadval uchun.

3-mashq (qiyin): bron formasi tugmalari

Bron formasi oxirida ikki tugma: "Tozalash" (type="reset", shaffof) va "Stolni band qilish" (type="submit", asosiy, katta). Talablar:

  1. Asosiy tugma oxirida, ikkalasi tor ekranda o'z-o'zidan ikki qatorga o'tsin.
  2. Telefon enida (40rem gacha) har ikki tugma butun enni egallasin.
  3. Yuklanish holati (aria-busy="true") da asosiy tugma eni o'zgarmasin.

Ishora: harakatlar qatori — «Tugmalar guruhi» bo'limi. Butun en — flex: 1 1 100% yoki inline-size: 100%; 40rem — «Bahor» breakpointi (Media queries), mobile-first yozing.

Yechim
html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  .tugma {
    --_fon: var(--rang-asosiy);
    --_matn: var(--rang-fon);
    --_chegara: var(--_fon);
    box-sizing: border-box;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: 2.75rem;
    padding: 0.25em 1.25em;
    border: 2px solid var(--_chegara);
    border-radius: 0.5rem;
    background: var(--_fon);
    color: var(--_matn);
    font-weight: 600;
  }
  .tugma.shaffof {
    --_fon: transparent;
    --_matn: var(--rang-asosiy);
    --_chegara: transparent;
  }
  .tugma.katta {
    min-block-size: 3.25rem;
    font-size: 1.125rem;
  }
  .harakatlar {
    display: flex;
    flex-wrap: wrap;
    justify-content: end;
    gap: 0.5rem;
  }
  .harakatlar > .tugma {
    flex: 1 1 100%;
  }
  @media (width >= 40rem) {
    .harakatlar > .tugma {
      flex: none;
    }
  }
</style>
<form action="https://example.com/bron" method="post">
  <div class="harakatlar">
    <button class="tugma shaffof" type="reset">Tozalash</button>
    <button class="tugma katta" type="submit">
      Stolni band qilish
    </button>
  </div>
</form>

Telefonda (360) ikki tugma ustma-ust, har biri butun enda. "Stolni band qilish" pastda — bosh barmoq yetadigan joyda. Kengroq ekranda (768 va 1280) ikkalasi o'ng chetda yonma-yon, asosiy tugma oxirida. 3-talab uchun qo'shimcha kod kerak emas: yuklanish qoidasi (color: transparent + ::after) enni o'zgartirmaydi — telefonda ham, kompyuterda ham. harakatlar — mashq uchun namoyish class'i.

4-mashq: Portfolio qadami — portfolio tugmalari bitta tizimda

Portfolio'da hozir uchta "tugma" bor, ular turli darslarda yozilgan:

Vazifa:

  1. komponentlar.css da ikkala asosiy tugmani bitta selektor ro'yxati va ichki o'zgaruvchilar (--_fon, --_matn, --_chegara) bilan yozing. Takror qolmasin.
  2. Footer'dagi tugma ikkinchi variantda bo'lsin (ramkali, shaffof fon). HTML'ga class qo'shmang.
  3. Hover va bosilish color-mix() bilan nisbiy bo'lsin; chegara hech qachon 0 bo'lmasin.
  4. Tekshiring: DevTools → Rendering → forced-colors active. Uchala tugma ham ramkali ko'rinadimi?

Ishora: portfolio'da class'lar faqat LOYIHA ro'yxatidan — teg va atribut selektorlari yetadi (footer button). Hover qoidasi bosilish qoidasidan oldin (UI/UX asoslari).

Yechim

komponentlar.css dagi eski button { ... }, main a[href="loyihalar/"] { ... } va ularning hover/active qoidalari o'rniga:

css
/* Tugmalar tizimi (Tugmalar tizimi darsi) */
button,
main a[href="loyihalar/"] {
  --_fon: var(--rang-asosiy);
  --_matn: var(--rang-fon);
  --_chegara: var(--_fon);

  box-sizing: border-box;
  appearance: none;
  font: inherit;
  text-decoration: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.75rem;
  padding: 0.25em 1.5em; /* shrift bilan o'sadi — ataylab em */
  border: 2px solid var(--_chegara);
  border-radius: var(--burchak-m);
  background-color: var(--_fon);
  color: var(--_matn);
}

/* Ikkinchi variant: footer'dagi "Sayt haqida" */
footer button {
  --_fon: transparent;
  --_matn: var(--rang-asosiy);
  --_chegara: var(--rang-asosiy);
}

@media (hover: hover) {
  :is(button, main a[href="loyihalar/"]):hover {
    background-color:
      color-mix(in oklch, var(--_fon), var(--rang-matn) 15%);
  }
}

:is(button, main a[href="loyihalar/"]):active {
  background-color:
    color-mix(in oklch, var(--_fon), var(--rang-matn) 25%);
}

@media (prefers-reduced-motion: no-preference) {
  :is(button, main a[href="loyihalar/"]) {
    transition:
      background-color 0.15s,
      scale 0.1s ease-out;
  }

  :is(button, main a[href="loyihalar/"]):active {
    scale: 0.97;
  }
}
  • Oldingi qoidalardagi black 10% va black 15% o'rniga --rang-matn aralashmasi. Yorug' rejimda natija deyarli bir xil (matn rangi — qora-yashil), qorong'i rejimda esa hover endi ochroq — Qorong'i rejim darsidagi juftlikka mos. Ikkinchi variantda hover — och yashil-kulrang dog'.
  • Doimiy chegara tufayli CSS'da accessibility darsidagi @media (forced-colors: active) { button { border: ... } } bloki endi keraksiz — uni olib tashlang. Majburiy ranglar rejimida uchala tugma ham ramkali. To'lovi: tugmalar 4 pikselga kengaydi. O'sha darsdagi "oddiy rejimda bir piksel ham o'zgarmasin" sharti tuzatish uchun edi; bu yerda esa tizimning o'zi o'zgaryapti.
  • button selektori summary ga tegmaydi — savol-javob o'zgarmaydi. Kelajakda portfolio'ga yangi button qo'shilsa (09-qismda JavaScript bilan), u avtomatik tizimdan uslub oladi.
  • Fokus halqasi — Yakuniy loyiha darsidagi umumiy :focus-visible qoidasi, u uchala tugmada ishlaydi.
  • @media bloklarining joyi: har biri o'z qoidasi yonida (CSS metodologiyalari).

Uchala sahifani 360 va 1280 pikselda, yorug' va qorong'i rejimda tekshiring. So'ng npm run check.

12. Real ishda

  • Dizayn tizimlari (GitHub Primer, Shopify Polaris, Material) tugmadan boshlanadi: bitta asos, 3–5 variant, 2–3 o'lcham va to'liq holatlar.
  • React kabi freymvorklarda (kursda keyinroq) tugma bitta komponent: <Tugma turi="ikkinchi">. Tailwind 4 darsidagi cva shu variant jadvalini JavaScript'da yozadi.
  • Figma'da tugma variant xususiyatlari bilan chiziladi: Type, Size, State (Figma dasturchi uchun 2). Siz ularni CSS o'zgaruvchilariga bir-bir o'tkazasiz.
  • Intervyuda so'raladi: "disabled va aria-disabled farqi?", "Yuklanishda tugma kengaymasligi uchun nima qilasiz?", "Faqat ikonkali tugmaga nom qanday beriladi?".

Xulosa

  • Vazifa tegni tanlaydi: olib borsa — a href, harakat qilsa — button. CSS ikkalasini bir xil ko'rsatadi, lekin xulqini o'zgartirmaydi.
  • Asos class'i reset (font: inherit, box-sizing, appearance) va ichki o'zgaruvchilarni (--_fon, --_matn, --_chegara) beradi; variant faqat shularni almashtiradi.
  • Holatlar — hamma variant uchun bitta qoida: hover va bosilish color-mix() bilan nisbiy, fokus — tugmadan tashqaridagi halqa, nofaol — :is(:disabled, [aria-disabled="true"]).
  • Chegara hech qachon 0 emas — majburiy ranglar rejimida tugma shu chegara tufayli ko'rinadi.
  • Faqat ikonkali tugma aria-label (yoki ko'rinmas matn) oladi; ikonka aria-hidden.
  • Yuklanishda matn color: transparent bilan joyida qoladi — tugma eni sakramaydi, nomi saqlanadi.

Keyingi dars: Kartalar — tugmalarimiz karta ichiga kiradi: butun karta bosiladigan bo'ladi, lekin ichidagi tugma alohida bosilishi kerak — bu ikkisini qanday kelishtirishni ko'ramiz.

Manbalar

  • MDN: "<button>", "appearance", "aria-disabled", "aria-busy", "aria-pressed", ":focus-visible", "forced-colors", "color-mix()" — developer.mozilla.org
  • WAI-ARIA Authoring Practices: "Button pattern" — w3.org/WAI/ARIA/apg
  • WCAG 2.2: 2.5.8 "Target Size (Minimum)", 1.4.11 "Non-text Contrast" — w3.org/TR/WCAG22
  • web-features (Baseline ma'lumotlari): "appearance", "forced-colors", "color-mix", "has" — github.com/web-platform-dx/web-features
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
CSS tugmalar tizimi: variantlar, o'lchamlar, holatlar va yuklanish — IlmHamroh