ABEM. En mer användbar anpassning av BEM.

0
24

BEM (Block-Element Modifierare) är en populär CSS-klass namngivning som gör CSS lättare att underhålla. I denna artikel förutsätts att du redan är bekant med namngivning. Om inte kan du lära dig mer om det på getbem.com för att fånga upp grunderna.

Den standardiserade syntax för BEM är:

blockera-namn__element-namn–modifier-namn

Jag är personligen ett massivt fan av metodiken bakom namngivning. Separera dina stilar i små komponenter är mycket lättare att behålla än att ha ett hav av hög specificitet utspridda under hela din stilmall. Det finns dock ett par problem som jag har med den syntax som kan orsaka problem i produktionen och orsaka förvirring för utvecklare. Jag föredrar att använda en något justerad version av syntax istället. Jag kallar det ABEM (Atomic Block Element Modifierare):

[a/m/o]-blockName__elementName -modifierName

En Atomär Design Prefix

Den a/m/o är en Atomär Design prefix. Inte att förväxla med Atomic CSS vilket är en helt annan sak. Atomär design är en metod för att organisera dina komponenter som maximerar möjligheten att återanvända kod. Den delar komponenter i tre mappar: atomer, molekyler, och organismer. Atomer är super enkla komponenter som i allmänhet består av bara ett enda element (exempelvis en knapp komponent). Molekyler är små grupper av delar och/eller komponenter (t ex bilda en enda område som visar en etikett och ett inmatningsfält). Organismer är stora komplexa komponenter som består av många molekyl och atom-komponenter (t ex en fullständig registrering form).

Det är svårt att använda atomär design med klassiska BEM är att det inte finns någon indikator som säger vilken typ av komponent som ett block. Detta kan göra det svårt att veta var koden för att komponenten är eftersom du kan ha för att söka i 3 separata mappar för att hitta det. Lägga till atomic prefixet till start-gör det genast självklart vilken mapp den komponent som är lagrad i.

camelCase

Det gör det möjligt för egen gruppering

Klassiska BEM separerar varje enskilt ord i ett avsnitt med ett enda streck. Observera att atomic prefix i exemplet ovan är också skild från resten av klassen namn med bindestreck. Ta en titt på vad som händer nu när du lägger till en atomic prefixet till BEM classic vs camelCase:

/* classic + atomic prefix */
.o-prenumerera-form__field-item {}

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

I korthet, den komponent namn när man läser den klassiska metoden ser ut som det kallas “o prenumerera form”. Betydelsen av “o” är helt förlorad. När du har installerat den “o-” till camelCase version men, det är klart att det var avsiktligt skrivna för att vara en separat bit av information till komponentens namn.

Nu kan du ansöka atomic prefixet till klassiska BEM genom att utnyttja den “o” så här:

/* classic + kapitaliserade atomic prefix */
.O-prenumerera-form__field-item {}

Det skulle lösa problemet med “o” att gå vilse bland resten av klassen namn men det löser inte den grundläggande kärnan i problemet i den klassiska BEM syntax. Genom att separera ord med bindestreck, tankstreck karaktär är inte längre tillgänglig för dig att använda som en gruppering mekanism. Genom att använda camelCase, det frigör dig att använda dash karaktär för ytterligare gruppering, även om denna gruppering är bara att lägga till ett nummer till i slutet av en klass namn.

Ditt sinne kommer att behandla grupperingar snabbare

camelCase har också den extra fördelen att den grupp av klassen namn lättare att mentalt bearbeta. Med camelCase, varje lucka som du ser i klass namn representerar en grupp av något slag. I klassiska BEM, varje lucka kan vara antingen en gruppering eller ett utrymme mellan två ord i samma grupp.

Ta en titt på denna siluett av en klassisk BEM klass (plus atomic prefix) och försöka lista ut var de prefix, block, element och modifierare avsnitt start och slut:

Ok, nu prova den här. Det är exakt samma klass som den ovan, utom den här gången är det med camelCase att separera varje ord i stället för tankstreck:

Det var mycket lättare var det inte? Dessa silhuetter är i huvudsak vad ditt sinne ser när det är skannar igenom din kod. Med alla dessa extra streck i klassens namn, göra grupperingar långt mindre tydlig. När du läser igenom din kod, hjärnan försöker att bearbeta väder de luckor som den stöter på är nya grupperingar eller bara nya ord. Denna brist på klarhet orsaker kognitiv belastning för att tynga ditt sinne när du arbetar.

