ABEM. En mer nyttig tilpasning av BEM.

0
26

BEM (Blokk-Element Modifier) er en populær CSS-klasse navnekonvensjon som gjør CSS enklere å vedlikeholde. Denne artikkelen forutsetter at du allerede er kjent med naming convention. Hvis ikke kan du lære mer om det på getbem.com for å fange opp det grunnleggende.

Standard syntaks for BEM er:

blokker-navn__ – element-navn–modifier-navn

Jeg er personlig en stor fan av metodikken bak naming convention. Å skille stilene i små komponenter er langt enklere å vedlikeholde enn å ha et hav av høy spesifisitet spredt over hele stilsettet. Det er imidlertid noen problemer jeg har med syntaksen som kan forårsake problemer i produksjon, så vel som kan føre til forvirring for utviklere. Jeg foretrekker å bruke en litt tilpasset versjon av syntaksen i stedet. Jeg kaller det ABEM (Atomic Blokk-Element Modifier):

[a/m/u]-blockName__elementName -modifierName

En Atomic Design Prefiks

Den a/m/o – er en Atomic Design prefiks. Ikke for å forveksles med Atomic CSS som er en helt annen ting. Atomic design er en metode for å organisere dine komponenter som maksimerer muligheten til å gjenbruke kode. Deler komponenter i tre mapper: atomer, molekyler og organismer. Atomer er super enkle komponenter som vanligvis består av kun en enkelt element (f.eks. en knapp komponent). Molekyler er små grupper av elementer og/eller komponenter (for eksempel et enkelt skjema-feltet for å vise en etikett og en input-feltet). Organismer er store komplekse komponenter består av mange molekyl og atom-komponenter (f.eks. en full registreringsskjemaet).

Vanskeligheten av å bruke atomic design med klassiske BEM er at det er ingen indikator for å si hvilken type komponent blokk en blokk er. Dette kan gjøre det vanskelig å vite hvor kode for at komponenten er siden du kan ha for å søke i 3 separate mapper for å finne det. Legge til atomic prefiks til start gjør det umiddelbart klart hvilken mappe den komponenten er lagret i.

camelCase

Det gir mulighet for tilpasset gruppering

Klassisk BEM skiller hvert enkelt ord innenfor et område med en enkel strek. Legg merke til at atom-prefiks i eksemplet ovenfor er også skilt fra resten av klassen navnet med en strek. Ta en titt på hva som skjer nå når du legger til en atomic prefiks å BEM klassisk vs camelCase:

/* klassisk + atomic prefiks */
.o-abonnere-form__field-item {}

/* camelCase + atomic prefiks */
.o-subscribeForm__fieldItem {}

På et øyekast, komponent navn når du leser den klassiske metoden ser ut som den er kalt “o abonnere form”. Betydningen av “o” er helt borte. Når du bruker “o” til camelCase versjon skjønt, det er klart at det var med vilje skrevet for å være en separat del av informasjonen til den komponenten navn.

Nå kan du bruke atomic prefiks til klassisk BEM ved å utnytte den “o” som dette:

/* klassisk + aktivert atomic prefiks */
.O-abonnere-form__field-item {}

Som ville løse problemet med “o” å gå seg vill blant resten av klassen navn, men det betyr ikke løse core underliggende problemet i den klassiske BEM syntaks. Ved å skille ord med bindestrek, tankestrek karakter er ikke lenger tilgjengelig for deg å bruke som en gruppering mekanisme. Ved hjelp av camelCase, det frigjør deg opp til å bruke bindestrek karakter for ekstra gruppering, selv om det gruppering er bare å legge til et tall på slutten av en klasse navn.

Ditt sinn vil behandle grupperinger raskere

camelCase har også den ekstra fordelen av å gjøre gruppering av klasse navn lettere å mentalt prosessen. Med camelCase, hver gap du se i den klassen navn som representerer en gruppering av noe slag. I klassisk BEM, hver gapet kan være enten en gruppering eller et mellomrom mellom to ord i samme gruppe.

