Platón adatintelligencia.
Vertical Search & Ai.

A kaszkád megszelídítése BEM-mel és modern CSS-választókkal

Találka:

BEM. Mint látszólag minden technika a front-end fejlesztés világában, CSS írása BEM formátumban polarizáló lehet. De ez – legalábbis az én Twitter-buborékomban – az egyik jobban kedvelt CSS-módszer.

Személy szerint szerintem a BEM jó, és szerintem használd. De azt is értem, hogy miért nem.

Függetlenül a BEM-mel kapcsolatos véleményétől, számos előnnyel jár, a legnagyobb az, hogy segít elkerülni a specifikusság ütközéseket a CSS Cascade-ban. Ennek az az oka, hogy megfelelő használat esetén minden BEM formátumban írt szelektornak azonos specifikussági pontszámmal kell rendelkeznie (0,1,0). Az évek során rengeteg nagyméretű webhelyhez terveztem a CSS-t (gondoljunk csak a kormányra, az egyetemekre és a bankokra), és ezeken a nagyobb projekteken tapasztaltam, hogy a BEM igazán ragyogó. A CSS írása sokkal szórakoztatóbb, ha biztos abban, hogy az írott vagy szerkesztett stílusok nincsenek hatással a webhely más részére.

Valójában vannak kivételek, ahol teljesen elfogadhatónak tekinthető a specifikusság hozzáadása. Például: a :hover és a :focus pszeudo osztályok. Ezeknek specifitási pontszámuk van 0,2,0. A másik a pszeudo elemek – mint pl ::before és a ::after — amelyek specifitási pontszáma: 0,1,1. A cikk hátralévő részében azonban tegyük fel, hogy nem akarunk semmilyen más specifikusságot. 🤓

De valójában nem azért vagyok itt, hogy eladjak téged a BEM-en. Ehelyett arról szeretnék beszélni, hogyan használhatjuk a modern CSS-szelektorok mellett – gondoljunk csak bele :is(), :has(), :where()stb. – még nyerni több ellenőrzése a Cascade.

Mi ez a modern CSS-választókkal?

A CSS Selectors Level 4 spec néhány hatékony új módszert kínál az elemek kiválasztására. Néhány kedvencem közé tartozik :is(), :where()és :not(), amelyek mindegyikét minden modern böngésző támogatja, és manapság szinte minden projekthez biztonságosan használható.

:is() és a :where() alapvetően ugyanazok, kivéve azt, hogy hogyan befolyásolják a specifikusságot. Kimondottan, :where() mindig rendelkezik egy specifikussági pontszámmal 0,0,0. Igen, akár :where(button#widget.some-class) nincs sajátossága. Eközben a sajátossága :is() az argumentumlistájában a legnagyobb specifitással rendelkező elem. Tehát már van egy lépcsőzetes különbségtétel két modern szelektor között, amelyekkel dolgozhatunk.

A hihetetlenül erős :has() relációs pszeudoosztály is az gyorsan növekvő böngésző támogatás (és azóta a CSS legnagyobb új funkciója Rács, szerény véleményem szerint). Az írás idején azonban a böngésző támogatja a :has() még nem elég jó a termelésben való használatra.

Ragasszunk be egy ilyen pszeudoosztályt a BEM-embe, és…

/* ❌ specificity score: 0,2,0 */
.something:not(.something--special) { /* styles for all somethings, except for the special somethings */
}

Hoppá! Látod ezt a specifikussági pontszámot? Ne feledje, hogy a BEM esetében ideális esetben azt szeretnénk, ha választóink mindegyikének specifikussági pontszáma lenne 0,1,0. Miért van 0,2,0 rossz? Tekintsük ugyanezt a példát kibontva:

.something:not(.something--special) { color: red;
}
.something--special { color: blue;
}

Annak ellenére, hogy a második szelektor a forrás sorrendjében az utolsó, az első szelektor magasabb specifitása (0,2,0) nyer, és a színe .something--special elemre lesznek beállítva red. Ez azt jelenti, hogy feltételezzük, hogy a BEM megfelelően van megírva, és a kiválasztott elem mindkét elemet tartalmazza .something alaposztály és .something--special módosító osztályt alkalmaznak rá a HTML-ben.

Gondatlanul használva ezek az álosztályok váratlan módon befolyásolhatják a kaszkádot. És pont az ilyen jellegű következetlenségek okozhatnak fejfájást a soron, különösen a nagyobb és összetettebb kódbázisokon.

Dang. Akkor most mi legyen?

Emlékezz, miről beszéltem :where() és az, hogy a specifitása nulla? Ezt az előnyünkre fordíthatjuk:

/* ✅ specificity score: 0,1,0 */
.something:where(:not(.something--special)) { /* etc. */
}

Ennek a választónak az első része (.something) megkapja szokásos specifitási pontszámát 0,1,0. De :where() – és mindennek, ami benne van – megvan a sajátossága 0, ami nem növeli tovább a szelektor specifitását.

:where() lehetővé teszi számunkra, hogy fészkelődjünk

Azok az emberek, akiket nem érdekel annyira a konkrétság, mint én (és az igazat megvallva valószínűleg sok emberről van szó), nagyon jól jártak a fészekrakás terén. Néhány gondtalan billentyűzetnyomással a CSS-t így zárhatjuk le (megjegyzendő, hogy a Sass-t a rövidség kedvéért használom):

.card { ... } .card--featured { /* etc. */ .card__title { ... } .card__title { ... }
} .card__title { ... }
.card__img { ... }

Ebben a példában van egy .card összetevő. Ha ez egy „kiemelt” kártya (a .card--featured osztály), a kártya címét és képét más stílusban kell kialakítani. De ahogy mi is Most Tudja, a fenti kód olyan specifikussági pontszámot eredményez, amely nem egyeztethető össze rendszerünk többi részével.

Lehet, hogy egy megrögzött specifikus nerd ezt tette volna helyette:

.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }

Ez nem is olyan rossz, igaz? Őszintén szólva, ez egy gyönyörű CSS.

A HTML-nek azonban van egy hátránya. A tapasztalt BEM szerzők valószínűleg fájdalmasan tudatában vannak annak a makacs sablonlogikának, amely szükséges ahhoz, hogy feltételesen alkalmazzák a módosító osztályokat több elemre. Ebben a példában a HTML-sablonnak feltételesen hozzá kell adnia a --featured módosító osztály három elemre (.card, .card__titleés .card__img), bár valós példában valószínűleg még inkább. Ez sok if nyilatkozatokat.

A :where() A kiválasztó segítségével sokkal kevesebb sablonlogikát írhatunk – és kevesebb indítandó BEM-osztályt – anélkül, hogy növelnénk a specifikusság szintjét.

.card { ... }
.card--featured { ... } .card__title { ... }
:where(.card--featured) .card__title { ... } .card__img { ... }
:where(.card--featured) .card__img { ... }

Itt ugyanaz a dolog, csak Sassban (figyeld meg a végét és jelek):

.card { ... }
.card--featured { ... }
.card__title { /* etc. */ :where(.card--featured) & { ... }
}
.card__img { /* etc. */ :where(.card--featured) & { ... }
}

Az, hogy ezt a megközelítést választja-e a módosító osztályok alkalmazása helyett a különböző gyermekelemekre, személyes preferencia kérdése. De legalább :where() most választási lehetőséget ad nekünk!

Mi a helyzet a nem BEM HTML-lel?

Nem élünk tökéletes világban. Néha olyan HTML-kóddal kell megküzdenie, amely kívül esik az ellenőrzésén. Például egy harmadik féltől származó szkript, amely beilleszti a stílushoz szükséges HTML-kódot. Ezt a jelölést gyakran nem BEM-osztálynevekkel írják. Egyes esetekben ezek a stílusok egyáltalán nem osztályokat használnak, hanem azonosítókat!

Még egyszer, :where() hátunk van. Ez a megoldás kissé hibás, mivel egy olyan elem osztályára kell hivatkoznunk, amely valahol a DOM-fában feljebb van, és amelyről tudjuk, hogy létezik.

/* ❌ specificity score: 1,0,0 */
#widget { /* etc. */
} /* ✅ specificity score: 0,1,0 */
.page-wrapper :where(#widget) { /* etc. */
}

A szülőelemre való hivatkozás azonban kissé kockázatosnak és korlátozónak tűnik. Mi van, ha a szülői osztály megváltozik, vagy valamilyen oknál fogva nincs? Egy jobb (de talán ugyanolyan durva) megoldás lenne a használata :is() helyette. Ne feledje, a sajátossága :is() egyenlő a választólistájában szereplő legspecifikusabb szelektorral.

Tehát ahelyett, hogy egy olyan osztályra hivatkoznánk, amelyről tudjuk (vagy reméljük!) létezik :where(), mint a fenti példában, hivatkozhatunk egy összeállított osztályra és a <body> címke.

/* ✅ specificity score: 0,1,0 */
:is(.dummy-class, body) :where(#widget) { /* etc. */
}

A mindenkori jelen body segít kiválasztani #widget elem, és a jelenléte .dummy-class osztályon belül ugyanaz :is() adja a body válassza ki ugyanazt a specifitási pontszámot, mint egy osztály (0,1,0)… és használata :where() biztosítja, hogy a választó ne legyen ennél pontosabb.

Ez az!

Így tudjuk kiaknázni a modern specifikációkezelő funkcióit :is() és a :where() pszeudoosztályok, valamint a specifikus ütközésmegelőzés, amelyet akkor kapunk, ha CSS-t írunk BEM formátumban. És a nem túl távoli jövőben, egyszer :has() elnyeri a Firefox támogatását (jelenleg egy zászló mögött van támogatva az írás idején) valószínűleg párosítani szeretnénk a :where()-vel, hogy visszavonjuk sajátosságait.

Akár all-in megy a BEM-elnevezéssel, akár nem, remélem, egyetértünk abban, hogy a választóspecifikusság következetessége jó dolog!

spot_img

Legújabb intelligencia

spot_img

Beszélj velünk

Szia! Miben segíthetek?