klassiska BEM + atomic prefix

camelCase BEM + atomic prefix

Använd multi klass väljare (på ett ansvarsfullt sätt)

En av de gyllene reglerna i BEM är att varje väljare bara är tänkt att innehålla en enda klass. Tanken är att det håller CSS underhålla genom att hålla specificitet av väljare låg och hanterbar. Å ena sidan håller jag med om att låg specificitet är att föredra över att ha specificitet köra skenande. På den andra, jag håller inte alls med om att en strikt en klass per väljare regel är det bästa för projekt. Med hjälp av några multi-klass väljare i din stilar kan faktiskt förbättra hanteringen snarare än att minska det.

“Men det leder till högre specificitet! Vet du inte att specificitet är i sig ont?!?”

Specificitet != dåligt.

Okontrollerad specificitet som har förvildats = dåligt.

Med en något högre specificitet förklaringar som inte omedelbart innebära att din CSS är svårare att upprätthålla. Om de används på rätt sätt, vilket ger vissa regler med högre specificitet kan faktiskt göra CSS lättare att underhålla. Nyckeln till att skriva att underhålla CSS med ojämn specificitet är att lägga till specificitet målmedvetet och inte bara för att ett objekt som händer att vara inuti ett element i lista.

Dessutom har vi inte faktiskt vill att våra modifierare stilar för att ha större makt över elementen än standard stilar? Att böja över bakåt för att hålla modifierare stilar på samma specificitet nivå som normala stilar verkar dumt till mig. När du verkligen vill att din vanliga standard stilar för att åsidosätta dina särskilt utsedda modifierare stilar?

Separera modifierare leder till en renare HTML –

Detta är den största förändringen att den syntax som ABEM införs. I stället för att ansluta modifierare till den del av klass, kan du använda det som en separat klass.

En av de saker som praktiskt taget alla klagar på när de börjar lära sig BEM är hur fult det är. Det är särskilt illa när det kommer till socker under vispning. Ta en titt på detta illdåd. Den har bara tre modifierare tillämpas på det och ändå ser det ut som ett tåg vraket:

B__E–M:
<knappen class=”blockera-namn__element-namn blockera-namn__element-namn-small block-namn__element-namn-gröna blocket-namn__element-namn-aktiva”>
Skicka
</button>

Titta på alla som repetition! Att upprepning gör det ganska svårt att läsa vad det är som faktiskt försöker göra. Ta nu en titt på detta ABEM exempel som har alla samma modifierare som i föregående exempel:

A-B__E -M:
<knappen class=”en-blockName__elementName -små -grön-active”>
Skicka
</button>

Mycket renare är inte det? Det är mycket lättare att se vad dessa modifierare klasser försöker säga, utan att alla som repetitiva gunk att komma i väg.

Vid inspektion av ett element med webbläsaren DevTools, du fortfarande se den fullständiga regel i styling-panelen så att den behåller anslutning till den ursprungliga delen på detta sätt:

.a-blockName__elementName.-gröna {
bakgrund: grön;
färg: vit.
}

Det är inte mycket olika till BEM motsvarande

.blockera-namn__element-namn–grön {
bakgrund: grön;
färg: vit.
}

Verkställande staten blir lätt

En stor fördel som ABEM har över klassiska BEM är att det blir oerhört lättare att hantera status för en komponent. Låt oss använda en grundläggande dragspel som ett exempel. När en del av detta dragspel är öppen, låt oss säga att vi vill tillämpa ändringarna till styling:

  • Ändra bakgrundsfärg på rubriken för avsnittet
  • Visa innehåll
  • Gör en pil pekar upp

Vi kommer att hålla sig till de klassiska B__E–M syntax för detta exempel och strikt hålla sig till en klass per css-väljare regel. Detta är vad vi kommer att sluta med (notera, att för enkelhetens skull, detta dragspel är inte tillgänglig):

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

Den SCSS ser ganska ren men ta en titt på alla de extra klasser som vi har för att lägga till i HTML-koden för bara en enda förändring i staten!