Ta en titt på denne silhuetten av en klassisk BEM-klasse (pluss atomic prefiks) og prøve å finne ut hvor prefiks, blokk, element, og modifier deler start og slutt:

Ok, nå kan du prøve denne. Det er nøyaktig det samme klasse som den ovenfor, med unntak denne gangen er det ved hjelp av camelCase for å skille ord i stedet for å bindestrek:

Det var mye lettere var det ikke? De silhuetter er egentlig hva ditt sinn ser når det er skanne gjennom koden. Å ha alle de ekstra bindestreker i klassen navnet gjøre grupperinger langt mindre klart. Når du leser gjennom koden din, hjernen forsøker å behandle vær hullene det møter nye grupperinger eller bare nye ord. Denne mangelen på klarhet fører til kognitiv belastning å veie seg på hodet ditt mens du arbeider.

klassisk BEM + atomic prefiks

camelCase BEM + atomic prefiks

Bruke multi-klasse-velgere (ansvarlig)

En av de gylne reglene i BEM er at hver selector er bare ment å inneholde en enkelt klasse. Ideen er at det holder CSS stabile ved å holde spesifisiteten av velgere lave og håndterlig. På den ene siden, jeg er enig i at lav spesifisitet er å foretrekke fremfor å ha spesifisitet kjøre tøylesløs. På den andre, er jeg sterkt uenig i at en streng én klasse per selector regel er det beste for prosjekter. Ved hjelp av noen multi-klasse-velgere i din stiler kan faktisk forbedre vedlikehold snarere enn å minske den.

“Men det fører til høyere spesifisitet! Vet du ikke at spesifisitet er iboende ondskap?!?”

Spesifisitet != dårlig.

Ukontrollert spesifisitet som har forvillet = dårlig.

Å ha noen høyere spesifisitet erklæringer ikke umiddelbart bety at CSS er mer vanskelig å opprettholde. Hvis brukt på riktig måte, noe som gir visse regler høyere spesifisitet kan faktisk gjøre CSS enklere å vedlikeholde. Nøkkelen til å skrive stabile CSS med ujevne spesifisitet er å legge til spesifisitet målbevisst, og ikke bare fordi en liste element skjer for å være inne i en liste-element.

Dessuten er ikke vi faktisk ønsker at våre endrede stiler å ha større makt over elementer enn standard stiler? Bøyd over bakover for å holde endrede stiler på samme spesifisitet nivå som normalt stiler virker dumt for meg. Da har du faktisk vil ha din vanlige standard stiler å overstyre din spesifikt angitte endrede stiler?

Å skille modifier fører til renere HTML

Dette er den største endringen til syntaksen som ABEM introduserer. I stedet for å koble modifier til elementet klasse, kan du bruke den som en egen klasse.

En av de tingene som praktisk talt alle klager om når de først begynner å lære BEM er hvor stygt det er. Det er spesielt ille når det kommer til modifikatorer. Ta en titt på denne grusomme handlingen. Det har bare tre modifikatorer brukes til det og, men det ser ut som et tog vrak:

B__E–M:
<- knappen class=”blokk-navn__ – element-navn blokk-navn__ – element-navn–liten blokk-navn__ – element-navn–grønn blokk-navn__ – element-navn–aktive”>
Send inn
</button>

Se på alt som repetisjon! Som repetisjon gjør det ganske vanskelig å lese hva det faktisk prøver å gjøre. Nå kan du ta en titt på denne ABEM eksempel som har alle de samme tast som den forrige eksempel:

A-B – __ – E -M:
<- knappen class=”en-blockName__elementName -liten -grønn -aktiv”>
Send inn
</button>

Mye renere, ikke sant? Det er langt lettere å se hva de endrede klasser prøver å si uten alle som repeterende gunk komme i veien.

Ved å undersøke et element med nettleser DevTools, vil du fremdeles se full regelen i styling panel så det beholder forbindelsen til den opprinnelige komponenten i så måte:

.a-blockName__elementName.-grønn {
bakgrunn: green;
color: white;
}

Det er ikke mye forskjellig fra de tilsvarende BEM

