CSS features are often more powerful than the Sass equivalents. A somewhat obvious example: CSS variables (custom properties) exist at runtime and can change dynamically, whereas Sass variables only exist at build time. This static nature of Sass used to be considered a "limitation", but here's the thing: just because CSS is adding features that used to be exclusive to Sass doesn't mean we need to go all in one and stop using the other. Once we realize their differences, we can use them together to get the best of both worlds.
— Mayank

Syntactically Awesome Style Sheets

Sass is een verplicht onderdeel in de cursus front-end development bij de bachelor Toegepaste informatica. Het is geen verplichting in het OPO front-end basis van het graduaat programmeren. Vanzelfsprekend mag je het daar wel gebruiken.

CSS preprocessor

Developers die samenwerken aan een grote site komen al snel in de problemen. Hoe werk je met vele mensen samen aan de CSS van een site? Hoe zorg je dat de code onderhoudbaar en schaalbaar is? Hoe vermijd je herhaling van code in CSS?

Een studentensite heeft gewoonlijk enkele honderden regels code. Maar hoe hou je een overzicht over duizenden regels CSS?

Al snel kwamen developers met oplossingen. Eén mogelijke oplossing is gebruik maken van een CSS preprocessor. De ‘pre’ slaat op het feit dat er iets vooraf gaat aan de CSS. Je schrijft een soort code die moet geconverteerd (‘gecompileerd’) worden naar CSS. De browser begrijpt immers alleen CSS, dus dat is uiteindelijk wat je moet gebruiken.

Deze preprocessors breiden a.h.w. CSS uit met extra eigenschappen. In dit deel bekijken we de preprocessor Sass. Er zijn er ook andere (e.g. ‘Less’), maar Sass is waarschijnlijk wel de meest gebruikte. Die breidt CSS uit met nesting, variabelen, functies, mixins, partials enz. In deze korte inleiding bekijken we een beperkt aantal topics en focussen we vooral op de dingen die ook voor een relatief kleine site (zoals die die we van jou verwachten) nuttig kunnen zijn.

Je vindt uitgebreide documentatie over Sass op https://sass-lang.com. Sass is zeer krachtig, maar we zullen ons in deze inleidende cursus tot de basis beperken: nesting, variabelen en partials.

Je vindt trouwens behoorlijk wat artikels of video's met als titel “Is Sass still relevant in 2022” (of een ander jaar). We durven deze vraag —voorlopig— met een voorzichtige ‘ja’ beantwoorden. CSS wordt echter steeds krachtiger. Zo hebben we nu in CSS al de beschikking over variabelen (‘custom properties’). CSS krijgt steeds meer functions. Nesting zal waarschijnlijk in 2023 in standaard CSS mogelijk worden enz. Wie weet wordt CSS zo krachtig dat een preprocessor over enkele jaren niet meer nodig is?

Sass compileren naar CSS

Een browser begrijpt geen Sass-code, enkel CSS. We hebben dus een manier nodig om Sass om te zetten naar CSS. Dat kan op verschillende manieren. Enkele van die manieren gebruiken zogenaamde ‘build tools’ (Webpack, Parcel, …) wat buiten het bestek van deze cursus valt. Er is gelukkig een eenvoudige manier in VS Code: gebruik maken van een extensie.

Installeer in VS Code de extensie ‘Live Sass compiler’ van Glenn Marks. Opgepast, er is ook een meer populaire (oude) extensie met dezelfde naam, gemaakt door Ritwick Dey. Deze extensie is echter verouderd. Glenn Marks heeft de code van Ritwick Dey als basis genomen en daarop verder gewerkt.

download de extensie Live Sass Compiler in VS Code

Notatie: .scss

Vooraleer we kunnen beginnen, nog één ding. Er zijn twee mogelijke syntaxen (notaties) voor Sass. We kiezen voor de meest gebruikte: .scss. Deze notatie heeft het voordeel dat je alles kan blijven noteren zoals je dat gewoon bent in CSS (met accolades). Alle voorbeelden hieronder zijn in deze versie van Sass genoteerd.

