IlmHamroh
JavaScript Full-stack/6-qism. CSS: harakat, zamonaviy CSS va dizayn54/57-dars20 daqiqa
Mundarija (31)

CSS tabs va accordion: details name, silliq ochilish va tablar stili

Qisqacha: Akkordeon (accordion) — bir-birining ostidagi ochiladigan bo'limlar; eng yaxshi asosi — details elementi va uning name atributi: bir xil name li bloklardan faqat bittasi ochiq turadi, klaviatura va ekran o'quvchi o'z-o'zidan ishlaydi. CSS belgini almashtiradi (summary::after), ochilishni silliq qiladi (::details-content) va holatni bezaydi (details[open]). Tablar (tabs) esa role="tablist" tuzilmasi bilan quriladi: CSS [aria-selected="true"] ni bezaydi, faol tab chizig'ini anchor positioning bilan suradi, atributlarni almashtirish esa — JavaScript ishi.

Bu darsda

  • details name bilan akkordeon quring va uning uchburchak belgisini o'z belgingizga almashtirasiz.
  • Akkordeonning ochiq holati, fokusi va silliq ochilishini harakatni kamaytirish sozlamasini hurmat qilgan holda bezaysiz.
  • ARIA tablarining CSS tomonini — tanlangan tab, panel, fokus — atribut selektorlari bilan yozasiz.
  • Faol tab ostidagi chiziqni anchor positioning bilan bir tabdan ikkinchisiga "suzdirasiz".
  • JavaScript'siz tab ko'rinishidagi tanlovni :has() va radio tugmalar bilan qurasiz va uning cheklovlarini bilasiz.

Oldin bilishingiz kerak: Kirish va chiqish animatsiyalari, Anchor positioning, details va summary, ARIA patternlari, Mantiqiy pseudo-klasslar: :has().

1. Nega bu kerak?

«Bahor» menyusi uzun: issiq taomlar, salatlar, ichimliklar. Telefonda Aziz uchta bo'limni o'tish uchun ekranni besh marta aylantiradi. Savol-javob sahifasida esa o'nta savol bor — javoblari hammasi ochiq bo'lsa, kerakli savolni topish qiyin.

Ikki tanish yechim bor:

  • Akkordeon (accordion) — bo'limlar bir-birining ostida, har biri sarlavhasi bilan. Bosilgani ochiladi. Nomi garmondan olingan: garmon cho'zilsa ochiladi, qisilsa yopiladi.
  • Tablar (tabs) — bo'lim nomlari bir qatorda, ostida bitta panel. Nom bosilsa, panel almashadi. Xuddi daftardagi bo'lim varaqchalari kabi.

HTML qismida ikkalasining ham tuzilmasini yozgan edik. Akkordeon details va summary darsida JavaScript'siz ishladi, lekin "chiroyli akkordeon — CSS ishi" degan edik. Tablarning esa ARIA patternlari darsida HTML va ARIA qismini yozdik va "CSS tomoni — keyinroq" dedik. Kirish va chiqish animatsiyalari darsida esa details ning silliq ochilishini ko'rdik. Bugun ularni tugallangan komponentga aylantiramiz.

Qaysi biri qachon? Qisqa qoida:

Savol Akkordeon Tablar
Bir vaqtda nechta bo'lim ko'rinsin? Bir nechta yoki bitta Faqat bitta
Telefonda qulaymi? Ha, tik joylashadi Nomlar ko'p bo'lsa, sig'maydi
Bo'limlarni solishtirish kerakmi? Ha, ikkitasini ochish mumkin Yo'q
JavaScript kerakmi? Yo'q Ha (yoki cheklangan CSS yo'li)

2. Akkordeon: details name

2.1 Asos va birinchi bezak

Asos — HTML qismidagi kod: har savol — details, sarlavhasi — summary, hammasida bir xil name. Eksklyuziv akkordeon (exclusive accordion) — bir guruhdan faqat bittasi ochiq turadigan akkordeon: yangisi ochilsa, eskisi o'zi yopiladi.

html
<style>
  :root {
    --rang-asosiy: #2f6b3a;
    --rang-fon: #fffaf0;
    --rang-matn: #1f2a24;
    --rang-chegara: #c9d6cf;
  }
  body {
    font-family: system-ui, sans-serif;
    color: var(--rang-matn);
  }
  .savollar { max-width: 28rem; }
  .savollar details {
    border: 1px solid var(--rang-chegara);
    border-radius: 8px;
    background: var(--rang-fon);
  }
  .savollar details + details { margin-top: 8px; }
  .savollar details[open] { border-color: var(--rang-asosiy); }
  .savollar summary {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    font-weight: bold;
  }
  .savollar summary::-webkit-details-marker { display: none; }
  .savollar summary::after {
    content: "+" / "";
    color: var(--rang-asosiy);
    font-size: 20px;
    line-height: 1;
  }
  .savollar details[open] summary::after { rotate: 45deg; }
  .savollar summary:focus-visible {
    outline: 3px solid #1a5d1a;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--rang-fon);
    border-radius: 8px;
  }
  .savollar details p { margin: 0; padding: 0 16px 12px; }
  @media (prefers-reduced-motion: no-preference) {
    .savollar details { interpolate-size: allow-keywords; }
    .savollar summary::after { transition: rotate 0.2s; }
    .savollar details::details-content {
      block-size: 0;
      overflow-y: clip;
      transition:
        block-size 0.25s ease-out,
        content-visibility 0.25s allow-discrete;
    }
    .savollar details[open]::details-content {
      block-size: auto;
    }
  }
