Kaskadin kesyttäminen BEM:llä ja nykyaikaisilla CSS-valitsimilla PlatoBlockchain Data Intelligence. Pystysuuntainen haku. Ai.

Kaskadin kesyttäminen BEM:llä ja nykyaikaisilla CSS-valitsimilla

BEM. Kuten näennäisesti kaikki tekniikat etupään kehityksen maailmassa, CSS:n kirjoittaminen BEM-muodossa voi olla polarisoivaa. Mutta se on – ainakin minun Twitter-kuplassani – yksi suosituimmista CSS-menetelmistä.

Henkilökohtaisesti mielestäni BEM on hyvä, ja mielestäni sinun pitäisi käyttää sitä. Mutta ymmärrän myös miksi et ehkä.

Huolimatta mielipiteestäsi BEM:stä, se tarjoaa useita etuja, joista suurin on se, että se auttaa välttämään spesifisten ristiriitojen CSS-kaskadissa. Tämä johtuu siitä, että jos niitä käytetään oikein, kaikilla BEM-muotoon kirjoitetuilla valitsimilla tulisi olla sama spesifisyyspiste (0,1,0). Olen suunnitellut CSS:n useille suurille verkkosivustoille vuosien varrella (ajatellen hallitusta, yliopistoja ja pankkeja), ja juuri näissä suuremmissa projekteissa olen huomannut, että BEM todella loistaa. CSS:n kirjoittaminen on paljon hauskempaa, kun olet varma, että kirjoittamasi tai muokkaamasi tyylit eivät vaikuta johonkin muuhun sivuston osaan.

Itse asiassa on poikkeuksia, joissa on täysin hyväksyttävää lisätä tarkkuutta. Esimerkiksi: :hover ja :focus pseudo-luokat. Niillä on spesifisyyspisteet 0,2,0. Toinen on pseudoelementit - kuten ::before ja ::after — joiden spesifisyyspistemäärä on 0,1,1. Oletetaan kuitenkin, että tämän artikkelin loppuosan osalta emme halua muita erityispiirteitä. 🤓

Mutta en todellakaan ole täällä myymässä sinua BEMissä. Sen sijaan haluan puhua siitä, kuinka voimme käyttää sitä nykyaikaisten CSS-valitsimien rinnalla - ajattele :is(), :has(), :where(), jne. - saada tasaista lisää kontrolli kaskadi.

Mitä nykyaikaisissa CSS-valitsimissa on?

- CSS-valitsimien taso 4 sp antaa meille tehokkaita uusia (omituisia) tapoja valita elementtejä. Joitakin suosikkejani ovat mm :is(), :where()ja :not(), joista kutakin tukevat kaikki nykyaikaiset selaimet, ja niitä on turvallista käyttää lähes kaikissa projekteissa nykyään.

