IVEO(S)CSS-stilguide

Generella riktlinjer

I den här artikeln går vi igenom hur vi på IVEO arbetar med CSS och inledningsvis hur vi namnger våra CSS-klasser. Kortfattat använder vi klassnamn som är passande men även tvetydiga: vi eftersträvar en balans mellan att förklara innehållet och hitta klassnamn med lång livslängd som är återanvändbara. Namngivningsmetoden BEM och en SCSS-linter hjälper till att upprätthålla en så klanderfri struktur som möjligt så vi kan skriva konsekvent genom hela projektets gång.

Hur vi namnger klasser

Följande klassnamn har kort livslängd och håller inte om t.ex. färgpaletten förändras med tiden:

.yellow {
    color: yellow;
}

Följande två exempel bygger på att elementet används på en specifik plats:

.header li span {
    color: yellow;
}

.header-color {
    color: yellow;
}

Så namnger vi inte våra klasser. Istället gör vi följande vis – lagom tydligt och väldigt anpassningsbart:

.highlight-color {
    color: yellow;
}

Alltså: om vi skulle namnge våra klasser för att förklara innehållet så riskerar vi att måla in dem i ett hörn där de är beroende av plats (headern) och färg (gul). Istället hittar vi lagom generiska namn som förklarar innehållstypen utan att begränsa vart den används eller exakt vilken färg den har.


BEM – block, element, modifier

BEM hjälper oss att namnge och strukturera våra CSS-klasser. Den här namngivningsmetoden handlar återigen om återanvändbarhet och skalbarhet. En HTML-komponent ska inte vara beroende av dess placering i DOM-trädet utan ska kunna anpassa sig till olika platser med olika containers.

Namngivningen sker på följande vis:

.block {}
.block__element {}
.block--modifier {}
  • .block representerar huvudkomponenten.
  • .block__element representerar en del av huvudkomponenten som hjälper till att forma .block som en helhet.
  • .block–modifier representerar en annan variant eller version av .block

Anledningen till att man använder dubbla binde- och understreck är för att en huvudkomponent (.block) kan innehålla ett bindesstreck (.my-block). Se skillnaden nedan:

.my-block--red {
    background-color: red;
}
.my-block-red {
    background-color: red;
}

Dubbla bindestreck hjälper helt enkelt till att separera ”Block” från ”Element” och ”Modifier”. Läs mer om BEM-metoden här eller på csswizardy:
http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax


Nästla inte!

Med Sass är det väldigt lätt hänt att ”nästla in sig”. Vi strävar efter att använda så få selektorer som möjligt. Ju mer vi ”nästlar”, desto längre tid tar det för webbläsaren att läsa vår CSS, och framförallt skapar det också en hög specificity. Mer om det längre ner. Här följer ett exempel på innästlad CSS:

header .container .navigation ul {}

Istället använder vi en enda klass för att träffa vår huvudmeny, som dessutom går att återanvända på andra ställen utanför vår header:

.primary-nav {}

Vi strävar efter att ”nästla” högst två led in. Här följer ett exempel på hur vi med hjälp av BEM och Sass kliver ett led in:

.primary-nav {
    font-size: bold;

    &--left {
        text-align: left;
    }
}

Detta kompileras sedan till:

.primary-nav--left {
    text-align: left;
}

På detta vis skapar vi en lägre specificity och ett bättre selector intent, begreppen förklaras nedan.


Selector Intent – konsten att välja rätt selektorer

Uttrycket Selector Intent  handlar om processen att välja vad du ska style:a och hur du ska gå till väga för att träffa just det elementet. Ett misstag många gör är att inte använda klasser utan istället träffa själva elementen:

header ul {}

Den här selektorn har ett så kallat Poor Selector Intent: en header kan innehålla mängder av element som i sin tur kan innehålla ul-element. Om så är fallet kommer vi behöva skriva över CSS som inte hade behövt finnas där från början.

Här är ett exempel på Good Selector Intent:

.primary-nav {}

Vi väljer klart och tydligt vilken UL-lista vi vill göra till vår huvudnavigation och riskerar inte att behöva tillskriva regler till andra element som råkar påverkas av hur vi vill att vår huvudnavigation ser ut.