</style>
<div class="savollar">
  <details name="savol" open>
    <summary>Bron qanday qilinadi?</summary>
    <p>Bron sahifasida ism, telefon, sana va vaqtni yozing.</p>
  </details>
  <details name="savol">
    <summary>Nechta odam sig'adi?</summary>
    <p>Bitta bronda 20 kishigacha.</p>
  </details>
  <details name="savol">
    <summary>Ish vaqti qanday?</summary>
    <p>Har kuni 7:00 dan 23:00 gacha.</p>
  </details>
</div>

Nimaga qarang: birinchi savol ochiq — ramkasi yashil, o'ngidagi "+" 45° burilib "×" ga aylangan. Qolgan ikkitasining ramkasi kulrang, belgisi "+". Ikkinchi savolni bosing: u silliq ochiladi, birinchisi bir vaqtda yopiladi. Tab bilan yurib ko'ring — summary atrofida to'q yashil halqa, uning ichida esa ingichka qaymoq chiziq chiqadi. Enter yoki Space ochadi. Bu — «Bahor»ning ikki rangli fokus halqasi (CSS'da accessibility): outline + fon rangidagi box-shadow, u och fonda ham, to'q fonda ham ko'rinadi.

Bitta name li akkordeonda HTML'da ikkita open yozsangiz nima bo'ladi? Chrome'da tekshirdik: faqat birinchisi ochiq qoldi, ikkinchisining open ini brauzer o'zi olib tashladi.

2.2 Uchburchak o'rniga o'z belgingiz

Brauzer summary ni ro'yxat bandi kabi chizadi: display: list-item va ::marker da uchburchak. Chrome'da tekshirdik: summary ning standart list-style-type qiymati — disclosure-closed (ochiq holatda disclosure-open). Uchburchakni olib tashlashning uch yo'li bor:

  1. list-style: none — Chrome va Firefox'da yetarli (Ro'yxatlar stili).
  2. display: flex (yoki block) — summary endi ro'yxat bandi emas, marker chizilmaydi. Biz shu yo'lni tanladik: belgini o'ng chetga surish uchun flex baribir kerak edi.
  3. summary::-webkit-details-marker { display: none; } — Safari uchun. Safari uchburchakni eski, o'ziga xos pseudo-element bilan chizadi — faqat shu qoida uni yashiradi. Zarari yo'q: boshqa brauzerlar bu selektorni tanimaydi.

O'rniga summary::after qo'yamiz. Ikki nozik joy:

  • content: "+" / "" — / dan keyingi bo'sh qator — muqobil matn (Pseudo-elementlar). Ekran o'quvchi "plyus" demasin: ochiq-yopiq holatni u details ning o'zidan biladi ("yig'ilgan", "yoyilgan").
  • rotate: 45deg — "+" ni "×" ga aylantiradi, yangi belgi kerak emas. rotate — alohida xususiyat (2D transformlar), shuning uchun transition bilan silliq buriladi.

[open] — atribut selektori (Atribut selektorlari). details ochilganda brauzer unga open atributini o'zi qo'yadi. Ochiq bo'limning ramkasi va belgisi shu selektor bilan bezaladi.

Diqqat: Belgini olib tashladingizmi — o'rniga boshqasini qo'ying. details va summary darsidagi qoida: sarlavha bosiladigan ekani ko'rinib tursin. Belgisiz summary oddiy qalin matnga o'xshaydi va Aziz uni bosish mumkinligini bilmaydi.

2.3 Silliq ochilish — eslatma

Harakat blokidagi to'rt qoida — Kirish va chiqish animatsiyalari darsidagi andoza, o'zgarishsiz: ::details-content ning balandligi 0 → auto, content-visibility uchun allow-discrete, overflow-y: clip. Bu yerda faqat bittasi qo'shildi: belgining burilishi ham harakat blokida. Harakatni kamaytirgan foydalanuvchida belgi darhol "×" bo'ladi — ma'no saqlanadi, harakat yo'q (Harakat etikasi).

Baseline ma'lumoti bo'yicha:

