IlmHamroh
JavaScript Full-stack/6-qism. CSS: harakat, zamonaviy CSS va dizayn51/57-dars27 daqiqa
Mundarija (34)

CSS forma komponentlari: input, checkbox, switch va xato holatlari

Qisqacha: Forma komponenti — yorliq, yordam matni, maydon va xato matni bitta o'ramda. Holatlar (hover, fokus, xato, nofaol) o'ramga :has() orqali tarqaladi: div:has(> :user-invalid) label — xato maydonning yorlig'i. Maxsus checkbox va radio appearance: none + ::before bilan chiziladi, o'chirgich esa role="switch" li checkbox. Qoida: avval accent-color ni sinang; o'zingiz chizsangiz — fokus, nofaol holat va majburiy ranglar rejimini ham o'zingiz chizasiz.

Bu darsda

  • Maydonning to'liq tuzilishini (yorliq, yordam, maydon, xato) CSS bilan tartibga keltirasiz.
  • Fokus, xato, nofaol holatlarni yozasiz va xatoni faqat rang bilan emas, belgi va so'z bilan ko'rsatasiz.
  • Maxsus checkbox, radio va o'chirgichni (switch) accessible qilib chizasiz.
  • Radio guruhini segmentli tanlovga aylantirasiz, prefiksli maydon va suzuvchi yorliq yasaysiz.
  • Brauzer avtomatik to'ldirgan maydonni (:autofill) qanday bezash mumkinligini va mumkin emasligini bilasiz.

Oldin bilishingiz kerak: Forma elementlarini zamonaviy stillash, Qulay va accessible forma, Holat pseudo-klasslari, Tugmalar tizimi.

1. Nega bu kerak?

O'tgan darsda navbar qurdik. Endi saytning eng "ishchi" qismiga o'tamiz — formaga. Mehmon stol band qilmoqchi: ism, telefon, sana, odam soni. Forma noqulay bo'lsa, u shunchaki telefon qiladi yoki boshqa choyxonaga ketadi.

«Bahor» bron formasi Qulay va accessible forma darsidan beri HTML jihatdan to'liq: har maydonning label i bor, yordam matni aria-describedby bilan ulangan, brauzer tekshiruvi ishlaydi. CSS esa unga deyarli tegmagan. O'sha darsda ikki va'da qolgan edi: "chiroyli joylashuvni keyinroq CSS bilan qilamiz" va "qizil rang va ikonka keyinroq CSS bilan qo'shiladi".

Yana uchta va'da bor. Birinchisi Zamonaviy forma imkoniyatlari va ARIA asoslari darslarida berilgan: hamma brauzerda o'chirgich — checkbox + role="switch" + CSS. Ikkinchisi — Forma elementlarini stillash darsidagi to'liq maxsus checkbox va radio. Uchinchisi — Tugmalar tizimi darsida: radio guruhini tugmalar ko'rinishiga keltirish.

2. Maydon anatomiyasi

2.1 To'rt qism

Har maydon to'rt qismdan iborat:

Qism «Bahor»da Kim uchun
Yorliq <label for="telefon"> Hamma: maydon nima haqida
Yordam matni <span id="telefon-yordam"> Xato qilmaslik uchun oldindan
Maydon <input id="telefon"> Kiritish
Xato matni <span id="telefon-xato"> Nima noto'g'ri va qanday tuzatish

«Bahor»da ular div ga o'ralgan (Qulay va accessible forma). O'ram — bizning komponentimiz: uning ichidagi holat (xato, fokus, nofaol) :has() orqali hamma qismga tarqaladi.

Tartib muhim: yordam matni maydondan oldin. Ekran o'quvchi uni aria-describedby orqali maydon bilan birga o'qiydi, ko'zi ko'radigan mehmon esa yozishni boshlashdan oldin ko'radi. Maydon ostidagi yordam matnini telefon klaviaturasi ko'pincha yopib qo'yadi.

2.2 Maydon va uning holatlari

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-matn: #1f2a24;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
    --rang-ikkinchi: #5b6660;
    --rang-xato: oklch(52% 0.19 27);
  }
  body {
    font-family: system-ui, sans-serif;
    background: var(--rang-fon);
    color: var(--rang-matn);
  }
  form > div {
    display: grid;
    gap: 0.25rem;
    max-inline-size: 22rem;
    margin-block-end: 1rem;
  }
  label { font-weight: 600; }
  span[id$="-yordam"] {
    font-size: 0.875rem;
    color: var(--rang-ikkinchi);
  }
  span[id$="-xato"] {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--rang-xato);
  }
  span[id$="-xato"]::before { content: "⚠ " / ""; }
  input {
    box-sizing: border-box;
    min-block-size: 2.75rem;
    padding: 0.5em 0.75em;
    border: 2px solid var(--rang-ikkinchi);
    border-radius: 0.5rem;
    background: white;
    color: var(--rang-matn);
    font: inherit;
  }
  @media (hover: hover) {
    input:not(:disabled):hover { border-color: var(--rang-matn); }
  }
  input:focus-visible {
    border-color: var(--rang-asosiy);
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  input:is(:user-invalid, [aria-invalid="true"]) {
    border-color: var(--rang-xato);
  }
  div:has(> :is(:user-invalid, [aria-invalid="true"])) label {
    color: var(--rang-xato);
  }
  div:has(> :user-invalid) span[id$="-yordam"] {
    color: var(--rang-xato);
  }
  div:has(> :user-invalid) span[id$="-yordam"]::before {
    content: "⚠ " / "Xato: ";
  }
  input:disabled {
    border-style: dashed;
    background: transparent;
    color: var(--rang-ikkinchi);
    cursor: not-allowed;
  }
</style>
<form action="https://example.com/bron" method="post">
  <div>
    <label for="ism">Ismingiz</label>
    <input id="ism" name="ism" autocomplete="name" required>
  </div>
  <div>
    <label for="telefon">Telefon raqamingiz</label>
    <span id="telefon-yordam">Masalan: +998 90 000 00 00</span>
    <input id="telefon" name="telefon" type="tel"
      autocomplete="tel" required pattern="[0-9 +\-]{9,17}"
      aria-describedby="telefon-yordam">
  </div>
  <div>
    <label for="odam">Mehmonlar soni</label>
    <input id="odam" name="odam" type="number" min="1" max="20"
      value="25" aria-invalid="true"
      aria-describedby="odam-xato">
    <span id="odam-xato">20 kishidan ko'p bo'lsa, qo'ng'iroq
      qiling.</span>
  </div>
  <div>
    <label for="stol">Stol raqami</label>
    <input id="stol" name="stol" value="4" disabled>
  </div>
</form>

Nimaga qarang: uchinchi maydon ("Mehmonlar soni") allaqachon xato holatida — qizil ramka, qizil yorliq va ostida " 20 kishidan ko'p bo'lsa, qo'ng'iroq qiling." To'rtinchi maydon nofaol: punktir ramka, kulrang matn. Endi telefon maydoniga abc yozib, Tab bosing — telefon ham qizaradi, yordam matni oldida "" paydo bo'ladi.

Chrome'da tekshirdik: sahifa ochilganda bo'sh "Ismingiz" maydoni required bo'lsa ham qizil emas. Unga kirib-chiqib ketsangiz ham — yo'q. Faqat yozib, o'chirib, chiqib ketsangiz yoki formani yuborishga urinsangiz qizaradi. Bu :user-invalid — Holat pseudo-klasslari darsidagi "foydalanuvchi ishlab bo'lgach" qoidasi. :invalid esa sahifa ochilishi bilan hamma bo'sh majburiy maydonni qizartirardi — mehmon hali hech narsa qilmasdan "xato qildingiz" degan xabarni ko'rardi.

2.3 Ikki xil xato manbai

Formada xatoni ikki joy aniqlaydi:

  • Brauzer — required, pattern, min/max bo'yicha. CSS'da :user-invalid. :user-valid va :user-invalid — keng tarqalgan Baseline: ular 2023-yil noyabridan hamma asosiy brauzerda, 2026-yil mayidan "keng tarqalgan".
  • Server — "bu sanada bo'sh stol yo'q" kabi brauzer bilmaydigan narsalar. Server sahifani qaytarganda maydonga aria-invalid="true" qo'yadi va xato matnini (-xato) yozadi. Keyinchalik JavaScript ham shunday qiladi (09-qismda o'rganasiz).