:is() ja :where() ovat periaatteessa sama asia, paitsi miten ne vaikuttavat spesifisyyteen. Erityisesti, :where() on aina spesifisyyspisteet 0,0,0. Joo, jopa :where(button#widget.some-class) ei ole erityistä. Samaan aikaan erityisyys :is() on elementti argumenttiluettelossaan, jolla on suurin spesifisyys. Meillä on siis jo Cascade-kiistanalainen ero kahden nykyaikaisen valitsimen välillä, joiden kanssa voimme työskennellä.

Uskomattoman voimakas :has() relaatiopseudoluokka on myös nopeasti saamassa selaintuen (ja on CSS:n suurin uusi ominaisuus sen jälkeen ruudukko, minun nöyrä mielipiteeni on). Kuitenkin kirjoittamishetkellä selaimen tuki :has() ei ole vielä tarpeeksi hyvä käytettäväksi tuotannossa.

Kiinnitäkäämme yksi niistä pseudoluokista BEM:iin ja…

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

Oho! Näetkö tuon tarkkuuden? Muista, että BEM:n avulla haluamme ihanteellisesti, että valitsimillamme on spesifisyyspisteet 0,1,0. Miksi on 0,2,0 huono? Harkitse tätä samaa esimerkkiä, laajennettuna:

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

Vaikka toinen valitsin on viimeinen lähdejärjestyksessä, ensimmäisen valitsimen korkeampi spesifisyys (0,2,0) voittaa, ja sen väri .something--special elementit asetetaan red. Eli olettaen, että BEM on kirjoitettu oikein ja valitulla elementillä on molemmat .something perusluokka ja .something--special modifier-luokkaa sovelletaan siihen HTML:ssä.

Huolimattomasti käytettynä nämä pseudo-luokat voivat vaikuttaa Cascadeen odottamattomilla tavoilla. Ja juuri tällaiset epäjohdonmukaisuudet voivat aiheuttaa päänsärkyä, etenkin suuremmissa ja monimutkaisemmissa koodikantoissa.

Hitto. Mitä nyt?

Muista, mistä puhuin :where() ja se, että sen spesifisyys on nolla? Voimme käyttää sitä hyväksemme:

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

Tämän valitsimen ensimmäinen osa (.something) saa tavanomaisen spesifisyyspisteensä 0,1,0. Mutta :where() - ja kaikella sen sisällä - on erityispiirre 0, mikä ei lisää valitsimen spesifisyyttä entisestään.

:where() antaa meille mahdollisuuden pesiytyä

Ihmiset, jotka eivät välitä niin paljon kuin minä spesifisyydestä (ja se on todennäköisesti paljon ihmisiä, ollakseni rehellinen), on ollut melko hyvä pesimisen suhteen. Joillakin huolettomilla näppäimistön painalluksilla saatamme päätyä CSS:ään näin (huomaa, että käytän Sassia lyhyyden vuoksi):

.card { ... }

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

.card__title { ... }
.card__img { ... }

Tässä esimerkissä meillä on a .card komponentti. Kun se on "suositeltu" kortti (käyttäen .card--featured luokka), kortin otsikko ja kuva on muotoiltava eri tavalla. Mutta kuten mekin nyt Yllä oleva koodi johtaa tarkkuuteen, joka on ristiriidassa muun järjestelmämme kanssa.

Kova spesifinen nörtti olisi voinut tehdä tämän sen sijaan:

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

Ei se niin paha ole, eihän? Suoraan sanottuna tämä on kaunis CSS.

HTML:ssä on kuitenkin huono puoli. Kokeneet BEM-kirjoittajat ovat luultavasti tuskallisen tietoisia kömpelöstä mallilogiikasta, jota vaaditaan ehdolliseen muokkaajaluokkien soveltamiseen useisiin elementteihin. Tässä esimerkissä HTML-malliin on lisättävä ehdollisesti --featured muokkausluokka kolmeen elementtiin (.card, .card__titleja .card__img), vaikkakin todellisessa esimerkissä todennäköisesti vielä enemmän. Se on paljon if lausuntoja.

- :where() valitsin voi auttaa meitä kirjoittamaan paljon vähemmän mallilogiikkaa – ja vähemmän BEM-luokkia käynnistettäviksi – lisäämättä tarkkuutta.

.card { ... }
.card--featured { ... }

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

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

Tässä on sama asia, mutta Sassissa (huomaa loppu et-merkit):

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

Se, kannattaako sinun valita tämä lähestymistapa muokkausluokkien soveltamisen sijaan eri alielementteihin, on henkilökohtaisten mieltymysten asia. Mutta ainakin :where() antaa meille nyt valinnanvaraa!

Entä ei-BEM-HTML?

Emme elä täydellisessä maailmassa. Joskus sinun on käsiteltävä HTML-koodia, joka ei ole sinun hallinnassasi. Esimerkiksi kolmannen osapuolen komentosarja, joka syöttää HTML-koodin, jota sinun on muotoiltava. Tätä merkintää ei usein kirjoiteta BEM-luokkien nimillä. Joissakin tapauksissa nämä tyylit eivät käytä lainkaan luokkia vaan tunnuksia!

Taas kerran, :where() on selkämme. Tämä ratkaisu on hieman hakkeroitu, koska meidän on viitattava DOM-puun yläpuolella olevan elementin luokkaan, jonka tiedämme olevan olemassa.

/* ❌ specificity score: 1,0,0 */
#widget {
  /* etc. */
}

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

Pääelementtiin viittaaminen tuntuu kuitenkin hieman riskialtiselta ja rajoittavalta. Entä jos vanhempi luokka vaihtuu tai sitä ei ole jostain syystä? Parempi (mutta ehkä yhtä hakkeroitu) ratkaisu olisi käyttää :is() sen sijaan. Muista, erikoisuus :is() on yhtä suuri kuin sen valitsinluettelon tarkin valitsin.

Joten sen sijaan, että viitattaisiin luokkaan, jonka tiedämme (tai toivomme!) olevan olemassa :where(), kuten yllä olevassa esimerkissä, voisimme viitata sovittuun luokkaan ja tunnisteita.

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

Aina läsnä body auttaa meitä valitsemaan omamme #widget elementti ja läsnäolo .dummy-class luokka samassa sisällä :is() antaa body valitse sama spesifisyyspiste kuin luokalla (0,1,0)… ja käyttö :where() varmistaa, että valitsin ei ole sen tarkempi.

Se siitä!

Näin voimme hyödyntää nykyaikaisia ​​spesifisyydenhallintaominaisuuksia :is() ja :where() pseudo-luokat rinnalla spesifisen törmäykseneston, jonka saamme kirjoitettaessa CSS:ää BEM-muodossa. Ja ei liian kaukaisessa tulevaisuudessa, kerran :has() saa Firefox-tuen (se on tällä hetkellä tuettu lipun takana kirjoitettaessa) haluamme todennäköisesti yhdistää sen :where():n kanssa kumotaksemme sen erityisyyden.

Menitpä sitten all-in BEM-nimeämisessä tai et, toivon, että voimme olla yhtä mieltä siitä, että valitsinspesifisyyden johdonmukaisuus on hyvä asia!

Aikaleima:

Lisää aiheesta CSS-temppuja