.blokker-navn__ – element-navn–grønn {
bakgrunn: green;
color: white;
}

Administrerende staten blir lett

En stor fordel at ABEM har over klassiske BEM er at det blir uhyre enklere å håndtere tilstanden til en komponent. La oss bruke en grunnleggende trekkspill som et eksempel. Når en del av dette trekkspill er åpne, la oss si at vi vil bruke disse endringene for å styling:

  • Endre fargen på bakgrunnen av kapitteloverskriften
  • Vise innholdet område
  • Gjøre en ned-pilen peker oppover

Vi kommer til å holde seg til den klassiske B__E–M syntaksen for dette eksemplet, og strengt holder seg til én klasse per css selector regelen. Dette er hva vi ender opp med (merk at på grunn av kortfattethet, dette trekkspill er ikke tilgjengelig):

Se Penn Trekkspill 1 – Ren BEM av Daniel Tonon (@daniel-tonon) på CodePen.

Den SCSS ser ganske ren, men ta en titt på alle de ekstra klasser som vi har for å legge til HTML-for bare en enkelt endring i tilstand!

HTML-mens et segment er lukket ved hjelp av BEM:
<div class=”revealer trekkspill__avsnittet”>
<div class=”revealer__trigger”>
<h2 class=”revealer__overskriften”>Tre</h2>
<div class=”revealer__ – ikonet”></div>
</div>
<div class=”revealer__innhold”>
Lorem ipsum dolor sit amet…
</div>
</div>
HTML-mens et segment er åpen ved hjelp av BEM:
<div class=”revealer trekkspill__avsnittet”>
<div class=”revealer__utløse revealer__utløse–åpne”>
<h2 class=”revealer__overskriften”>En</h2>
<div class=”revealer__ – ikonet revealer__ – ikonet–åpne”></div>
</div>
<div class=”revealer__innhold revealer__innhold–åpne”>
Lorem ipsum dolor sit amet…
</div>
</div>

La oss nå ta en titt på hva som skjer når vi bytter over til å bruke denne fancy nye A-B – __ – E -M-metoden:

Se Penn Trekkspill 2 – ABEM alternativ av Daniel Tonon (@daniel-tonon) på CodePen.

En enkelt klasse nå kontrollerer staten-spesifikke styling for hele komponent nå i stedet for å måtte bruke en egen klasse for hvert element individuelt.

HTML-mens et segment er åpen ved hjelp av ABEM:
<div class=”m-revealer o-trekkspill__ – delen -åpne”>
<div class=”m-revealer__trigger”>
<h2 class=”m-revealer__overskriften”>En</h2>
<div class=”m-revealer__ – ikonet”></div>
</div>
<div class=”m-revealer__innhold”>
Lorem ipsum dolor sit amet…
</div>
</div>

Ta også en titt på hvor mye enklere javascript har blitt. Jeg skrev JavaScript som rent som jeg kunne, og dette ble resultatet:

JavaScript-når du bruker ren BEM:
klasse revealer {
constructor(el){
Objektet.tilordne(dette, {
$wrapper: el,
mål: [‘trigger’, ‘ved’, ‘content’],
isOpen: false,
});
dette.gather_elements();
dette.$trigger.onclick = ()=> dette.veksle();
}

gather_elements(){
const tastene = dette.- mål.kart(selector => `$${selector}`);
const elementer = dette.- mål.kart(selector => {
gå tilbake til denne.$wrapper.querySelector(`.revealer__${selector}`);
});
la elObject = {};
tastene.forEach((key, i) => {
elObject[nøkkel] = elementer[i];
});
Objektet.tilordne(dette elObject);
}

veksle(){
hvis (denne.isOpen) {
dette.close();
} else {
dette.open();
}
}

åpne(){
dette.- mål.forEach(target => {
dette[`$${target}`].classList.legg til(`revealer__${target}–åpne`);
})
dette.isOpen = true;
}

close(){
dette.- mål.forEach(target => {
dette[`$${target}`].classList.fjern(`revealer__${target}–åpne`);
})
dette.isOpen = false;
}
}