Imkoniyat Holat
details ning name atributi Baseline, 2024-yil sentabrdan (yangi)
::details-content Baseline, 2025-yil sentabrdan (yangi)
interpolate-size Baseline emas: faqat Chrome/Edge 129 dan
content-visibility, allow-discrete Baseline (yangi)

"Yangi" — eski telefonlarda yo'q. Eski brauzerda nima bo'ladi? name ni tanimasa — bir nechta savol birga ochiladi, zarar yo'q. ::details-content ni tanimasa — animatsiya yo'q, blok darhol ochiladi. interpolate-size faqat Chrome'da — Firefox va Safari'da blok ham darhol ochiladi. Akkordeon hamma joyda ishlaydi, faqat chiroyi farq qiladi.

2.4 ::details-content ni bezash

::details-content faqat animatsiya uchun emas. U summary dan keyingi hamma narsani o'raydi — shuning uchun javob qismiga alohida fon yoki chiziq berish mumkin:

css
details[open]::details-content {
  border-block-start: 1px dashed #c9d6cf;
  padding-block-start: 0.5rem;
}

Ilgari buning uchun javobni qo'shimcha div ga o'rash kerak edi. Endi HTML toza qoladi.

Tekshirib ko'ring: Akkordeonda summary { display: flex; } yozildi, lekin iPhone'da uchburchak hamon ko'rinib turibdi. Nima qo'shasiz?

Javob

summary::-webkit-details-marker { display: none; }. Safari markerni ::marker bilan emas, o'zining eski pseudo-elementi bilan chizadi — display va list-style unga ta'sir qilmaydi. Boshqa brauzerlar bu qoidani tanimaydi va shunchaki tashlab ketadi.

2.5 Akkordeon va sarlavhalar

Ekran o'quvchi foydalanuvchilari sahifani ko'pincha sarlavhalar bo'yicha aylanadi. HTML summary ichiga bitta sarlavha qo'yishga ruxsat beradi: <summary><h3>Bron qanday qilinadi?</h3></summary>. Lekin CSS'da ikki narsani unutmang: sarlavhaning standart margin i va o'lchami summary ni kattalashtirib yuboradi — h3 { margin: 0; font-size: inherit; }. Ekran o'quvchilar bunday sarlavhani turlicha e'lon qiladi, shuning uchun muhim sahifada NVDA bilan tekshirib ko'ring (Accessibility'ni tekshirish). Sarlavhalar muhim bo'lsa, ARIA patternlari darsidagi "sarlavha ichida tugma" varianti ishonchliroq — lekin u JavaScript talab qiladi.

3. Tablar: ARIA tuzilmasining CSS tomoni

3.1 Holat — atributlarda

ARIA patternlari darsidagi «Bahor» menyu tablarini eslang: role="tablist", har tabda aria-selected, har panelda role="tabpanel", ko'rinmaydiganlarida hidden. JavaScript tab almashganda shu atributlarni o'zgartiradi.

CSS uchun bu juda qulay: holat HTML atributida yozilgan. Yangi class kerak emas — atribut selektorlari yetadi. Bu qoidaning nomi bor: holatni bitta joyda saqlash. Ekran o'quvchi ko'radigan aria-selected="true" bilan ekrandagi "tanlangan" ko'rinish hech qachon ajralib qolmaydi.

