Kaskaadi taltsutamine BEM-i ja kaasaegsete CSS-i selektoritega PlatoBlockchain Data Intelligence. Vertikaalne otsing. Ai.

Kaskaadi taltsutamine BEM-i ja kaasaegsete CSS-valijatega

BEM. Nagu näiliselt kõik tehnikad esiotsa arenduse maailmas, CSS-i kirjutamine BEM-vormingus võib olla polariseeriv. Kuid see on – vähemalt minu Twitteri mullis – üks rohkem meeldinud CSS-i metoodikaid.

Isiklikult arvan, et BEM on hea ja arvan, et peaksite seda kasutama. Aga ma saan ka aru, miks sa ei võiks.

Sõltumata teie arvamusest BEM-i kohta pakub see mitmeid eeliseid, millest suurim on see, et see aitab vältida spetsiifilisuse kokkupõrkeid CSS-i kaskaadis. Seda seetõttu, et õige kasutamise korral peaks kõigil BEM-vormingus kirjutatud selektoritel olema sama spetsiifilisuse skoor (0,1,0). Olen aastate jooksul loonud CSS-i paljude suuremahuliste veebisaitide jaoks (mõelge valitsusele, ülikoolidele ja pankadele) ning just nende suuremate projektide puhul olen avastanud, et BEM paistab tõeliselt särama. CSS-i kirjutamine on palju lõbusam, kui olete kindel, et laadid, mida kirjutate või redigeerite, ei mõjuta saidi mõnda muud osa.

Tegelikult on erandeid, mille puhul peetakse spetsiifilisuse lisamist täiesti vastuvõetavaks. Näiteks: :hover ja :focus pseudoklassid. Nende spetsiifilisuse skoor on 0,2,0. Teine on pseudoelemendid - nagu ::before ja ::after — mille spetsiifilisuse skoor on 0,1,1. Selle artikli ülejäänud osas aga oletame, et me ei soovi muud spetsiifikat. 🤓

Aga ma ei ole siin, et sind BEM-is müüa. Selle asemel tahan rääkida sellest, kuidas saaksime seda kaasaegsete CSS-i valijate kõrval kasutada – mõelge :is(), :has(), :where()jm — saada isegi rohkem kontroll kaskaad.

Mis see tänapäevaste CSS-i valijate kohta on?

. CSS-i valijate 4. taseme spetsifikatsioon annab meile uusi võimsaid viise elementide valimiseks. Mõned minu lemmikud hõlmavad :is(), :where()ja :not(), millest kõiki toetavad kõik kaasaegsed brauserid ja mida on tänapäeval ohutu kasutada peaaegu kõigis projektides.