HTML-samtidigt som ett segment är stängt med hjälp av BEM:
<div class=”uppenbarar dragspel__avsnittet”>
<div class=”uppenbarar__trigger”>
<h2 class=”uppenbarar__rubriken”>Tre</h2>
<div class=”uppenbarar__icon”></div>
</div>
<div class=”uppenbarar__content”>
Lorem ipsum dolor sit amet…
</div>
</div>
HTML-samtidigt som ett segment är öppna med BEM:
<div class=”uppenbarar dragspel__avsnittet”>
<div class=”uppenbarar__utlösa uppenbarar__utlösa–öppna”>
<h2 class=”uppenbarar__rubriken”>En</h2>
<div class=”uppenbarar__ikon uppenbarar__ikonen–öppna”></div>
</div>
<div class=”uppenbarar__innehåll som uppenbarar__innehåll–öppna”>
Lorem ipsum dolor sit amet…
</div>
</div>

Låt oss nu ta en titt på vad som händer när vi växlar över till att använda den här fina nya A-B__E -M metod:

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

En enda klass som nu kontrollerar staten-specifika styling för hela komponenten nu istället för att behöva tillämpa en separat klass för att varje element för sig.

HTML-samtidigt som ett segment är öppna med hjälp av ABEM:
<div class=”m-uppenbarare o-dragspel__avsnitt -öppna”>
<div class=”m-uppenbarare__trigger”>
<h2 class=”m-uppenbarare__rubriken”>En</h2>
<div class=”m-uppenbarare__icon”></div>
</div>
<div class=”m-uppenbarare__content”>
Lorem ipsum dolor sit amet…
</div>
</div>

Ta också en titt på hur mycket enklare javascript har blivit. Jag skrev JavaScript så rent som jag kunde och det här blev resultatet:

JavaScript när du använder ren BEM:
klass uppenbarar {
konstruktör(el){
Objektet.tilldela(detta {
$omslag: el,
mål: [‘utlösare’, ‘ikon’, ‘content’],
isOpen: false,
});
detta.gather_elements();
detta.$trigger.onclick = ()=> här.växla();
}

gather_elements(){
const nycklar = detta.mål.karta(selector => `$${selector}`);
const element = det här.mål.karta(selector => {
tillbaka detta.$omslaget.querySelector(`.revealer__${selector}`);
});
låt elObject = {};
nycklar.forEach((key, i) => {
elObject[key] = elementen[i];
});
Objektet.tilldela(detta elObject);
}

växla(){
om (detta.isOpen) {
detta.stäng();
} else {
detta.open();
}
}

open(){
detta.mål.forEach(mål => {
detta[`$${target}`].classList.add(`uppenbarar__${target}–open”);
})
detta.isOpen = true;
}

stäng(){
detta.mål.forEach(mål => {
detta[`$${target}`].classList.ta bort(`uppenbarar__${target}–open”);
})
detta.isOpen = false;
}
}

dokumentet.querySelectorAll(‘.revealer’).forEach(el => {
nya uppenbarare(el);
})
JavaScript när du använder ABEM:
klass uppenbarar {
konstruktör(el){
Objektet.tilldela(detta {
$omslag: el,
isOpen: false,
});
detta.$utlösa =.$omslaget.querySelector(‘.m-uppenbarare__trigger”);
detta.$trigger.onclick = ()=> här.växla();
}

växla(){
om (detta.isOpen) {
detta.stäng();
} else {
detta.open();
}
}

open(){
detta.$omslaget.classList.add (`öppna`);
detta.isOpen = true;
}

stäng(){
detta.$omslaget.classList.ta bort (`öppna`);
detta.isOpen = false;
}
}

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

Detta var bara en mycket enkel dragspel exempel. Tänk på vad som händer när du extrapolera detta till något som en klibbig header som ändras när klibbig. En klibbig header kanske måste berätta 5 olika komponenter när huvudet är klibbig. Sedan i var och en av de 5 komponenterna, 5 element kan behöva reagera på att huvudet är klibbig. Det är 25-element.classList.lägga till(“[componentName]__[elementName]–klibbig”) regler som vi skulle behöva att skriva i vår js för att hålla sig strikt till BEM namngivning. Vad är mer logiskt? 25 unika klasser som läggs till varje element som påverkas, eller bara en klibbig klass lagts till i huvudet att alla 5 delar i alla 5 komponenter som har möjlighet att komma åt och lätt att läsa?

Den BEM “lösning” är helt opraktiskt. Tillämpa modifierare styling till stora komplexa komponenter slutar att förvandlas till lite av en gråzon. En gråzon som orsakar förvirring för alla utvecklare som försöker att hålla sig strikt till BEM namngivning så nära som möjligt.