dokumentet.querySelectorAll(‘.revealer’).forEach(el => {
nye revealer(el);
})
JavaScript-når du bruker ABEM:
klasse revealer {
constructor(el){
Objektet.tilordne(dette, {
$wrapper: el,
isOpen: false,
});
dette.$trigger = dette.$wrapper.querySelector(‘.m-revealer__trigger’);
dette.$trigger.onclick = ()=> dette.veksle();
}

veksle(){
hvis (denne.isOpen) {
dette.close();
} else {
dette.open();
}
}

åpne(){
dette.$wrapper.classList.legg til (`åpne`);
dette.isOpen = true;
}

close(){
dette.$wrapper.classList.fjern (`åpne`);
dette.isOpen = false;
}
}

dokumentet.querySelectorAll(‘.m-revealer’).forEach(el => {
nye revealer(el);
})

Dette var bare en veldig enkel trekkspill eksempel. Tenk på hva som skjer når du vurdere dette ut til noe som en klebrig header som endres når klebrig. En klebrig header kanskje å fortelle 5 forskjellige komponenter når overskriften er klissete. I hvert enkelt av de 5 komponentene, 5 elementer kanskje reagere på at overskriften blir klissete. Det er 25 element.classList.legge til(“[componentName]__[elementName]–sticky”) regler ville vi trenger for å skrive i vår js strengt å forholde seg til BEM naming convention. Hva gjør det mer fornuftig? 25 unike klasser som er lagt til hvert element som er berørt, eller bare en -klebrig klasse lagt til den overskriften som alle de 5 elementer i alle de 5 komponentene er i stand til å få tilgang til og lese lett?

Den BEM “løsning” er helt upraktisk. Søker modifier styling til store komplekse komponenter ender opp med å slå inn en bit av en gråsone. En gråsone som fører til forvirring for alle utviklere prøver å strengt overholde BEM naming convention så tett som mulig.

ABEM modifier problemer

Å skille modifier er ikke uten sine feil. Imidlertid, er det noen enkle måter å omgå disse feilene.

Problem 1: Nesting

Så vi har våre trekkspill, og det er alt fungerer perfekt. Senere ned linjen, klient ønsker å hekke andre trekkspill inne i den første. Så kan du gå videre og gjøre det… dette skjer:

Se Penn Trekkspill 3 – ABEM hekkende feil av Daniel Tonon (@daniel-tonon) på CodePen.

Hekkende andre trekkspill inne i den første fører til en ganske problematisk feil. Åpne den overordnede trekkspill gjelder også den åpne staten styling til alle barn trekkspill i det segmentet.

Dette er noe som du åpenbart ikke vil skal skje. Det er en god måte å unngå dette selv.

For å forklare det, la oss spille et lite spill. Forutsatt at begge disse CSS-regler som er aktive på det samme element, hvilken farge tror du at elementet er bakgrunnen ville være?

.-grønn > * > * > * > * > * > .element {
bakgrunn: green;
}

.elementet.-blå {
bakgrunn: blå;
}

Hvis du sa grønt på grunn av den første regelen med å ha en høyere spesifisitet enn den andre regelen, kan du faktisk ville være galt. Bakgrunnen skulle være blå.

Fun fact: * er det laveste spesifisitet selector i CSS. Det betyr “noe” i CSS. Det har faktisk ingen specificy, betyr det ikke legg til noen spesifisitet til en selector du legge den til. Det betyr at selv om du har brukt en regel som besto av en enkelt klasse og 5 stjerner (.element > * > * > * > * > *) det kan likevel lett bli overskrevet av bare en enkelt klasse på neste linje av CSS!

Vi kan dra nytte av denne lille CSS egenskap til å skape en mer målrettet tilnærming til trekkspill SCSS kode. Dette vil tillate oss å trygt reir våre trekkspill.

Se Penn Trekkspill 4 – ABEM hekkende bug fix av Daniel Tonon (@daniel-tonon) på CodePen.

