4 August 2016

Skriv struktureret, vedligeholdsvenlig og genanvendelig CSS med BEM

Selvom CSS/Cascading Style Sheets ikke er et programmerings- eller scriptsprog, men et styling-sprog, der bruges til at beskrive, hvordan et HTML-dokument skal præsenteres, så er der dog en række grundprincipper, der kan overføres mellem strukturering/udarbejdelse af CSS og programmeringssprog.

Et af de principper, er struktur: Hvis der ikke eksisterer en form for grundstruktur og arbejdsprincipper i ens kodebase, bliver den hurtig uoverskuelig at arbejde med. Det gælder særligt, når man arbejder i hold og på store projekter; her risikerer CSS-deklarationer simpelthen at blive til et virvar, hvor det ikke er til at finde hoved og hale i, hvilke »class modifiers« der effektivt har hvilke attributter, ligesom det kan knibe med klassenavnes genkendelighed, når man gennemser et HTML-output, hvis ikke der er lagt omtanke i projektets CSS-nomenklatur, såvel som individuel klassenavngivning på elementniveau.

For at imødegå den udfordring, er der gennem tiden blevet udarbejdet en række forskellige klassifikationsstrategier. De tre der er mest kendt, er nok henholdsvis OOCSS, SMACSS og BEM. Resten af dette blogindlæg vil blive brugt på en kursorisk gennemgang af BEM med en række lavpraktiske eksempler.

Kort fortalt er BEM en forkortelse for Block Element Modifier, der bedst kan karakteriseres som en teknik til hurtig og struktureret udvikling af hjemmesider. Når der skrives ”hjemmesider” frem for CSS, er det fordi, BEM-strukturen også kan overføres til design af JavaScript-kode (hvilket dog ligger uden for dette blogindlægs sigte).

BEM-princippet er udviklet hos Yandex og bruges i skrivende stund til frontend udvikling på deres forskellige services. Kort fortalt er hovedformålet med BEM, at udviklere kan skrive CSS, hvor klassenavne inddeles i uafhængige moduler, og som:

  • Er let at vedligeholde og udvikle på efterhånden som et projekt vokser i størrelse
  • Tilskynder til at genbruge CSS
  • Tillader små, inkrementielle og omkostningseffektive ændringer I eksisterende CSS.

Disse tre ting opnås ved at inddele CSS modulært, så Block-elementer ikke afhænger af andre CSS-elementer på den givne hjemmeside. På den måde sikres der mod »cascading« (et stylesheet med flere enslydende klassenavne, hvorved man kommer til at blande flere CSS-elementers styling sammen).

Ved at inddele sin CSS modulært opnår man derudover også den sidegevinst, at man kan overføre færdigudviklede Blocks fra ét projekt til et andet. Endnu vigtigere er det, at man sikrer genanvendelighed inden for ét givent projekt. Genanvendeligheden gør samtidig, at man reducerer størrelsen af den CSS-kode, der både skal skrives i første omgang, men endnu vigtigere: Som skal vedligeholdes fremadrettet.

Med det grundliggende sigte bag Block Element Modifier på plads, følger hermed et overordnet eksempel på, hvordan BEM-strukturen benyttes:

// Block
.block {}

// Element
.block__element {}

// Block Modifier
.block--modifier {}

// Block Element Modifier
.block__element--modifier {}

Som eksemplet viser, har man et overordnet block-element, der kan sammenlignes med et overordnet »classname«, som det eksempelvis kendes fra PHP. En ”Block” er med andre ord en helhed, eller et objekt, der giver mening på egen hånd. Eksempler på, hvad en Block kan repræsentere, er:

  • En menu
  • En loginform
  • En søgeform

Element-angivelsen er en del af block-elementet, og er semantisk knyttet til dette. Et "Element" har ingen semantisk-relationel mening på egen hånd. Man kan med andre ord sige, at et element er en »komponent« i block-elementet, som repræsenterer en specifik del af denne, og derfor kun giver mening i forhold til denne. Eksempler på et ”Element” kan være:

  • En login knap i en loginform
  • Et menu-element i en menu
  • Et input-felt i en søgeform

En Modifier er en måde at overskrive standard-styling/opførsel på både ”block” og ”element” klasser. Man bruger så at sige en ”Modifier” til at skabe variationer i Block og Elements. Eksempler på dette kan være:

  • En komprimeret udgave af en loginform (hvor man eksempelvis fjerner mellemrum/margin mellem input-felter)
  • Ændring af farve på menu-elementer, så de kan bruges i en footer frem for en header
  • Ændring af baggrundfarve på et bestemt input-felt i en søgeform

Et andet praktisk eksempel på dette er styling af knapper. Man kan eksempelvis have en standard CSS-klasse med navnet "button". Denne kan så styles med forskellige modifiers, så den skifter farve. Eksempelvis button--green eller button--red.

Det er i denne sammenhæng vigtigt at nævne, at en modifier ikke kan stå alene. I ovenstående eksempel med knappen, ville en knaps korrekte CSS-klasseangivelse derfor være "element modifier" eller button button--green.

Som afslutning på dette blogindlæg, gennemgås der et konkret eksempel nedenfor. På denne blogside er der en datoangivelse oven for hvert blogindlæg. Datoangivelsen er struktureret efter BEM-princippet:

<div class="blog-date">
    <span class="blog-date__day">Dato</span>
    <span class="blog-date__month">Måned</span>
    <span class="blog-date__year">År</span>
</div>

Det giver altså fire overordnede CSS-klasser:

// Block
.blog-date {}

//Element
.blog-date__day {}

// Element
.blog-date__month {}

// Element
.blog-date__year {}

Hvis der på et tidspunkt blev brug for, at eksempelvis farven på årstallet blev ændret til sort, kunne der tilføjes en modifier til <span class="blog-date__year">År</span>, så HTML-elementet i stedet har følgende klassenavne <span class="blog-date__year blog-date__year--black">År</span>.

Der er selvfølgelig en del mere at lære om brugen af BEM. Men ovenstående retningslinjer/eksempel viser de overordnede principper og har forhåbentligt fanget din interesse for at lære mere om BEM. I så fald kan du læse meget mere på bem.info og getbem.com.

Hvis du har konkrete spørgsmål til brugen af BEM, er du velkommen til at kontakte os.