ABEM modifierare frågor

Separera modifierare är inte utan sina brister. Men det finns några enkla sätt att komma runt dessa brister.

Fråga 1: Kapsling

Så vi har vår dragspel och allt fungerar perfekt. Senare ner linjen, kunden vill bo en andra dragspel inuti den första. Så du går vidare och göra det… det här händer:

Se Pennan Dragspel 3 – ABEM häckande fel av Daniel Tonon (@daniel-tonon) på CodePen.

Häckande en andra dragspel inuti den första orsakar en ganska problematisk fel. Öppna den överordnade dragspel gäller även öppet läge styling till alla barn dragspel i det segmentet.

Detta är något som du uppenbarligen inte vill ska hända. Det är ett bra sätt att undvika detta men.

För att förklara det, låt oss spela lite spel. Om man antar att båda dessa CSS-regler är verksamma på samma faktor, vilken färg tror du att elementet bakgrund skulle vara?

.-grön > * > * > * > * > * > .element {
bakgrund: grön;
}

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

Om du säger green på grund av att den första regeln att ha en högre specificitet än den andra regeln är att du faktiskt skulle vara fel. Bakgrunden skulle vara blå.

Kul fakta: * är lägst specificitet väljare i CSS. Det betyder i princip “allt” i CSS. Det har faktiskt ingen specificy, betyder det inte att lägga någon specificitet för att en väljare du lägga till det till. Det innebär att även om du har använt en regel som bestod av en enda klass och 5 stjärnor (.element > * > * > * > * > *) det kan ändå vara lätt att skrivas över av bara en enda klass på nästa rad i CSS!

Vi kan dra nytta av denna lilla CSS sarkasm för att skapa en mer målinriktad strategi för dragspel SCSS-kod. Detta gör det möjligt för oss att på ett säkert sätt boet våra dragspel.

Se Pennan Dragspel 4 – ABEM häckande buggfix av Daniel Tonon (@daniel-tonon) på CodePen.

Genom att använda den .-modifierName > * > & mönster, du kan rikta direkta ättlingar som är flera nivåer djupt utan att orsaka din specificitet för att få ut av kontroll.

Jag använder bara denna direkt inriktning på teknik som det blir nödvändigt dock. Som standard, när jag skriver ABEM ska jag skriva här hur jag gjorde i den ursprungliga ABEM dragspel exempel. Den icke-riktade metod är i allmänhet allt som behövs i de flesta fall. Problemet med målinriktad strategi är att lägga till ett enda skal runt något som potentiellt kan bryta hela systemet. Icke-målinriktad strategi inte lider av detta problem. Det är mycket mer överseende och förhindrar stilar från att bryta om du någonsin behöver för att ändra HTML senare ner linjen.

Fråga 2: Namngivning kollisioner

Ett problem som du kan stöta på med den icke-riktade modifierare teknik är namngivning av kollisioner. Låt oss säga att du behöver för att skapa en uppsättning flikar och under varje flik finns ett dragspel i det. När du skriver den här koden, som du har gjort med både dragspel och flikar svara till -aktiv klass. Detta leder till ett namn kollision. Alla dragspel i den aktiva fliken kommer att ha sina aktiva formatmallar. Detta är på grund av att alla dragspel är barn av fliken behållaren element. Det är den fliken behållare element som har den faktiska-aktiv klass tillämpas på dem. (Varken flikar eller dragspel i följande exempel är tillgänglig för enkelhetens skull.)

Se Pennan Dragspel i flikarna 1 – bryts av Daniel Tonon (@daniel-tonon) på CodePen.

Nu ett sätt att lösa denna konflikt skulle vara att helt enkelt ändra dragspel för att svara på en öppen klass i stället för en aktiv klass. Jag skulle faktiskt rekommendera denna metod. För den skull ett exempel men låt oss säga att det är inte ett alternativ. Du kan använda den direkt inriktning på teknik som nämns ovan, men som gör ditt stilar mycket spröda. Istället vad du kan göra är att lägga till komponent namn på framsidan av modifier så här:

.o-componentName {
&__elementName {
.-componentName–modifierName & {
/* modifierare stilar gå här */
}
}
}