Hoog tijd om Sass in werking te zien. Bekijk van onderstaande video het begin tot tijdstip 8:34 . Daarna komen mixins en dat topic is geen leerstof voor dit inleidend OPO. De extensie ‘Live Sass Compiler’ die Kevin Powell hier toont is de oude versie (zie boven).

Nesting

Een klassiek stukje CSS i.v.m. de navigatie kan er zo uitzien:

nav {
    max-width: 40em;
}
        
nav ul {
    display: flex;
    flex-direction: row;
}
    
nav ul li {
    padding: 0.5em 1em;
}

Het gaat hier dus over een nav element, een ul die in een nav zit en een li in een ul in een nav. We noemen dat ‘elementen nesten’. In sass (.scss syntax zoals hierboven afgesproken) kan deze code er als volgt uitzien:

nav {
    max-width: 40em;

    ul {
        display: flex;
        flex-direction: row;

        li {
            padding: 0.5em 1em;
        }
    }
}

In dit verband een opmerking: er is niets mis met de laatste selector nav ul li. De meeste mensen raden echter aan om niet teveel elementen te noteren in een selector. De selector nav li is vermoedelijk voldoende. De specificiteit is eentje lager: (0, 0, 2) i.p.v. (0, 0, 3) maar dat maakt meestal niets uit. Volgende Sass code is hiermee equivalent:

nav {
    max-width: 40em;
        
    ul {
        display: flex;
        flex-direction: row;
    }
        
    li {
        padding: 0.5em 1em;
    }
}

Ouderselector & (‘parent selector’)

Er is een speciale rol weggelegd voor de ampersand (‘&’) in Sass. Met dit teken verwijs je naar de selector één niveau hoger, net buiten de accolades {}. We tonen een klein voorbeeld om dit te verduidelijken. De & wordt in dit voorbeeld op drie manieren gebruikt:

  1. een class toevoegen;
  2. een pseudoclass toevoegen (bvb :hover);
  3. een nieuwe element vooraan de huidige selector toevoegen.
nav {
    padding:0.5em 0;

    ul {
        list-style-type: none;
        display: flex;
        flex-direction: row;
    }

    li {
        flex-basis: 25%;

        &.hier {  /* 1. hier zal de & vervangen worden door li */
            background-color: orange;
        }
    }

    a {
        text-decoration: none;

        &:hover {  /* 2. zo kan je een pseudoclass toekennen aan de parent a */
            text-decoration: underline;
        }
    }

    footer & {  /* 3. & wordt hier vervangen door de parent nav */
        padding: 0;
    }
}

Deze Sass-code geeft volgend resultaat:

nav {
    padding: 0.5em 0;
  }
nav ul {
    list-style-type: none;
    display: flex;
    flex-direction: row;
}
nav li {
    flex-basis: 25%;
}
nav li.hier { /* 1. class toegevoegd */
    background-color: orange;
}
nav a {
    text-decoration: none;
}
nav a:hover { /* 2. pseudoclass */
    text-decoration: underline;
}
footer nav { /* 3. nav in footer */
    padding: 0;
}

Een klein nadeel van het gebruik van & is dat je mogelijk wat moeilijker kan zijn om in je .scss bestand te zoeken naar bvb. li.hier. Deze zoekterm ga je in dit bestand niet vinden, want er staat enkel &.hier.

Media queries nesten

Je kan nesting in Sass ook toepassen op media queries. Dat vergt een beetje een andere kijk op je CSS. Ik heb mijn @media regels graag helemaal onderaan mijn CSS bestand. Sass heeft echter een meer componentgerichte kijk op CSS en dan is er wel iets voor te zeggen om de @media regels in het element te zetten waarop ze van toepassing zijn. Dat geeft dan wel wat meer herhaling in de uiteindelijke CSS code (heel wat dezelfde @media), maar die herhalingen kunnen door een CSS postprocessor (ja, die bestaan dus ook!) eruit gehaald worden door dingen te groeperen.