Ved hjelp av den .-modifierName > * > & mønster, kan du målrette direkte etterkommere som er flere nivåer dypt, uten at det forårsaker din spesifisitet for å komme ut av kontroll.

Jeg bare bruke dette direkte målretting teknikk som det blir nødvendig om. Som standard, når jeg skriver ABEM, jeg skal skrive det slik jeg gjorde i den opprinnelige ABEM trekkspill eksempel. Den ikke-målrettede metoden er generelt alt som er nødvendig i de fleste tilfeller. Problemet med målrettet tilnærming er at du legger til en enkel wrapper rundt noe som kan potensielt ødelegge hele systemet. Den ikke-målrettede tilnærmingen ikke lider av dette problemet. Det er mye mer skånsom og hindrer stiler fra å bryte hvis du noen gang trenger å endre HTML senere ned linjen.

Problem 2: Navngi kollisjoner

Et problem som du kan kjøre inn ved hjelp av den ikke-målrettede modifier teknikk er å navngi kollisjoner. La oss si at du trenger å opprette et sett av kategorier, og hver kategori har et trekkspill i det. Mens du skriver denne koden, som du har laget både trekkspill og kategoriene svarer til -aktiv klasse. Dette fører til et navn kollisjon. Alle trekkspill i den aktive fanen vil ha sin aktive stiler som er brukt. Dette er fordi alle trekkspill er barn av den kategorien beholder elementer. Det er kategorien beholder elementer som har den faktiske aktive klasse gjaldt dem. (Ingen av kategoriene eller trekkspill som i følgende eksempel er tilgjengelig på grunn av kortfattethet.)

Se Penn Trekkspill i kategoriene 1 – brutt av Daniel Tonon (@daniel-tonon) på CodePen.

Nå er én måte å løse denne konflikten ville være å bare endre trekkspill til å svare på en åpen klasse i stedet for en aktiv klasse. Jeg vil faktisk anbefale at tilnærmingen. For å få til et eksempel om, la oss si at det ikke er et alternativ. Du kan bruke den direkte målretting teknikk som er nevnt ovenfor, men som gjør din stiler veldig sprø. I stedet hva du kan gjøre, er å legge til komponenten navn til forsiden av modifikator som dette:

.o-componentName {
&__elementName {
.-componentName–modifierName & {
/* endrede stiler gå her */
}
}
}

Dashbordet på forsiden av navnet fortsatt betyr at det er en modifikator klasse. Komponenten navn hindrer navnerom kollisjoner med andre komponenter som ikke skulle være å bli berørt. Double dash er i hovedsak bare et nikk til klassiske BEM modifier syntaks til å doble understreke at det er en modifikator klasse.

Her er det trekkspill og kategorier som eksempel igjen, men denne gangen med navnerommet fikse brukt:

Se Penn Trekkspill i kategoriene 2 – løst av Daniel Tonon (@daniel-tonon) på CodePen.

Jeg anbefaler ikke å bruke denne teknikken som standard, men hovedsakelig på grunn av å holde den ren HTML og også for å unngå forvirring når flere komponenter trenger å dele samme modifier.

Mesteparten av tiden, en modifikator klasse brukes for å betegne en endring i tilstand som i trekkspill eksemplet ovenfor. Når et element endrer status, alle barn elementer, uansett hvilken komponent som de hører til, skal være i stand til å lese at staten endres og svare til den lett. Når en modifikator klasse er ment å påvirke flere komponenter samtidig, forvirring kan oppstå rundt hva komponent som modifikator spesifikt tilhører. I disse tilfellene navn-avstand modifier gjør mer skade enn godt.

ABEM modifier teknikk oppsummering

Så for å gjøre det beste bruk av ABEM modifier, bruk .-modifierName & eller &.-modifierName syntaks som standard (avhenger av hva element har klassen på det)

.o-componentName {
&.-modifierName {
/* componentName endrede stiler gå her */
}

&__elementName {
.-modifierName & {
/* elementName endrede stiler gå her */
}
}
}

Bruk direkte målretting hvis hekkende en komponent inne i seg selv som er årsaken til et problem.