CSS ikkalasini bitta qoida bilan chizadi: :is(:user-invalid, [aria-invalid="true"]). Tashqi ko'rinish bir xil — mehmon uchun xato qayerdan kelgani ahamiyatsiz.

Diqqat: Xato matnini HTML'da oldindan yozib qo'yib, CSS bilan yashirish (display: none) va faqat xatoda ko'rsatish — xato fikr. Sababi: aria-describedby yashirin elementning matnini ham o'qiydi. Malika xato bo'lmasa ham "20 kishidan ko'p bo'lsa…" ni har safar eshitadi. Xato matni faqat xato bo'lganda HTML'da paydo bo'lsin — uni server yoki skript qo'shadi. CSS'ning vazifasi — tayyor holatni chizish.

2.4 Kodni o'qiymiz

  • Ramka --rang-ikkinchi da, 2 piksel. WCAG 1.4.11: interfeys elementining chegarasi fonga nisbatan kamida 3:1 bo'lsin. Kulrang #5b6660 oq fonda — 6.0:1. Ko'p saytlardagi och kulrang ramka (#ddd) 1.4:1 — ko'rish zaif odam maydonni umuman ko'rmaydi.
  • Halqa — ikki rangli (CSS'da accessibility): to'q outline va fon rangidagi ichki chiziq. «Bahor»da u asos.css da umumiy; natijalarda namoyish uchun takrorlangan.
  • :focus-visible matn maydonida sichqoncha bilan ham ishlaydi. Brauzer matn maydonini "klaviatura kutayotgan joy" deb biladi — Chrome'da bosib tekshirdik, halqa chiqdi. Tugmadan farqli: tugmada halqa faqat klaviaturada.
  • div:has(> :user-invalid) label — "ichida xato maydoni bor o'ramning yorlig'i" (Mantiqiy pseudo-klasslar). > — faqat bevosita bola: ichma-ich o'ramlar bir-birini "yuqtirmaydi".
  • Xato — rang + belgi + so'z. "" belgisining muqobil matni "Xato: " — ekran o'quvchi "Xato: Masalan: +998…" deb o'qiydi (Pseudo-elementlar). Rang ko'r odam ham, ekran o'quvchi ham xatoni biladi — Rang nazariyasi darsidagi qoida.
  • Nofaol maydon — punktir ramka. Faqat rang emas, shakl ham o'zgaradi. Nofaol elementlar uchun WCAG kontrast talab qilmaydi, lekin matn baribir o'qilsin. cursor: not-allowed — cursor Baseline emas (telefonda kursor yo'q), zaxira kerak emas.
  • font: inherit va kamida 16 piksel — iPhone kichik shriftli maydonga fokus bo'lganda sahifani kattalashtiradi (Mobil qurilma tuzoqlari).

Tekshirib ko'ring: Nega xato qoidasi :invalid emas, :user-invalid bilan yozilgan? Bo'sh bron formasi ochilganda farq qanday ko'rinadi?

Javob

Agar :invalid yozilsa, sahifa ochilishi bilan hamma bo'sh majburiy maydon (ism, telefon, sana) qizil bo'lardi. Mehmon hali hech narsa yozmagan, forma esa unga "xato" deb qichqiradi. :user-invalid faqat mehmon maydon bilan ishlab bo'lgach yoki formani yuborishga uringach mos keladi. Natijada qizil rang faqat haqiqiy xatoni bildiradi.

3. Maxsus checkbox va radio

3.1 Avval — accent-color

Forma elementlarini stillash darsida accent-color bilan checkbox va radio'ni bitta qatorda brend rangiga bo'yagan edik. Ko'p hollarda shu yetadi. O'zingiz chizish kerak bo'ladigan holatlar: dizayner belgining shakli, o'lchami yoki animatsiyasini boshqacha istaydi; yoki accent-color ishlamaydigan brauzer ham muhim (u Baseline emas: Android'dagi Chrome ro'yxatda yo'q).

3.2 appearance: none + ::before

O'sha darsda ko'rgan tuzoq: appearance: none checkbox'ni 0×0 pikselga aylantiradi. Endi hammasini o'zimiz chizamiz — va hech bir holatni unutmaymiz:

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: var(--rang-fon);
    color: var(--rang-matn);
  }
  fieldset {
    display: grid;
    gap: 0.75rem;
    max-inline-size: 22rem;
    border: 0;
    padding: 0;
  }
  legend { font-weight: 600; margin-block-end: 0.5rem; }
  fieldset div {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  input:is([type="checkbox"], [type="radio"]) {
    appearance: none;
    flex: none;
    display: inline-grid;
    place-content: center;
    inline-size: 1.5rem;
    block-size: 1.5rem;
    margin: 0;
    border: 2px solid var(--rang-ikkinchi);
    border-radius: 0.375rem;
    background: white;
    font: inherit;
  }
  input[type="radio"] { border-radius: 50%; }
  input:is([type="checkbox"], [type="radio"])::before {
    content: "";
    inline-size: 0.875rem;
    block-size: 0.875rem;
    background: var(--rang-fon);
    scale: 0;
  }
  input[type="checkbox"]::before {
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%,
      80% 0, 43% 62%);
  }
  input[type="radio"]::before {
    inline-size: 0.625rem;
    block-size: 0.625rem;
    border-radius: 50%;
  }
  input:checked {
    border-color: var(--rang-asosiy);
    background: var(--rang-asosiy);
  }
  input:checked::before { scale: 1; }
  input:focus-visible {
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  input:disabled {
    border-style: dashed;
    background: transparent;
  }
  input:disabled + label { color: var(--rang-ikkinchi); }
  @media (prefers-reduced-motion: no-preference) {
    input::before { transition: scale 0.12s ease-out; }
  }
  @media (forced-colors: active) {
    input::before { background: CanvasText; }
  }
</style>
<form action="https://example.com/bron" method="post">
  <fieldset>
    <legend>Qayerda o'tirasiz?</legend>
    <div>
      <input id="joy-zal" name="joy" type="radio" value="zal"
        checked>
      <label for="joy-zal">Umumiy zal</label>
    </div>
    <div>
      <input id="joy-ayvon" name="joy" type="radio" value="ayvon">
      <label for="joy-ayvon">Ayvon (ochiq havoda)</label>
    </div>
    <div>
      <input id="joy-xona" name="joy" type="radio" value="xona"
        disabled>
      <label for="joy-xona">Alohida xona — bugun band</label>
    </div>
  </fieldset>
  <p>
    <input id="sms" name="sms" type="checkbox" checked>
    <label for="sms">Bron haqida SMS eslatma yuborilsin</label>
  </p>
</form>

Nimaga qarang: radio'lar — dumaloq, belgilangani yashil to'la doira, markazida qaymoq nuqta. Checkbox — burchaklari yumaloq kvadrat, ichida qaymoq "" belgisi. "Alohida xona" nofaol: punktir doira, kulrang yozuv. "Ayvon" ni bosing — nuqta bir lahzada "o'sib" chiqadi. Tab bilan radio guruhiga kiring va strelkalar bilan yuring: tanlov almashadi, fokus halqasi ko'rinadi — klaviatura xulqi brauzerniki bo'lib qoldi.

Kodni o'qiymiz:

  • display: inline-grid; place-content: center — ::before markazda (Flex naqshlari dagi markazlash, grid bilan).
  • Belgi — clip-path: polygon(...) — kvadratdan "" shaklini qirqib olamiz (clip-path). Rasm yoki SVG fayl kerak emas, rangi esa oddiy background.
  • Belgilanmagan holatda scale: 0 — belgi bor, lekin ko'rinmaydi. Belgilanganda scale: 1. scale — arzon, kompozitor xususiyati (Rendering pipeline).
  • Belgilangan holat faqat belgi bilan emas, fon bilan ham ko'rsatiladi. input — "almashtiriladigan" element va unga ::before qo'yish standartda to'liq kafolatlanmagan. Zamonaviy brauzerlar appearance: none bo'lgan checkbox'da uni chizadi (Chrome'da tekshirdik). Lekin biror brauzer chizmasa ham, yashil fon "belgilangan" deb aytadi.
  • @media (forced-colors: active) — mana eng ko'p unutiladigan joy. Majburiy ranglar rejimida (Tugmalar tizimi) brauzer fonlarni o'zining ranglariga almashtiradi. Chrome'da tekshirdik: bu qatorsiz belgilangan va belgilanmagan checkbox bir xil — ikkalasi ham qora kvadrat, "" yo'qoldi. CanvasText — tizim rangi (asosiy matn rangi), uni brauzer almashtirmaydi.

Accessibility daraxtida hech narsa o'zgarmadi: Chrome "checkbox, belgilangan" va "radio tugma" deb aytadi. Biz faqat ko'rinishni o'zgartirdik — element o'sha-o'sha.

Tekshirib ko'ring: Stajyor checkbox'ni display: none qilib, label::before da kvadrat chizdi. Sichqoncha bilan ishlaydi. Nima buzildi?

Javob

display: none element fokus tartibidan va accessibility daraxtidan chiqadi. Bobur Tab bilan checkbox'ga bora olmaydi, Malika uni eshitmaydi. appearance: none esa faqat ko'rinishni o'chiradi, elementni joyida qoldiradi. Checkbox'ni butunlay yashirish kerak bo'lsa — keyingi bo'limdagi kabi opacity: 0 va position: absolute bilan, display: none bilan emas.

4. Radio'dan segmentli tanlov

Tugmalar tizimi darsida birlashgan tugmalar guruhini ko'rdik va dedik: tanlov formada yuborilsa, tugma emas, radio kerak. Mana o'sha radio'lar tugmalar ko'rinishida:

html
<style>
  :root {
    --rang-fon: #fffaf0;
    --rang-asosiy: #2f6b3a;
    --rang-asosiy-toq: #1a5d1a;
  }
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  fieldset { border: 0; padding: 0; }
  legend { font-weight: 600; margin-block-end: 0.5rem; }
  .tanlov {
    display: inline-flex;
    flex-wrap: wrap;
  }
  .tanlov input {
    position: absolute;
    opacity: 0;
    inline-size: 1px;
    block-size: 1px;
  }
  .tanlov label {
    display: grid;
    place-items: center;
    min-block-size: 2.75rem;
    padding-inline: 1em;
    border: 2px solid var(--rang-asosiy);
    color: var(--rang-asosiy);
    font-weight: 600;
    cursor: pointer;
  }
  .tanlov label:not(:first-of-type) { margin-inline-start: -2px; }
  .tanlov label:first-of-type {
    border-start-start-radius: 0.5rem;
    border-end-start-radius: 0.5rem;
  }
  .tanlov label:last-of-type {
    border-start-end-radius: 0.5rem;
    border-end-end-radius: 0.5rem;
  }
  .tanlov input:checked + label {
    background: var(--rang-asosiy);
    color: var(--rang-fon);
  }
  .tanlov input:focus-visible + label {
    position: relative;
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
</style>
<form action="https://example.com/bron" method="post">
  <fieldset>
    <legend>Vaqt</legend>
    <div class="tanlov">
      <input id="v12" name="vaqt" type="radio" value="12:00">
      <label for="v12">12:00</label>
      <input id="v15" name="vaqt" type="radio" value="15:00">
      <label for="v15">15:00</label>
      <input id="v18" name="vaqt" type="radio" value="18:00"
        checked>
      <label for="v18">18:00</label>
      <input id="v20" name="vaqt" type="radio" value="20:00">
      <label for="v20">20:00</label>
    </div>
  </fieldset>
</form>

Nimaga qarang: to'rtta vaqt bitta tasmada, "18:00" yashil — tanlangan. Boshqasini bosing — yashil unga ko'chadi. Tab bilan guruhga kiring: halqa tanlangan vaqt atrofida. Strelkalar bilan yuring — tanlov va halqa birga ko'chadi. Bu radio'ning o'z klaviatura xulqi: guruhga bitta Tab, ichida — strelkalar.

  • Radio yashiringan, lekin yo'qolmagan: position: absolute; opacity: 0 va 1 piksellik o'lcham. U fokus oladi va ekran o'quvchi uni radio tugma deb aytadi — nomi label dan. display: none yoki visibility: hidden emas — ular radio'ni o'chirib yuboradi.
  • Holatlar input + label orqali: :checked + label — tanlangan, :focus-visible + label — fokus (Asosiy selektorlar dagi qo'shni kombinator). Shuning uchun HTML'da har input o'z label idan oldin turadi.
  • :first-of-type / :last-of-type — chetki label lar; ular orasida input lar bor, shuning uchun :first-child ishlamaydi (Tuzilma pseudo-klasslari).
  • «Bahor» formasida vaqt hozir select (Qulay va accessible forma). To'rt variant uchun segmentli tanlov telefonda tezroq: bitta bosish, ro'yxat ochilmaydi. Variantlar 5–6 tadan ko'p bo'lsa — select qolsin.

Tekshirib ko'ring: HTML'da label ni o'z input idan oldin yozib qo'ydingiz. input:checked + label nima bo'ladi?

Javob

Ishlamay qoladi: tanlangan vaqt yashil bo'lmaydi. + faqat keyingi qo'shnini tanlaydi — input dan keyin kelgan label ni. Label oldinda tursa, input dan keyin boshqa vaqtning label i keladi va yashil noto'g'ri tugmaga tushadi (yoki hech qayerga).

5. O'chirgich (switch)

5.1 Checkbox yoki switch

Zamonaviy forma imkoniyatlari darsidagi qoida: checkbox forma yuborilganda kuchga kiradi, o'chirgich — darhol. Bron formasidagi "SMS eslatma" — checkbox. "Qorong'i rejim" — o'chirgich: bosishingiz bilan sahifa qorayadi.

HTML'dagi yangi switch atributi hozircha faqat Safari'da. Hamma brauzerda ishlashi uchun oddiy checkbox'ga role="switch" qo'shamiz (ARIA asoslari): ekran o'quvchi "belgilash katakchasi" o'rniga "o'chirgich, yoqilgan/o'chirilgan" deydi.

5.2 Chizamiz

html
<style>
  :root {
    color-scheme: light;
    --fon: light-dark(#fffaf0, #16301b);
    --yuza: light-dark(white, #22402a);
    --matn: light-dark(#1f2a24, #fffaf0);
    --asosiy: light-dark(#2f6b3a, #8fd19e);
    --ikkinchi: light-dark(#5b6660, #b5c1bb);
  }
  :root:has(#qorongi:checked) { color-scheme: dark; }
  body {
    font-family: system-ui, sans-serif;
    background: var(--fon);
    color: var(--matn);
  }
  p {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }
  input[role="switch"] {
    appearance: none;
    position: relative;
    flex: none;
    inline-size: 2.75rem;
    block-size: 1.5rem;
    margin: 0;
    border: 2px solid var(--ikkinchi);
    border-radius: 999px;
    background: var(--yuza);
  }
  input[role="switch"]::before {
    content: "";
    position: absolute;
    inset-block-start: 2px;
    inset-inline-start: 2px;
    inline-size: calc(1.5rem - 8px);
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--ikkinchi);
  }
  input[role="switch"]:checked {
    border-color: var(--asosiy);
    background: var(--asosiy);
  }
  input[role="switch"]:checked::before {
    translate: 1.25rem 0;
    background: var(--fon);
  }
  input[role="switch"]:focus-visible {
    outline: 3px solid var(--asosiy);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--fon);
  }
  @media (prefers-reduced-motion: no-preference) {
    input[role="switch"]::before { transition: translate 0.15s; }
  }
  @media (forced-colors: active) {
    input[role="switch"]::before { background: CanvasText; }
  }
</style>
<h1>Sozlamalar</h1>
<p>
  <input id="qorongi" type="checkbox" role="switch">
  <label for="qorongi">Qorong'i rejim</label>
</p>
<p>
  <input id="katta" type="checkbox" role="switch" checked>
  <label for="katta">Katta shrift</label>
</p>

Nimaga qarang: ikki o'chirgich. "Katta shrift" yoqilgan — yashil yo'lak, qaymoq "tugmacha" o'ngda. "Qorong'i rejim" o'chirilgan — oq yo'lak, kulrang tugmacha chapda. "Qorong'i rejim" ni bosing: tugmacha o'ngga suriladi va butun sahifa darhol qorong'i yashilga o'tadi — JavaScript'siz.

  • :root:has(#qorongi:checked) — "ichida belgilangan #qorongi bor hujjat". O'chirgich yoqilishi bilan color-scheme: dark bo'ladi va hamma light-dark() rang ikkinchi qiymatini oladi (Qorong'i rejim). O'chirgich semantikasiga aynan mos: darhol kuchga kiradi.
  • Cheklovi: sahifa yangilansa, tanlov unutiladi. Tanlovni eslab qolish — localStorage va JavaScript ishi; «Bahor»dagi tema-tanlash.js aynan shuni qiladi, uning kodini 09-qismda tushuntiramiz.
  • Tugmacha o'lchami: yo'lak ichki balandligi 24 − 4 = 20 piksel, tugmacha har tomondan 2 piksel bo'shliq bilan — 16 piksel (1.5rem - 8px). Siljish: 44 − 4 − 16 − 4 = 20 piksel = 1.25rem.
  • Holat faqat rangda emas: tugmachaning joyi (chap/o'ng) — asosiy signal. Rangni ajratmaydigan odam ham farqni ko'radi.

Chrome'ning accessibility daraxtida tekshirdik: "Qorong'i rejim — switch, belgilanmagan", "Katta shrift — switch, belgilangan". Ekran o'quvchi odatda buni "o'chirgich, o'chiq/yoqiq" deb aytadi.

Tekshirib ko'ring: Bron formasida "SMS eslatma yuborilsin" uchun o'chirgich chizish to'g'rimi?

Javob

Yo'q. O'chirgich "darhol kuchga kiradi" deb va'da beradi. SMS esa faqat forma yuborilganda buyuriladi — mehmon o'chirgichni yoqib, formani yubormasa, SMS kelmaydi va u aldangandek his qiladi. Formada — checkbox, sozlamalarda — o'chirgich.

6. Prefiksli maydon va suzuvchi yorliq

6.1 Prefiks va suffiks

Telefon maydonida "+998" doim bir xil — mehmon uni yozmasin. Mehmonlar soni yonida "kishi". Bular maydon ichida ko'rinadigan, lekin tahrirlanmaydigan qismlar:

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: var(--rang-fon);
    color: var(--rang-matn);
  }
  form > div {
    display: grid;
    gap: 0.25rem;
    max-inline-size: 18rem;
    margin-block-end: 1rem;
  }
  label { font-weight: 600; }
  .maydon-guruh {
    display: flex;
    border: 2px solid var(--rang-ikkinchi);
    border-radius: 0.5rem;
    background: white;
    overflow: clip;
  }
  .maydon-guruh:focus-within {
    border-color: var(--rang-asosiy);
    outline: 3px solid var(--rang-asosiy-toq);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
  }
  .maydon-guruh span {
    display: grid;
    place-items: center;
    padding-inline: 0.75em;
    background: color-mix(in oklch, var(--rang-ikkinchi) 12%,
      white);
    color: var(--rang-ikkinchi);
  }
  .maydon-guruh input {
    flex: 1;
    min-inline-size: 0;
    min-block-size: 2.75rem;
    padding: 0.5em 0.75em;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
  }
  .maydon-guruh input:focus-visible { outline: none; }
</style>
<form action="https://example.com/bron" method="post">
  <div>
    <label for="telefon">Telefon raqamingiz</label>
    <div class="maydon-guruh">
      <span id="telefon-prefiks">+998</span>
      <input id="telefon" name="telefon" type="tel"
        autocomplete="tel-national" placeholder="90 000 00 00"
        aria-describedby="telefon-prefiks">
    </div>
  </div>
  <div>
    <label for="odam">Mehmonlar soni</label>
    <div class="maydon-guruh">
      <input id="odam" name="odam" type="number" min="1" max="20"
        value="4" aria-describedby="odam-birlik">
      <span id="odam-birlik">kishi</span>
    </div>
  </div>
</form>

Nimaga qarang: "+998" kulrang katakchada maydonning chap chetida, "kishi" — o'ng chetida. Telefon maydonini bosing: halqa ichki maydon atrofida emas, butun guruh atrofida chiqadi — prefiks ham ichida.

  • Ramka o'ramda, maydonda emas. Ichki input — chegarasiz va shaffof, ko'zga u butun guruhning bir qismi.
  • :focus-within — "ichida fokus bor element" (Holat pseudo-klasslari). Halqa o'ramga ko'chdi, shuning uchun ichki maydonning o'z halqasi o'chirildi. :focus-within Baseline, 2020-yildan.
  • min-inline-size: 0 — tor ekranda maydon siqila olsin (min-width: 0).
  • Prefiks o'qilishi kerak. Ko'z uni ko'radi, ekran o'quvchi esa maydon ichidagi matnni o'zi o'qimaydi. aria-describedby="telefon-prefiks" bilan Malika "Telefon raqamingiz, +998" ni eshitadi.
  • autocomplete="tel-national" — brauzer raqamni mamlakat kodisiz to'ldiradi (autocomplete), "+998" ikki marta yozilmaydi.
  • maydon-guruh — namoyish class'i.

6.2 Suzuvchi yorliq

Ba'zi dizaynlarda yorliq maydon ichida turadi va yozishni boshlaganingizda tepaga "suzib" chiqadi. CSS'da buni :placeholder-shown qiladi — "namuna matni hozir ko'rinib turibdi", ya'ni maydon bo'sh:

css
.suzuvchi {
  position: relative;
}

.suzuvchi input {
  padding: 1.25em 0.75em 0.25em; /* tepada yorliq uchun joy */
}

.suzuvchi label {
  position: absolute;
  inset-block-start: 0.35em;
  inset-inline-start: 0.75em;
  transform-origin: left top;
  scale: 0.75;
  pointer-events: none;
}

/* Maydon bo'sh va fokussiz — yorliq o'rtada, katta */
.suzuvchi input:placeholder-shown:not(:focus) + label {
  translate: 0 0.55em;
  scale: 1;
}

HTML'da maydonga bo'sh joydan iborat namuna qo'yiladi — placeholder=" " — aks holda :placeholder-shown hech qachon mos kelmaydi. input esa label dan oldin turadi (+ kombinatori uchun).

Ehtiyot bo'ling: bu uslub chiroyli, lekin muammolari ko'p. Yozish paytida yorliq kichrayib, qiyin o'qiladi. Brauzer avtomatik to'ldirganda ba'zan yorliq va matn ustma-ust tushadi. Namuna matn (masalan, telefon formati) uchun joy qolmaydi — u yordam matniga ko'chadi. Ko'p dizayn tizimlari (masalan, GOV.UK) yorliqni doim maydon ustida saqlaydi. Tanlov sizniki; «Bahor»da oddiy yorliq qoladi.

7. :autofill: brauzer to'ldirgan maydon

Mehmon "Ismingiz" maydonini bossa, brauzer saqlangan ismni taklif qiladi. Tanlangach, maydon brauzerning o'z rangiga bo'yaladi. Chrome'da bu och ko'k fon (#e8f0fe) — qaymoq formada begona dog'.

CSS'da bunday maydon — :autofill. Chrome'ning o'z stilini tekshirdik: fon va matn rangi u yerda !important bilan yozilgan. Kaskad darsidan eslang: brauzerning !important i muallifning !important idan ham kuchli. Tekshirdik — background-color: ... !important ham ishlamadi.

Nima qilish mumkin:

css
input:autofill {
  border-color: var(--rang-asosiy);
  /* Fonni ichki soya bilan "bo'yash" — soya fon ustida chiziladi */
  box-shadow: inset 0 0 0 100px var(--rang-yuza);
}
  • Chegara, halqa, soya — ruxsat. Chrome'da tekshirdik: ichki soya och ko'k fonni butunlay yopdi, ramka yashil bo'ldi. Faqat tartibga e'tibor bering: input:autofill va input:not([type="radio"]) bir xil og'irlikda — :autofill qoidasi maydon qoidasidan keyin tursin, aks holda ramka o'zgarmaydi.
  • Matn rangi ham brauzer qo'lida (fieldtext). Qorong'i rejimda u muammo bo'lishi mumkin — eski kodlarda buning uchun -webkit-text-fill-color ni uchratasiz.
  • Brauzer rangi — foydali signal: "bu yerni men to'ldirdim, tekshiring". Uni butunlay yo'qotmang: ramka rangi bilan belgilab qo'yish yaxshi murosa.

:autofill Baseline emas: Baseline ma'lumotiga ko'ra Chrome, Edge va Safari'da bor, Firefox ro'yxatda yo'q. Ishlamagan joyda brauzerning o'z ko'rinishi qoladi — hech narsa buzilmaydi.

Tekshirib ko'ring: Nega input:autofill { background-color: white !important; } Chrome'da ishlamaydi, box-shadow: inset ... esa ishlaydi?

Javob

Fon rangi Chrome'ning o'z stilida !important bilan yozilgan. Kaskadda brauzerning !important i sizning !important ingizdan kuchli — fon baribir och ko'k qoladi. box-shadow ni esa brauzer band qilmagan. Ichki soya fon ustida chiziladi va uni yopib qo'yadi.

8. «Bahor»ning komponentlar.css iga

Bron formasi uchun asosiy qoidalar (segmentli tanlov va prefiks — namoyish, «Bahor»ga kirmaydi):

css
/* === Forma (Forma komponentlari darsi) === */
form :is(div, fieldset) {
  display: grid;
  gap: var(--masofa-2xs);
}

form label {
  font-weight: 600;
}

span[id$="-yordam"] {
  font-size: var(--step--1);
  color: var(--rang-ikkinchi);
}

span[id$="-xato"] {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--rang-xato);
}

span[id$="-xato"]::before {
  content: "⚠ " / "";
}

:is(input:not([type="checkbox"], [type="radio"]), select, textarea) {
  min-block-size: 2.75rem;
  padding: 0.5em 0.75em; /* shrift bilan o'sadi — ataylab em */
  border: 2px solid var(--rang-ikkinchi);
  border-radius: var(--burchak-m);
  background: var(--rang-yuza);
  color: var(--rang-matn);
}

/* Halqa — asos.css dagi umumiy ikki rangli :focus-visible */
:is(input, select, textarea):focus-visible {
  border-color: var(--rang-asosiy);
}

:is(input, select, textarea):is(:user-invalid,
  [aria-invalid="true"]) {
  border-color: var(--rang-xato);
}

form div:has(> :is(:user-invalid, [aria-invalid="true"])) label {
  color: var(--rang-xato);
}

form div:has(> :user-invalid) span[id$="-yordam"]::before {
  content: "⚠ " / "Xato: ";
}

:is(input, select, textarea):disabled {
  border-style: dashed;
  background: transparent;
  cursor: not-allowed;
}

input:autofill {
  border-color: var(--rang-asosiy);
  box-shadow: inset 0 0 0 100px var(--rang-yuza);
}

/* Checkbox va radio */
input:is([type="checkbox"], [type="radio"]) {
  appearance: none;
  flex: none;
  display: inline-grid;
  place-content: center;
  inline-size: 1.5rem;
  block-size: 1.5rem;
  margin: 0;
  border: 2px solid var(--rang-ikkinchi);
  border-radius: var(--burchak-s);
  background: var(--rang-yuza);
}

input[type="radio"] {
  border-radius: 50%;
}

input:is([type="checkbox"], [type="radio"])::before {
  content: "";
  inline-size: 0.875rem;
  block-size: 0.875rem;
  background: var(--rang-fon);
  scale: 0;
}

input[type="checkbox"]::before {
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0,
    43% 62%);
}

input[type="radio"]::before {
  inline-size: 0.625rem;
  block-size: 0.625rem;
  border-radius: 50%;
}

input:is([type="checkbox"], [type="radio"]):checked {
  border-color: var(--rang-asosiy);
  background: var(--rang-asosiy);
}

input:is([type="checkbox"], [type="radio"]):checked::before {
  scale: 1;
}

fieldset div:has(> [type="radio"]),
form p:has(> [type="checkbox"]) {
  display: flex;
  align-items: center;
  gap: var(--masofa-xs);
}

@media (forced-colors: active) {
  input::before {
    background: CanvasText;
  }
}
  • form :is(div, fieldset) — bron formasidagi o'ramlar. subgrid darsidagi ogohlantirish: Chrome 154 da fieldset subgrid bo'lmaydi — shuning uchun fieldset o'z to'rini oladi, ota to'rga ulanmaydi.
  • Qorong'i rejimda --rang-yuza va --rang-ikkinchi o'zi o'zgaradi. --rang-xato ning qorong'i qiymati «Bahor» tokenlarida hali yo'q — uni yakuniy loyihada (Yakuniy loyiha: landing) palitra bilan birga qo'shasiz.
  • O'chirgich «Bahor» sozlamalar sahifasida bo'ladi — «O'chirgich (switch)» bo'limidagi qoidalar [role="switch"] selektori bilan shu faylga qo'shiladi.

9. Ko'p uchraydigan xatolar

9.1 Placeholder — yorliq o'rnida

<input placeholder="Ismingiz">, label yo'q. Yozishni boshlagan zahoti "Ismingiz" yo'qoladi, ekran o'quvchi uchun nom ishonchsiz. Tuzatish: har doim label; namuna matn — faqat misol uchun.

9.2 Hamma bo'sh maydon ochilishda qizil

:invalid ishlatilgan. Tuzatish: :user-invalid.

9.3 Xato faqat qizil ramka

Rang ko'r odam va ekran o'quvchi xatoni bilmaydi. Tuzatish: belgi + so'z + ramka; xato matni aria-describedby bilan ulangan.

9.4 Checkbox display: none

Klaviatura va ekran o'quvchi uchun element yo'qoladi. Tuzatish: appearance: none yoki ko'rinmas qilib yashirish (opacity: 0 + position: absolute).

9.5 Majburiy ranglar rejimida belgi yo'q

::before belgisi fon rangi bilan chizilgan, rejim uni o'chirdi. Tuzatish: @media (forced-colors: active) { input::before { background: CanvasText; } }.

9.6 Och kulrang ramka

border: 1px solid #ddd — 1.4:1, maydon ko'rinmaydi. Tuzatish: kamida 3:1 kontrastli ramka.

10. Mashqlar

Mashqlarni kurs/mashqlar/06/ papkasida bajaring.

1-mashq (oson): muvaffaqiyat belgisi

Telefon maydoni to'g'ri to'ldirilgach (:user-valid), ramka yashil bo'lsin va yorliq yonida "" chiqsin. Ekran o'quvchi belgini o'qimasin.

Ishora: div:has(> :user-valid) label::after. Muqobil matnni bo'sh qiling: content: " ✓" / "". Muvaffaqiyat rangi — --rang-muvaffaqiyat (Rang nazariyasi: oklch(52% 0.13 150)).

Yechim
css
input:user-valid {
  border-color: var(--rang-muvaffaqiyat);
}

div:has(> input:user-valid) label::after {
  content: " ✓" / "";
  color: var(--rang-muvaffaqiyat);
}

Muqobil matn bo'sh — ekran o'quvchi uchun bu shunchaki bezak: maydon to'g'riligini brauzer baribir biladi. Ehtiyot bo'ling: har maydonga "" qo'yish formani shovqinli qiladi. Uni faqat xatoga moyil maydonlarda (telefon, email) ishlatish yaxshi.

2-mashq (o'rta): checkbox'ning uchinchi holati

"Hamma taomlarni tanlash" checkbox'i ba'zi taomlar tanlanganda qisman holatda ko'rinsin: yashil fon va ichida gorizontal chiziq ("−"). Bu holatni HTML atributi bilan emas, JavaScript indeterminate xususiyati bilan qo'yadi; CSS'da — :indeterminate.

Ishora: ::before ning shaklini almashtiring — clip-path: none va balandlikni kichraytiring. Holatni qo'yadigan qism JavaScript'da — uni 09-qismda o'rganasiz; bu mashqda faqat CSS tomoni.

Yechim

«Checkbox va radio» bo'limidagi qoidalarga qo'shiladi:

css
input:indeterminate {
  border-color: var(--rang-asosiy);
  background: var(--rang-asosiy);
}

input:indeterminate::before {
  block-size: 0.1875rem;
  clip-path: none;
  scale: 1;
}

Natija: yashil kvadrat, ichida qaymoq gorizontal chiziq — "qisman tanlangan". Chrome'da skript bilan indeterminate ni yoqib tekshirdik: ::before 14 × 3 piksellik chiziqqa aylandi, accessibility daraxtida holat — mixed (ekran o'quvchi "qisman belgilangan" deydi). Qoida «Checkbox va radio» dagi :checked qoidasidan keyin yozilsin: og'irligi bir xil, keyingisi yutadi. :indeterminate radio tugmada ham mos keladi — guruhda hech biri tanlanmagan bo'lsa. Shuning uchun uni input[type="checkbox"]:indeterminate deb toraytirsangiz, ishonchliroq.

3-mashq (qiyin): o'chirgichda holat so'zi

Katta yoshdagi mehmonlar o'chirgichni tushunmay qolmasin: yo'lak ichida "Yoq" / "O'ch" so'zlari ko'rinsin — tugmacha qarama-qarshi tomonda, so'z bo'sh tomonda. Ekran o'quvchi bu so'zlarni ikki marta eshitmasin.

Ishora: o'chirgichga ::after qo'shing va content ni holatga qarab almashtiring. Yo'lak eni so'z sig'ishi uchun kattaroq (masalan, 3.5rem), siljish ham qayta hisoblanadi. Muqobil matn — bo'sh.

Yechim
html
<style>
  body { font-family: system-ui, sans-serif; background: #fffaf0; }
  p { display: flex; align-items: center; gap: 0.75rem; }
  input[role="switch"] {
    appearance: none;
    position: relative;
    inline-size: 3.5rem;
    block-size: 1.75rem;
    margin: 0;
    border: 2px solid #5b6660;
    border-radius: 999px;
    background: white;
    font: inherit;
  }
  input[role="switch"]::before {
    content: "";
    position: absolute;
    inset-block-start: 2px;
    inset-inline-start: 2px;
    inline-size: calc(1.75rem - 8px);
    aspect-ratio: 1;
    border-radius: 50%;
    background: #5b6660;
  }
  input[role="switch"]::after {
    content: "O'ch" / "";
    position: absolute;
    inset-block: 0;
    inset-inline-end: 0.375rem;
    display: grid;
    place-items: center;
    font-size: 0.6875rem;
    font-weight: 600;
    color: #5b6660;
  }
  input[role="switch"]:checked {
    border-color: #2f6b3a;
    background: #2f6b3a;
  }
  input[role="switch"]:checked::before {
    translate: 1.75rem 0;
    background: #fffaf0;
  }
  input[role="switch"]:checked::after {
    content: "Yoq" / "";
    inset-inline: 0.5rem auto;
    color: #fffaf0;
  }
  input[role="switch"]:focus-visible {
    outline: 3px solid #1a5d1a;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fffaf0;
  }
</style>
<p>
  <input id="eslatma" type="checkbox" role="switch" checked>
  <label for="eslatma">Aksiyalar haqida xabar</label>
</p>
<p>
  <input id="ovoz" type="checkbox" role="switch">
  <label for="ovoz">Ovozli bildirishnoma</label>
</p>

Birinchi o'chirgichda "Yoq" chapda, tugmacha o'ngda; ikkinchisida tugmacha chapda, "O'ch" o'ngda. Siljish: yo'lak ichi 56 − 4 = 52, tugmacha 20, bo'shliqlar 2 + 2 → 52 − 20 − 4 = 28 piksel = 1.75rem. Muqobil matn bo'sh — Malika "o'chirgich, yoqilgan" ni eshitadi, "Yoq" so'zini ikkinchi marta emas. 11 piksellik so'z kichik, lekin u faqat qo'shimcha signal: asosiy — tugmacha joyi va rang.

4-mashq: Portfolio qadami — aloqa formasi komponentlari

Portfolio'ning aloqa formasi (Yakuniy loyiha): ism va email (form > p ichida label, span[id$="-yordam"], input), "Qaysi mavzuda?" radio guruhi (fieldset), xabar (textarea). Xato holati UI/UX asoslari darsida qo'shilgan.

  1. Matn maydonlari: 2 piksellik --rang-ikkinchi ramka, --burchak-m burchak, fokusda brend ramka + halqa, nofaol — punktir. Brauzerning standart ramkasi qolmasin.
  2. "Qaysi mavzuda?" radio'lari segmentli tanlovga aylansin. HTML'da input o'z label idan oldin turibdi.
  3. Avtomatik to'ldirilgan maydon qaymoq/qorong'i fonda begona ko'rinmasin.
  4. Qorong'i rejimda va majburiy ranglar rejimida tekshiring.

Ishora: portfolio'da class qo'shilmaydi — fieldset:has(> p > [type="radio"]). Radio'lar hozir fieldset p ichida, har biri alohida p da (Yakuniy loyiha). Segmentli tanlovda chetki elementlar — p:first-of-type, p:last-of-type.

Yechim

komponentlar.css dagi forma qismida input:not([type="radio"]), textarea qoidasini kengaytiring va yangi qoidalar qo'shing:

css
/* Matn maydonlari (Forma komponentlari darsi) */
input:not([type="radio"]),
textarea {
  padding: 0.5em; /* shrift bilan o'sadi — ataylab em */
  border: 2px solid var(--rang-ikkinchi);
  border-radius: var(--burchak-m);
  background-color: var(--rang-fon);
  color: var(--rang-matn);
  caret-color: var(--rang-asosiy);
}

:is(input, textarea):focus-visible {
  border-color: var(--rang-asosiy);
}

:is(input, textarea):disabled {
  border-style: dashed;
}

input:autofill {
  border-color: var(--rang-asosiy);
  box-shadow: inset 0 0 0 100px var(--rang-fon);
}

/* "Qaysi mavzuda?" — segmentli tanlov */
fieldset:has(> p > [type="radio"]) {
  display: flex;
  flex-wrap: wrap;
}

fieldset:has(> p > [type="radio"]) legend {
  inline-size: 100%;
}

fieldset:has(> p > [type="radio"]) p {
  margin: 0;
}

fieldset [type="radio"] {
  position: absolute;
  opacity: 0;
  inline-size: 1px;
  block-size: 1px;
}

fieldset [type="radio"] + label {
  display: grid;
  place-items: center;
  min-block-size: 2.75rem;
  padding-inline: 1em;
  border: 2px solid var(--rang-asosiy);
  color: var(--rang-asosiy);
  cursor: pointer;
}

fieldset p:not(:first-of-type) [type="radio"] + label {
  margin-inline-start: -2px;
}

fieldset p:first-of-type [type="radio"] + label {
  border-start-start-radius: var(--burchak-m);
  border-end-start-radius: var(--burchak-m);
}

fieldset p:last-of-type [type="radio"] + label {
  border-start-end-radius: var(--burchak-m);
  border-end-end-radius: var(--burchak-m);
}

fieldset [type="radio"]:checked + label {
  background-color: var(--rang-asosiy);
  color: var(--rang-fon);
  font-weight: bold;
}

fieldset [type="radio"]:focus-visible + label {
  position: relative;
  outline: 2px solid var(--rang-asosiy);
  outline-offset: 2px;
}

@media (forced-colors: active) {
  fieldset [type="radio"]:checked + label {
    border-width: 4px;
  }
}
  • Oldingi fieldset p { display: flex; ... } va input:checked + label { font-weight: bold; } qoidalari endi keraksiz — yangi qoidalar ularni almashtiradi (qalinlik tanlangan chip ichida qoldi). Forma elementlarini stillash darsidagi form { accent-color } ham radio uchun ishlamay qoladi — u endi ko'rinmaydi; qatorni olib tashlasangiz bo'ladi.
  • fieldset ramkasi (Yakuniy loyiha dagi karta ramkasi) qoladi — chiplar uning ichida.
  • Majburiy ranglar rejimida fon rangi o'chadi: tanlangan chip ham, qolganlari ham bir xil ramka bo'lib qoladi. Shuning uchun u yerda tanlanganini qalinroq ramka bilan ajratdik — rangga tayanmaydigan signal.
  • Xato holati o'zgarmadi: label:has(~ :user-invalid) va yordam matnidagi "" (UI/UX asoslari) ishlayveradi. Radio guruhida xato bo'lsa, legend qizaradi.
  • Qorong'i rejimda --rang-fon, --rang-ikkinchi va --rang-asosiy o'zgaradi — ramkalar, chiplar va avtomatik to'ldirish soyasi ham moslashadi.

Tekshiring: Tab bilan radio guruhiga kiring va strelkalar bilan yuring. DevTools → Rendering → forced-colors active — tanlangan mavzu qalin ramkali. So'ng npm run check.

11. Real ishda

  • Har bir mahsulotda formalar bor: ro'yxatdan o'tish, to'lov, buyurtma. Click va Payme kabi to'lov sahifalarida maydon holatlari juda aniq: prefiks (+998), maskalangan karta raqami, darhol xato matni.
  • Dizayn tizimlari forma komponentlarini tugmadan keyin ikkinchi bo'lib quradi. GOV.UK Design System — accessible formalar bo'yicha eng ko'p o'rganiladigan namuna: yorliq doim tepada, xato matni maydon ustida, xatolar ro'yxati sahifa boshida.
  • Kutubxonalar (React Hook Form, Zod — kursda keyinroq) xato holatini boshqaradi, lekin CSS qismi — aria-invalid, xato matni, holatlar — bugun yozganimizdek qoladi.
  • Intervyuda so'raladi: ":invalid va :user-invalid farqi?", "Maxsus checkbox'ni qanday accessible qilasiz?", "Switch va checkbox qachon?", "Autofill fonini nega o'zgartirib bo'lmaydi?".

Xulosa

  • Maydon — yorliq, yordam matni (maydondan oldin), maydon va xato matni bitta o'ramda; holat o'ramga :has() bilan tarqaladi.
  • Xato — :is(:user-invalid, [aria-invalid="true"]); rang + belgi + so'z. Xato matnini CSS bilan yashirib qo'ymang — aria-describedby uni baribir o'qiydi.
  • Maxsus checkbox va radio — appearance: none + ::before; belgilangan holat fon bilan ham ko'rinsin, majburiy ranglar rejimida — CanvasText.
  • O'chirgich — role="switch" li checkbox; u darhol kuchga kiradigan sozlama uchun. :has() bilan JavaScript'siz ta'sir ham berishi mumkin.
  • Radio'ni yashirib, label ni bezash — segmentli tanlov; yashirish opacity: 0 bilan, display: none bilan emas.
  • :autofill foni va matni brauzer qo'lida; chegara va ichki soya — sizning qo'lingizda.

Keyingi dars: Modal oyna va skroll bloklash — bron formasi oynada ochiladi: orqa sahifa surilmasin, oyna telefonda pastdan chiqsin, uzun forma oyna ichida surilsin.

Manbalar

  • MDN: ":user-invalid", ":user-valid", ":has()", "appearance", ":indeterminate", ":placeholder-shown", ":focus-within", ":autofill", "forced-colors", "ARIA: switch role" — developer.mozilla.org
  • WCAG 2.2: 1.4.1 "Use of Color", 1.4.11 "Non-text Contrast", 3.3.1 "Error Identification" — w3.org/TR/WCAG22
  • GOV.UK Design System: "Text input", "Error message" — design-system.service.gov.uk
  • web-features (Baseline ma'lumotlari): "user-pseudos", "has", "appearance", "accent-color", "autofill", "focus-within", "placeholder-shown", "forced-colors" — github.com/web-platform-dx/web-features
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
CSS forma komponentlari: input, checkbox, switch va xato holatlari — IlmHamroh