:is() ja :where() on põhimõtteliselt sama asi, välja arvatud see, kuidas need mõjutavad spetsiifilisust. Täpsemalt :where() on alati spetsiifilisuse skoor 0,0,0. Jah, isegi :where(button#widget.some-class) pole spetsiifilisust. Vahepeal spetsiifilisus :is() on selle argumentide loendi kõrgeima spetsiifilisusega element. Niisiis, meil on juba kaskaadiga vaieldav vahe kahe kaasaegse valija vahel, millega saame töötada.

Uskumatult võimas :has() relatsiooniline pseudoklass on samuti kiiresti koguv brauseri tugi (ja on alates sellest ajast CSS-i suurim uus funktsioon võre, minu tagasihoidlik arvamus). Kuid kirjutamise ajal toetas brauser :has() ei ole veel piisavalt hea tootmises kasutamiseks.

Kleepige üks neist pseudoklassidest minu BEM-i ja…

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

Oih! Kas näete seda spetsiifilisuse skoori? Pidage meeles, et BEM-i puhul soovime ideaalis, et meie valijatel oleks spetsiifilisuse skoor 0,1,0. Miks on 0,2,0 halb? Vaatleme seda sama näidet, laiendatuna:

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

Kuigi teine ​​valija on lähtejärjekorras viimane, on esimese valija kõrgem spetsiifilisus (0,2,0) võidab ja selle värv .something--special elemendid seatakse väärtusele red. See tähendab, et eeldades, et teie BEM on õigesti kirjutatud ja valitud elemendil on mõlemad .something baasklass ja .something--special HTML-is sellele rakendatud modifikaatoriklass.

Hooletu kasutamisel võivad need pseudoklassid kaskaadi ootamatul viisil mõjutada. Ja just sellised ebakõlad võivad tekitada peavalu, eriti suuremate ja keerukamate koodibaaside puhul.

Dang. Mis siis nüüd?

Pea meeles, millest ma rääkisin :where() ja see, et selle spetsiifilisus on null? Saame seda enda huvides ära kasutada:

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

Selle valija esimene osa (.something) saab oma tavapärase spetsiifilisuse hinde 0,1,0. kuid :where() - ja kõigel selle sees - on spetsiifilisus 0, mis ei suurenda selektori spetsiifilisust veelgi.

:where() võimaldab meil pesitseda

Inimestel, kes ei hooli spetsiifilisusest nii palju kui mina (ja see on ausalt öeldes ilmselt paljudel inimestel), on pesitsemise osas päris hästi läinud. Mõne muretu klahvivajutusega võime lõpetada CSS-i järgmiselt (pange tähele, et ma kasutan Sassi lühiduse huvides):

.card { ... }

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

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

Selles näites on meil a .card komponent. Kui see on esiletõstetud kaart (kasutades .card--featured klass), tuleb kaardi pealkiri ja pilt erinevalt kujundada. Aga nagu meiegi nüüd Teate, et ülaltoodud kood annab spetsiifilisuse skoori, mis pole meie ülejäänud süsteemiga kooskõlas.

Paadunud spetsiifilisusega nohik oleks võinud hoopis seda teha:

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

See polegi nii hull, eks? Ausalt öeldes on see ilus CSS.

HTML-il on siiski ka negatiivne külg. Kogenud BEM-i autorid on ilmselt valusalt teadlikud kohmakast malliloogikast, mis on vajalik modifikaatoriklasside tingimuslikuks rakendamiseks mitmele elemendile. Selles näites peab HTML-mall tingimuslikult lisama --featured modifikaatoriklass kolmele elemendile (.card, .card__titleja .card__img), kuigi reaalse maailma näitel ilmselt veelgi enam. See on palju if avaldused.

. :where() valija aitab meil kirjutada palju vähem malliloogikat – ja vähem BEM-klasse, mida käivitada – ilma spetsiifilisuse taset suurendamata.

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

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

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

Siin on sama asi, kuid Sassis (märkige lõpus ampersandid):

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

See, kas peaksite valima selle lähenemisviisi muutmisklasside rakendamise asemel erinevatele alamelementidele, on isiklike eelistuste küsimus. Aga vähemalt :where() annab meile kohe valiku!

Aga mitte-BEM HTML?

Me ei ela täiuslikus maailmas. Mõnikord peate tegelema HTML-iga, mis on väljaspool teie kontrolli. Näiteks kolmanda osapoole skript, mis sisestab HTML-i, mida peate stiilima. Seda märgistust ei kirjutata sageli BEM-klassi nimedega. Mõnel juhul ei kasuta need stiilid klasse, vaid ID-sid!

Taas :where() on meie seljataga. See lahendus on veidi hämmingus, kuna me peame viitama elemendi klassile, mis asub DOM-puust kõrgemal, mille olemasolu kohta teame.

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

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

Vanemelemendile viitamine tundub siiski veidi riskantne ja piirav. Mis saab siis, kui see vanemklass muutub või seda mingil põhjusel pole? Parem (kuid võib-olla sama häkkiv) lahendus oleks kasutada :is() selle asemel. Pea meeles, spetsiifilisus :is() on võrdne selle valijate loendi kõige spetsiifilisema valijaga.

Seega, selle asemel, et viidata klassile, mille olemasolu me teame (või loodame!). :where(), nagu ülaltoodud näites, võiksime viidata väljamõeldud klassile ja tag.

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

Alati kohalolev body aitab meil valida meie #widget element ja olemasolu .dummy-class klass sees sama :is() annab body vali sama spetsiifilisuse skoor kui klassil (0,1,0)… ja kasutamine :where() tagab, et valija ei muutu sellest täpsemaks.

See ongi!

Nii saame kasutada seadme kaasaegseid spetsiifilisust haldavaid funktsioone :is() ja :where() pseudoklassid kõrvuti spetsiifilise kokkupõrke vältimisega, mille saame CSS-i kirjutamisel BEM-vormingus. Ja mitte liiga kauges tulevikus, kunagi :has() saab Firefoxi toe (seda on kirjutamise ajal praegu lipu taga toetatud) tahame selle spetsiifilisuse tühistamiseks tõenäoliselt siduda funktsiooniga :where().

Olenemata sellest, kas lähete BEM-i nimetamise osas all-ini või mitte, loodan, et saame nõustuda, et valija spetsiifilisuse järjepidevus on hea!

Ajatempel:

Veel alates CSSi trikid