Pseudo-class — :is(), :where(), :has(), :not()
Muammodan boshlaylik
3 va 5-darslarda bu to'rt pseudo-class bilan qisqacha tanishdik. Ular CSS ning so'nggi yillardagi eng kuchli qo'shimchalari: bir paytlar faqat JavaScript bilan qilinadigan ishlarni sof CSS ga o'tkazdi va selektorlarni ancha qisqartirdi.
Bu dars — ularning chuqur tahlili: specificity ga ta'siri, nozik jihatlari va real vazifalar.
:is() — selektorlar ro'yxatini qisqartirish
Takrorlanadigan qismli selektorlar:
/* ❌ uzun va takroriy */
.article h1 a,
.article h2 a,
.article h3 a,
.sidebar h1 a,
.sidebar h2 a,
.sidebar h3 a {
color: inherit;
}
/* ✅ */
:is(.article, .sidebar) :is(h1, h2, h3) a {
color: inherit;
}
:is(A, B, C) — "A, B yoki C dan istalgan biri". Kombinatsiyalarni brauzer o'zi hosil qiladi.
Kechirimli ro'yxat
2-darsdan: oddiy guruhlashda (a, b, c) bitta noto'g'ri selektor butun qoidani bekor qiladi. :is() ichida esa noto'g'ri yoki brauzer tushunmaydigan selektor shunchaki o'tkazib yuboriladi, qolganlari ishlaydi:
:is(input:focus-visible, input:yangi-pseudo-class) {
outline: 2px solid #2563eb; /* eski brauzer ham focus-visible qismini qo'llaydi */
}
Specificity — eng yuqorisi
:is() ning specificity si — ichidagi eng aniq selektorniki (5-dars):
:is(#header, .nav) a { } /* (1, 0, 1) — #header tufayli, hatto .nav ga mos kelganda ham! */
[!WARNING]
:is()ichiga ID qo'yish — butun qoidani ID darajasiga ko'taradi, element.navorqali mos kelsa ham. Keyin uni oddiy class bilan o'zgartirib bo'lmaydi.:is()ichida bir xil "og'irlikdagi" selektorlar bo'lsin.
:where() — nol specificity
:where() — :is() ning egizagi, bitta farq bilan: specificity si har doim nol.
:where(.article, .sidebar) a { } /* (0, 0, 1) — faqat "a" hisoblanadi */
Qachon kerak — oson o'zgartiriladigan standart stillar:
/* Reset va bazaviy stillar — har qanday class ularni yengsin */
:where(ul, ol)[role="list"] {
list-style: none;
padding: 0;
}
:where(button) {
font: inherit;
cursor: pointer;
}
Kutubxona va dizayn tizimlari mualliflari uchun ideal: kutubxona stillari :where() da bo'lsa, foydalanuvchi ularni bitta oddiy class bilan, !important va uzun selektorlarsiz o'zgartira oladi.
:is() |
:where() |
|
|---|---|---|
| Vazifa | Bir xil — ro'yxatdan istalgani | Bir xil |
| Specificity | Ichidagi eng yuqorisi | 0 |
| Qachon | Oddiy qisqartirish | Bazaviy, reset, kutubxona stillari |
:not() — istisno
.btn:not(.btn-primary) { background: #e2e8f0; }
li:not(:last-child) { border-bottom: 1px solid #e2e8f0; }
a:not([href^="/"]) { /* tashqi havolalar */ }
Zamonaviy :not() ro'yxat qabul qiladi:
input:not([type="checkbox"], [type="radio"]) {
width: 100%;
padding: 10px 12px;
}
"Checkbox va radio dan tashqari barcha input lar" — oldin ikkita :not() kerak edi.
Specificity — :is() kabi, ichidagi eng yuqorisi: .btn:not(.btn-primary) = (0, 2, 0).
"Oxirgisidan tashqari" naqshi
/* ❌ ikki qoida */
.menu li { border-right: 1px solid #ccc; }
.menu li:last-child { border-right: none; }
/* ✅ bitta */
.menu li:not(:last-child) { border-right: 1px solid #ccc; }
Yoki bugun — gap (14-dars) va chegaralar o'rniga divide naqshi; lekin ajratuvchi chiziqlar uchun :not(:last-child) — eng aniq.
:has() — ota selektor
CSS tarixidagi eng ko'p kutilgan imkoniyat. Selektorlar doim pastga qarardi (4-dars): "ota ichidagi bola". :has() — yuqoriga qaraydi: "ichida X bor bo'lgan element".
.card:has(img) {
padding-top: 0; /* rasmli kartochkalarda tepada padding yo'q */
}
Real vazifalar
Forma holati:
/* Ichida xato bo'lgan maydon guruhi */
.field:has(input:user-invalid) {
--border: #dc2626;
}
.field:has(input:user-invalid) .error {
display: block;
}
/* Majburiy maydonning label i */
label:has(+ input:required)::after {
content: " *";
color: #dc2626;
}
:user-invalid — :invalid dan farqli o'laroq, foydalanuvchi maydonni o'zgartirgandan keyingina ishlaydi: sahifa ochilganda bo'sh formaning hammasi qizil bo'lib turmaydi.
Checkbox bilan holat — JavaScript siz:
.todo:has(input:checked) .title {
text-decoration: line-through;
color: #94a3b8;
}
/* Butun sahifa — qorong'i rejim tugmasi checkbox bo'lsa */
:root:has(#dark-mode:checked) {
--bg: #0b0f19;
--matn: #f1f5f9;
}
Miqdorga qarab layout:
/* 5 va undan ko'p element bo'lsa — ikki ustun */
.list:has(> :nth-child(5)) {
columns: 2;
}
Oldingi qo'shni (4-dars: kombinatorlar faqat oldinga qarardi):
h2:has(+ p) {
margin-bottom: 8px; /* darhol keyin paragraf kelgan sarlavha */
}
Modal ochiq bo'lsa — sahifa scroll bo'lmasin:
body:has(dialog[open]) {
overflow: hidden;
}
Ehtiyotkorlik
:has()ni keng selektorlarda (body:has(...),*:has(...)) haddan tashqari ishlatmang — har bir DOM o'zgarishida brauzer ko'p elementni qayta tekshirishi mumkin. Aniq konteynerlarga bog'lang:has()ichida yana:has()ishlatib bo'lmaydi- Barcha zamonaviy brauzerlarda (2023 yildan) ishlaydi
Hammasi birga
/* Bazaviy — oson o'zgartiriladigan */
:where(.prose) :is(h2, h3) {
margin-top: 2em;
}
/* Rasmsiz va oxirgi bo'lmagan kartochkalar */
.card:not(:has(img)):not(:last-child) {
border-bottom: 1px solid #e2e8f0;
}
/* Ichida faol havola bo'lgan menyu bo'limi */
.nav-section:has(a[aria-current="page"]) > summary {
font-weight: 700;
color: #2563eb;
}
Nima uchun shunday?
Nima uchun :has() ning paydo bo'lishi shunchalik katta voqea hisoblandi?
Chunki u CSS va JavaScript o'rtasidagi chegarani surdi. Oldin "bola holatiga qarab otani o'zgartirish" — checkbox belgilanganda kartochkani, maydon xato bo'lganda guruhni, rasm bo'lganda layoutni — faqat JavaScript bilan qilinardi: hodisani tinglash, class qo'shish va olib tashlash, holatni sinxronlash. Bu kod xatolarga moyil (class qo'shilib, olib tashlanishi unutiladi) va JavaScript yuklanmaguncha ishlamaydi. :has() bilan bunday holatlar deklarativ: "ichida belgilangan checkbox bo'lsa — shunday ko'rin" — brauzer holatni o'zi kuzatadi, hech qachon sinxrondan chiqmaydi. 4-darsda aytilganidek, brauzer muhandislari buni tez ishlatish yo'lini yillar davomida izlashdi — va natija frontend dasturlashda ko'p narsani soddalashtirdi.
Xulosa
Eslab qoling:
:is(a, b)— ro'yxatdan istalgani; noto'g'ri selektorni kechiradi; specificity — ichidagi eng yuqorisi:is()ichiga ID qo'ymang — butun qoida og'irlashadi:where(a, b)— xuddi shunday, lekin specificity 0 — reset va kutubxona stillari uchun:not(a, b)— istisno, ro'yxat bilan;li:not(:last-child)— ajratuvchilar:has()— ota selektor: ichidagi narsaga qarab tanlash; oldingi qo'shni ham (h2:has(+ p))- Forma holatlari:
:has(input:user-invalid); JavaScript siz holatlar::has(input:checked) :has()ni aniq konteynerlarga bog'lang,body:has()ni haddan oshirmang
Keyingi dars
32-dars: CSS Functions — calc(), min(), max(), clamp()