.o-componentName {
&__elementName {
.-nestedModifierName > * > & {
/* endrede stiler gå her */
}
}
}

Bruk komponent navn i modifier hvis du kjører inn i felles modifier navn kollisjoner. Bare gjøre dette hvis du ikke kan tenke på en annen modifier navn som fortsatt gir mening.

.o-componentName {
&__elementName {
.-componentName–sharedModifierName & {
/* endrede stiler gå her */
}
}
}

Kontekst-sensitiv stiler

Et annet problem med strengt overholde BEM én klasse per selector metoden er at den ikke tillater deg å skrive kontekst-sensitiv stiler.

Kontekst-sensitiv stiler er i utgangspunktet “hvis dette elementet er inne i denne forelder, gjelder disse stilene til det”.

Med kontekst-sensitiv stiler, det er en overordnet komponent og et barn komponent. Den overordnede komponent skal være den som gjelder layout relaterte stiler som margin, og posisjon til barnet komponent (.forelder .barnet { margin: 20 piksler }). Barnet komponent, bør alltid som standard ikke har noen margin rundt utsiden av komponenten. Dette gjør barnet komponenter som skal brukes i flere sammenhenger, siden det er det overordnede ansvaret for sin egen layout snarere enn sine barn.

I likhet med virkelige foreldre, foreldrene er de som bør ha ansvaret. Du bør ikke la deres uskikkelig clueless barn kaller skudd når det kommer til foreldrene layout.

Å grave videre inn i dette konseptet, la oss late som vi bygger et nytt nettsted, og akkurat nå bygger vi den abonnere form komponent for området.

Se Penn Kontekst-sensitiv 1 – DVS. uvennlig av Daniel Tonon (@daniel-tonon) på CodePen.

Dette er første gang vi har måttet sette et skjema på denne awesome nye nettstedet som vi bygger. Vi ønsker å være som alle de kule barna så vi brukte CSS rutenett for å gjøre layout. Vi er smart om. Vi vet at knappen styling kommer til å bli brukt på mange flere steder i hele området. For å forberede seg på dette, kan vi skille abonner-knappen stiler i sin egen komponent som god liten utviklere.

En stund senere er vi starter cross-browser testing. Vi åpner opp IE11 bare for å se denne stygge ting stirrer oss i ansiktet:

IE11 gjør slags støtte CSS rutenett, men det betyr ikke støtte grid-gap eller auto plassering. Etter noen rensende banning og ønsker at folk ville oppdatere sine lesere, må du justere stiler å se mer ut som dette:

Se Penn Kontekst-sensitiv 2 – hva du ikke skal gjøre av Daniel Tonon (@daniel-tonon) på CodePen.

Nå ser perfekt ut i IE. Alt er rett med verden. Hva kunne gå galt?

Et par timer senere setter du denne knappen for komponenten i en annen komponent på nettstedet. Denne andre komponenten også bruker css-grid layout sine barn.

Du skrive følgende kode:

Se Penn Kontekst-sensitiv 3 – den andre komponenten av Daniel Tonon (@daniel-tonon) på CodePen.

Du forvente å se en layout som ser ut som dette selv i IE11:

Men i stedet, på grunn av grid-kolonnen: 3; – koden du skrev tidligere, det ender opp som ser ut som dette:

Yikes! Så hva gjør vi om dette grid-kolonnen: 3; CSS vi skrev tidligere? Vi må begrense det til det overordnede komponent, men hvordan skal vi gå om å gjøre det?

Vel den klassiske BEM metoden for å håndtere dette på er å legge til en ny forelder komponent element klasse til knappen som dette:

Se Penn Kontekst-sensitiv 4 – klassisk BEM løsning av Daniel Tonon (@daniel-tonon) på CodePen.

På overflaten denne løsningen ser ganske bra:

  • Det holder lav spesifisitet
  • Den overordnede komponent, er å kontrollere sin egen layout
  • Styling er ikke sannsynlig å blø inn i andre komponenter som vi ikke vil at den skal blø inn