Selektorer vi underviker att använda:

  • IDs (#header)
  • Types (header)
  • Descendants (`ul li)
  • Universals (*)

CSS Specificity

CSS Specificity handlar om hur webbläsaren väljer att prioritera vilken CSS som ska användas av de regler som ett element har tillskrivits. Skriver man CSS med hög specificity riskerar man att måla in sig i ett hörn, och en vanlig väg ut är att sätta !important, alternativt gräva sig en grop i hörnet genom att skapa ytterligare en klass på en redan lång selektor.

Vi försöker att hålla så låg specificitet som möjligt genom att:

  • inte använda IDs (de går inte att återanvända, de har extremt hög specificitet och det är helt enkelt inte värt risken.)
  • inte nästla in en selektor (.header ul li a)
  • inte använda ”qualified selectors” (ul.a)
  • inte använda för långa selektorer (body.home .header ul.primary-nav .primary-nav__link).

Om vi har kommit till en punkt där !important måste användas så är det alltså ett tydligt tecken på att vi har skrivit CSS med hög specificity. !important hör endast hemma vid så kallade ”helper-classes”, som till exempel:

.hidden { display: none !important; }

Tumregel: använd !important proaktivt och inte retroaktivt.


Återanvändbarhet

Hittills har alla punkter kokat ner i en strävan efter att skriva CSS som går att återanvända och som kan upprätthålla en hög standard längs hela projektets väg. Alla val vi gör ska göras med återanvändbarheten i åtanke: style:a inte saker baserat på var de är, utan vad de är. En komponent ska inte vara beroende av en specifik plats för att se ut på ett speciellt sätt.

 

Syntax och formatering

Nedan följer IVEOs mer tekniska riktlinjer för hur vi skriver vår CSS. Här är övergripande punkter som är viktiga för att CSS:en förblir konsekvent när fler utvecklare arbetar tillsammans i ett projekt.

  • Indentera med 2 spaces, ej tabbar.
  • Lämna en radbrytning mellan varje selektor.
  • Skriv varje regel på en egen rad.
  • Mellanrum efter kolonet(:).
  • Semikolon ( ; ) efter -alla- regler.
  • Radbrytning efter varje måsvinge ( } ).
  • Använd whitespace för att skapa luft och rymd.

Viktiga Sass-riktlinjer:

  • Nästlade selektorer får en radbrytning ovanför och under sig.
      .foo {
          display: block;
          margin: 10px 0;
    
          &:hover {
              color: red;
          }
    
          &.foo--bar {
              margin: 20px 0;
          }
      }
    
  • Ingen radbrytning efter den sista nästlade selektorn (se exempel ovanför).
  • Mixins (@include) och Extends (@extend) hamnar överst i grupp. Först @extends, sen @includes.
      .foo {
          @extend %bar;
          @include bp('sm');
          @include radius(2px);
    
          display: block;
          margin: 10px 0;
      }
    

Strängar

CSS kräver inte att vi placerar citattecken runt våra strängar. Men det gör vi ändå.

NEJ:

font-family: Helvetica, Arial, sans-serif;
background-image: url(assets/img/logo.png);

JA:

font-family: 'Helvetica', 'Arial', sans-serif;
background-image: url('assets/img/logo.png');

Siffror

Med Sass så använder vi flitigt med siffror och nedan följer riktlinjer för hur vi behandlar dem.

Nollor (0): Vi sätter alltid en nolla innan decimalvärdet:

NEJ:

opacity: .5;

JA:

opacity: 0.5;


Enheter (px): 
När en egenskap får ett nollvärde ska inte enheten definieras:

NEJ:

margin: 0px 0px 10px;

JA:

margin: 0 0 10px;

Färger

Sass låter oss enkelt manipulera färger genom enkla funktioner, och så här förhåller vi oss till dem:

Variabler: Om vi använder en färg mer än en gång ska den sparas som en variabel. Här är det viktigt att vi namnger på ett sätt som gör variabeln återanvändbar och långlivad.

NEJ:

$red: #ff0000;
$blue: #ccc;

JA:

$primary-color: #ff0000;
$accent-color: #ccc;


RGBA: 
När vi använder rgba för att utnyttja opacity-egenskapen så ser vi till att addera ett mellanslag efter kommatecknet (, ) och inget mellanslag mellan paranteserna ((, )). Så här:

NEJ:

color: rgba(0,0,0,0.5);

JA:

color: rgba(0, 0, 0, 0.5);


Samma princip gäller när vi använder lighten och darken:

NEJ:

background-color: darken($primary-color,5%);

JA:

background-color: darken($primary-color, 5%);

Mixins, extend & vendor prefixes

Mixins

En stor anledning till varför Sass blev så populärt. En klassisk mixin är ”clearfixen”:

@mixin clearfix {
      &::after {
        content: '';
        display: table;
        clear: both;
      }
}

Extend

Använder vi också, till exempel på följande vis:

.lead {
      font-size: 1rem;
      font-weight: 400;
      margin: 0 0 2rem;
}

p:first-child {
      @extend %lead;
}

Vendor prefixes (-moz, -webkit, -ms)

…vill vi inte behöva skriva, istället använder vi Autoprefixer.

 

Responsive

Vi skriver responsiv CSS med hjälp av så kallade ”breakpoint mixins”. Till exempel:

@mixin bp($point) {
      @if $point == 'xxs' {
        @media (max-width: 460px) {
              @content;
        }    
      }
  }

Den breakpointen används för att anpassa stylingen för en mobil enhet och så här används mixin:en:

.foo {
    color: blue;

    @include bp('xxs') {
        color: red;
    }
}

…och kompileras till följande CSS-kod:

.foo {
    color: blue;
}

@media (max-width: 460px) {
    .foo {
        color: red;
    }
}

 

Arkitektur

Vi gillar att stycka upp vår CSS i mindre bitar. Beroende på vilken typ av CSS vi skriver så placeras filerna i olika mappar. Ungefär så här brukar strukturen se ut:

sass/
|
|– base/
|   |– _reset.scss       # Reset/normalize
|   |– _typo.scss        # Regler för typsnitt
|   ...                  # OSV…
|
|– components/
|   |– _buttons.scss     # Knappar
|   |– _forms.scss       # Formulär
|   |– _lists.scss       # Listor
|   |– _promo.scss       # Slider 
|   |– _icons.scss       # Ikoner
|   |– _dropdown.scss    # Dropdown
|   ...                  # OSV…
|
|– layout/
|   |– _navigation.scss  # Navigationen
|   |– _grid.scss        # Gridsystemet
|   |– _header.scss      # Header
|   |– _footer.scss      # Footer
|   |– _sidebar.scss     # Sidebar
|   ...                  # OSV…
|
|– pages/
|   |– _home.scss        # Sidspecifik styling för startsidan
|   |– _about.scss       # Sidspecifik styling för "about"-sidan
|   ...                  # OSV…
|
|
|– helpers/
|   |– _variables.scss   # Sass-variablar
|   |– _functions.scss   # Sass-funktioner
|   |– _mixins.scss      # Sass-mixins
|   |– _helpers.scss     # Hjälp/utility-klasser
|
|
|
– main.scss             # Huvudfilen som importerar dessa så kallade scss-partials.

 

Sammanfattningsvis

Det är relativt enkelt att lära sig skriva CSS. Den stora utmaningen ligger i att hitta en teknik och struktur som gör att en grupp utvecklare kan vidareutveckla ett stort och långvarigt projekt som en annan grupp utvecklare en gång i tiden skapat. Att på egen hand upprätthålla en klanderfri struktur och vara konsekvent genom hela projektets gång kan bara det vara svårt. För att kunna underhålla, skala, läsa och tyda vår CSS är dessa riktlinjer väldigt viktiga för oss som arbetar med frontend på IVEO. Nya tekniker och metoder dyker upp var och varannan månad och vi försöker testa och utvärdera dessa för att hela tiden förbättra och optimera vårt arbetsflöde. Förhoppningsvis kommer den här artikeln uppdateras likaså.

Jobbar du med CSS och har synpunkter på vårt arbetssätt? Lämna gärna dem i kommentarsfältet!

Tycker du artikeln var intressant och skulle vilja dyka ner djupare bland CSS-guidelines? Då rekommenderar vi Harry Roberts matiga cssguidelin.es

PS: Vi söker nya medarbetare – läs mer här

Skrivet den 10 juli av

Johan Wallberg

Skriv en kommentar

  • XHTML: Du kan använda följande taggar: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>