html
<style>
  body { font-family: system-ui, sans-serif; color: #1f2a24; }
  [role="tablist"] {
    display: flex;
    gap: 4px;
    border-bottom: 2px solid #c9d6cf;
  }
  [role="tab"] {
    padding: 10px 14px;
    border: 0;
    border-bottom: 3px solid transparent;
    margin-bottom: -2px;
    background: none;
    color: #5b6660;
    font: inherit;
  }
  [role="tab"]:hover { color: #1f2a24; }
  [role="tab"][aria-selected="true"] {
    border-bottom-color: #2f6b3a;
    color: #2f6b3a;
    font-weight: bold;
  }
  [role="tab"]:focus-visible,
  [role="tabpanel"]:focus-visible {
    outline: 3px solid #1a5d1a;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fffaf0;
  }
  [role="tabpanel"] { padding: 12px 4px; }
  [role="tabpanel"] ul { margin: 0; padding-left: 20px; }
</style>
<div role="tablist" aria-label="Menyu bo'limlari">
  <button type="button" role="tab" id="tab-issiq"
          aria-selected="true"
          aria-controls="panel-issiq">Issiq taomlar</button>
  <button type="button" role="tab" id="tab-salat"
          aria-selected="false" tabindex="-1"
          aria-controls="panel-salat">Salatlar</button>
  <button type="button" role="tab" id="tab-ichimlik"
          aria-selected="false" tabindex="-1"
          aria-controls="panel-ichimlik">Ichimliklar</button>
</div>
<div role="tabpanel" id="panel-issiq"
     aria-labelledby="tab-issiq" tabindex="0">
  <ul>
    <li>Osh — 35 000</li>
    <li>Lag'mon — 28 000</li>
  </ul>
</div>
<div role="tabpanel" id="panel-salat"
     aria-labelledby="tab-salat" tabindex="0" hidden>
  <ul><li>Vinegret — 15 000</li></ul>
</div>
<div role="tabpanel" id="panel-ichimlik"
     aria-labelledby="tab-ichimlik" tabindex="0" hidden>
  <ul><li>Ko'k choy (choynak) — 5 000</li></ul>
</div>

Nimaga qarang: "Issiq taomlar" yashil, qalin va ostida yashil chiziq; qolgan ikki tab kulrang. Umumiy kulrang chiziq ustida faol tabning yashil chizig'i turibdi — margin-bottom: -2px uni ikki piksel pastga tushirib, kulrang chiziqni "yopdi". Panelda faqat issiq taomlar, qolgan ikki panel hidden.

"Salatlar" ni bossangiz — hech narsa bo'lmaydi. Bu kutilgan: aria-selected va hidden ni almashtiradigan JavaScript yo'q. JavaScript'ni 08-qismdan boshlaymiz; tablarni "jonlantiradigan" kodni — strelkalar, tabindex ni ko'chirish, hidden — Dinamik UI'da qulaylik darsida yozamiz. Bugungi CSS o'shanda o'zgarishsiz ishlaydi: JavaScript atributni almashtiradi, ko'rinishni CSS o'zi yangilaydi.

Ish taqsimoti — bir rasmda: atribut bitta, uni ikki tomon o'qiydi.

flowchart LR
  A[Mehmon tabni bosadi] --> B["JavaScript:<br>aria-selected, hidden"]
  B --> C["CSS: tanlangan<br>tabni bezaydi"]
  B --> D["Ekran o'quvchi:<br>'tanlangan' deydi"]

3.2 Uchta selektor — uchta vazifa

  • [role="tab"][aria-selected="true"] — tanlangan tab. Rangdan tashqari qalinlik va chiziq ham bor: rangni farqlamaydigan odam ham tanlanganini ko'radi (Rang nazariyasi darsidagi WCAG 1.4.1).
  • :focus-visible — klaviatura fokusi. Panelda ham: ARIA patternlari darsida panelga tabindex="0" bergan edik, Tab panelga ham tushadi va Bobur buni ko'rishi kerak. Halqa — «Bahor»ning ikki rangli halqasi (CSS'da accessibility): --rang-asosiy-toq rangidagi outline va ichida fon rangidagi box-shadow. Haqiqiy saytda u asos.css dagi umumiy :focus-visible qoidasidan keladi — natijada uni ko'rinsin deb takrorladik.
  • [hidden] — CSS yozish shart emas: brauzer hidden elementni o'zi yashiradi. Faqat bitta xavf bor: panelga display: grid kabi qoida yozsangiz, u hidden ni bosib ketadi (display darsidagi tuzoq). Portfolio'da buning uchun [hidden] qoidasi allaqachon bor.

Tekshirib ko'ring: Dizayner "tanlangan tab faqat yashil rangda bo'lsin, chiziqsiz va oddiy qalinlikda" dedi. Nima deysiz?

Javob

Faqat rang bilan holatni ko'rsatish WCAG 1.4.1 ga zid: rangni ajrata olmaydigan foydalanuvchi qaysi tab tanlanganini bilmaydi. Kamida bitta rangsiz belgi qolsin — chiziq, qalinlik, fon yoki belgi. Ekran o'quvchi uchun esa aria-selected bor — u ko'rinishdan qat'i nazar ishlaydi.

4. Suzuvchi indikator: anchor bilan

4.1 G'oya

Zamonaviy interfeyslarda faol tab chizig'i sakramaydi — bir tabdan ikkinchisiga suzib o'tadi va enini ham yangi tabga moslaydi. Ilgari buni JavaScript qilardi: faol tabning o'rni va enini o'lchab, chiziqqa yozardi.

Anchor positioning bilan bu — bir necha qator CSS:

  1. Tanlangan tab — langar: [aria-selected="true"] { anchor-name: --faol-tab; }.
  2. Chiziq — tablist ning ::after i, u langarga bog'lanadi: left: anchor(left), width: anchor-size(width).
  3. transition: left, width — langar boshqa tabga ko'chganda chiziq suriladi.

Chrome'da tekshirdik: aria-selected ni birinchi tabdan uchinchisiga o'tkazdik. 0,4 soniyali linear o'tishda chiziqning chap cheti 0,2 soniyada 79 pikselda edi (yo'lning taxminan yarmi), 0,6 soniyada — uchinchi tabning boshida, 146 pikselda. En ham 92 dan 75 pikselga silliq o'zgardi.