Streck på framsidan av namn fortfarande betyder att det är en modifierare klass. Komponenten namnet förhindrar namespace kollisioner med andra komponenter som inte ska bli drabbade. Double dash är huvudsakligen bara en blinkning till den klassiska BEM modifierare syntax för att dubbel förstärka att det är en modifierare klass.

Här är dragspel och flikar exempel igen men denna gång med namespace fixa tillämpas:

Se Pennan Dragspel i flikar 2 – fast av Daniel Tonon (@daniel-tonon) på CodePen.

Jag rekommenderar inte att använda denna teknik som standard men främst för den skull hålla HTML-ren och också för att förhindra förvirring när flera komponenter måste dela samma modifierare.

Majoriteten av tiden, en modifierare klass används för att beteckna en förändring i staten som i dragspel exemplet ovan. När en del förändringar staten, alla underordnade element, oavsett vilken komponent som de tillhör, ska kunna läsa att tillstånd förändras och svara på det enkelt. När en modifierare klass är avsedda att påverka flera komponenter på en gång, förvirring kan uppstå kring vad komponent som modifierare specifikt hör till. I dessa fall, namn-avstånd modifierare som gör mer skada än nytta.

ABEM modifierare teknik sammanfattning

Så för att göra den bästa användningen av ABEM modifierare, användning.modifierName & eller &.-modifierName syntax som standard (beror på vilka element som har klassen på det)

.o-componentName {
&.-modifierName {
/* componentName modifierare stilar gå här */
}

&__elementName {
.-modifierName & {
/* elementName modifierare stilar gå här */
}
}
}

Använd direkt inriktning om häckande en komponent inuti sig självt orsakar ett problem.

.o-componentName {
&__elementName {
.-nestedModifierName > * > & {
/* modifierare stilar gå här */
}
}
}

Använda komponenten namn i modifier om du kör i delad modifierare namn kollisioner. Gör endast det här om du inte kan tänka på ett annat modifierare namn som fortfarande är vettigt.

.o-componentName {
&__elementName {
.-componentName–sharedModifierName & {
/* modifierare stilar gå här */
}
}
}

Sammanhangsberoende stilar

En annan fråga med strikt följa de BEM en klass per väljare metoden är att det inte tillåter dig att skriva sammanhangsberoende stilar.

Sammanhangsberoende stilar är i princip “om denna del finns i denna förälder, tillämpas dessa stilar till det”.

Med sammanhangsberoende stilar, det finns en överordnad komponent och en underordnad komponent. Den överordnade delen bör vara den som gäller layout närliggande stilar som marginal och position för att barnet komponent (.förälder .barnet { margin: 20px }). Barnet komponent skall alltid som standard inte har någon marginal runt utsidan av komponenten. Detta gör att barnet komponenter som ska användas i fler sammanhang eftersom det är det överordnade ansvaret för det egna layout snarare än sina barn.

Precis som med riktiga föräldraskap, föräldrarna är de som ska ha ansvaret. Du ska inte låta sina stygga barn borta kallar skotten när det kommer till föräldrarna layout.

Att gräva vidare i detta begrepp, låt oss låtsas att vi håller på att bygga en ny webbplats och just nu håller vi på att bygga prenumerera på formuläret komponent för webbplatsen.

Se Pennan Sammanhangsberoende 1 – DVS ovänliga av Daniel Tonon (@daniel-tonon) på CodePen.

Detta är första gången som vi har varit tvungna att sätta ett formulär på den här sköna nya webbplats som vi håller på att bygga. Vi vill vara som alla coola kids så vi använde CSS nätet för att göra layout. Vi är smart ändå. Vi vet att knappen styling kommer att användas på många fler ställen på hela webbplatsen. Att förbereda sig för detta, vi separat på knappen prenumerera stilar i sin egen separat komponent som god små utvecklare.

En stund senare börjar vi webbläsar-testning. Vi öppnar upp IE11 bara för att se denna fula sak som stirrar oss i ansiktet:

IE11 inte typ av stöd för CSS nätet men det har inte stöd för grid-gap eller automatisk placering. Efter några renande svordomar och önskar att människor skulle uppdatera sin webbläsare, du justera stilar för att ser mer ut så här:

Se Pennan Sammanhangsberoende 2 – vad man inte ska göra av Daniel Tonon (@daniel-tonon) på CodePen.

Nu ser det ut perfekt i IE. Allt är rätt med världen. Vad kan möjligen gå fel?

Ett par timmar senare du sätter denna knapp komponent i en annan komponent på webbplatsen. Denna andra komponent också använder css-grid layout sina barn.

