Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. Loyiha talablari
- 2.1 Nima quriladi
- 2.2 Talablar
- 3. Ish tartibi: olti bosqich
- 4. 1-bosqich: maketdan tokenlarga
- 4.1 Maket
- 4.2 Pikseldan tokenga
- 4.3 Holat ranglarining qorong'i qiymatlari
- 5. 2-bosqich: loyiha tuzilmasi
- 6. 3-bosqich: yig'ish — yechim bo'laklarda
- 6.1 HTML skelet
- 6.2 asosiy.css va tokenlar.css
- 6.3 reset.css, asos.css, layout.css
- 6.4 komponentlar.css
- 6.5 yordamchi.css va skriptlar
- 7. Natija: bosh blok va container query
- 8. 4-bosqich: tekshirish
- 8.1 Enlar va layout
- 8.2 Klaviatura, oyna, harakat va qorong'i rejim
- 8.3 html-validate: ikkita yangi tuzoq
- 8.4 Stylelint: kanonik nomlar va standart to'plam
- 8.5 Lighthouse — Node API orqali
- 8.6 Boshqa brauzerlar
- 9. 5-bosqich: deploy — yangi landing reposi
- 10. Portfolio'ga qo'shing (login.github.io)
- 11. Baholash va o'zingizni tekshirish
- 12. Ko'p uchraydigan xatolar
- 13. Mashqlar
- 1-mashq (oson): o'z brendingiz tokenlari
- 2-mashq (o'rta): 320 pikselda header
- 3-mashq (qiyin): "bron qabul qilindi" toast'i
- 14. 06-qism yakuni: endi nimalarni qila olasiz
- 15. Real ishda
- Xulosa
- Manbalar
Yakuniy loyiha: Figma'dan dizayn tizimi va responsive landing
Qisqacha: Bitta real biznes uchun bir sahifali landing quriladi. Figma maketidagi ranglar, shriftlar va masofalar tokenlarga aylanadi. CSS olti faylga va
@layerqatlamlariga bo'linadi, sahifa 9 ta tayyor komponentdan yig'iladi. Natija Stylelint va html-validate'dan xatosiz o'tadi, Lighthouse'da Accessibility 100 va Performance 99–100 oladi va GitHub Pages'da ishlaydi.
Bu darsda
- Figma maketidan tokenlar yozasiz va holat ranglarining qorong'i qiymatlarini kontrast bilan tanlaysiz.
- 06-qism komponentlaridan landing yig'asiz — qatlamlar, container query va qorong'i rejim bilan.
- Sahifani enlar, klaviatura, lint va Lighthouse bilan tekshirasiz.
- Landing'ni yangi
landingreposiga joylab, portfolio'ingizga qo'shasiz.
Oldin bilishingiz kerak: Yakuniy loyiha: portfolio'ni CSS bilan bezash, Dizayn tokenlari, Qorong'i rejim va temalash, Figma dasturchi uchun 2, Tugmalar tizimi, Modal oyna, Stylelint va Prettier.
1. Nega bu kerak?
06-qismda har dars bitta bo'lakni o'rgatdi: tugma, karta, menyu, oyna, qorong'i rejim, animatsiya. Real ishda ular bir sahifada uchrashadi.
Bu dars — birinchi "buyurtma". Tanishingizning kichik biznesiga (non do'koni, sartaroshxona, o'quv markazi) bitta sahifa kerak: nima qiladi, qancha turadi, qanday bog'lanish mumkin. Bunday sahifa landing (landing page — "qo'nish sahifasi") deyiladi: mehmon reklama yoki qidiruvdan shu sahifaga "qo'nadi" va bitta harakat qiladi — qo'ng'iroq, bron yoki buyurtma.
Usta uyni chizmadan boshlaydi, keyin g'isht va derazalarni tayyor o'lchamda buyuradi. Sizda chizma — Figma maketi, o'lchamlar — tokenlar, g'isht va derazalar — komponentlar.
2. Loyiha talablari
2.1 Nima quriladi
Biznesni o'zingiz tanlaysiz. Namunaviy yechim — «Bahor» choyxonasi landing'i: tuzilishi va fayllari siznikiga mos, faqat matn va ranglar boshqa.
| Bo'lim | Nima bor | Komponent |
|---|---|---|
| Header | Nom, menyu (telefonda yon panel) | Navbar, tugma, ikonka |
| Bosh blok | Sarlavha, 2 ta harakat, 3 ta afzallik, "kun taomi" | Tugma, ikonka, karta |
| Menyu | 4 ta taom kartasi | Karta |
| Fikrlar | Gorizontal lenta | Lenta |
| Savollar | 3 ta savol-javob | Akkordeon |
| Aloqa va footer | Manzil, telefon, bron, mavzu tanlash | Tugmalar guruhi |
| Bron oynasi | 5 maydonli forma | Modal oyna, forma |
Jami 9 ta komponent — hammasi 06-qism darslaridan tayyor keladi, faqat tokenlarga ulanadi.
2.2 Talablar
Bu ro'yxat — baholash jadvalining asosi ham ("Baholash" bo'limi).
- Tokenlar — Figma maketidan, uch daraja: primitiv → semantik → komponent (Dizayn tokenlari). Komponentlarda xom rang yo'q.
- Olti fayl va qatlamlar:
tokenlar, reset, asos, layout, komponentlar, yordamchi(Kaskadni boshqarish). HTML'da bittalink. - Sarlavhalar shkaladan:
h1—--step-3,h2—--step-2,h3—--step-1(Tipografik shkala). - Holat ranglari (
--rang-xatova boshqalar) — ikkala rejimda fonda kamida 4.5:1. - 320, 360, 800 va 1280 pikselda gorizontal skroll yo'q; kamida bitta komponent konteynerga qarab o'zgaradi.
- Qorong'i rejim tizimga ergashadi, foydalanuvchi o'zi ham tanlay oladi (
data-tema). - Har animatsiya
prefers-reduced-motion: reduceda o'chadi. npm run check— 0 xato; Lighthouse (Mobile): Accessibility 100, qolgan uchtasi ≥ 95.
Cheklovlar:
styleatributi va<style>tegi yo'q — CSP ularni to'sadi (HTML darajasidagi xavfsizlik).- JavaScript — faqat uchta kichik fayl (mavzu uchun 2 ta, menyu uchun 1 ta), aynan ko'chiriladi.
class— faqat kanonik nomlar:tugma(+ modifikatorlar),tugma-guruh,ikonka,taom-karta,narx,otish,korinmas. Qolgani — teg, atribut vaidselektorlari.
Tekshirib ko'ring: Sahifa JavaScript'siz ham o'qilishi va bron oynasi ochilishi kerak. Nega, axir hamma brauzerda JavaScript yoqilgan-ku?
Javob
Skript yuklanmay qolishi mumkin: sekin internet, xato, bloklovchi kengaytma. Landing'ning asosiy ishi esa — mehmonni bronga olib kelish. Oyna command="show-modal" bilan (Modal oyna), menyu popover bilan ochiladi — bular HTML imkoniyati. Skriptlar faqat qulaylik qo'shadi. Bu — Brauzer mosligi darsidagi progressive enhancement.
3. Ish tartibi: olti bosqich
| # | Bosqich | Natija |
|---|---|---|
| 1 | Maketdan tokenlar | Token jadvali, tokenlar.css |
| 2 | Loyiha tuzilmasi | Papkalar, sozlamalar, bo'sh fayllar |
| 3 | Yig'ish | HTML skelet, 6 ta CSS fayl, 3 ta skript |
| 4 | Tekshirish | 4 ta en, klaviatura, qorong'i rejim, lint, Lighthouse |
| 5 | Deploy | login.github.io/landing/ |
| 6 | Portfolio | Loyiha kartasi va qayta yuklash |
flowchart LR
F["Figma<br/>Variables"] --> T["tokenlar.css"]
T --> K["komponentlar.css"]
K --> S["index.html"]
S --> L["Lint va<br/>Lighthouse"]
L --> D["GitHub Pages"]Nimaga qarang: zanjir bir yo'nalishda. Maketda rang o'zgarsa, faqat tokenlar.css o'zgaradi — komponentlar va HTML tegilmaydi.
4. 1-bosqich: maketdan tokenlarga
4.1 Maket
Landing maketi Figma dasturchi uchun 2 darsidagi faylda davom etadi:
- Ikki frame: Phone (360) va Desktop (1280). O'rtadagi enlarni kod hal qiladi (fluid shkala, RAM to'r, container query).
- Ikki kolleksiya:
Primitivlar(yashil/600,qaymoq/50...) vaSemantik(rang/asosiy→yashil/600), Web code syntax bilan. - Komponentlar:
Tugma(to'rt tur, uch o'lcham) vaTaom karta(tik va yotiq).
Bepul tarifda Figma rejim (Yorug'/Qorong'i) qo'shishga yo'l bermaydi. Shuning uchun maketda faqat yorug' variant, qorong'i qiymatlar kodda — light-dark() ichida.
4.2 Pikseldan tokenga
Har qiymatni Figma dasturchi uchun 1 darsidagidek o'qing: piksel → rem → token. Namunaviy maketdan bir qismi:
| Maketda (Phone) | Qiymat | Token yoki qoida |
|---|---|---|
| Bosh sarlavha | 28 px, Lora 700 | h1 → --step-3 |
| Bo'lim sarlavhasi | 23 px | h2 → --step-2 |
| Asosiy tugma | balandligi 52 | .tugma.katta (3.25rem) |
| Bo'limlar orasi | 48 | --masofa-2xl |
| Karta burchagi | 8 | --burchak-m |
| Narx rangi | #B4461A |
--rang-urgu |
Maketda 28, kodda 27.6 piksel: --step-3 telefonda 16 × 1.2³ = 27.65. Yarim piksel farq — bu shkala, xato emas. Dizaynerga savol faqat shkalaga umuman tushmaydigan son uchun kerak (Dizayn tokenlari). Tokenlar 60 taga yetmaydi, shuning uchun tokenlar.css qo'lda yoziladi; Figma'dan JSON eksport faqat solishtirish uchun.
4.3 Holat ranglarining qorong'i qiymatlari
«Bahor» tokenlarida bitta bo'shliq qolgan edi: --rang-xato, --rang-muvaffaqiyat, --rang-ogohlantirish, --rang-malumot faqat yorug' rejimda (Rang nazariyasi). Yorug' qiymat oklch(52% 0.19 27) to'q yashil fonda qiyin o'qiladi — qorong'i matn qorong'i fonda.
Qorong'i rang yorqinroq va kamroq to'yingan bo'lsin (Qorong'i rejim). To'rttasiga bir xil ravshanlik berdik: yorug'da L = 52% edi, qorong'ida 75%, to'yinganlik 0.10–0.12. Keyin har rangni ikki fonda tekshirdik: sahifa foni (--rang-fon, #16301b) va karta/oyna foni (--rang-yuza). Yuza fondan yorqinroq — kontrast unda pastroq, og'irroq sinov shu.
Yuzaning hisoblangan rangi Chrome'da — #2a3c24. Kontrastni WCAG formulasi bilan (CSS'da accessibility) colorjs.io kutubxonasida hisobladik:
| Token | Qorong'i qiymat | Fonda | Yuzada |
|---|---|---|---|
--rang-xato |
oklch(75% 0.12 27) |
6.1 | 5.1 |
--rang-muvaffaqiyat |
oklch(75% 0.12 150) |
6.7 | 5.6 |
--rang-ogohlantirish |
oklch(75% 0.11 70) |
6.3 | 5.3 |
--rang-malumot |
oklch(75% 0.1 250) |
6.4 | 5.4 |
Hammasi 4.5:1 dan yuqori. L = 72% da xato yuzada 4.56 — chegarada, shuning uchun 75%.
Xavfli tugma (Tugmalar tizimi) teskari juftlik: matn --rang-fon, fon --rang-xato. Yorug'da — 5.8:1, qorong'ida — 6.1:1, qo'shimcha qoida kerak emas.
<style>
.panel {
--oq: oklch(100% 0 0);
--rang-fon: light-dark(#fffaf0, #16301b);
--rang-yuza: light-dark(var(--oq),
color-mix(in oklch, #16301b, var(--oq) 7%));
--rang-matn: light-dark(#1f2a24, #fffaf0);
--rang-xato: light-dark(oklch(52% 0.19 27),
oklch(75% 0.12 27));
--rang-muvaffaqiyat: light-dark(oklch(52% 0.13 150),
oklch(75% 0.12 150));
--rang-ogohlantirish: light-dark(oklch(52% 0.11 70),
oklch(75% 0.11 70));
--rang-malumot: light-dark(oklch(52% 0.13 250),
oklch(75% 0.1 250));
margin-block: 0.5rem;
padding: 0.75rem;
border-radius: 0.5rem;
font-family: system-ui, sans-serif;
color: var(--rang-matn);
background: var(--rang-fon);
}
.yorug { color-scheme: light; }
.qorongi { color-scheme: dark; }
.panel p { margin: 0.25rem 0; }
.yuza {
padding: 0.5rem 0.75rem;
border-radius: 0.5rem;
background: var(--rang-yuza);
}
.ok { color: var(--rang-muvaffaqiyat); }
.xato { color: var(--rang-xato); }
.ogoh { color: var(--rang-ogohlantirish); }
.info { color: var(--rang-malumot); }
button {
margin-block-start: 0.5rem;
min-block-size: 2.75rem;
padding-inline: 1.25em;
border: 0;
border-radius: 0.5rem;
font: inherit;
font-weight: 600;
background: var(--rang-xato);
color: var(--rang-fon);
}
</style>
<div class="panel yorug">
<p class="ok"><strong>✔ Bron qabul qilindi.</strong></p>
<p class="ogoh"><strong>▲ Shanbaga 2 ta stol qoldi.</strong></p>
<div class="yuza">
<p class="xato"><strong>✖ Telefon noto'g'ri.</strong></p>
<p class="info"><strong>ℹ Bron 2 soat oldin.</strong></p>
</div>
<button type="button">Bronni bekor qilish</button>
</div>
<div class="panel qorongi">
<p class="ok"><strong>✔ Bron qabul qilindi.</strong></p>
<p class="ogoh"><strong>▲ Shanbaga 2 ta stol qoldi.</strong></p>
<div class="yuza">
<p class="xato"><strong>✖ Telefon noto'g'ri.</strong></p>
<p class="info"><strong>ℹ Bron 2 soat oldin.</strong></p>
</div>
<button type="button">Bronni bekor qilish</button>
</div>Nimaga qarang: ikkala panelda CSS bir xil. Yuqorida to'q ranglar qaymoq fonda, pastda och ranglar to'q yashil fonda. Ichki blok — yuza: qorong'ida fondan biroz yorqinroq, ranglar unda ham o'qiladi. .yorug, .qorongi va rang class'lari — faqat namoyish; landing'da rejimni data-tema hal qiladi.
Tekshirib ko'ring: Nega kontrastni
--rang-yuzabilan tekshirish muhimroq?
Javob
Xato matni ko'pincha forma ichida — bron oynasida, ya'ni yuzada. Qorong'ida yuza fondan yorqinroq, och matn bilan farqi kamroq: fonda 6.1, yuzada 5.1. Eng og'ir sharoitda o'tgan rang yengilida ham o'tadi.
5. 2-bosqich: loyiha tuzilmasi
Landing — alohida loyiha, portfolio'ning ichida emas. kurs/ papkangizda yangi papka oching:
landing/
├── package.json
├── .prettierrc
├── .htmlvalidate.json
├── .stylelintrc.json
├── tekshiruv/
│ └── lighthouse.mjs
└── sayt/ ← internetga faqat shu papka ichi
├── index.html
├── favicon.svg
└── assets/
├── css/ asosiy.css + 6 ta fayl
├── js/ tema.js, tema-tanlash.js, menyu.js
├── fonts/ bahor.woff2, OFL.txt
└── images/ osh.svg.prettierrc, .htmlvalidate.json va .stylelintrc.json ni portfolio'dan ko'chiring (Yakuniy loyiha: portfolio). Stylelint sozlamasiga keyin ikki belgi qo'shiladi — sababi "Tekshirish" bosqichida.
Terminalda landing/ ichida buyruqlarni aynan takrorlang (Stylelint va Prettier darsidagidek):
npm init -y
npm install --save-dev prettier html-validate lighthouse
npm install --save-dev stylelint stylelint-config-standardpackage.json ga "type": "module" qatorini qo'shing. "scripts" — portfolio'dagidek, bitta yangisi (audit) bilan:
{
"format": "prettier --write sayt",
"lint": "html-validate \"sayt/**/*.html\"",
"lint:css": "stylelint \"sayt/**/*.css\"",
"check": "prettier --check sayt && npm run lint && npm run lint:css",
"audit": "node tekshiruv/lighthouse.mjs"
}"type": "module" — lighthouse.mjs dagi import qatorlari uchun (JavaScript, 09-qismda).
6. 3-bosqich: yig'ish — yechim bo'laklarda
Avval o'zingiz yozing, keyin solishtiring. Qatorlar telefon uchun 70 belgida bo'lingan — npm run format ularni qayta tekislaydi.
6.1 HTML skelet
Talab: head da tema skripti CSS'dan oldin (Qorong'i rejim), CSS va shrift uchun preload (CSS yuklash samaradorligi); body da skip link, ikonka sprite'i, header, main (bosh blok va 4 bo'lim), footer va oyna.
Yechim: index.html (qisqartirilgan)
<!doctype html>
<html lang="uz">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src 'self' data:;
object-src 'none'; base-uri 'self';
form-action https://example.com">
<title>Choyxona «Bahor» — Chilonzorda oilaviy osh</title>
<meta name="description" content="Choyxona «Bahor»: har kuni
7:00 dan 23:00 gacha osh, lag'mon va manti. 20 kishigacha
stolni bir daqiqada band qiling.">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<script src="assets/js/tema.js"></script>
<link rel="preload" href="assets/css/tokenlar.css" as="style">
<!-- ... reset, asos, layout, komponentlar, yordamchi ... -->
<link rel="preload" href="assets/fonts/bahor.woff2" as="font"
type="font/woff2" crossorigin>
<link rel="stylesheet" href="assets/css/asosiy.css">
<script src="assets/js/menyu.js" defer></script>
<script src="assets/js/tema-tanlash.js" defer></script>
</head>
<body>
<a class="otish" href="#asosiy">Asosiy qismga o'tish</a>
<svg hidden>
<symbol id="i-menyu" viewBox="0 0 24 24">
<path d="M4 7h16M4 12h16M4 17h16"/>
</symbol>
<!-- i-yopish, i-soat, i-joy, i-odam, i-telefon -->
</svg>
<header>
<a href="./">Choyxona «Bahor»</a>
<button class="tugma ikkinchi" type="button"
popovertarget="asosiy-menyu">
<svg class="ikonka" aria-hidden="true">
<use href="#i-menyu"/></svg>
Menyu
</button>
<nav id="asosiy-menyu" aria-label="Asosiy menyu" popover>
<button class="tugma shaffof" type="button"
popovertarget="asosiy-menyu" popovertargetaction="hide">
<svg class="ikonka" aria-hidden="true">
<use href="#i-yopish"/></svg>
Yopish
</button>
<!-- [html-validate-disable-next no-redundant-role] -->
<ul role="list">
<li><a href="#menyu">Menyu</a></li>
<li><a href="#fikrlar">Fikrlar</a></li>
<li><a href="#savollar">Savollar</a></li>
<li><a href="#aloqa">Aloqa</a></li>
</ul>
</nav>
</header>
<main id="asosiy">
<header>
<div>
<svg width="56" height="56" viewBox="0 0 56 56" fill="none"
stroke="currentColor" stroke-width="3"
stroke-linecap="round" aria-hidden="true">
<path d="M10 30h32v4a16 16 0 0 1-32 0Z"/>
<path d="M42 32h3a5 5 0 0 1 0 10h-5"/>
<path d="M20 22c-3-4 3-6 0-10" pathLength="1"/>
<path d="M28 22c-3-4 3-6 0-10" pathLength="1"/>
<path d="M36 22c-3-4 3-6 0-10" pathLength="1"/>
</svg>
<h1>Rustam akaning oshi — har kuni soat 7:00 dan</h1>
<p>Chilonzordagi oilaviy choyxona: katta qozonda osh,
qo'lda cho'zilgan lag'mon va issiq ko'k choy.</p>
<p>
<button class="tugma katta" type="button"
commandfor="bron-oyna" command="show-modal">
Stolni band qilish
</button>
<a class="tugma katta ikkinchi" href="#menyu">
Menyuni ko'rish</a>
</p>
<!-- [html-validate-disable-next no-redundant-role] -->
<ul role="list">
<li><svg class="ikonka" aria-hidden="true">
<use href="#i-soat"/></svg> Har kuni 7:00–23:00</li>
<!-- i-joy: Chilonzor, i-odam: 20 kishigacha stol -->
</ul>
</div>
<aside aria-labelledby="kun-taomi">
<article class="taom-karta">
<img src="assets/images/osh.svg" alt="Lagandagi osh:
sabzi, go'sht va bedana tuxumi" width="480"
height="300" fetchpriority="high">
<h2 id="kun-taomi">Kun taomi: to'y oshi</h2>
<p class="narx">35 000 so'm</p>
<p>Devzira guruch, qo'y go'shti, sariq sabzi va bedana
tuxumi. Tushlikkacha tayyor.</p>
</article>
</aside>
</header>
<section id="menyu" aria-labelledby="menyu-sarlavha">
<h2 id="menyu-sarlavha">Bugungi menyu</h2>
<!-- [html-validate-disable-next no-redundant-role] -->
<ul role="list">
<li>
<article class="taom-karta">
<h3>Osh</h3>
<p>Qazonda, o'tin olovida — har kuni ertalab.</p>
<p class="narx">35 000 so'm</p>
</article>
</li>
<!-- Lag'mon 28 000, Manti 30 000, Ko'k choy 5 000 -->
</ul>
</section>
<section id="fikrlar" aria-labelledby="fikrlar-sarlavha">
<h2 id="fikrlar-sarlavha">Mehmonlar fikri</h2>
<!-- [html-validate-disable-next no-redundant-role] -->
<ul role="list" aria-label="Mehmonlar fikri" tabindex="0">
<li>
<figure>
<blockquote><p>Osh har safar bir xil mazali. Bolalar
uchun alohida stol ham berishdi.</p></blockquote>
<figcaption>Malika, Yunusobod</figcaption>
</figure>
</li>
<!-- yana 3 ta fikr -->
</ul>
</section>
<section id="savollar" aria-labelledby="savollar-sarlavha">
<h2 id="savollar-sarlavha">Ko'p so'raladigan savollar</h2>
<details name="savollar" open>
<summary>Bron qanday qilinadi?</summary>
<p>"Stolni band qilish" tugmasini bosing: ism, telefon,
sana va vaqtni yozing. Biz qo'ng'iroq qilib
tasdiqlaymiz.</p>
</details>
<!-- yana 2 ta savol -->
</section>
<section id="aloqa" aria-labelledby="aloqa-sarlavha">
<h2 id="aloqa-sarlavha">Aloqa</h2>
<!-- [html-validate-disable-next no-redundant-role] -->
<ul role="list">
<li><svg class="ikonka" aria-hidden="true">
<use href="#i-telefon"/></svg>
<a href="tel:+998900000000"
>+998 90 000 00 00</a></li>
<!-- manzil va ish vaqti -->
</ul>
<button class="tugma" type="button"
commandfor="bron-oyna" command="show-modal">
Stolni band qilish
</button>
</section>
</main>
<footer>
<p>© 2026 Choyxona «Bahor». O'quv loyihasi — ma'lumotlar
namuna.</p>
<div class="tugma-guruh" role="group"
aria-label="Sayt mavzusi" hidden>
<button class="tugma ikkinchi kichik" id="tema-tizim"
type="button" aria-pressed="true">Tizim</button>
<button class="tugma ikkinchi kichik" id="tema-yorug"
type="button" aria-pressed="false">Yorug'</button>
<button class="tugma ikkinchi kichik" id="tema-qorongi"
type="button" aria-pressed="false">Qorong'i</button>
</div>
</footer>
<dialog id="bron-oyna" aria-labelledby="bron-sarlavha">
<form action="https://example.com/bron" method="post">
<header role="none">
<h2 id="bron-sarlavha">Stolni band qilish</h2>
<button class="tugma shaffof belgi" type="button"
commandfor="bron-oyna" command="close"
aria-label="Yopish">
<svg class="ikonka" aria-hidden="true">
<use href="#i-yopish"/></svg>
</button>
</header>
<div>
<div>
<label for="ism">Ismingiz</label>
<input id="ism" name="ism" type="text"
autocomplete="name" required>
</div>
<div>
<label for="telefon">Telefon raqamingiz</label>
<input id="telefon" name="telefon" type="tel"
autocomplete="tel" required
pattern="\+?998 ?[0-9]{2} ?[0-9]{3} ?[0-9]{2} ?[0-9]{2}"
aria-describedby="telefon-yordam">
<span id="telefon-yordam">Namuna: +998 90 000 00 00</span>
</div>
<!-- sana (date), vaqt (time, 07:00–22:00),
odam (number, 1–20) — xuddi shunday -->
</div>
<footer role="none">
<button class="tugma shaffof" type="button"
commandfor="bron-oyna" command="close">
Bekor qilish
</button>
<button class="tugma" type="submit">Yuborish</button>
</footer>
</form>
</dialog>
</body>
</html>main > header— bosh blok,body > header— sayt header'i. Navbar darsidagi selektor shuning uchunbody > header: bosh blok yopishqoq bo'lib qolmaydi.role="list"— Safari tuzog'i (Ro'yxatlar stili); izohdagi direktiva html-validate'ningno-redundant-rolexabarini shu qatorda o'chiradi.- Oyna ichidagi
role="none"— sababini "Tekshirish" bosqichida html-validate topadi. form-action https://example.com— forma faqat shu manzilga yuboriladi. O'zingizda bron qabul qiladigan xizmat manzilini yozasiz.
6.2 asosiy.css va tokenlar.css
asosiy.css — qatlamlar e'loni va olti import. tokenlar.css — primitivlar, semantik ranglar, shrift, --step-*, masofa, burchak, soya, qatlam va @font-face.
Yechim: asosiy.css
/* «Bahor» landing — kirish fayli: qatlamlar va importlar */
@layer tokenlar, reset, asos, layout, komponentlar, yordamchi;
@import url("tokenlar.css") layer(tokenlar);
@import url("reset.css") layer(reset);
@import url("asos.css") layer(asos);
@import url("layout.css") layer(layout);
@import url("komponentlar.css") layer(komponentlar);
@import url("yordamchi.css") layer(yordamchi);Yechim: tokenlar.css
/* tokenlar.css — faqat qiymatlar: hech narsa chizmaydi.
Manba: Figma "Bahor landing", Variables. Breakpointlar token
bo'la olmaydi: 40rem va 64rem — qo'lda yoziladi. */
:root {
/* 1. Primitivlar */
--oq: oklch(100% 0 0deg);
--yashil-200: oklch(88% 0.08 150.8deg); /* #b2e7bd */
--yashil-300: oklch(80.3% 0.098 150.8deg); /* #8fd19e */
--yashil-600: oklch(47.5% 0.1 147.7deg); /* #2f6b3a */
--yashil-700: oklch(42.1% 0.12 143.1deg); /* #1a5d1a */
--yashil-900: oklch(28.2% 0.05 148.6deg); /* #16301b */
--qaymoq-50: oklch(98.6% 0.014 84.6deg); /* #fffaf0 */
--gisht-300: oklch(75% 0.13 39.8deg);
--gisht-600: oklch(53.7% 0.153 39.8deg); /* #b4461a */
--kul-300: oklch(80% 0.016 162deg);
--kul-600: oklch(49.9% 0.016 162deg); /* #5b6660 */
--kul-900: oklch(27.2% 0.019 161deg); /* #1f2a24 */
/* 2. Semantik ranglar — zaxira: light-dark() yo'q brauzer
faqat yorug' rejimni ko'radi */
color-scheme: light;
--rang-fon: var(--qaymoq-50);
--rang-yuza: var(--oq);
--rang-matn: var(--kul-900);
--rang-asosiy: var(--yashil-600);
--rang-asosiy-toq: var(--yashil-700);
--rang-urgu: var(--gisht-600);
--rang-ikkinchi: var(--kul-600);
--rasm-filtr: none;
/* Holat ranglari (Rang nazariyasi darsi): L 52% */
--rang-xato: oklch(52% 0.19 27deg);
--rang-muvaffaqiyat: oklch(52% 0.13 150deg);
--rang-ogohlantirish: oklch(52% 0.11 70deg);
--rang-malumot: oklch(52% 0.13 250deg);
/* 3. Shrift */
--shrift-matn: system-ui, sans-serif;
--shrift-sarlavha: "Bahor", "Bahor zaxira", serif;
--qator-matn: 1.5;
--qator-sarlavha: 1.2;
/* O'lcham shkalasi: 360 da 16 × 1.2, 1280 da 18 × 1.25 */
--step--1: clamp(0.8333rem, 0.8072rem + 0.1159vw, 0.9rem);
--step-0: clamp(1rem, 0.9511rem + 0.2174vw, 1.125rem);
--step-1: clamp(1.2rem, 1.1193rem + 0.3587vw, 1.4063rem);
--step-2: clamp(1.44rem, 1.3156rem + 0.5527vw, 1.7578rem);
--step-3: clamp(1.728rem, 1.5444rem + 0.8161vw, 2.1973rem);
/* 4. Masofa: asos 16 → 18 px */
--masofa-2xs: clamp(0.25rem, 0.2378rem + 0.0543vw, 0.2813rem);
--masofa-xs: clamp(0.5rem, 0.4755rem + 0.1087vw, 0.5625rem);
--masofa-s: clamp(0.75rem, 0.7133rem + 0.163vw, 0.8438rem);
--masofa-m: clamp(1rem, 0.9511rem + 0.2174vw, 1.125rem);
--masofa-l: clamp(1.5rem, 1.4266rem + 0.3261vw, 1.6875rem);
--masofa-xl: clamp(2rem, 1.9022rem + 0.4348vw, 2.25rem);
--masofa-2xl: clamp(3rem, 2.8533rem + 0.6522vw, 3.375rem);
--masofa-s-l: clamp(0.75rem, 0.3832rem + 1.6304vw, 1.6875rem);
/* 5. Burchak, soya, qatlam */
--burchak-s: 0.25rem;
--burchak-m: 0.5rem;
--burchak-toliq: 999px;
--soya-1: 0 1px 2px oklch(0% 0 0deg / 12%);
--soya-2:
0 1px 2px oklch(0% 0 0deg / 12%),
0 4px 12px oklch(0% 0 0deg / 12%);
--soya-3:
0 2px 4px oklch(0% 0 0deg / 12%),
0 12px 32px oklch(0% 0 0deg / 18%);
--qatlam-yopishqoq: 10;
--qatlam-menyu: 20;
--qatlam-ustki: 30;
--qatlam-otish: 40;
}
@supports (color: light-dark(white, black)) {
:root {
color-scheme: light dark;
--rang-fon: light-dark(var(--qaymoq-50), var(--yashil-900));
--rang-yuza: light-dark(
var(--oq),
color-mix(in oklch, var(--yashil-900), var(--oq) 7%)
);
--rang-matn: light-dark(var(--kul-900), var(--qaymoq-50));
--rang-asosiy: light-dark(var(--yashil-600), var(--yashil-300));
--rang-asosiy-toq: light-dark(
var(--yashil-700),
var(--yashil-200)
);
--rang-urgu: light-dark(var(--gisht-600), var(--gisht-300));
--rang-ikkinchi: light-dark(var(--kul-600), var(--kul-300));
/* Holat ranglari: qorong'ida L 75%, C pastroq */
--rang-xato: light-dark(
oklch(52% 0.19 27deg),
oklch(75% 0.12 27deg)
);
--rang-muvaffaqiyat: light-dark(
oklch(52% 0.13 150deg),
oklch(75% 0.12 150deg)
);
--rang-ogohlantirish: light-dark(
oklch(52% 0.11 70deg),
oklch(75% 0.11 70deg)
);
--rang-malumot: light-dark(
oklch(52% 0.13 250deg),
oklch(75% 0.1 250deg)
);
/* Soyalar qorong'ida shaffof — balandlikni yuza beradi */
--soya-1:
0 1px 2px light-dark(oklch(0% 0 0deg / 12%), transparent);
--soya-2:
0 1px 2px light-dark(oklch(0% 0 0deg / 12%), transparent),
0 4px 12px light-dark(oklch(0% 0 0deg / 12%), transparent);
--soya-3:
0 2px 4px light-dark(oklch(0% 0 0deg / 12%), transparent),
0 12px 32px light-dark(oklch(0% 0 0deg / 18%), transparent);
}
/* Foydalanuvchi tanlovi (assets/js/tema.js qo'yadi) */
:root[data-tema="yorug"] {
color-scheme: light;
}
:root[data-tema="qorongi"] {
color-scheme: dark;
--rasm-filtr: brightness(0.85);
}
@media screen and (prefers-color-scheme: dark) {
:root:not([data-tema="yorug"]) {
--rasm-filtr: brightness(0.85);
}
}
}
/* Sarlavha shrifti — Lora, SIL OFL 1.1 (Web shriftlar darsi) */
@font-face {
font-family: Bahor;
src: url("../fonts/bahor.woff2") format("woff2");
font-weight: 400 700;
font-display: swap;
}
@font-face {
font-family: "Bahor zaxira";
src: local("Times New Roman");
size-adjust: 115.2%;
ascent-override: 87.33%;
descent-override: 23.78%;
line-gap-override: 0%;
}- Qiymatlar — Dizayn tokenlari va Qorong'i rejim darslaridagi «Bahor» tokenlari. Yangisi — holat ranglarining
light-dark()qatorlari. - Tuslardagi
degva bo'sh qatorlar — Stylelint talablari (Stylelint va Prettier). Token ichidagi"Bahor"esa qo'shtirnoq bilan: aks holda Stylelint uni kalit so'z deb, "kichik harf bilan yozing" deydi.
6.3 reset.css, asos.css, layout.css
reset.css — CSS reset darsidagi «Bahor» reseti o'zgarishsiz. asos.css — teglar, fokus halqasi, oyna ochiqligida skroll bloki. layout.css — ustun, bo'limlar, bosh blok va menyu to'ri, karta konteyneri.
Yechim: asos.css
/* asos.css — teglar: sahifa, sarlavha, havola, fokus. */
html {
scroll-padding-block-start: 5rem; /* sticky header */
scrollbar-gutter: stable;
}
html:has(dialog:modal) {
overflow: hidden;
}
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
body {
font-family: var(--shrift-matn);
font-size: var(--step-0);
line-height: var(--qator-matn);
color: var(--rang-matn);
background: var(--rang-fon);
}
h1,
h2,
h3 {
font-family: var(--shrift-sarlavha);
line-height: var(--qator-sarlavha);
text-wrap: balance;
color: var(--rang-asosiy);
}
h1 {
font-size: var(--step-3);
}
h2 {
font-size: var(--step-2);
}
h3 {
font-size: var(--step-1);
}
p,
li,
dd {
text-wrap: pretty;
}
a {
color: var(--rang-asosiy);
text-decoration-thickness: max(1px, 0.0625em);
text-underline-offset: 0.15em;
}
img {
filter: var(--rasm-filtr);
}
/* Fokus: tashqi to'q halqa + ichki fon rangidagi chiziq */
:focus-visible {
outline: 3px solid var(--rang-asosiy-toq);
outline-offset: 2px;
box-shadow: 0 0 0 2px var(--rang-fon);
}
::selection {
background: var(--rang-asosiy);
color: var(--rang-fon);
}scroll-behavior: smooth faqat no-preference ichida: harakatni kamaytirgan odamda sahifa darhol sakraydi (prefers-reduced-motion).
Yechim: layout.css
/* layout.css — sahifa skeleti. Komponent ichi bu yerda yo'q. */
main > *,
body > footer {
inline-size: min(100% - 2 * var(--masofa-m), 72rem);
margin-inline: auto;
}
main > section {
padding-block-start: var(--masofa-2xl);
}
main > section > h2 {
margin-block: 0 var(--masofa-m);
}
/* Bosh blok: telefonda bitta ustun, 64rem dan ikki ustun */
main > header {
display: grid;
gap: var(--masofa-l);
padding-block-start: var(--masofa-l);
}
@media (width >= 64rem) {
main > header {
grid-template-columns: 3fr 2fr;
align-items: center;
column-gap: var(--masofa-2xl);
}
}
/* Karta konteyneri: karta o'z ustuniga qaraydi, ekranga emas */
:has(> .taom-karta) {
container: kartalar / inline-size;
}
/* Menyu to'ri — RAM (Intrinsic layout darsi) */
#menyu > ul {
display: grid;
grid-template-columns:
repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
gap: var(--masofa-m);
margin: 0;
}
#menyu > ul > li {
display: grid;
}
/* Narx doim kartaning pastida — qo'shni kartalar bir chiziqda */
#menyu .taom-karta {
grid-template-rows: auto 1fr auto;
}
body > footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: var(--masofa-s) var(--masofa-l);
margin-block-start: var(--masofa-2xl);
padding-block: var(--masofa-l);
border-block-start: 1px solid
color-mix(in oklch, var(--rang-asosiy) 25%, var(--rang-fon));
color: var(--rang-ikkinchi);
font-size: var(--step--1);
}:has(> .taom-karta)— "ichida karta bor element": bosh blokdagiasideham, menyudagi harliham class'siz konteyner bo'ladi (Container queries).- Breakpoint bitta — 64rem, bosh blok uchun. Qolgani media query'siz moslashadi (Intrinsic layout).
6.4 komponentlar.css
Komponentlarning ko'pi o'z darsidagi «Bahor» blokidan o'zgarishsiz ko'chadi — dizayn tizimining asosiy foydasi shu:
| Blok | Qayerdan | O'zgarish |
|---|---|---|
| Tugma va guruh | Tugmalar tizimi | Yuklanish holati olib tashlandi, aria-pressed qo'shildi |
| Header va navbar | Navbar va mobil menyu | Brend havolasi, ul margin'i |
| Taom kartasi | Kartalar | Stretched link yo'q, rasmsiz karta |
| Forma | Forma komponentlari | Faqat matn maydonlari (checkbox yo'q) |
| Modal oyna | Modal oyna | O'zgarishsiz |
| Akkordeon | Tabs va accordion | details[name="savollar"] selektori |
| Lenta | Karusel | #fikrlar > ul selektori |
Tartib: skip link → ikonka → tugma → header → bosh blok → karta → lenta → akkordeon → aloqa → forma → oyna → animatsiya. Tugma, navbar, forma va oyna bloklarini o'sha darslardan ko'chiring; quyida — faqat yangi va o'zgargan qismlar.
Yechim: skip link, ikonka, tugmaga qo'shimcha, header
/* === Skip link (CSS'da accessibility darsi) === */
.otish:not(:focus) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.otish:focus {
position: fixed;
inset-block-start: var(--masofa-xs);
inset-inline-start: var(--masofa-xs);
z-index: var(--qatlam-otish);
padding: var(--masofa-xs) var(--masofa-m);
border-radius: var(--burchak-m);
background: var(--rang-asosiy);
color: var(--rang-fon);
}
@keyframes otish-kirish {
from {
translate: 0 -150%;
}
}
@media (prefers-reduced-motion: no-preference) {
.otish:focus {
animation: otish-kirish 0.2s ease-out;
}
}
/* === Ikonka (SVG va ikonka tizimi darsi) — chiziqli to'plam === */
.ikonka {
flex: none;
inline-size: 1.25em;
block-size: 1.25em;
fill: none;
stroke: currentcolor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
/* === Tugma: .tugma bloklaridan keyin (Tugmalar tizimi) === */
.tugma[aria-pressed="true"] {
--_fon: var(--rang-asosiy);
--_matn: var(--rang-fon);
--_chegara: var(--rang-asosiy);
}
/* === Header: navbar blokidan keyin (Navbar darsi) === */
body > header > a {
padding-block: var(--masofa-2xs);
font-family: var(--shrift-sarlavha);
font-size: var(--step-1);
font-weight: 700;
text-decoration: none;
}- Skip link
fixed(portfolio'daabsolute): landing uzun, havola qayerda bo'lsangiz ham ekran burchagida chiqsin. ulmargin'i — navbar blokining o'zidamargin: 0bor (Navbar va mobil menyu). Usiz brauzerning 16 piksellik margin'i qolib, header 1280 pikselda 100 piksel bo'lib ketadi.aria-pressed— tanlangan mavzu tugmasi. Holat HTML'da, CSS faqat uni o'qiydi (Tugmalar tizimi).
Yechim: bosh blok va taom kartasi
/* === Bosh blok === */
main > header h1 {
margin-block: var(--masofa-xs) var(--masofa-s);
}
main > header > div > p {
margin-block: 0 var(--masofa-l);
font-size: var(--step-1);
}
main > header > div > p:has(> .tugma) {
display: flex;
flex-wrap: wrap;
gap: var(--masofa-s);
}
main > header > div > ul {
display: flex;
flex-wrap: wrap;
gap: var(--masofa-xs) var(--masofa-l);
margin: 0;
color: var(--rang-ikkinchi);
}
main > header li,
#aloqa li {
display: flex;
align-items: center;
gap: var(--masofa-xs);
}
main > header li .ikonka,
#aloqa li .ikonka {
color: var(--rang-asosiy);
}
/* === Taom kartasi (Kartalar darsi) === */
.taom-karta {
position: relative;
isolation: isolate;
display: grid;
align-content: start;
gap: var(--masofa-xs);
padding: var(--masofa-xs) var(--masofa-xs) var(--masofa-m);
border-radius: var(--burchak-m);
background: var(--rang-yuza);
box-shadow: var(--soya-1);
}
.taom-karta > :not(img) {
margin: 0;
margin-inline: var(--masofa-xs);
}
.taom-karta img {
inline-size: 100%;
aspect-ratio: 16 / 10;
object-fit: cover;
border-radius: var(--burchak-s);
}
.taom-karta:not(:has(img)) {
padding-block-start: var(--masofa-m);
}
.taom-karta .narx {
color: var(--rang-urgu);
font-weight: 700;
font-variant-numeric: tabular-nums;
}
/* Hover soyasi — faqat shaffoflik o'zgaradi */
.taom-karta::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
box-shadow: var(--soya-3);
opacity: 0;
}
@media (hover: hover) {
.taom-karta:hover::before {
opacity: 1;
}
}
@media (prefers-reduced-motion: no-preference) {
.taom-karta {
transition: translate 0.2s ease-out;
}
.taom-karta::before {
transition: opacity 0.2s ease-out;
}
@media (hover: hover) {
.taom-karta:hover {
translate: 0 -4px;
}
}
}
/* Keng konteynerda — media object */
@container kartalar (width >= 28rem) {
.taom-karta {
grid-template-columns: minmax(8rem, 1fr) 2fr;
grid-template-rows: auto auto 1fr;
padding: var(--masofa-xs);
}
.taom-karta img {
grid-row: span 3;
block-size: 100%;
}
}- Stretched link yo'q — kartalar hech qayerga olib bormaydi.
main > header > div > p— faqat bosh blok matni. Avvalmain > header pyozgan edik: kun taomi kartasidagi narx ham--step-1bo'lib kattalashib ketdi.
Yechim: lenta, akkordeon, aloqa
/* === Fikrlar lentasi (Karusel darsi) === */
#fikrlar > ul {
display: grid;
grid-auto-flow: column;
grid-auto-columns: min(80%, 20rem);
gap: var(--masofa-s);
margin: 0;
padding-block-end: var(--masofa-s);
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
scrollbar-width: thin;
scrollbar-color: var(--rang-asosiy) transparent;
}
#fikrlar > ul > li {
display: grid;
scroll-snap-align: start;
}
#fikrlar figure {
display: grid;
align-content: space-between;
gap: var(--masofa-s);
margin: 0;
padding: var(--masofa-m);
border-inline-start: 4px solid var(--rang-asosiy);
border-radius: var(--burchak-m);
background: var(--rang-yuza);
}
#fikrlar blockquote,
#fikrlar blockquote p {
margin: 0;
}
#fikrlar figcaption {
color: var(--rang-ikkinchi);
font-size: var(--step--1);
}
/* === Savol-javob (Tabs va accordion darsi) === */
details[name="savollar"] {
max-inline-size: 48rem;
border: 1px solid
color-mix(in oklch, var(--rang-asosiy) 25%, var(--rang-fon));
border-radius: var(--burchak-m);
background: var(--rang-yuza);
}
details[name="savollar"] + details[name="savollar"] {
margin-block-start: var(--masofa-xs);
}
details[name="savollar"][open] {
border-color: var(--rang-asosiy);
}
details[name="savollar"] summary {
display: flex;
justify-content: space-between;
gap: var(--masofa-s);
padding: var(--masofa-s) var(--masofa-m);
border-radius: inherit;
font-weight: 700;
cursor: pointer;
}
details[name="savollar"] summary::-webkit-details-marker {
display: none;
}
details[name="savollar"] summary::after {
content: "+" / "";
color: var(--rang-asosiy);
font-size: var(--step-1);
line-height: 1;
}
details[name="savollar"][open] summary::after {
rotate: 45deg;
}
details[name="savollar"] p {
margin: 0;
padding: 0 var(--masofa-m) var(--masofa-s);
}
@media (prefers-reduced-motion: no-preference) {
details[name="savollar"] {
interpolate-size: allow-keywords;
}
details[name="savollar"] summary::after {
transition: rotate 0.2s;
}
details[name="savollar"]::details-content {
block-size: 0;
overflow-y: clip;
transition:
block-size 0.25s ease-out,
content-visibility 0.25s allow-discrete;
}
details[name="savollar"][open]::details-content {
block-size: auto;
}
}
/* === Aloqa ro'yxati === */
#aloqa ul {
display: grid;
gap: var(--masofa-xs);
margin: 0 0 var(--masofa-l);
}Lentada havola yo'q, shuning uchun ul da tabindex="0": Bobur Tab bilan kelib, → bilan suradi (Karusel).
Yechim: forma xatosi va bug' animatsiyasi
Forma bloki Forma komponentlari darsidan (checkbox va radio'siz), bitta qoida qo'shiladi — xato bo'lsa yordam matni ham qizaradi:
form div:has(> :user-invalid) span[id$="-yordam"] {
color: var(--rang-xato);
}Fayl oxiriga — bosh blokdagi piyola bug'i (SVG va ikonka tizimi darsidagi chizilish animatsiyasi):
/* === Bug' chizilishi — bosh blok rasmi === */
main > header > div > svg {
color: var(--rang-asosiy);
}
main > header svg path[pathLength] {
stroke-dasharray: 1;
}
@keyframes bug-chiz {
from {
stroke-dashoffset: 1;
}
}
@media (prefers-reduced-motion: no-preference) {
main > header svg path[pathLength] {
animation: bug-chiz 1.2s ease-out 0.3s backwards;
}
}- Harakatsiz holat — birinchi.
stroke-dasharray: 1vapathLength="1"bilan chiziq to'liq ko'rinadi. Animatsiya faqatno-preferenceda: bug' 0.3 soniyadan keyin 1.2 soniyada "chiziladi".backwardskutish vaqtida chiziqsiz kadrni ushlab turadi (keyframes). - Piyola inline SVG:
<use>ichidagipathga tashqi selektor yetmaydi (SVG va ikonka tizimi). - Sarlavhani animatsiya qilmadik.
h1yoki kun taomi rasmi shaffoflikdan chiqsa, LCP (eng katta element chizilgan vaqt) kechikadi — birinchi ekran "sekin" ko'rinadi.
6.5 yordamchi.css va skriptlar
Yechim: yordamchi.css
/* yordamchi.css — yordamchi class'lar va chop etish. */
.korinmas {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
@media print {
:root,
:root[data-tema] {
color-scheme: light;
}
body > header,
dialog,
main > header > div > p:has(> .tugma),
body > footer [role="group"] {
display: none;
}
#fikrlar > ul {
grid-auto-flow: row;
overflow: visible;
}
section {
break-inside: avoid;
}
}
@page {
size: a4;
margin: 15mm;
}Qog'ozda tugmalar va menyu keraksiz, lenta esa ustun bo'lib to'liq chiqadi — qog'ozni surib bo'lmaydi.
Skriptlarni aynan ko'chiring (JavaScript — 09-qismda). tema.js — Qorong'i rejim darsidagi fayl o'zgarishsiz. Qolgan ikkitasi:
Yechim: tema-tanlash.js va menyu.js
assets/js/tema-tanlash.js:
// Mavzu tugmalari: guruhni ochadi, tanlovni belgilaydi va saqlaydi
const guruh = document.getElementById("tema-tizim")?.parentElement;
const tugmalar = guruh ? guruh.querySelectorAll("button") : [];
function belgila(tema) {
for (const tugma of tugmalar) {
const tanlandi = tugma.id === "tema-" + tema;
tugma.setAttribute("aria-pressed", String(tanlandi));
}
}
for (const tugma of tugmalar) {
tugma.addEventListener("click", () => {
const tema = tugma.id.replace("tema-", "");
if (tema === "tizim") {
delete document.documentElement.dataset.tema;
} else {
document.documentElement.dataset.tema = tema;
}
try {
localStorage.setItem("tema", tema);
} catch {
// saqlab bo'lmasa — tanlov shu sahifada ishlaydi
}
belgila(tema);
});
}
if (guruh) {
belgila(document.documentElement.dataset.tema ?? "tizim");
guruh.hidden = false;
}Mazmuni: "guruhni ko'rsat; tugma bosilsa, <html> ga data-tema qo'y (yoki "Tizim" da olib tashla), tanlovni saqla va tugmani belgila". To'liq tushuntirish — matchMedia va foydalanuvchi sozlamalari darsida.
assets/js/menyu.js:
// Telefon menyusi: havola bosilganda panel yopilsin
const menyu = document.getElementById("asosiy-menyu");
menyu?.addEventListener("click", (hodisa) => {
if (hodisa.target.closest("a") && menyu.matches(":popover-open")) {
menyu.hidePopover();
}
});Nega kerak? Menyu havolasi shu sahifaning bo'limiga olib boradi, popover esa faqat tashqariga bosilganda yoki Esc da yopiladi. Chrome'da skriptsiz "Savollar" bosilgach sahifa surildi, panel ochiq qoldi; skript bilan yopildi.
7. Natija: bosh blok va container query
Eng qiziq joy — kun taomi kartasi: bitta karta uch enda uch xil turadi. Quyida bosh blok (tokenlar o'rniga qiymatlar, shrift Google Fonts'dan, rasm data: SVG — natija oynasi nisbiy yo'lni ochmaydi):
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Lora:wght@400..700">
<style>
:root {
--rang-fon: #fffaf0;
--rang-yuza: #fff;
--rang-matn: #1f2a24;
--rang-asosiy: #2f6b3a;
--rang-urgu: #b4461a;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.5;
color: var(--rang-matn);
background: var(--rang-fon);
}
h1, h2 {
font-family: Lora, serif;
line-height: 1.2;
color: var(--rang-asosiy);
}
h1 {
margin: 0 0 0.75rem;
font-size: clamp(1.728rem, 1.5444rem + 0.8161vw, 2.1973rem);
}
h2 { font-size: 1.3rem; }
main > header {
display: grid;
gap: 1.5rem;
inline-size: min(100% - 2rem, 72rem);
margin-inline: auto;
padding-block: 1.5rem;
}
@media (width >= 64rem) {
main > header {
grid-template-columns: 3fr 2fr;
align-items: center;
column-gap: 3rem;
}
}
main > header > div > p { margin: 0 0 1.5rem; }
main > header > div > p:has(> .tugma) {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.tugma {
display: inline-flex;
align-items: center;
min-block-size: 3.25rem;
padding: 0.25em 1.25em;
border: 2px solid var(--rang-asosiy);
border-radius: 0.5rem;
background: var(--rang-asosiy);
color: var(--rang-fon);
font: inherit;
font-size: 1.2rem;
font-weight: 600;
text-decoration: none;
}
.tugma.ikkinchi {
background: transparent;
color: var(--rang-asosiy);
}
:has(> .taom-karta) { container: kartalar / inline-size; }
.taom-karta {
display: grid;
align-content: start;
gap: 0.5rem;
padding: 0.5rem 0.5rem 1rem;
border-radius: 0.5rem;
background: var(--rang-yuza);
box-shadow: 0 1px 2px #0000001f;
}
.taom-karta > :not(img) { margin: 0 0.5rem; }
.taom-karta img {
inline-size: 100%;
aspect-ratio: 16 / 10;
object-fit: cover;
border-radius: 0.25rem;
}
.narx { color: var(--rang-urgu); font-weight: 700; }
@container kartalar (width >= 28rem) {
.taom-karta {
grid-template-columns: minmax(8rem, 1fr) 2fr;
grid-template-rows: auto auto 1fr;
padding: 0.5rem;
}
.taom-karta img { grid-row: span 3; block-size: 100%; }
}
</style>
<main>
<header>
<div>
<h1>Rustam akaning oshi — har kuni soat 7:00 dan</h1>
<p>Chilonzordagi oilaviy choyxona: katta qozonda osh,
qo'lda cho'zilgan lag'mon va issiq ko'k choy.</p>
<p>
<button class="tugma" type="button">
Stolni band qilish</button>
<a class="tugma ikkinchi" href="#menyu">Menyuni ko'rish</a>
</p>
</div>
<aside aria-labelledby="kun-taomi">
<article class="taom-karta">
<img alt="Lagandagi osh" width="480" height="300"
src="data:image/svg+xml,%3Csvg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 160 100'%3E%3Crect width='160' height='100'
fill='%23e9dcc3'/%3E%3Cellipse cx='80' cy='52' rx='62'
ry='38' fill='%23fffaf0'/%3E%3Cellipse cx='80' cy='52'
rx='50' ry='29' fill='%232f6b3a'/%3E%3Cellipse cx='80'
cy='51' rx='43' ry='23' fill='%23f3d9a4'/%3E%3C/svg%3E">
<h2 id="kun-taomi">Kun taomi: to'y oshi</h2>
<p class="narx">35 000 so'm</p>
<p>Devzira guruch, qo'y go'shti, sariq sabzi va bedana
tuxumi.</p>
</article>
</aside>
</header>
</main>Nimaga qarang:
- 360: bitta ustun, karta tik — rasm tepada.
- 768: hali bitta ustun, lekin karta yotiq: konteyneri 28rem dan oshdi.
- 1280: bosh blok ikki ustunli, karta o'ng ustunda va yana tik — ekran keng, konteyner esa tor.
Media query uchinchi holatni bera olmasdi: ekran kengaygan sari karta yotiq qolardi. Container query kartaga ekranni emas, o'z joyini so'ratadi.
8. 4-bosqich: tekshirish
Sonlar — namunaviy yechimni Chrome'da (Windows) o'lchaganimiz; telefon enlari — mobil qurilma emulyatsiyasida.
8.1 Enlar va layout
| En | Header | Kun taomi kartasi | Menyu to'ri |
|---|---|---|---|
| 320 | 2 qator, 106 px | tik, 288 | 1 ustun |
| 360 | 1 qator, "Menyu" tugmasi | tik, 328 | 1 ustun |
| 800 | Havolalar qatorda | yotiq, 751 | 2 ustun |
| 1280 | Havolalar qatorda | tik, 439 | 4 ustun |
To'rtala enda scrollWidth - clientWidth musbat emas (Yakuniy loyiha: portfolio darsidagi Console tekshiruvi). 320 pikselda header ikki qatorga o'tadi — buni 2-mashqda tuzatasiz.
Sarlavhalar: h1 360 da 27.6, 1280 da 35.2 piksel; h2 — 23.0 va 28.1. Tugmalar: katta — 52, kichik (mavzu) — 32 piksel, 24×24 dan katta (O'lchamlar).
8.2 Klaviatura, oyna, harakat va qorong'i rejim
Tab— chap yuqorida skip link (197×45 piksel) tushib keladi.- "Stolni band qilish" — oyna ochiladi, orqa sahifa surilmaydi. 360 pikselda oyna ekran pastiga yopishadi.
- Telefon maydoniga
12345yozibTabbosing: yorliq, chegara va yordam matni xato rangida, oldida "". - DevTools → Rendering → prefers-reduced-motion: reduce: bug' chizilmaydi, menyu va oyna siljimasdan chiqadi, havola sahifani darhol o'tkazadi.
- Footer'da "Qorong'i":
<html data-tema="qorongi">, fon#16301b. Sahifani yangilang — tanlov saqlangan, oq "chaqnash" yo'q (tema.jsCSS'dan oldin ishlaydi). Oynadagi xato rangi —oklch(0.75 0.12 27), jadvaldagi qiymat. "Tizim" — sayt yana tizimga ergashadi.
8.3 html-validate: ikkita yangi tuzoq
npm run lint birinchi urinishda 9 ta xato berdi:
55:6 error Landmarks must have a non-empty and unique accessible name (aria-label or aria-labelledby) unique-landmark
219:45 error " " should be replaced with " " (non-breaking space) in telephone number tel-non-breaking
230:6 error Landmarks must have a non-empty and unique accessible name (aria-label or aria-labelledby) unique-landmark
245:10 error Landmarks must have a non-empty and unique accessible name (aria-label or aria-labelledby) unique-landmark
256:14 error <input> is missing recommended "type" attribute no-implicit-input-type
284:10 error Landmarks must have a non-empty and unique accessible name (aria-label or aria-labelledby) unique-landmark
✖ 9 problems (9 errors, 0 warnings)(tel-non-breaking to'rt marta — telefon raqamidagi har bo'sh joyga; bu yerda bittasi qoldirildi.)
unique-landmark— "landmark nomlari takrorlanmasin". To'rtta qator: sahifa header/footer'i va oyna ichidagi header/footer.dialogHTML'ga ko'ra "bo'lim" emas, shuning uchun Chrome'ning accessibility daraxtida oynadagiheaderikkinchibanner,footerikkinchicontentinfobo'lib chiqdi — Malika ekran o'quvchisida ikkita "banner" eshitadi. Tuzatish —role="none": element va CSS selektori qoladi, landmark roli o'chadi.tel-non-breaking— telefon raqami bo'linmasin: bo'sh joylar o'rniga (Bo'sh joylar va qator uzish).no-implicit-input-type—type="text"ni aniq yozing.
Tuzatishlardan keyin — 0 xato.
8.4 Stylelint: kanonik nomlar va standart to'plam
Sozlama — portfolio'dagi .stylelintrc.json (Stylelint va Prettier). Undagi custom-property-pattern namunasi _? bilan boshlanadi — shu muhim: «Bahor» komponentlarida pastki chiziq bilan boshlangan ichki o'zgaruvchilar ko'p (--_fon, --_matn, --_chegara — CSS o'zgaruvchilari 2).
Namunada _? bo'lmasa nima bo'lishini sinab ko'rdik (stylelint 17.15, stylelint-config-standard 40.0) — 32 ta xato, hammasi bitta qoida:
sayt/assets/css/komponentlar.css
52:3 ✖ Nom: kichik harf, raqam, chiziqcha custom-property-pattern
53:3 ✖ Nom: kichik harf, raqam, chiziqcha custom-property-pattern
54:3 ✖ Nom: kichik harf, raqam, chiziqcha custom-property-pattern
✖ 32 problems (32 errors, 0 warnings)Shunday xatoni ko'rsangiz, sozlamangiz eski — namunani yangilang:
"custom-property-pattern": [
"^_?([a-z][a-z0-9]*)(--?[a-z0-9]+)*$",
{ "message": "Nom: kichik harf, raqam, chiziqcha" }
]Boshida ixtiyoriy _, qolgani o'zgarishsiz: --Fon yoki --rang_fon baribir ushlanadi. To'g'ri sozlama bilan:
> landing@1.0.0 check
> prettier --check sayt && npm run lint && npm run lint:css
Checking formatting...
All matched files use Prettier code style!
> landing@1.0.0 lint
> html-validate "sayt/**/*.html"
> landing@1.0.0 lint:css
> stylelint "sayt/**/*.css"
Uchala tekshiruv jim — 0 xato.
8.5 Lighthouse — Node API orqali
CSS yuklash samaradorligi darsida Lighthouse'ni brauzerda ishlatgan edik; loyihada uni bitta buyruq qilamiz. tekshiruv/lighthouse.mjs ni aynan ko'chiring:
// Lighthouse — Node API orqali (Mobile, standart sozlama)
// Avval Live Server'ni ishga tushiring: 127.0.0.1:5500
import lighthouse from "lighthouse";
import * as chromeLauncher from "chrome-launcher";
const manzil = process.argv[2] ?? "http://127.0.0.1:5500/";
const chrome = await chromeLauncher.launch({
chromeFlags: ["--headless=new"],
});
const natija = await lighthouse(manzil, {
port: chrome.port,
onlyCategories: [
"performance", "accessibility", "best-practices", "seo",
],
});
const { categories, audits } = natija.lhr;
for (const bolim of Object.values(categories)) {
console.log(bolim.title.padEnd(15), Math.round(bolim.score * 100));
}
console.log(
"FCP", audits["first-contentful-paint"].displayValue,
"| LCP", audits["largest-contentful-paint"].displayValue,
"| CLS", audits["cumulative-layout-shift"].displayValue,
);
chrome.kill();chrome-launcher Lighthouse bilan birga o'rnatiladi. Chrome topilmasa, CHROME_PATH muhit o'zgaruvchisida uning yo'lini bering. npm run audit natijasi (Lighthouse 12.8.2, Mobile, lokal server):
Performance 99
Accessibility 100
Best Practices 100
SEO 100
FCP 1.2 s | LCP 1.7 s | CLS 0Ikkinchi ishga tushirishda Performance 100 chiqdi, qolgani o'sha.
- LCP elementi — kun taomi rasmi. Birinchi o'lchovda "LCP request discovery" qizil edi;
fetchpriority="high"uni yo'qotdi (Resurs maslahatlari). - CLS 0 — rasmda
width/height, shriftdasize-adjustli zaxira. - Sariq qatorlar — matnni siqish va kesh: bu serverning ishi, GitHub Pages ikkalasini o'zi qiladi.
8.6 Boshqa brauzerlar
Landing'ni Firefox va Safari'da (yoki iPhone'da) ham oching. Yangi imkoniyat bo'lmasa — oddiyroq ko'rinish (Brauzer mosligi):
| Imkoniyat | Holati (web-features) | Ishlamagan joyda |
|---|---|---|
light-dark(), @starting-style |
Yangi Baseline (2024) | Faqat yorug' rejim; oyna va menyu animatsiyasiz |
popover (2025-01), invoker commands (2025-12) |
Yangi Baseline | Menyu oddiy ro'yxat, oyna ochilmaydi — "Aloqa"da telefon bor |
scrollbar-gutter, scrollbar-width, text-wrap: balance, @page |
Yangi Baseline (2024) | Oddiy skrollbar va o'rash |
::details-content, scrollbar-color |
Yangi Baseline (2025) | Akkordeon darhol ochiladi, skrollbar tizim rangida |
interpolate-size, overlay |
Baseline emas (Chrome/Edge) | Balandlik va parda animatsiyasi yo'q |
text-wrap: pretty, ::selection, overscroll-behavior, ascent-override |
Baseline emas | Oddiy o'rash va belgilash; zaxira shrift Lora'dan biroz farq qiladi |
Birortasi yo'q bo'lsa ham sahifa o'qiladi va mehmon telefon qilib bron qila oladi.
9. 5-bosqich: deploy — yangi landing reposi
Git'ni hali bilmaysiz (07-qismda), shuning uchun Birinchi deploy darsidagi brauzer yo'li bilan yangi repo ochamiz:
- github.com → + → New repository. Nomi:
landing. Public. Create repository. - uploading an existing file →
sayt/papkasining ichidagi hamma narsani tashlang (index.html,favicon.svg,assets/).package.json,node_modulesva sozlamalar yuklanmaydi — ular faqat kompyuteringizda kerak. - Izoh:
Landing: birinchi versiya→ Commit changes (commit — o'zgarishni saqlash, Git atamasi). - Settings → Pages → Deploy from a branch →
main,/ (root)→ Save.
Bir necha daqiqadan keyin sayt https://login.github.io/landing/ da ochiladi. Bu — loyiha sayti: u landing/ papkasida yashaydi, shuning uchun / bilan boshlangan yo'l ishlamaydi (Birinchi deploy). Landing'da hamma yo'l nisbiy (assets/css/asosiy.css, ./, #menyu).
Deploy'dan keyingi tekshiruv:
- Network: 7 ta CSS, 3 ta JS,
bahor.woff2,osh.svg— hammasi200; Console'da CSP xatosi yo'q. - Telefonda: "Menyu" → havola → panel yopiladi; bron oynasi pastdan chiqadi; qorong'i tizimda sayt ham qorong'i.
- PageSpeed Insights (pagespeed.web.dev), Mobile: siqish va kesh tavsiyalari yo'qolgan.
10. Portfolio'ga qo'shing (login.github.io)
- Loyiha kartasi —
loyihalar/index.htmldagi.loyihalarichiga yangiarticle. Unda sarlavha "«Bahor» landing", sana, tavsif ("Figma maketidan dizayn tizimi, 9 ta komponent, qorong'i rejim, Lighthouse 100") va ikki havola: "Saytni ochish" (https://login.github.io/landing/) va "Kodni ko'rish". Kartada to'rt bola (h2, ikkip,ul) — subgrid'dagispan 4o'zgarmaydi (Yakuniy loyiha: portfolio). - Stylelint — portfolio sozlamasida
_?borligini tekshiring (Stylelint va Prettier);npm run check— 0 xato. - Qayta yuklash — o'zgargan
loyihalar/index.htmlnilogin.github.iorepoga Upload files bilan, izohLoyihalar: landing kartasi.
11. Baholash va o'zingizni tekshirish
Majburiy shartlar: landing login.github.io/landing/ da ochiladi; npm run check — 0 xato; HTML'da style atributi va tegi yo'q.
Ballar (jami 100, o'tish — 80). Talablar — "Loyiha talablari" bo'limida; jadvalda — qanday tekshirish:
| Bo'lim | Qanday tekshiriladi | Ball |
|---|---|---|
| Tokenlar | Ctrl + F → #: rang faqat tokenlar.css da; Figma'da rang/asosiy o'zgarsa, CSS'da bitta qator o'zgaradi |
15 |
| Qatlamlar | 6 fayl, @layer e'loni, !important faqat [hidden] da |
10 |
| Komponentlar | 8+ komponent, kanonik class'lar, komponentlar.css da faqat var(--…) |
15 |
| Responsive | 4 enda skroll yo'q; 800 da karta yotiq, 1280 da tik — sababini ayta olasiz | 10 |
| Qorong'i rejim | data-tema="qorongi" da xato matni, soya va rasm filtri ham o'zgaradi |
10 |
| Harakat | reduce emulyatsiyasida hech narsa siljimaydi, hammasi ko'rinadi |
10 |
| Accessibility | Faqat klaviatura bilan bron formasi to'ldiriladi; oyna landmark'lari | 10 |
| Audit | Lighthouse: A11y 100, qolgani ≥ 95 | 10 |
| Deploy va portfolio | Deploy ro'yxati bajarildi, portfolio'da karta | 10 |
Har bo'limda: hammasi bajarilgan — to'liq ball, bitta kamchilik — yarmi, ko'p — 0.
12. Ko'p uchraydigan xatolar
- Komponentda primitiv.
.narx { color: var(--gisht-600); }— qorong'ida narx to'q qizg'ish qoladi. Tuzatish: faqat semantik token —var(--rang-urgu). - LCP elementiga kirish animatsiyasi.
h1yoki kun taomi rasmiopacity: 0dan chiqsa, Performance tushadi. Tuzatish: birinchi ekranda faqat bezak (bug', ikonka) harakatlansin. /bilan boshlangan yo'l.href="/assets/css/asosiy.css"lokal serverda ishlaydi,login.github.io/landing/da CSS yuklanmaydi. Tuzatish: nisbiy yo'l.node_modulesni yuklash. Butunlanding/tashlansa — minglab fayl, yuklash to'xtaydi. Tuzatish: faqatsayt/ning ichi.
13. Mashqlar
1-mashq (oson): o'z brendingiz tokenlari
Biznesingiz rangini tanlang (masalan, non do'koni uchun jigarrang oklch(45% 0.08 55)), uni --rang-asosiy ga ulang. Yorug' fonda kontrast ≥ 4.5 bo'lsin, qorong'i variant ham qo'shing.
Ishora: Rang nazariyasi shkalasida 600-qadam — brend rangi, qorong'iga 300-qadam. Kontrast — DevTools rang tanlagichida.
Yechim
tokenlar.css da:
:root {
--jigar-300: oklch(78% 0.07 55deg);
--jigar-600: oklch(45% 0.08 55deg);
--rang-asosiy: var(--jigar-600);
}
@supports (color: light-dark(white, black)) {
:root {
--rang-asosiy: light-dark(var(--jigar-600), var(--jigar-300));
}
}Formula bilan: oklch(45% 0.08 55) qaymoq fonda 7.3:1, oklch(78% 0.07 55) to'q yashil fonda 7.0:1 — ikkalasi o'tadi. Semantik nom o'sha, shuning uchun komponentlar o'zgarishni sezmaydi ham. Qorong'i fon ham yashil bo'lmasin desangiz, --yashil-900 o'rniga o'z rangingizni qo'shing va kontrastni qayta hisoblang.
2-mashq (o'rta): 320 pikselda header
320 pikselda header ikki qator (106 piksel) — scroll-padding-block-start: 5rem (80 piksel) dan baland. Menyu havolasi bosilganda bo'lim sarlavhasi header ostida qoladi. Header bir qatorga sig'sin.
Ishora: brend nomi --step-1 (19 piksel). 22.5rem (360 piksel) dan tor ekranda kichikroq qadam yetadimi?
Yechim
komponentlar.css dagi header qismiga:
@media (width < 22.5rem) {
body > header > a {
font-size: var(--step-0);
}
}Chrome'da 320 pikselda: header bir qatorda, 61 piksel — 360 dagidek. Kengroq ekranlarda hech narsa o'zgarmaydi. scroll-padding-block-start ni kattalashtirish ham mumkin edi, lekin keng ekranda sarlavha tepasida ortiqcha bo'shliq qolardi.
3-mashq (qiyin): "bron qabul qilindi" toast'i
Bron yuborilgach, xizmat mehmonni landing'ga qaytaradi deylik. Tooltip, dropdown va toast darsidagi bron-toast ni qo'shing: popover="manual", role="status", muvaffaqiyat rangi, qorong'ida ham o'qiladigan. Uni avtomatik ko'rsatish — JavaScript ishi (09-qism). Hozir tekshirish uchun HTML'ga vaqtincha popovertarget="bron-toast" li tugma qo'ying.
Ishora: faqat tokenlar — --rang-yuza, --rang-muvaffaqiyat, --soya-3, --masofa-*. Harakat no-preference ichida.
Yechim
<div id="bron-toast" popover="manual" role="status">
<p><strong>✔ Bron qabul qilindi.</strong>
Biz qo'ng'iroq qilib tasdiqlaymiz.</p>
<button class="tugma shaffof belgi kichik" type="button"
popovertarget="bron-toast" popovertargetaction="hide"
aria-label="Xabarni yopish">
<svg class="ikonka" aria-hidden="true">
<use href="#i-yopish"/></svg>
</button>
</div>/* === Toast (Tooltip, dropdown va toast darsi) === */
#bron-toast {
inset: auto var(--masofa-m) var(--masofa-m) auto;
max-inline-size: min(100% - 2 * var(--masofa-m), 22rem);
margin: 0;
padding: var(--masofa-s) var(--masofa-xs) var(--masofa-s)
var(--masofa-m);
border: 0;
border-inline-start: 4px solid var(--rang-muvaffaqiyat);
border-radius: var(--burchak-m);
background: var(--rang-yuza);
color: var(--rang-matn);
box-shadow: var(--soya-3);
}
#bron-toast:popover-open {
display: flex;
gap: var(--masofa-s);
align-items: start;
}
#bron-toast p {
margin: 0;
}
#bron-toast strong {
color: var(--rang-muvaffaqiyat);
}
@media (prefers-reduced-motion: no-preference) {
#bron-toast {
opacity: 0;
translate: 0 1rem;
transition:
opacity 0.25s,
translate 0.25s,
display 0.25s allow-discrete,
overlay 0.25s allow-discrete;
}
#bron-toast:popover-open {
opacity: 1;
translate: 0 0;
}
@starting-style {
#bron-toast:popover-open {
opacity: 0;
translate: 0 1rem;
}
}
}display: flexfaqat:popover-openda — yopiq popover'gadisplaybersangiz, u ko'rinib qoladi (Top layer).reduceda toast shunchaki paydo bo'ladi.- Qorong'i rejimga qo'shimcha qoida kerak emas: tokenlar o'zi o'zgaradi, muvaffaqiyat rangi yuzada 5.6:1. Holat ranglarini tokenga qo'shganimizning foydasi shu.
.tugma.belgi.kichik— 32×32 piksel, 24×24 dan katta.
14. 06-qism yakuni: endi nimalarni qila olasiz
Tabriklaymiz — CSS'ning ikkinchi, eng katta qismi tugadi! Endi bilasiz:
- Harakat: transform, transition,
@keyframes, skroll va sahifa o'tishlari —prefers-reduced-motionni hurmat qilib. - Zamonaviy CSS: nesting,
@property,@layer, popover, anchor, container queries va Baseline. - Vositalar: Sass, PostCSS, Stylelint, Prettier, Tailwind.
- Dizayn: tokenlar, shkalalar, rang nazariyasi, Figma'dan kod, komponentlar tizimi.
Eng muhimi — ish usuli: maket → token → komponent → sahifa → o'lchov.
Oldinda: hozir saytni yangilash uchun fayllarni qo'lda yuklaysiz. 07-qismda — Git: har o'zgarish tarixga yoziladi, xato bo'lsa ortga qaytasiz. Qism oxirida portfolio va landing'ni GitHub Actions o'zi joylaydi (GitHub Pages va Actions).
15. Real ishda
- Frilans. Kichik biznes uchun landing — boshlovchi frontend dasturchining eng ko'p uchraydigan birinchi buyurtmasi: mijoz Figma havolasini yuboradi, "telefonda ham chiroyli bo'lsin" deydi.
- Intervyuda: "Qorong'i rejimni tokenlar bilan qanday qildingiz?", "Container va media query farqi?" — o'z landing'ingiz bilan javob berasiz.
Xulosa
- Zanjir: Figma Variables →
tokenlar.css→komponentlar.css→ HTML; o'zgarish bitta nuqtada. - Holat ranglarining qorong'i qiymatlari — L 75%: fonda 6.1–6.7, yuzada 5.1–5.6.
- 9 ta komponent o'z darsidan deyarli o'zgarishsiz keldi; kartani konteyner, menyuni popover, oynani invoker commands boshqaradi.
- Tekshiruv topgan tuzoqlar: oyna ichidagi landmark'lar, ichki o'zgaruvchi nomlari, LCP rasmining ustuvorligi.
- Natija:
npm run check— 0 xato, Lighthouse — Accessibility 100, Performance 99–100.
Keyingi dars: Versiya nazorati nima va nega aynan Git — 07-qism boshlanadi.
Manbalar
- Figma Learn: "Guide to variables in Figma", "Export and import variables" — help.figma.com
- Lighthouse: "Using programmatically" (Node moduli) — github.com/GoogleChrome/lighthouse
- Stylelint: "custom-property-pattern" qoidasi — stylelint.io/user-guide/rules/custom-property-pattern
- html-validate: "unique-landmark", "tel-non-breaking" — html-validate.org/rules
- HTML-AAM:
headervafooterelementlarining roli — w3.org/TR/html-aam-1.0 - web-features (Baseline ma'lumotlari) — github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!