4.2 JavaScript'siz sinab ko'ramiz: radio tugmalar va :has()

Anchor indikatorini sinash uchun bosilganda haqiqatan almashadigan tablar kerak. JavaScript'siz buning bitta halol yo'li bor — radio tugmalar. Radio guruhidan faqat bittasi tanlanadi — tablar kabi. :has() (Mantiqiy pseudo-klasslar) esa "qaysi radio tanlangan" degan savolga javob beradi va mos panelni ko'rsatadi:

html
<style>
  body { font-family: system-ui, sans-serif; color: #1f2a24; }
  .tanlov fieldset {
    position: relative;
    display: flex;
    gap: 4px;
    margin: 0;
    padding: 0;
    border: 0;
    border-bottom: 2px solid #c9d6cf;
  }
  .tanlov legend {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .tanlov input {
    position: absolute;
    opacity: 0;
  }
  .tanlov label {
    padding: 10px 14px;
    color: #5b6660;
  }
  .tanlov input:checked + label {
    anchor-name: --faol-tab;
    color: #2f6b3a;
    font-weight: bold;
  }
  .tanlov input:focus-visible + label {
    outline: 3px solid #1a5d1a;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fffaf0;
  }
  .tanlov fieldset::after {
    content: "";
    position: absolute;
    position-anchor: --faol-tab;
    top: anchor(bottom);
    left: anchor(left);
    width: anchor-size(width);
    height: 3px;
    background: #2f6b3a;
  }
  @media (prefers-reduced-motion: no-preference) {
    .tanlov fieldset::after {
      transition: left 0.25s ease-out, width 0.25s ease-out;
    }
  }
  .tanlov .panel { display: none; padding: 12px 4px; }
  .tanlov:has(#b-issiq:checked) #p-issiq,
  .tanlov:has(#b-salat:checked) #p-salat,
  .tanlov:has(#b-ichimlik:checked) #p-ichimlik {
    display: block;
  }
</style>
<div class="tanlov">
  <fieldset>
    <legend>Menyu bo'limi</legend>
    <input type="radio" name="bolim" id="b-issiq" checked>
    <label for="b-issiq">Issiq taomlar</label>
    <input type="radio" name="bolim" id="b-salat">
    <label for="b-salat">Salatlar</label>
    <input type="radio" name="bolim" id="b-ichimlik">
    <label for="b-ichimlik">Ichimliklar</label>
  </fieldset>
  <p class="panel" id="p-issiq">Osh — 35 000, lag'mon — 28 000</p>
  <p class="panel" id="p-salat">Vinegret — 15 000</p>
  <p class="panel" id="p-ichimlik">Ko'k choy (choynak) — 5 000</p>
</div>

Nimaga qarang: "Salatlar" ni bosing — yashil chiziq "Issiq taomlar" ostidan chorak soniyada suzib o'tadi va eni "Salatlar" so'ziga moslashadi, panel ham almashadi. Klaviatura bilan: Tab bilan guruhga kiring, keyin → va ← — radio tugmalar kabi tanlov almashadi va chiziq ergashadi. Chrome'da tekshirdik: → bosilganda fokus ham, tanlov ham ikkinchi bandga o'tdi va ikkinchi panel ko'rindi.

Kodda uchta muhim joy:

  • Radio ko'zdan yashiringan, lekin fokus oladi. opacity: 0 va position: absolute — u joy egallamaydi, lekin sahifada bor. display: none qilsangiz, klaviatura unga yetib bora olmasdi. Fokus halqasi esa label ga chiziladi: input:focus-visible + label.
  • legend ko'rinmas, lekin o'qiladi. Ekran o'quvchi guruh nomini eshitadi: "Menyu bo'limi, guruh". Yashirish usuli — 1×1 piksellik o'lcham, overflow: hidden va clip-path: inset(50%): element ko'zga ko'rinmaydi, lekin sahifada qoladi (position darsidagi "ko'rinmas, lekin o'qiladi" texnikasi).
  • Indikator harakati — faqat harakatga ruxsat bo'lsa. Aks holda chiziq darhol yangi tab ostiga "sakraydi".

4.3 Bu tablar emasmi?

Halol javob: bu — radio guruh, tablar emas. Ekran o'quvchi uni taxminan "Menyu bo'limi, guruh, Issiq taomlar, radio tugma, tanlangan" deb e'lon qiladi. Bu yolg'on emas — foydalanuvchi haqiqatan bittasini tanlayapti. Tablar "tablist, tab, panel" rollari bilan bu vazifani aniqroq aytadi, lekin ular JavaScript talab qiladi.

Qachon radio yo'li mos:

  • sahifada JavaScript yo'q yoki taqiqlangan (masalan, xavfsizlik qoidalari skriptni taqiqlagan sahifa yoki brauzerda JavaScript o'chirilgan);
  • tanlov filtr ma'nosida bo'lsa: "Barchasi / Issiq / Salat" — bu tabiiy radio guruh.

Qachon mos emas: panelda uzun kontent va ichida havolalar bo'lgan haqiqiy "bo'limlar" — u yerda ARIA tablari va JavaScript.

div role="tablist" ga radio tugmalarni joylab, "tab" deb e'lon qilish — eng yomon variant: ekran o'quvchi tab deb o'qiydi, lekin strelkalar va aria-selected ishlamaydi. ARIA patternlari darsidagi "rol bor, klaviatura yo'q" xatosining o'zi.

4.4 Brauzer holati

Baseline ma'lumotiga ko'ra anchor positioning — 2026-yil yanvardan Baseline (yangi). Lekin anchor bilan joylashgan elementning animatsiyasi — langar boshqa elementga ko'chganda left/width ning silliq o'zgarishi — Baseline emas: Chrome/Edge 125 va Safari 26 dan bor, Firefox'da yo'q. Firefox'da chiziq yangi tab ostiga darhol sakraydi — ishlaydi, faqat harakatsiz. :has() esa 2026-yil iyunidan keng tarqalgan Baseline: bemalol ishlatsa bo'ladi.

Eski brauzer anchor positioning'ni umuman bilmasa-chi? ::after langarsiz qoladi va fieldset ning chap burchagida 3 piksellik chiziq bo'lib chiqadi — chalg'itadi. Zaxira:

css
@supports not (anchor-name: --x) {
  .tanlov fieldset::after {
    display: none;
  }

  .tanlov input:checked + label {
    border-bottom: 3px solid #2f6b3a;
  }
}

Anchor'siz brauzerda chiziq har tabning o'zida chiziladi — harakatsiz, lekin to'g'ri.

Tekshirib ko'ring: Indikator qoidasida anchor-name label ga emas, input:checked ga yozildi. Chiziq qayerda chiqadi?

Javob

Ko'rinmas radio tugmaning joyida. input position: absolute va opacity: 0 bilan yashiringan, lekin uning qutisi bor — chiziq o'sha kichik qutining enida va joyida chiziladi. Langar — ko'rinadigan narsa bo'lishi kerak: label.

5. Telefonda tablar

Uchta tab telefonga sig'adi, yettitasi — yo'q. Ikki yo'l bor:

  • Gorizontal skroll — tablist ga overflow-x: auto va tablarga flex-shrink: 0. Oxirgi tabning bir qismi chetdan ko'rinib tursin — "yana bor" ishorasi (Skroll xulqi va scroll-snap). Batafsil — keyingi darsda.
  • Tor ekranda akkordeon — kontent bir xil, faqat ko'rinishi boshqa. Bu JavaScript bilan tuzilmani almashtirishni talab qiladi — katta dizayn tizimlari shunday qiladi.

Oddiy saytda ko'pincha birinchi yo'l yetadi. Tab nomlari qisqa bo'lsin: "Issiq taomlar" o'rniga "Issiq".

6. Ko'p uchraydigan xatolar

6.1 Belgi olib tashlandi, o'rniga hech narsa

summary { list-style: none; } — va tamom. Sarlavha oddiy matnga aylandi. Tuzatish: ::after bilan o'z belgingiz va fokus halqasi.

6.2 Belgi ekran o'quvchida "plyus" deb o'qiladi

content: "+" muqobil matnsiz. Tuzatish: content: "+" / ""; — holatni details o'zi aytadi.

6.3 Tanlangan tab faqat rang bilan

Kulrang va yashil — yagona farq. Tuzatish: qalinlik, chiziq yoki fon qo'shing.

6.4 Yashirin radio display: none

Radio-tablarda input { display: none; } — sichqoncha bilan ishlaydi, klaviatura bilan umuman kirib bo'lmaydi. Tuzatish: opacity: 0 + position: absolute, fokus halqasi label da.

6.5 Panelning display i hidden ni bosdi

[role="tabpanel"] { display: grid; } — uchala panel ham ko'rinib qoldi. Tuzatish: [role="tabpanel"]:not([hidden]) yoki umumiy [hidden] { display: none !important; } qoidasi (display).

7. Mashqlar

Mashqlarni kurs/mashqlar/06/ papkasida bajaring: har mashqqa alohida papka, ichida index.html va asosiy.css.

1-mashq (oson): Strelka belgili akkordeon

Akkordeon natijasida "+" belgisini "▾" ga almashtiring: yopiqda pastga qarasin, ochiqda — tepaga.

Ishora: rotate ning qaysi burchagi strelkani teskari qiladi? Muqobil matnni unutmang (/ "").

Yechim
css
.savollar summary::after {
  content: "▾" / "";
}

.savollar details[open] summary::after {
  rotate: 180deg;
}

180° — teskari. Harakat blokidagi transition: rotate 0.2s o'zgarishsiz ishlaydi: strelka chorak soniyadan tezroq aylanadi. Harakatni kamaytirgan foydalanuvchida esa darhol teskari bo'ladi.

2-mashq (o'rta): Tablarga "pilyulya" ko'rinishi

ARIA tablari natijasini boshqa dizaynga o'tkazing: tanlangan tab — yashil fonli, qaymoq matnli, burchaklari to'liq yumaloq "pilyulya"; qolganlari — shaffof fonli, yashil matnli. Pastki kulrang chiziq kerak emas.

Ishora: border-radius ning katta qiymati (Chegara va soyalar). Kontrast: qaymoq matn yashil fonda 6.1:1 — yetarli.

Yechim
css
[role="tablist"] {
  display: flex;
  gap: 4px;
  border-bottom: 0;
}

[role="tab"] {
  padding: 8px 16px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: #2f6b3a;
  font: inherit;
}

[role="tab"][aria-selected="true"] {
  background: #2f6b3a;
  color: #fffaf0;
}

Tanlangan tabda endi fon bor — rangsiz ham ajralib turadi: fon ko'rinadi. margin-bottom: -2px hiylasi kerak emas: pastki chiziq yo'q. 999px — «Bahor» tokenlaridagi --burchak-toliq qiymati (Dizayn tokenlari).

3-mashq (qiyin): Filtr — «Bahor» menyusi

«Bahor» menyu sahifasida filtr kerak: "Barchasi / Issiq / Salat". Har taom kartasida data-tur="issiq" yoki data-tur="salat" bor. JavaScript'siz:

  1. Radio guruh ko'rinishidagi uch tugma, tanlangani anchor chizig'i bilan.
  2. "Issiq" tanlansa — faqat data-tur="issiq" kartalar ko'rinsin; "Barchasi" — hammasi.
  3. Anchor positioning bo'lmagan brauzerda chiziq noto'g'ri joyda chiqmasin.
html
<div class="filtr">
  <fieldset>
    <legend>Taom turi</legend>
    <input type="radio" name="tur" id="f-hammasi" checked>
    <label for="f-hammasi">Barchasi</label>
    <input type="radio" name="tur" id="f-issiq">
    <label for="f-issiq">Issiq</label>
    <input type="radio" name="tur" id="f-salat">
    <label for="f-salat">Salat</label>
  </fieldset>
  <article class="taom-karta" data-tur="issiq">Osh</article>
  <article class="taom-karta" data-tur="salat">Vinegret</article>
  <article class="taom-karta" data-tur="issiq">Manti</article>
</div>

Ishora: 2-band — :has() va atribut selektori birga: "filtr ichida #f-issiq tanlangan bo'lsa, data-tur si issiq bo'lmagan kartalar yashirinsin" — :not() (Mantiqiy pseudo-klasslar). 1- va 3-band — «JavaScript'siz sinab ko'ramiz» va «Brauzer holati» bo'limlari.

Yechim
css
.filtr:has(#f-issiq:checked) .taom-karta:not([data-tur="issiq"]),
.filtr:has(#f-salat:checked) .taom-karta:not([data-tur="salat"]) {
  display: none;
}

"Barchasi" uchun qoida kerak emas: hech bir yashirish sharti bajarilmaydi. Radio, legend, chiziq va @supports not zaxirasi — natijadagi .tanlov qoidalari, faqat .tanlov o'rniga .filtr. Bu yerda radio guruh — to'g'ri semantika: filtr aynan "bittasini tanlash".

filtr — mashq uchun namoyish class'i; «Bahor»ga qo'shish kerak bo'lsa, nom bosh muharrir tasdig'i bilan kanonik ro'yxatga kiritiladi. data-tur — Global atributlar darsidagi data-*.

4-mashq: Portfolio qadami — savol-javob akkordeoni

Portfolio "Aloqa" sahifasidagi details[name="savollar"] endi silliq ochiladi (Kirish va chiqish animatsiyalari darsi). Lekin uchburchagi hamon brauzerniki, rangi faqat ::marker bilan o'zgartirilgan (Yakuniy loyiha). Uni tugallang:

  1. Uchburchak o'rniga o'ng chetda "+" belgisi; ochiqda "×" ga burilsin (harakat faqat ruxsat bo'lsa).
  2. Safari'da ham uchburchak ko'rinmasin.
  3. Ekran o'quvchi belgini o'qimasin.
  4. summary ga klaviatura fokusi aniq ko'rinsin va barmoq uchun kamida 44 piksel balandlik bo'lsin.
  5. Qorong'i rejimda ham, npm run check da ham tekshiring.

Ishora: ::marker qoidasi endi keraksiz — o'rniga ::after. Ranglar — tokenlar.css dagi o'zgaruvchilardan. Fokus halqasi portfolio'da allaqachon bormi — umumiy :focus-visible qoidasini tekshiring.

Yechim

komponentlar.css dagi «Savol-javob» qismida details[name="savollar"] summary::marker qoidasi o'rniga:

css
/* --- Savol-javob belgisi: "+" → "×" (Tabs va accordion darsi) --- */
details[name="savollar"] summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  min-block-size: 2.75rem;
}

details[name="savollar"] summary::-webkit-details-marker {
  display: none;
}

details[name="savollar"] summary::after {
  content: "+" / "";
  color: var(--rang-asosiy);
  font-size: 1.25em;
  line-height: 1;
}

details[name="savollar"][open] summary::after {
  rotate: 45deg;
}

@media (prefers-reduced-motion: no-preference) {
  details[name="savollar"] summary::after {
    transition: rotate 0.2s;
  }
}
  • display: flex — summary ro'yxat bandi bo'lmay qoladi, Chrome va Firefox uchburchagi yo'qoladi; ::-webkit-details-marker — Safari'niki.
  • min-block-size: 2.75rem — 44 piksel. align-items: center matnni shu balandlik o'rtasiga qo'yadi.
  • ::marker qoidasi olib tashlandi — display: flex dan keyin u baribir chizilmaydi; o'lik kod qoldirmang.
  • Fokus — portfolio'ning umumiy :focus-visible halqasi summary ga ham ishlaydi, alohida qoida shart emas. Tekshiring: Tab bilan savolga keling.
  • Harakat bloki Kirish va chiqish animatsiyalari darsidagi ::details-content bloki bilan bir xil shartda; ularni bitta @media ichiga birlashtirsangiz ham bo'ladi.

Qorong'i rejimda --rang-asosiy och yashilga almashadi — belgi ham o'zi moslashadi. npm run check: Stylelint (17.15, standard config) ::-webkit-details-marker ga e'tiroz bildirmadi — alohida faylda tekshirdik.

8. Real ishda

  • Savol-javob (FAQ) sahifalari deyarli hamma saytda akkordeon. details asosida qurilgani qulay: yopiq matn ham HTML'da bor, zamonaviy brauzerlarda Ctrl + F uni topib ochadi.
  • Komponent kutubxonalari — Radix, Headless UI, shadcn/ui (React qismida uchratasiz, hozir bilish shart emas) — tablar va akkordeonni ARIA atributlari bilan chiqaradi. Ularni bezashda aynan shu darsdagi selektorlar ishlaydi: [aria-selected="true"], [data-state="open"].
  • Intervyuda so'raladi: "Akkordeonni JavaScript'siz qanday qilasiz?", "Tablar uchun qaysi ARIA rollari kerak?", "height: auto ni qanday animatsiya qilasiz?". details name, role="tablist" va ::details-content — uchala savolga javob.
  • Dizayn tizimlarida tab indikatori ko'pincha "suzuvchi" — endi uni JavaScript'siz, anchor bilan qila olasiz.

Xulosa

  • Akkordeon — details + bir xil name; eski brauzerda ham ishlaydi, faqat bir nechtasi birga ochilishi mumkin.
  • Uchburchak: display: flex yoki list-style: none + Safari uchun ::-webkit-details-marker; o'rniga summary::after (content: "+" / ""), ochiq holat — details[open].
  • Silliq ochilish — ::details-content + interpolate-size (faqat Chrome), harakat blokida.
  • Tablar holati — ARIA atributlarida; CSS [aria-selected="true"], :focus-visible va [hidden] ga tayanadi, atributlarni JavaScript almashtiradi.
  • Suzuvchi indikator — tanlangan tab langar, chiziq anchor() va anchor-size() bilan; animatsiyasi Firefox'da yo'q, anchor'siz brauzerga @supports not zaxirasi.
  • Radio + :has() — JavaScript'siz halol "bittasini tanlash" (filtr uchun ideal), lekin u tablar emas.

Keyingi dars: Karusel va gorizontal skroll lentasi — scroll-snap lentaga tugma va nuqtalar qo'shamiz, karusel qachon kerak emasligini ham ko'ramiz.

Manbalar

  • MDN: "The Details disclosure element", "::details-content", "interpolate-size" — developer.mozilla.org
  • WAI-ARIA APG: "Tabs Pattern", "Accordion Pattern" — w3.org/WAI/ARIA/apg
  • web-features: "details-name", "details-content", "anchor-positioning-animations" — web-platform-dx.github.io/web-features-explorer
  • Chrome for Developers: "Animate to height: auto; (and other intrinsic sizing keywords) in CSS" — developer.chrome.com
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
CSS tabs va accordion: details name, silliq ochilish va tablar stili — IlmHamroh