Du skriva följande kod:

Se Pennan Sammanhangsberoende 3 – den andra komponenten av Daniel Tonon (@daniel-tonon) på CodePen.

Du förväntar dig att se en layout som ser ut så här även i IE11:

Men i stället, på grund av grid-kolumn: 3; koden som du skrev tidigare, det slutar se ut som detta:

Usch! Så vad gör vi om detta grid-kolumn: 3; CSS vi skrev tidigare? Vi måste begränsa det till den överordnade delen men hur ska vi gå tillväga för att göra det?

Samt den klassiska BEM metod för att hantera detta är att lägga till en ny överordnad komponent element klass till knappen som denna:

Se Pennan Sammanhangsberoende 4 – klassiska BEM lösning av Daniel Tonon (@daniel-tonon) på CodePen.

På ytan denna lösning ser ganska bra:

  • Det håller låg specificitet
  • Den överordnade delen är att kontrollera sin egen layout
  • Styling är inte troligt att blöda i andra komponenter vi vill inte att det ska blöda i

Allt är awesome och allt är rätt med världen… rätt?

Nackdelen med denna metod är främst på grund av det faktum att vi var tvungna att lägga till en extra klass på knappen komponent. Sedan prenumerera-form__lämna klassen finns inte i base-knappen komponent, det innebär att vi behöver lägga till extra logik till vad vi använder som vår mallhantering motor för att få rätt på stilar.

Jag älskar att använda Mops för att skapa mina mallar. Jag ska visa dig vad jag menar med Mops mixins som ett exempel.

Först, här är den ursprungliga IE ovänliga kod som skrivits i mixin-format:

Se Pennan Sammanhangsberoende 5 – DVS ovänliga med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Nu kan lägga till att IE 11 prenumerera-form__lämna klassen för att det:

Se Pennan Sammanhangsberoende 6 – IE säker BEM lösning med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Det var inte så svårt, så vad är jag att klaga på? Bra låt oss nu säga att vi ibland vill att modulen skall placeras inne i en sidebar. När det är, vi vill att e-ingång och-knappen för att staplas ovanpå varandra. Kom ihåg att för att hålla sig strikt till BEM, vi är inte tillåtna att använda något högre specificitet än en enda klass i våra stilar.

Se Pennan Sammanhangsberoende 7 – IE säker BEM med mixins i sidofältet av Daniel Tonon (@daniel-tonon) på CodePen.

Som Mops koden ser inte så lätt nu det är? Det finns några saker som bidrar till den här röran.

  1. Behållare frågor skulle göra det långt mindre av ett problem men att de ännu inte finns inbyggt i alla webbläsare
  2. Problemen kring BEM modifierare syntax uppfödning sina fula huvuden.

Nu kan prova att göra det igen, men denna gång med en sammanhangsberoende stilar:

Se Pennan Sammanhangsberoende 8 – DVS säker Sammanhangsberoende med mixins i sidofältet av Daniel Tonon (@daniel-tonon) på CodePen.

Titta på hur mycket enklare Mops markup har blivit. Det finns inga “om det här då” logik för att oroa dig i mops-kod. Alla som föräldrarnas logik skickas iväg till css som är mycket bättre på att förstå vilka faktorer är föräldrar till andra delar i alla fall.

Du kanske har märkt att jag använde en väljare som var tre klasser djupt i det sista exemplet. Det var som används för att tillämpa 100% bredd knappen. Ja en tre-klass väljare är ok om du kan motivera det.

Jag ville inte 100% bredd och tillämpas på knappen varje gång det var:

  • används på alla överallt
  • placerad inuti prenumerera form
  • placeras inne i side-bar

Jag ville bara ha 100% bredd ska tillämpas när det var både inuti prenumerera form och inne i sidofältet. Det bästa sättet att hantera det var med en klass tre väljare.

Ok, i verkligheten, jag skulle mer sannolikt att använda en ABEM stil -verticalStack modifierare klass på prenumerera-form-element för att tillämpa vertikal stapel stilar eller kanske till och med göra det via del frågor med hjälp av EQCSS. Detta skulle innebära att jag kunde tillämpa vertikal stapel stilar i fler situationer än bara när det är i sidomenyn. För den skull ett exempel men jag har gjort det som sammanhangsberoende stilar.