Alt er fantastisk og alle som er rett med verden… ikke sant?

Ulempen med denne tilnærmingen er hovedsakelig på grunn av det faktum at vi måtte legge til en ekstra klasse på knappen for komponenten. Siden abonnere-form__send klasse ikke finnes i basen knappen for komponenten, det betyr at vi må legge til ekstra logikk til hva vi bruker som vår templating søkemotoren for å få de riktige stiler.

Jeg elsker ved hjelp av Mopsen for å generere min side maler. Jeg vil vise deg hva jeg mener med Pug mixins som et eksempel.

Først, her er den originale DVS. uvennlig kode re-skrevet i mixin-format:

Se Penn Kontekst-sensitiv 5 – DVS. uvennlig med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Nå kan du legge til at IE 11 abonnere-form__send klasse til det:

Se Penn Kontekst-sensitiv 6 – DVS. trygt BEM løsning med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Det var ikke så hardt, så hva er det jeg klager over? Vel la oss nå si at vi noen ganger vil bruke denne modulen til å være plassert inne i en sidebar. Når det er, vi vil at e-inndata og-på-knappen for å bli stablet oppå hverandre. Husk at for å strengt overholde BEM, vi er ikke lov til å bruke noe høyere spesifisitet enn en enkelt klasse i vår stiler.

Se Penn Kontekst-sensitiv 7 – DVS. trygt BEM med mixins i sidebar av Daniel Tonon (@daniel-tonon) på CodePen.

Som Pug-koden ikke er ute så lett nå er det? Det er et par ting som bidrar til dette rotet.

  1. Beholder spørsmål ville gjøre dette langt mindre av et problem, men at de ikke eksisterer ennå innebygd i enhver nettleser
  2. Problemene rundt BEM modifier syntaks er oppdra sine stygge hoder.

Nå kan du prøve å gjøre det igjen, men denne gangen med kontekstsensitiv stiler:

Se Penn Kontekst-sensitiv 8 – DVS. sikre Sammenhengen med mixins i sidebar av Daniel Tonon (@daniel-tonon) på CodePen.

Se på hvor mye enklere Mopsen markup har blitt. Det er ingen “hvis dette da at” logikk for å bekymre seg for i mopsen markup. Alle som foreldrenes logikk er gått ut til css som er mye bedre til å forstå hvilke elementer foreldre av andre elementer uansett.

Du har kanskje lagt merke til at jeg brukte en velger det var tre klasser dypt i det siste eksempelet. Det ble brukt til å bruke 100% bredde til-knappen. Ja en tre klasse selector er ok om du kan begrunne det.

Jeg ønsker ikke 100% bredde skal brukes til-knappen hver gang det var:

  • brukt i det hele tatt hvor som helst
  • plassert inne i abonnere form
  • plassert inne i side-baren

Jeg ville bare 100% bredde til å bli brukt når det var både inni abonnere form og inne i sidefeltet. Den beste måten å håndtere det var med en tre-klasse-velgeren.

Ok, i virkeligheten, jeg vil mer sannsynlig bruke en ABEM stil -verticalStack modifier klasse på abonner-element til å gjelde vertikal stabling stiler eller kanskje til og med gjøre det via element spørringer ved hjelp av EQCSS. Dette ville bety at jeg kunne bruke vertikal stabling stiler i flere situasjoner enn bare når det er i sidefeltet. For å få til et eksempel om, jeg har gjort det som kontekst-sensitiv stiler.

Nå som vi forstår sammenhengen stiler, la oss gå tilbake til det opprinnelige eksempel hadde jeg og bruke litt kontekst-sensitiv stiler å bruke som plagsom grid-kolonnen: 3 regel:

Se Penn Kontekst-sensitiv 9 – kontekst-sensitiv metode med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Kontekst-sensitiv stiler føre til enklere HTML og templating logikk mens du fremdeles beholder den reusability av barn komponenter. BEM én klasse per selector filosofi ikke tillate at dette skal skje selv om.