Ook hier weer een voorbeeld. Ik wil de font-size van mijn h1 3em groot maken, behalve als de breedte van de pagina onder de 30em zakt. In dat geval wordt dit lettertype maar 2em groot. Dat kan als volgt in Sass:

h1 {
    font-size: 3em;

    @media (max-width: 30em) {
        font-size:2em;
    }
}

Deze code wordt door de preprocessor vertaald naar volgende CSS:

h1 {
    font-size: 3em;
  }
@media (max-width: 30em) {
    h1 {
      font-size: 2em;
    }
}

Variabelen

Al van bij het onstaan van de taal CSS klonk de roep van de developers “geef ons variabelen in CSS, zoals in vele andere programmeertalen!” . Niet verwonderlijk dus dat Sass in dat gat sprong en het gebruik van variabelen mogelijk maakte. Een simpel voorbeeld als illustratie:

$hoofdkleur: #25e309;
$secundairekleur: #56002a;
$afronding: 4px;

body {
    color: $hoofdkleur;
}

h1,
h2,
h3 {
    color: $secundairekleur;
    border-radius: $afronding;
}

Je kan wel raden wat de resulterende CSS wordt?

body {
  color: #25e309;
}

h1,
h2,
h3 {
  color: #56002a;
  border-radius: 4px;
}

In dit verband toch even opmerken dat CSS ondertussen native een soort van variabelen heeft. Zie het deeltje ‘Custom Properties’ in de pagina CSS kleuren en achtergrond. Beide systemen (Sass variabelen en CSS custom properties) hebben hun voor- en nadelen en kunnen naast elkaar bestaan. Je kiest zelf wat je gebruikt.

CSS splitsen in meerdere bestanden

Voor je het beseft bevat je CSS-bestand verschillende honderden regels code. Tenzij je geregeld je code reorganiseerde en opkuiste is er veel kans dat die honderden regels een … mesthoop zijn. Je kan natuurlijk je CSS-code opsplitsen in verschillende deelbestanden en die allemaal met de CSS regel @import inladen . Dat verhoogt echter het aantal requests naar de browser, want elk deelbestand moet apart aangevraagd worden aan de server. Aangezien (op smartphone) elke request een paar honderd milliseconden tijd vergt, gaat er daardoor dus veel tijd verloren. Eén CSS-bestand verdient dus de voorkeur boven meerdere deelbestanden!

Sass heeft hiervoor een oplossing: partials. Het principe is eenvoudig: je splitst je grote CSS-bestand in kleinere stukjes die je dan samenbrengt met @use of @forward (@import zie je soms nog gebruikt worden, maar dat is verouderd). De details kunnen best wel complex worden omwille van namespacing enz. We proberen het principe hieronder zo eenvoudig mogelijk voor te stellen.

Het hoofdbestand (stijl.scss) van de cursussite die je nu leest ziet er zo uit:

@use 'basis';
@use 'header';
@use 'main/main';
@use 'main/quote';
@use 'main/typografie';
@use 'main/code';
@use 'main/video';
@use 'main/subnav';
@use 'main/kaders';
@use 'main/CSSfun';
@use 'footer';

De bestandsstructuur (screenshot uit VS Code) ziet er als volgt uit:

mapje styles bevat stijl.scss en dan aantal bestanden die allemaal beginnen met underscore

Merk op dat al deze deelbestanden (‘partials’) beginnen met een underscore (_). Dit karakter geeft aan de Sass compiler de boodschap dat deze bestanden niet omgezet moeten worden naar CSS. Alleen het hoofdbestand (dat alle deelbestanden importeert met @use) wordt gecompileerd naar CSS.

Kevin Powell geeft een mooie inleiding op @use en @forward. Je zal merken dat het al snel redelijk moeilijk wordt omwille van de namespacing. Tussen haakjes, de extensie ‘Live Sass Compiler’ (Glenn Marks) ondersteunt wel deze nieuwe syntaxis.

Meer geavanceerde topics

Sass kan nog zoveel meer: mixins, functions, loops enz. Gebruik deze dingen gerust als jouw specifieke situatie daar baat zou bij hebben. Ze vallen in elk geval buiten het bestek van deze inleiding.