Nu när vi förstår sammanhanget stilar, låt oss gå tillbaka till det ursprungliga exemplet jag hade och använda vissa sammanhangsberoende stilar att gälla som besvärande grid-kolumn: 3-regeln:

Se Pennan Sammanhangsberoende 9 – sammanhang känslig metod med mixins av Daniel Tonon (@daniel-tonon) på CodePen.

Sammanhangsberoende stilar leda till enklare HTML och mallhantering logik samtidigt behålla återanvändning av barn komponenter. BEM en klass per väljare filosofi inte tillåter detta att hända dock.

Eftersom sammanhangsberoende stilar i första hand sysslar med layout, beroende på omständigheterna, bör du i allmänhet använda dem när du arbetar med dessa CSS-egenskaper:

  • Något CSS nätrelaterade som tillämpas för att barnet element (grid-kolumn, grid-rad etc.)
  • Något flexbox rör som används till barn element (flex-växa, flex-shrink, align-själv etc.)
  • marginalen värden som är större än 0
  • position andra värden än släkting (tillsammans med toppen, till vänster, botten, höger och egenskaper)
  • omvandla om det används för positionering som translateY

Du kanske också vill placera dessa egenskaper i ett sammanhang som är känsliga stilar men de är inte så ofta som behövs i ett sammanhang känsligt sätt.

  • bredd
  • höjd
  • stoppning
  • gräns

För att vara helt tydlig men, sammanhangsberoende stilar är inte kapsling för den skull häckning. Du måste tänka på dem som om du skulle skriva en if-sats i JavaScript.

Så för en CSS-regel som denna:

.förälder .element {
/* sammanhangsberoende stilar */
}

Du bör tänka på det som du skriver detta slags logik:

om (.elementet .parent) {
.element { /* sammanhangsberoende stilar */ }
}

Förstår även att du skriver en regel som är tre nivåer djupt som denna:

.mor-eller farförälder .förälder .element {
/* sammanhangsberoende stilar */
}

Bör vara tänkt som du skriver logik så här:

if (
(.elementet .förälder) &&
(.elementet .morfar) &&
(.förälder i .far-eller morförälder)
) {
.element { /* sammanhangsberoende stilar */ }
}

Så med alla medel, skriv en css-väljare som är tre nivåer djupt om du verkligen tror att du behöver den grad av specificitet. Vänligen förstå den bakomliggande logiken i css som du skriver om. Använd endast en nivå av specificiteten som är meningsfullt för just styling som du försöker uppnå.

Och igen, en gång till, bara för att vara super klart inte bo för den skull häckande!

Summering

Metoden bakom BEM namngivning är något som jag helhjärtat stödjer. Det gör att css för att brytas ner i små lätthanterliga komponenter snarare än att lämna css i en otymplig röra av hög specificitet som är svår att upprätthålla. Den officiella syntax för BEM har en hel del att önska dock.

Den officiella BEM syntax:

  • Inte har stöd för Atom Design
  • Kan inte förlängas lätt
  • Tar det längre tid för din kropp att bearbeta gruppering av klass namn
  • Är fruktansvärt inkompetent när det kommer till verkställande staten på stora komponenter
  • Försöker att uppmuntra dig att använda samma klass väljare när dubbel klass väljare leda till enklare underhåll
  • Försöker namn-space allt även när namespacing orsakar mer problem än det löser.
  • Gör HTML extremt uppsvälld när den görs rätt

Min inofficiella ABEM tillvägagångssätt:

  • Gör som arbetar med Atomär Design lättare
  • Frigör dash karaktär som en extra metod som kan användas för att gruppera
  • Gör ditt sinne för att behandla den grupp av klassnamn snabbare
  • Är bra på att hantera stat på någon medelstora komponent oavsett hur många sub komponenter som det har
  • Uppmuntrar kontrolleras specificitet snarare än bara rena låg specificitet för att minska team förvirring och förbättra webbplatsen underhåll
  • Undviker namespacing när det inte behövs
  • Håller HTML ganska ren med minimal extra klasser tillämpas på moduler och ändå behålla alla BEM fördelar

Ansvarsfriskrivning

Jag uppfann inte -modifierare (enda streck innan modifierare namn) idé. Jag upptäckte det i 2016 från att läsa en artikel. Jag kan inte komma ihåg vem som ursprungligen conceptualized tanken. Jag är glad att tillgodogöra sig dem om någon vet artikel.