Siden sammenhengen stiler er først og fremst opptatt med layout, avhengig av omstendigheter, bør du vanligvis bruke dem når du arbeider med disse CSS-egenskaper:

  • Noe CSS grid relaterte som brukes til barn element (grid-kolonnen, grid-rad etc.)
  • Noe flexbox i slekt som brukes til barn element (flex-vokse, flex-svinn, rett-selv etc.)
  • margin-verdier større enn 0
  • posisjon verdier annet enn relativ (sammen med topp -, venstre -, bunn -, høyre og egenskaper)
  • transformere hvis det brukes for posisjonering som translateY

Du kan også være lurt å plassere disse egenskapene inn i kontekst-sensitive stiler, men de er ikke så ofte nødvendig i en kontekst-sensitiv måte.

  • bredde
  • høyde
  • polstring
  • grense

For å være helt klart skjønt, kontekst-sensitiv stiler er ikke hekkende på grunn av hekkende. Du trenger å tenke på dem som om du var å skrive en if-setning i JavaScript.

Så for en CSS-regel som dette:

.forelder .element {
/* kontekst-sensitiv stiler */
}

Du bør tenke på det som om du skriver denne type logikk:

if (.- element .forelder) {
.element { /* kontekst-sensitiv stiler */ }
}

Også forstå at det å skrive en regel som er tre nivåer dypt som dette:

.besteforeldre .forelder .element {
/* kontekst-sensitiv stiler */
}

Bør være tenkt som du skriver logikk som dette:

hvis (
(.- element .foreldre) &&
(.- element .besteforeldre) &&
(.foreldrene i .besteforeldre)
) {
.element { /* kontekst-sensitiv stiler */ }
}

Så for all del, skriv en css-velgeren som er tre nivåer dypt, hvis du virkelig tror at du trenger det grad av spesifisitet. Vær så snill å forstå den underliggende logikken i css som du skriver om. Bruk kun en grad av spesifisitet som gir mening for den aktuelle styling som du prøver å oppnå.

Og igjen, en gang til, bare for å være svært tydelig, ikke hekker på grunn av hekkende!

Oppsummering

Metodikken bak BEM naming convention er noe som støtter jeg helhjertet. Det gjør css for å bli brutt ned i små, lett håndterlig komponenter heller enn å forlate css i en uhåndterlig rot av høy spesifisitet som er vanskelig å vedlikeholde. Den offisielle syntaks for BEM har mye å være ønsket om.

Den offisielle BEM syntaks:

  • Ikke støtte Atomic Design
  • Er ikke i stand til å bli utvidet lett
  • Det tar lengre tid for hjernen din til å behandle gruppering av klasse navn
  • Er forferdelig inkompetent når det gjelder å styre staten på store komponenter
  • Prøver å oppmuntre deg til å bruke en enkelt klasse velgere når du dobbeltklikker klasse velgere føre til enklere vedlikehold
  • Prøver å navn-plass alt selv når navneområder forårsaker flere problemer enn det løser.
  • Gjør HTML ekstremt oppblåst når det gjøres riktig

Min uoffisielle ABEM tilnærming:

  • Gjør som arbeider med Atomic Design enklere
  • Frigjør dashbordet karakter som en ekstra metode som kan brukes for å gruppere
  • Lar tankene til å behandle gruppering av klasse navn raskere
  • Er gode på å håndtere tilstanden på alle størrelser komponent uansett hvor mange sub-komponenter det har
  • Oppfordrer kontrollert spesifisitet snarere enn bare regelrett lav spesifisitet for å redusere team forvirring og forbedre nettstedet vedlikehold
  • Unngår navneområder når det ikke er nødvendig
  • Holder HTML ganske rent med minimalt med ekstra klasser som brukes til å moduler mens du fremdeles beholder alle BEM fordeler

Ansvarsfraskrivelse

Jeg fant ikke opp-modifikator (enkelt dash før modifier navn) ide. Jeg oppdaget at det i 2016 fra å lese en artikkel. Jeg kan ikke huske hvem som opprinnelig ble begrepsfestet ideen. Jeg er glad for å kreditere dem hvis noen vet artikkelen.