Sass Guidelines

Een eigenzinnige stijlgids voor het schrijven van gezonde, onderhoudbare en schaalbare Sass.

U bekijkt de nederlandse vertaling van Noah van der Veer van de originele Sass Guidelines van Kitty Giraudel.

Deze versie wordt exclusief onderhouden door bijdragers zonder de beoordeling van de hoofdauteur en is daarom mogelijk niet volledig authentiek.

Open het optiepaneel

Over de auteur

Mijn naam is Kitty Giraudel, ik ben een Franse front-end ontwikkelaar, gevestigd in Berlijn (Duitsland) sinds 2015, momenteel werkzaam bij Cofenster.

Ik schrijf nu al een aantal jaren Sass en ik ben de auteur van veel Sass-gerelateerde projecten zoals SassDoc, SitePoint Sass Reference en Sass-Compatibility. Als u geïnteresseerd bent in meer van mijn bijdragen aan de Sass-gemeenschap, kijk dan in die lijst.

Ik ben toevallig ook de auteur van een boek over CSS (in het Frans) getiteld CSS3 Pratique du Design Web (Eyrolles editions), evenals een boek over Sass (in het Engels) getiteld Jump Start Sass (Learnable editions).

Bijdragen

Sass Guidelines is een gratis project dat ik in mijn vrije tijd onderhoud. Het behoeft geen betoog dat het nogal wat werk is om alles up-to-date, gedocumenteerd en relevant te houden. Gelukkig word ik geholpen door veel geweldige bijdragers, vooral als het gaat om het onderhouden van tientallen verschillende vertalingen. Bedank ze!

Als u nu zin hebt om een bijdrage te leveren, weet dan dat erover tweeten, het verspreiden van het woord of het oplossen van een kleine typefout door een issue of een pull-request te openen in de GitHub-repository geweldig zou zijn!

Last but not least voordat we beginnen: als u dit document leuk vond, of als het nuttig is voor u of uw team, overweeg dan om het te steunen zodat ik eraan kan blijven werken!

Over Sass

Dit is hoe Sass zichzelf beschrijft in de documentatie:

Sass is een uitbreiding van CSS die kracht en elegantie toevoegt aan de basistaal.

Het uiteindelijke doel van Sass is om de fouten van CSS op te lossen. CSS is, zoals we allemaal weten, niet de beste taal ter wereld [citation needed]. Hoewel het heel eenvoudig te leren is, kan het snel behoorlijk rommelig worden, vooral bij grote projecten.

Dit is waar Sass binnenkomt, als een meta-taal, om de syntaxis van CSS te verbeteren om extra functies en handige tools te bieden. Ondertussen wil Sass conservatief zijn met betrekking tot de CSS-taal.

Het punt is niet om CSS om te zetten in een volledig functionele programmeertaal; Sass wil alleen helpen waar CSS faalt. Hierdoor is aan de slag gaan met Sass niet moeilijker dan het leren van CSS: het voegt er simpelweg een paar extra features aan toe.

Dat gezegd hebbende, er zijn veel manieren om deze features te gebruiken. Sommige goed, sommige slecht, sommige ongebruikelijk. Deze richtlijnen zijn bedoeld om u een consistente en gedocumenteerde benadering te geven voor het schrijven van Sass-code.

Ruby Sass of LibSass

De eerste commit van Sass gaat terug tot eind 2006, meer dan 10 jaar geleden. Onnodig te zeggen dat het sindsdien een lange weg heeft afgelegd. Aanvankelijk ontwikkeld in Ruby, doken hier en daar verschillende varianten op. De meest succesvolle, LibSass (geschreven in C/C++) is nu bijna volledig compatibel met de originele Ruby-versie.

In 2014 besloten Ruby Sass- en LibSass-teams te wachten tot beide versies gesynchroniseerd waren voordat ze verder gingen. Sindsdien heeft LibSass actief versies uitgebracht om een functie-pariteit te hebben met zijn oudere broer/zus. De laatst overgebleven inconsistenties zijn door mijzelf verzameld en vermeld onder het Sass-Compatibility project. Als u zich bewust bent van een incompatibiliteit tussen de twee versies die niet wordt vermeld, wees dan zo vriendelijk om een issue te openen.

Terugkomend op het kiezen van uw compiler. Eigenlijk hangt het allemaal af van uw project. Als het een Ruby on Rails-project is, kunt u beter Ruby Sass gebruiken, wat perfect geschikt is voor zo’n geval. Houd er ook rekening mee dat Ruby Sass altijd de referentie-implementatie zal zijn en altijd LibSass zal leiden in functies. En als u wilt overstappen van Ruby Sass naar LibSass, dan is dit artikel iets voor jou.

Voor niet-Ruby-projecten die een workflow-integratie nodig hebben, is LibSass waarschijnlijk een beter idee, omdat het meestal is bedoeld om te worden ingepakt. Dus als u Node.js wilt gebruiken, is node-sass allemaal gekozen.

Sass of SCSS

Er is nogal wat verwarring over de semantiek van de naam Sass, en terecht: Sass betekent zowel de preprocessor als zijn eigen syntaxis. Niet erg handig, toch?

Eigenlijk beschreef Sass aanvankelijk een syntaxis waarvan het bepalende kenmerk de inspringingsgevoeligheid was. Al snel besloten Sass-beheerders om de kloof tussen Sass en CSS te dichten door een CSS-vriendelijke syntaxis aan te bieden genaamd SCSS voor Sassy CSS. Het motto is: als het geldige CSS is, is het geldige SCSS.

Sindsdien levert Sass (de preprocessor) twee verschillende syntaxis: Sass (niet alleen in hoofdletters, alstublieft), ook bekend als de ingesprongen syntaxis, en SCSS. Welke u moet gebruiken, is vrijwel aan jou, aangezien beide strikt gelijkwaardig zijn in functies. Op dit moment is het alleen een kwestie van esthetiek.

De witruimte-gevoelige syntaxis van Sass is afhankelijk van inspringen om accolades, puntkomma’s en andere leestekens te verwijderen, wat leidt tot een slankere en kortere syntaxis. Ondertussen is SCSS gemakkelijker te leren omdat het meestal een paar kleine extra functionaliteiten zijn bovenop CSS.

Zelf geef ik de voorkeur aan SCSS boven Sass omdat het dichter bij CSS ligt en vriendelijker voor de meeste ontwikkelaars is. Daarom is SCSS de standaardsyntaxis in deze richtlijnen. U kunt overschakelen naar de ingesprongen syntaxis van Sass in het .

Andere preprocessors

Sass is onder meer preprocessor. De meest serieuze concurrent is Less, een op Node.js gebaseerde preprocessor die behoorlijk populair is geworden dankzij het beroemde CSS-framework Bootstrap die het gebruikt(tot versie 4). Er is ook Stylus, een zeer tolerante en flexibele preprocessor die echter iets moeilijker te gebruiken is en met een kleinere gemeenschap.

Waarom kiezen voor Sass in plaats van een andere preprocessor? is vandaag de dag nog steeds een geldige vraag. Nog niet zo lang geleden raadden we Sass aan voor op Ruby gebaseerde projecten, omdat het voor het eerst in Ruby was gemaakt en goed speelde met Ruby on Rails. Nu LibSass (grotendeels) de originele Sass heeft ingehaald, is dit niet langer relevant advies.

Wat ik leuk vind aan Sass, is de conservatieve benadering van CSS. Het ontwerp van Sass is gebaseerd op sterke principes: een groot deel van de ontwerpbenadering komt van nature voort uit de overtuigingen van de kernteam dat a) het toevoegen van extra functies een complexiteitskost heeft die moet worden gerechtvaardigd door het nut en, b) dat het gemakkelijk moet zijn om te redeneren over wat een bepaald blok stijlen doet door alleen naar dat blok te kijken. Sass heeft ook een veel scherpere aandacht voor detail dan andere preprocessors. Voor zover ik kan nagaan, hechten de kernontwerpers er veel belang aan om elk hoekgeval van CSS-compatibiliteit te ondersteunen en ervoor te zorgen dat elk algemeen gedrag consistent is. Met andere woorden, Sass is software gericht op het oplossen van actuele problemen; helpen om nuttige functionaliteit te bieden aan CSS waar CSS tekortschiet.

Afgezien van de preprocessors, moeten we ook tools noemen zoals PostCSS en cssnext die in de afgelopen maanden veel aandacht hebben gekregen .

PostCSS wordt gewoonlijk (en ten onrechte) een “postprocessor” genoemd. De veronderstelling, gecombineerd met de ongelukkige naam, is dat PostCSS parseert over CSS dat al is verwerkt door een preprocessor. Hoewel het op deze manier kan werken, is het geen vereiste, dus PostCSS is eigenlijk gewoon een “processor”.

Het geeft u toegang tot “tokens” van uw stylesheets (zoals selectors, eigenschappen en waarden), om deze te verwerken met JavaScript om een of andere bewerking uit te voeren en de resultaten te compileren naar CSS. De populaire prefixbibliotheek Autoprefixer is bijvoorbeeld gebouwd met PostCSS. Het parseert elke regel om te zien of vendorvoorvoegsels nodig zijn door te verwijzen naar de browserondersteuningstool CanIUse en verwijdert en voegt vervolgens vendorvoorvoegsels toe die nodig zijn.

Dit is ongelooflijk krachtig en geweldig voor het bouwen van bibliotheken die met elke preprocessor werken (evenals vanille CSS), maar PostCSS is nog niet bijzonder gemakkelijk te gebruiken. U moet een beetje JavaScript kennen om er iets mee te bouwen, en de API kan soms verwarrend zijn. Hoewel Sass slechts een reeks functies biedt die handig zijn om CSS te schrijven, biedt PostCSS directe toegang tot de CSS AST (abstract syntax tree) en JavaScript.

Kortom, Sass is enigszins eenvoudig en lost de meeste van uw problemen op. Aan de andere kant kan PostCSS moeilijk in de hand te houden zijn (als u niet goed bent met JavaScript), maar het blijkt ongelooflijk krachtig te zijn. Er is geen reden waarom u beide niet kunt en zou moeten gebruiken. In feite biedt PostCSS een officiële SCSS-parser voor precies dit ding.

Met dank aan Cory Simmons voor zijn hulp en expertise op dit gebied.

Inleiding

Waarom een stijlgids

Een stijlgids is niet alleen een aangenaam document om te lezen, een ideale staat voor uw code voor te stellen. Het is een belangrijk document in het leven van een project, beschrijft hoe en waarom code moet worden geschreven. Het lijkt misschien op overkill voor kleine projecten, maar het helpt veel in het schoon, schaalbaar en gemakkelijk te onderhouden houden van de codebase.

Onnodig te zeggen dat hoe meer ontwikkelaars betrokken zijn bij een project, hoe meer coderichtlijnen nodig zijn. Langs dezelfde lijnen, hoe groter het project, hoe meer een stijlgids een must is.

Harry Roberts stelt het heel goed in CSS Guidelines:

Een coderingsstijlgids (opmerking: geen visuele stijlgids) is een waardevol hulpmiddel voor teams die:

  • producten bouwen en onderhouden voor een redelijke tijdsduur;
  • ontwikkelaars van verschillende vaardigheden en specialiteiten hebben;
  • een aantal verschillende ontwikkelaars hebben die op een bepaald moment aan een product werken;
  • regelmatig nieuw personeel aan boord nemen;
  • een aantal codebases hebben die ontwikkelaars in en uit dippen.

Disclaimer

Allereerst: Dit is geen CSS-stijlgids. Dit document zal geen conventies van naamgevingsconventies voor CSS-klassen geven, modulaire patronen en de vraag van ID’s in de CSS-wereld. Deze richtlijnen zijn alleen gericht op het omgaan met sass-specifieke inhoud.

Ook is deze stijlgids de mijne en daarom zeer eigenwijs. Zie het als een verzameling van methodologieën en advies die ik in de loop van de jaren heb gepolijst en gegeven. Het geeft me ook de mogelijkheid om te linken naar een handvol inzichtelijke bronnen, dus controleer de verdere metingen.

Vanzelfsprekend is dit zeker niet de enige manier om dingen te doen, en het kan al dan niet bij uw project passen. Voelt u vrij om eruit te halen en het aan te passen aan uw behoeften. Zoals we zeggen, kunnen uw kilometers variëren.

Basisprincipes

Aan het einde van de dag, als er één ding is, zou ik willen dat u van deze hele stijlgids krijgt, is het dat SASS zo eenvoudig moet worden gehouden als het kan zijn.

Dankzij mijn domme experimenten zoals bitwise operators, iterators and generators en een JSON parser in Sass, zijn we allemaal goed bewust van wat men kan doen met deze preprocessor.

Ondertussen is CSS een eenvoudige taal. Sass, die bedoeld is om CSS te schrijven, mag niet veel complexer worden dan gewone CSS. Het KISS Principe (Keep It Simple Stupid) is hier de sleutel en kan zelfs voorrang hebben over het DRY principe (Don’t Repeat Yourself) in sommige omstandigheden.

Soms is het beter om een beetje te herhalen om de code onderhoudbaar te houden, in plaats van een topzware, onhandelbare, onnodig gecompliceerde systeem te bouwen dat volledig ontmoedigend is omdat het overdreven complex is.

Ook, en laat me Harry Roberts opnieuw citeren, pragmatisme overtreft perfectie. Op een gegeven moment zult u waarschijnlijk merken dat u tegen de hier beschreven regels gaat. Als het logisch is, als het goed voelt, doe het dan. Code is slechts een middel, geen einde.

Verlengen van de richtlijnen

Een groot deel van deze stijlgids is sterk eigenwijs. Ik ben nu al enkele jaren Sass aan het lezen en schrijven, tot het punt waarop ik nu veel principes heb als het gaat om het schrijven van schone stylesheets. Ik begrijp dat het misschien niet bij iedereen past, en dit is volkomen normaal.

Hoewel, ik ben van mening dat richtlijnen worden gemaakt om te worden verlengd. Uitbreiden van SASS-richtlijnen kan zo eenvoudig zijn als het hebben van een document waarin staat dat de code de richtlijnen van deze stijlgids volgt, behalve een paar dingen; In welk geval zouden specifieke regels hieronder worden uitgelegd.

Een voorbeeld van stijlgids-extensie is te vinden op de Sassdoc-repository:

Dit is een extensie van Node StyleGuide van Felix Geisendörfer. Alles van dit document overschrijft wat erin kan worden gezegd in de Node Styleguide.

Syntaxis en opmaak

Als u het mij vraagt, is het allereerste dat een stijlgids zou moeten doen, beschrijven hoe we willen dat onze code eruitziet.

Wanneer meerdere ontwikkelaars betrokken zijn bij het schrijven van CSS op dezelfde project(en), is het slechts een kwestie van tijd voordat een van hen de dingen op zijn eigen manier gaat doen. Coderichtlijnen die consistentie bevorderen, voorkomen dit niet alleen, maar helpen ook bij het lezen en bijwerken van de code.

We willen grofweg (schaamteloos geïnspireerd door CSS Guidelines):

  • twee (2) spaties inspringen, geen tabs;
  • idealiter 80 tekens brede regels;
  • correct geschreven CSS-regels met meerdere regels;
  • zinvol gebruik van witruimte.
// Yep
.foo {
  display: block;
  overflow: hidden;
  padding: 0 1em;
}

// Nope
.foo {
    display: block; overflow: hidden;

    padding: 0 1em;
}
// Omdat Sass indented-syntax deze coderingsstandaarden afdwingt
// Is er geen verkeerde manier om verder te gaan
.foo
  display: block
  overflow: hidden
  padding: 0 1em

Tekenreeksen

Geloof het of niet, tekenreeksen spelen een vrij grote rol in zowel CSS- als Sass-ecosystemen. De meeste CSS-waarden zijn lengtes of identifiers, dus het is eigenlijk vrij cruciaal om u aan enkele richtlijnen te houden bij het omgaan met tekenreeksen in Sass.

Codering

Om mogelijke problemen met tekencodering te voorkomen, wordt het ten zeerste aanbevolen om UTF-8 codering te forceren in het hoofd stylesheet met behulp van de @charset richtlijn. Zorg ervoor dat dit het allereerste element van de stylesheet is en dat er geen karakter voor staat.

@charset 'utf-8';
@charset 'utf-8'

Aanhalingstekens

CSS vereist geen aanhalingstekens, zelfs niet die spaties bevatten. Neem bijvoorbeeld namen van lettertypen: het maakt niet uit of u ze tussen aanhalingstekens plaatst voor de CSS-parser.

Daarom vereist Sass ook geen aanhalingstekens voor tekenreeksen. Nog beter (en gelukkig, u zult toegeven), een tekenreeks tussen aanhalingstekens is strikt gelijk aan zijn niet-aangehaalde tweeling (bijv. 'abc' is strikt gelijk aan abc).

Dat gezegd hebbende, talen waarvoor tekenreeksen geen aanhalingstekens nodig hebben, zijn beslist een minderheid en daarom moeten tekenreeksen altijd worden omwikkeld met enkele aanhalingstekens (') in Sass (enkele is gemakkelijker te typen dan dubbel op qwerty toetsenborden). Naast consistentie met andere talen, waaronder JavaScript, de neef van CSS, zijn er verschillende redenen voor deze keuze:

  • kleurnamen worden als kleuren behandeld als ze niet worden vermeld, wat tot ernstige problemen kan leiden;
  • de meeste syntaxisaccentueerders zullen stikken in tekenreeksen zonder aanhalingstekens;
  • het bevordert de algemene leesbaarheid;
  • er is geen geldige reden om geen aanhalingstekens aan tekenreeksen toe te voegen.
// Yep
$direction: 'left';

// Nope
$direction: left;
// Yep
$direction: 'left'

// Nope
$direction: left

Volgens de CSS-specificaties moet de @charset-richtlijn tussen dubbele aanhalingstekens worden aangegeven om als geldig te worden beschouwd. Sass zorgt hier echter voor bij het compileren naar CSS, zodat het schrijven geen invloed heeft op het eindresultaat. U kunt veilig vasthouden aan enkele aanhalingstekens, zelfs voor @charset.

Tekenreeksen als CSS-waarden

Specifieke CSS-waarden (identifiers) zoals initial of sans-serif hoeven geen aanhalingstekens. Inderdaad, de verklaring font-family: 'sans-serif' zal stilletjes mislukken omdat CSS een identifier verwacht, geen tekenreeks tussen aanhalingstekens. Daarom citeren we die waarden niet.

// Yep
$font-type: sans-serif;

// Nope
$font-type: 'sans-serif';

// Okay I guess
$font-type: unquote('sans-serif');
// Yep
$font-type: sans-serif

// Nope
$font-type: 'sans-serif'

// Okay I guess
$font-type: unquote('sans-serif')

Daarom kunnen we een onderscheid maken tussen tekenreeksen die bedoeld zijn om te worden gebruikt als CSS-waarden (CSS-identifiers) zoals in het vorige voorbeeld, en tekenreeksen wanneer we vasthouden aan het gegevenstype Sass, bijvoorbeeld _map_sleutels.

Bij het eerste zetten we geen aanhalingstekens, maar het laatste zetten we tussen enkele aanhalingstekens.

Tekenreeksen met aanhalingstekens

Als een tekenreeks een of meer enkele aanhalingstekens bevat, zou men kunnen overwegen om het in plaats daarvan te omwikkelen met dubbele aanhalingstekens ("), om te voorkomen dat tekens binnen de tekenreeks ontsnappen.

// Okay
@warn 'You can\'t do that.';

// Okay
@warn "You can't do that.";
// Okay
@warn 'You can\'t do that.'

// Okay
@warn "You can't do that."

URL’s

URL’s moeten ook worden geciteerd, om dezelfde redenen als hierboven:

// Yep
.foo {
  background-image: url('/images/kittens.jpg');
}

// Nope
.foo {
  background-image: url(/images/kittens.jpg);
}
// Yep
.foo
  background-image: url('/images/kittens.jpg')

// Nope
.foo
  background-image: url(/images/kittens.jpg)

Getallen

In Sass is getal een gegevenstype dat alles omvat, van eenheidsloze getallen tot lengtes, looptijden, frequenties, hoeken enzovoort. Hierdoor kunnen berekeningen op dergelijke maatregelen worden uitgevoerd.

Nullen

Getallen moeten voorloopnullen weergeven voor een decimale waarde kleiner dan één. Geef nooit volgnullen weer.

// Yep
.foo {
  padding: 2em;
  opacity: 0.5;
}

// Nope
.foo {
  padding: 2.0em;
  opacity: .5;
}
// Yep
.foo
  padding: 2em
  opacity: 0.5

// Nope
.foo
  padding: 2.0em
  opacity: .5

In Sublime Text en andere editors die een door reguliere expressie (regex) aangedreven zoek-en-vervang bieden, is het heel gemakkelijk om een voorloopnul toe te voegen aan (de meeste, zo niet alle) zwevende getallen. Vervang eenvoudig \s+\.(\d+) door \0.$1. Vergeet niet de spatie voor de 0.

Eenheden

Als het om lengtes gaat, mag een 0 waarde nooit een eenheid hebben.

// Yep
$length: 0;

// Nope
$length: 0em;
// Yep
$length: 0

// Nope
$length: 0em

Pas op, deze praktijk moet worden beperkt tot alleen lengtes. Het hebben van een nul zonder eenheid voor een tijdeigenschap zoals transition-delay is niet toegestaan. Theoretisch, als een eenheidloze nul wordt gespecificeerd voor een duur, wordt de verklaring als ongeldig beschouwd en moet deze worden weggegooid. Niet alle browsers zijn zo streng, maar sommige zijn dat wel. Om een lang verhaal kort te maken: laat de eenheid alleen weg voor lengtes.

De meest voorkomende fout die ik kan bedenken met betrekking tot getallen in Sass, is te denken dat eenheden slechts tekenreeksen zijn die veilig aan een getal kunnen worden toegevoegd. Hoewel dat waar klinkt, is het zeker niet hoe eenheden werken. Beschouw eenheden als algebraïsche symbolen. In de echte wereld levert het vermenigvuldigen van 5 meter met 5 meter u bijvoorbeeld 25 vierkante meter op. Dezelfde logica is van toepassing op Sass.

Om een eenheid bij een getal op te tellen, moet u dit getal vermenigvuldigen met 1 eenheid.

$value: 42;

// Yep
$length: $value * 1px;

// Nope
$length: $value + px;
$value: 42

// Yep
$length: $value * 1px

// Nope
$length: $value + px

Merk op dat het toevoegen van 0-lid van die eenheid ook werkt, maar ik zou liever de bovengenoemde methode aanbevelen, aangezien het toevoegen van 0-eenheid een beetje verwarrend kan zijn. Inderdaad, als u een getal probeert om te zetten naar een andere compatibele eenheid, zal het toevoegen van 0 niet werken. Daarover meer in dit artikel.

$value: 42 + 0px;
// -> 42px

$value: 1in + 0px;
// -> 1in

$value: 0px + 1in;
// -> 96px
$value: 42 + 0px
// -> 42px

$value: 1in + 0px
// -> 1in

$value: 0px + 1in
// -> 96px

Uiteindelijk hangt het er echt van af wat u probeert te bereiken. Houd er wel rekening mee dat het toevoegen van de eenheid als een tekenreeks geen goede manier is om verder te gaan.

Om de eenheid van een waarde te verwijderen, moet u deze delen door één eenheid van zijn soort.

$length: 42px;

// Yep
$value: $length / 1px;

// Nope
$value: str-slice($length + unquote(''), 1, 2);
$length: 42px

// Yep
$value: $length / 1px

// Nope
$value: str-slice($length + unquote(''), 1, 2)

Het toevoegen van een eenheid als tekenreeks aan een getal resulteert in een tekenreeks, waardoor extra bewerkingen op de waarde worden voorkomen. Het doorsnijden van het numerieke deel van een getal met een eenheid resulteert ook in een tekenreeks. Dit is niet wat u wilt. Gebruik lengtes, geen tekenreeksen.

Berekeningen

Numerieke berekeningen op het hoogste niveau moeten altijd tussen haakjes staan. Deze vereiste verbetert niet alleen de leesbaarheid aanzienlijk, het voorkomt ook enkele edge cases door Sass te dwingen de inhoud van de haakjes te evalueren.

// Yep
.foo {
  width: (100% / 3);
}

// Nope
.foo {
  width: 100% / 3;
}
// Yep
.foo
  width: (100% / 3)

// Nope
.foo
  width: 100% / 3

Magische getallen

“Magisch getal” is een oude schoolprogrammering term voor naamloze numerieke constante. Kortom, het is gewoon een willekeurig getal dat toevallig werkt™, maar het is niet gebonden aan een logische verklaring.

Onnodig te zeggen magische getallen zijn een plaag en moeten koste wat het kost worden vermeden. Als het u niet lukt om een redelijke verklaring te vinden waarom een getal werkt, voeg dan een uitgebreide opmerking toe waarin u uitlegt hoe u daar bent gekomen en waarom u denkt dat het werkt. Toegeven dat u niet weet waarom iets werkt, is nog steeds nuttiger voor de volgende ontwikkelaar dan dat hij moet uitzoeken wat er vanaf het begin aan de hand is.

/**
 * 1. Magisch nummer. Deze waarde is de laagste die ik kon vinden om de bovenkant van
 * `.foo` uit te lijnen met de ouder. Idealiter zouden we het op de juiste manier moeten repareren.
 */
.foo {
  top: 0.327em; /* 1 */
}
/**
 * 1. Magisch nummer. Deze waarde is de laagste die ik kon vinden om de bovenkant van
 * `.foo` uit te lijnen met de ouder. Idealiter zouden we het op de juiste manier moeten repareren.
 */
.foo
  top: 0.327em /* 1 */

Over het onderwerp heeft CSS-Tricks een geweldig artikel over magische getallen in CSS die ik u aanmoedig om te lezen.

Kleuren

Kleuren nemen een belangrijke plaats in in de CSS-taal. Natuurlijk wordt Sass een waardevolle bondgenoot als het gaat om het manipuleren van kleuren, meestal door een handvol krachtige functies.

Sass is zo handig als het gaat om het manipuleren van kleuren dat artikelen over dit onderwerp overal op internet een grote vlucht hebben genomen. Mag ik een paar teksten aanbevelen:

Kleurformaten

Om kleuren zo eenvoudig mogelijk te maken, zou mijn advies zijn om de volgende voorkeursvolgorde voor kleurformaten te respecteren:

  1. HSL-notatie;
  2. RGB-notatie;
  3. Hexadecimale notatie (kleine letters en afgekort).

CSS-kleurzoekwoorden mogen niet worden gebruikt, tenzij voor snelle prototyping. Het zijn inderdaad Engelse woorden en sommige zijn behoorlijk slecht in het beschrijven van de kleur die ze vertegenwoordigen, vooral voor niet-moedertaalsprekers. Bovendien zijn sleutelwoorden niet perfect semantisch; bijvoorbeeld grey is eigenlijk donkerder dan darkgrey, en de verwarring tussen grey en gray kan leiden tot inconsistent gebruik van deze kleur.

De HSL-weergave is niet alleen de gemakkelijkste voor het menselijk brein om te begrijpen [citation needed], het maakt het ook voor schrijvers van stylesheets gemakkelijk om de kleur aan te passen door de tint, verzadiging en lichtheid individueel aan te passen.

RGB heeft nog steeds het voordeel dat het meteen zichtbaar is als de kleur meer blauw, groen of rood is. Daarom is het in sommige situaties misschien beter dan de HSL, vooral als het om puur rood, groen of blauw gaat. Hoewel het niet gemakkelijk is om uit de drie delen een kleur op te bouwen.

Ten slotte, hexadecimaal is bijna niet te ontcijferen voor de menselijke brein. Gebruik het alleen als laatste redmiddel als het moet.

// Yep
.foo {
  color: hsl(0, 100%, 50%);
}

// Also yep
.foo {
  color: rgb(255, 0, 0);
}

// Meh
.foo {
  color: #f00;
}

// Nope
.foo {
  color: #FF0000;
}

// Nope
.foo {
  color: red;
}
.foo
  color: hsl(0, 100%, 50%)

// Also yep
.foo
  color: rgb(255, 0, 0)

// Nope
.foo
  color: #f00

// Nope
.foo
  color: #FF0000

// Nope
.foo
  color: red

Wanneer u HSL- of RGB-notatie gebruikt, voeg dan altijd een enkele spatie toe na een komma (,) en geen spatie tussen haakjes ((, )) en inhoud.

// Yep
.foo {
  color: rgba(0, 0, 0, 0.1);
  background: hsl(300, 100%, 100%);
}

// Nope
.foo {
  color: rgba(0,0,0,0.1);
  background: hsl( 300, 100%, 100% );
}
// Yep
.foo
  color: rgba(0, 0, 0, 0.1)
  background: hsl(300, 100%, 100%)

// Nope
.foo
  color: rgba(0,0,0,0.1)
  background: hsl( 300, 100%, 100% )

Kleuren en variabelen

Als u een kleur meer dan eens gebruikt, slaat u deze op in een variabele met een betekenisvolle naam die de kleur vertegenwoordigt.

$sass-pink: hsl(330, 50%, 60%);
$sass-pink: hsl(330, 50%, 60%)

Nu bent u vrij om deze variabele te gebruiken waar u maar wilt. Als uw gebruik echter sterk gebonden is aan een thema, raad ik af om de variabele te gebruiken zoals hij is. Sla het in plaats daarvan op in een andere variabele met een naam die uitlegt hoe het moet worden gebruikt.

$main-theme-color: $sass-pink;
$main-theme-color: $sass-pink

Als u dit doet, wordt voorkomen dat het thema verandert in zoiets als $sass-pink: blue. Dit artikel legt goed uit waarom het belangrijk is om na te denken over uw kleurvariabelen.

Kleuren lichter of donkerder maken

Zowel lighten als darken-functies manipuleren de lichtheid van een kleur in de HSL-ruimte door toe te voegen aan of af te trekken van de lichtheid in de HSL-ruimte. In wezen zijn het niets anders dan aliassen voor de $lightness-parameter van de adjust-color functie.

Het punt is dat die functies vaak niet het verwachte resultaat opleveren. Aan de andere kant is de mix functie een leuke manier om een kleur lichter of donkerder te maken door deze te mengen met white of black.

Het voordeel van het gebruik van mix in plaats van een van de twee bovengenoemde functies is dat het geleidelijk naar zwart (of wit) gaat naarmate u het aandeel van de kleur verkleint, terwijl darken en lighten snel een kleur helemaal naar zwart of wit uitblaast.

Illustratie van het verschil tussen lighten/darken en mix door KatieK
Illustratie van het verschil tussen lighten/darken en mix door KatieK

Als u niet elke keer de mix-functie wilt schrijven, kunt u twee gebruiksvriendelijke functies tint en shading maken (die ook deel uitmaken van Compass) om hetzelfde te doen:

/// Maak een kleur iets lichter
/// @access public
/// @param {Color} $color - kleur om te kleuren
/// @param {Number} $percentage - percentage van `$color` in geretourneerde kleur
/// @return {Color}
@function tint($color, $percentage) {
  @return mix(white, $color, $percentage);
}

/// Een kleur iets donkerder maken
/// @access public
/// @param {Color} $color - kleur tot schaduw
/// @param {Number} $percentage - percentage van `$color` in geretourneerde kleur
/// @return {Color}
@function shade($color, $percentage) {
  @return mix(black, $color, $percentage);
}
/// Maak een kleur iets lichter
/// @access public
/// @param {Color} $color - kleur om te kleuren
/// @param {Number} $percentage - percentage van `$color` in geretourneerde kleur
/// @return {Color}
@function tint($color, $percentage)
  @return mix($color, white, $percentage)

/// Een kleur iets donkerder maken
/// @access public
/// @param {Color} $color - kleur tot schaduw
/// @param {Number} $percentage - percentage van `$color` in geretourneerde kleur
/// @return {Color}
@function shade($color, $percentage)
  @return mix($color, black, $percentage)

De scale-color-functie is ontworpen om eigenschappen vloeiender te schalen door rekening te houden met hoe hoog of laag ze al zijn. Het zou resultaten moeten opleveren die net zo mooi zijn als die van mix, maar met een duidelijkere aanroepconventie. De schaalfactor is echter niet precies hetzelfde.

Lijsten

Lijsten zijn het Sass-equivalent van arrays. Een lijst is een platte gegevensstructuur (in tegenstelling tot maps) die bedoeld is om waarden van elk type op te slaan (inclusief lijsten die naar geneste lijsten leiden).

Lijsten dienen de volgende richtlijnen te respecteren:

  • ofwel inline of multiregel;
  • noodzakelijkerwijs op meerdere regels als deze te lang zijn om op een regel van 80 tekens te passen;
  • tenzij gebruikt zoals het is voor CSS-doeleinden, altijd gescheiden door komma’s;
  • altijd tussen haakjes gewikkeld;
  • achterliggende komma als er meerdere regels zijn, niet als ze inline zijn.
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif);

// Yep
$font-stack: (
  'Helvetica',
  'Arial',
  sans-serif,
);

// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif;

// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif;

// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,);
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif)

// Nope (not supported)
$font-stack: (
  'Helvetica',
  'Arial',
  sans-serif,
)

// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif

// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif

// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,)

Gebruik altijd de meegeleverde API om nieuwe items aan een lijst toe te voegen. Probeer niet handmatig nieuwe items toe te voegen.

$shadows: (0 42px 13.37px hotpink);

// Yep
$shadows: append($shadows, $shadow, comma);

// Nope
$shadows: $shadows, $shadow;
$shadows: (0 42px 13.37px hotpink)

// Yep
$shadows: append($shadows, $shadow, comma)

// Nope
$shadows: $shadows, $shadow

In dit artikel, ga ik door een heleboel trucs en tips om lijsten correct te behandelen en te manipuleren in Sass.

Maps

Met Sass kunnen stylesheet-auteurs maps definiëren - de Sass-term voor associatieve arrays, hashes of zelfs JavaScript-objecten. Een map is een gegevensstructuur die sleutels aan waarden koppelt. Zowel sleutels als waarden kunnen van elk gegevenstype zijn, inclusief maps, hoewel ik het gebruik van complexe gegevenstypen als mapsleutels niet zou aanraden, al was het maar om gezond verstand te hebben.

Maps moeten als volgt worden geschreven:

  • spatie na de dubbele punt (:);
  • accolade openen (() op dezelfde regel als de dubbele punt (:);
  • geciteerde sleutels als het tekenreeksen zijn (wat 99% van de gevallen vertegenwoordigt);
  • elk sleutel/waarde-paar op zijn eigen nieuwe regel;
  • komma (,) aan het einde van elke sleutel/waarde;
  • achterliggende komma (,) op het laatste item om het gemakkelijker te maken om items toe te voegen, te verwijderen of opnieuw te ordenen;
  • sluitende accolade ()) op zijn eigen nieuwe regel;
  • geen spatie of nieuwe regel tussen accolade ()) en puntkomma (;).

Illustratie:

// Yep
$breakpoints: (
  'small': 767px,
  'medium': 992px,
  'large': 1200px,
);

// Nope
$breakpoints: ( small: 767px, medium: 992px, large: 1200px );
// Yep
$breakpoints: ('small': 767px, 'medium': 992px, 'large': 1200px,)

// Nope
$breakpoints: ( 'small': 767px, 'medium': 992px, 'large': 1200px )

// Nope
$breakpoints: (small: 767px, medium: 992px, large: 1200px,)

// Nope (since it is not supported)
$breakpoints: (
  'small': 767px,
  'medium': 992px,
  'large': 1200px,
)

Er zijn veel verhalen over Sass-maps, gezien hoe lang naar deze functie was verlangd. Hier zijn er 3 die ik aanbeveel: Using Sass Maps, Extra Map functions in Sass, Real Sass, Real Maps.

CSS-regelset

Op dit punt is dit voornamelijk het herzien van wat iedereen weet, maar hier is hoe een CSS-regelset moet worden geschreven (tenminste, volgens de meeste richtlijnen, inclusief CSS Guidelines):

  • gerelateerde selectors op dezelfde lijn; niet-gerelateerde selectors op nieuwe regels;
  • de openingsaccolade ({) met een enkele spatie tussen de laatste selector;
  • elke verklaring op zijn eigen nieuwe regel;
  • een spatie na de dubbele punt (:);
  • een puntkomma (;) aan het einde van alle verklaringen;
  • de sluitende accolade (}) op zijn eigen nieuwe regel;
  • een nieuwe regel na de sluitaccolade }.

Illustratie:

// Yep
.foo, .foo-bar,
.baz {
  display: block;
  overflow: hidden;
  margin: 0 auto;
}

// Nope
.foo,
.foo-bar, .baz {
    display: block;
    overflow: hidden;
    margin: 0 auto }
// Yep
.foo, .foo-bar,
.baz
  display: block
  overflow: hidden
  margin: 0 auto

// Nope
.foo,
.foo-bar, .baz
    display: block
    overflow: hidden
    margin: 0 auto

Naast die CSS-gerelateerde richtlijnen willen we letten op:

  • lokale variabelen die worden verklaard vóór alle verklaringen, en vervolgens worden gescheiden van verklaringen door een nieuwe regel;
  • mixin-aanroepen zonder @content die vóór een verklaring komen;
  • geneste selectors komen altijd na een nieuwe regel;
  • geneste selectors komen altijd na een nieuwe regel;
  • geen nieuwe regel voor een sluitende accolade (}).

Illustratie:

.foo, .foo-bar,
.baz {
  $length: 42em;

  @include ellipsis;
  @include size($length);
  display: block;
  overflow: hidden;
  margin: 0 auto;

  &:hover {
    color: red;
  }

  @include respond-to('small') {
    overflow: visible;
  }
}
.foo, .foo-bar,
.baz
  $length: 42em

  +ellipsis
  +size($length)
  display: block
  overflow: hidden
  margin: 0 auto

  &:hover
    color: red

  +respond-to('small')
    overflow: visible

Verklaringsortering

Ik kan niet veel onderwerpen bedenken waar de meningen zo verdeeld zijn als ze zijn over het sorteren van declaraties in CSS. Concreet zijn er hier twee facties:

  • vasthouden aan de alfabetische volgorde;
  • verklaringen ordenen op type (positie, display, kleuren, lettertype, diversen…).

Er zijn voor- en nadelen voor beide manieren. Aan de ene kant is alfabetische volgorde universeel (althans voor talen die het Latijnse alfabet gebruiken), dus er is geen argument om de ene eigenschap voor de andere te sorteren. Het lijkt me echter buitengewoon raar om eigenschappen als bottom en top niet direct naast elkaar te zien. Waarom moeten animaties vóór het weergavetype verschijnen? Er zijn veel eigenaardigheden met alfabetische volgorde.

.foo {
  background: black;
  bottom: 0;
  color: white;
  font-weight: bold;
  font-size: 1.5em;
  height: 100px;
  overflow: hidden;
  position: absolute;
  right: 0;
  width: 100px;
}
.foo
  background: black
  bottom: 0
  color: white
  font-weight: bold
  font-size: 1.5em
  height: 100px
  overflow: hidden
  position: absolute
  right: 0
  width: 100px

Aan de andere kant is het sorteren van eigenschappen op type volkomen logisch. Alle lettertypegerelateerde verklaringen worden verzameld, top en bottom worden herenigd en het lezen van een regelset voelt als het lezen van een kort verhaal. Maar tenzij u aan een aantal conventies houdt, zoals Idiomatic CSS, is er veel ruimte voor interpretatie op deze manier van doen. Waar zou white-space naartoe gaan: lettertype of weergave? Waar hoort overflow precies thuis? Wat is de eigendomsvolgorde binnen een groep (het kan alfabetisch zijn, oh de ironie)?

.foo {
  height: 100px;
  width: 100px;
  overflow: hidden;
  position: absolute;
  bottom: 0;
  right: 0;
  background: black;
  color: white;
  font-weight: bold;
  font-size: 1.5em;
}
.foo
  height: 100px
  width: 100px
  overflow: hidden
  position: absolute
  bottom: 0
  right: 0
  background: black
  color: white
  font-weight: bold
  font-size: 1.5em

Er is ook een andere interessante subboom van type-ordening genaamd Concentric CSS, die ook behoorlijk populair lijkt. Kortom, Concentric CSS vertrouwt op het box-model om een volgorde te definiëren: begint buiten, beweegt naar binnen.

.foo {
  width: 100px;
  height: 100px;
  position: absolute;
  right: 0;
  bottom: 0;
  background: black;
  overflow: hidden;
  color: white;
  font-weight: bold;
  font-size: 1.5em;
}
.foo
  width: 100px
  height: 100px
  position: absolute
  right: 0
  bottom: 0
  background: black
  overflow: hidden
  color: white
  font-weight: bold
  font-size: 1.5em

Ik moet zeggen dat ik zelf niet kan beslissen. Een recente peiling op CSS-Tricks heeft vastgesteld dat meer dan 45% van de ontwikkelaars hun verklaringen sorteert op type tegen 14% alfabetisch. Er zijn ook 39% die volledig willekeurig gaan, inclusief ikzelf.

Grafiek die de volgorde van de CSS-declaraties van ontwikkelaars laat zien
Grafiek die de volgorde van de CSS-declaraties van ontwikkelaars laat zien

Daarom zal ik in deze stijlgids geen keuze opleggen. Kies degene die u verkiest, zolang u maar consistent bent in al uw stylesheets (dus niet de willekeurige optie).

Een recent onderzoek toont aan dat het gebruik van CSS Comb (die type ordering gebruikt) voor het sorteren van CSS-verklaringen leidt tot een verkorting van de gemiddelde bestandsgrootte onder Gzip-compressie met 2,7%, vergeleken met 1,3% bij het alfabetisch sorteren.

Selector nesten

Een specifieke functie die Sass biedt en die door veel ontwikkelaars overdreven wordt misbruikt, is selector nesten. Het nesten van selectors biedt een manier voor auteurs van stylesheets om lange selectors te berekenen door kortere selectors in elkaar te nestelen.

Algemene regel

Bijvoorbeeld de volgende Sass-nesten:

.foo {
  .bar {
    &:hover {
      color: red;
    }
  }
}
.foo
  .bar
    &:hover
      color: red

… zal deze CSS genereren:

.foo .bar:hover {
  color: red;
}

In dezelfde lijn is het sinds Sass 3.3 mogelijk om de huidige selectorreferentie (&) te gebruiken om geavanceerde selectors te genereren. Bijvoorbeeld:

.foo {
  &-bar {
    color: red;
  }
}
.foo
  &-bar
    color: red

… zal deze CSS genereren:

.foo-bar {
  color: red;
}
.foo-bar
  color: red

Deze methode wordt vaak gebruikt in combinatie met BEM-naamgevingsconventies om .block__element en .block--modifier selectors gebaseerd op de originele selector te genereren (dwz .block in dit geval).

Hoewel het misschien anekdotisch is, het genereren van nieuwe selectors op basis van de huidige selectorreferentie (&) maakt die selectors niet doorzoekbaar in de codebase omdat ze niet per se bestaan.

Het probleem met het nesten van selectors is dat het de code uiteindelijk moeilijker maakt om te lezen. Men moet mentaal de resulterende selector berekenen uit de inspringingsniveaus; het is niet altijd even duidelijk wat de CSS zal worden.

Deze verklaring wordt meer waar naarmate selectors langer worden en verwijzingen naar de huidige selector (&) frequenter. Op een gegeven moment is het risico om het overzicht te verliezen en niet meer te kunnen begrijpen wat er aan de hand is zo groot dat het het niet waard is.

Om dergelijke situaties te voorkomen, hebben we een paar jaar geleden veel gesproken over de Inception-regel. Het raadde af om meer dan 3 niveaus diep te nesten, als verwijzing naar de film Inception van Christopher Nolan. Ik zou drastischer zijn en aanbevelen om * selector-nesten zoveel mogelijk te vermijden**.

Hoewel er duidelijk een paar uitzonderingen op deze regel zijn, zoals we in de volgende sectie zullen zien, lijkt deze mening behoorlijk populair te zijn. U kunt er meer in detail over lezen in Beware of Selector Nesting en Avoid nested selectors for more modular CSS.

Uitzonderingen

Om te beginnen is het toegestaan en zelfs aanbevolen om pseudo-klassen en pseudo-elementen in de initiële selector te nestelen.

.foo {
  color: red;

  &:hover {
    color: green;
  }

  &::before {
    content: 'pseudo-element';
  }
}
.foo
  color: red

  &:hover
    color: green

  &::before
    content: 'pseudo-element'

Het gebruik van selector-nesten voor pseudo-klassen en pseudo-elementen is niet alleen logisch (omdat het zich bezighoudt met nauw verwante selectors), het helpt ook om alles over een component op dezelfde plaats te houden.

Ook bij het gebruik van component-agnostische statusklassen zoals .is-active, is het prima om deze onder de componentselector te nesten om de zaken netjes te houden.

.foo {
  // …

  &.is-active {
    font-weight: bold;
  }
}
.foo
  // …

  &.is-active
    font-weight: bold

Last but not least, wanneer een element wordt gestileerd omdat het toevallig in een ander specifiek element zit, is het ook prima om nesten te gebruiken om alles over het component op dezelfde plaats te houden.

.foo {
  // …

  .no-opacity & {
    display: none;
  }
}
.foo
  // …

  .no-opacity &
    display: none

Zoals met alles, zijn de details enigszins irrelevant, consistentie is de sleutel. Als u zich volledig zeker voelt bij het nesten van selectors, gebruik dan selector nesten. Zorg er gewoon voor dat uw hele team het daar goed mee eens is.

Naamgevingsconventies

In deze sectie zullen we niet ingaan op de beste CSS-naamgevingsconventies voor onderhoudbaarheid en schaal; dat is niet alleen aan jou, het valt ook buiten het bereik van een Sass-stijlgids. Ik raad degenen aan die worden aanbevolen door CSS Guidelines.

Er zijn een paar dingen die u in Sass kunt noemen, en het is belangrijk om ze goed te noemen, zodat de hele codebasis er zowel consistent als gemakkelijk te lezen uitziet:

  • variabelen;
  • functies;
  • mixins.

Tijdelijke aanduidingen voor Sass zijn opzettelijk weggelaten uit deze lijst, omdat ze kunnen worden beschouwd als gewone CSS-selectors, en dus hetzelfde naamgevingspatroon volgen als klassen.

Wat betreft variabelen, functies en mixins, houden we vast aan iets heel CSS-ig: door kleine letters gescheiden koppeltekens, en vooral zinvol.

$vertical-rhythm-baseline: 1.5rem;

@mixin size($width, $height: $width) {
  // …
}

@function opposite-direction($direction) {
  // …
}
$vertical-rhythm-baseline: 1.5rem

=size($width, $height: $width)
  // …

@function opposite-direction($direction)
  // …

Constanten

Als u toevallig een framework-ontwikkelaar of bibliotheek-schrijver bent, kan het zijn dat u te maken heeft met variabelen die onder geen enkele omstandigheid moeten worden bijgewerkt: constanten. Helaas (of gelukkig?), Biedt Sass geen enkele manier om dergelijke entiteiten te definiëren, dus we moeten ons houden aan strikte naamgevingsconventies om ons punt duidelijk te maken.

Zoals voor veel talen, raad ik variabelen met hoofdletters aan als ze constanten zijn. Dit is niet alleen een heel oude conventie, maar het staat ook goed in contrast met de gebruikelijke variabelen met een koppelteken in kleine letters.

// Yep
$CSS_POSITIONS: (top, right, bottom, left, center);

// Nope
$css-positions: (top, right, bottom, left, center);
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center)

// Nope
$css-positions: (top, right, bottom, left, center)

Als u echt wilt spelen met de ideeën van constanten in Sass, zou u dit toegewijde artikel kunnen lezen.

Namespace

Als u van plan bent uw Sass-code te verspreiden, in het geval van een bibliotheek, een framework, een rastersysteem of wat dan ook, kunt u overwegen om al uw variabelen, functies, mixins en tijdelijke aanduidingen een naam te geven, zodat deze niet conflicteert met de code van iemand anders.

Als u bijvoorbeeld aan een Sassy Unicorn-project werkt dat bedoeld is om te worden gedistribueerd, zou u kunnen overwegen om su- als namespace te gebruiken. Het is specifiek genoeg om botsingen met namen te voorkomen en kort genoeg om niet lastig te schrijven.

$su-configuration: (  );

@function su-rainbow($unicorn) {
  // …
}
$su-configuration: (  )

@function su-rainbow($unicorn)
  // …

Kaelig heeft een zeer verhelderend artikel over de wereldwijde CSS-namespace, voor het geval dit onderwerp u interesseert.

Merk op dat automatische namespace zeker een ontwerpdoel is voor de aanstaande @import-vernieuwing van Sass 4.0. Naarmate dat dichterbij komt, zal het steeds minder nuttig worden om handmatige namespace toe te passen; uiteindelijk kunnen libraries met handmatige namespace in feite moeilijker te gebruiken zijn.

Commentaar geven

CSS is een lastige taal, vol hacks en eigenaardigheden. Daarom moet er veel commentaar op worden gegeven, vooral als u of iemand anders van plan is de code over 6 maanden of 1 jaar te lezen en bij te werken. Laat u of iemand anders niet in de positie zijn van ik-heb-dit-niet-geschreven-oh-mijn-god-waarom.

Hoe eenvoudig CSS ook kan zijn, er is nog steeds veel ruimte voor commentaar. Deze zouden het volgende kunnen verklaren:

  • de structuur en/of rol van een dossier;
  • het doel van een regelset;
  • het idee achter een magisch getal;
  • de reden voor een CSS-verklaring;
  • de volgorde van CSS-verklaring;
  • het denkproces achter een manier om dingen te doen.

En ik ben waarschijnlijk ook veel andere verschillende redenen vergeten. Commentaar geven kost heel weinig tijd als het naadloos samen met de code wordt gedaan, dus doe het op het juiste moment. Terugkomen op een stukje code om commentaar te geven, is niet alleen volkomen onrealistisch, maar ook buitengewoon vervelend.

Commentaar schrijven

Idealiter moet elke CSS-regelset worden voorafgegaan door een commentaar in C-stijl waarin het punt van het CSS-blok wordt uitgelegd. Deze commentaar bevat ook genummerde uitleg over specifieke delen van de regelset. Bijvoorbeeld:

/**
 * Helper-klasse om af te kappen en ellips toe te voegen aan een string die te lang is om
 * op een enkele regel te passen.
 * 1. Voorkom dat inhoud wordt ingepakt door deze op één regel te dwingen.
 * 2. Voeg ellipsis toe aan het einde van de regel.
 */
.ellipsis {
  white-space: nowrap; /* 1 */
  text-overflow: ellipsis; /* 2 */
  overflow: hidden;
}
/**
 * Helper-klasse om af te kappen en ellips toe te voegen aan een string die te lang is om
 * op een enkele regel te passen.
 * 1. Voorkom dat inhoud wordt ingepakt door deze op één regel te dwingen.
 * 2. Voeg ellipsis toe aan het einde van de regel.
 */
.ellipsis
  white-space: nowrap /* 1 */
  text-overflow: ellipsis /* 2 */
  overflow: hidden

In principe moet alles wat op het eerste gezicht niet duidelijk is, worden becommentarieerd. Er bestaat niet zoiets als te veel documentatie. Onthoud dat u niet teveel commentaar kunt geven, dus ga in vuur en vlam en schrijf commentaar voor alles wat het waard is.

Gebruik bij het reageren op een Sass-specifieke sectie Sass inline-commentaar in plaats van een blok in C-stijl. Dit maakt het commentaar onzichtbaar in de uitvoer, zelfs in uitgebreide modus tijdens de ontwikkeling.

// Voeg de huidige module toe aan de lijst met geïmporteerde modules.
// `!global` flag is vereist, zodat het de globale variabele daadwerkelijk bijwerkt.
$imported-modules: append($imported-modules, $module) !global;
// Voeg de huidige module toe aan de lijst met geïmporteerde modules.
// `!global` flag is vereist, zodat het de globale variabele daadwerkelijk bijwerkt.
$imported-modules: append($imported-modules, $module) !global

Merk op dat deze manier van doen ook wordt ondersteund door CSS-richtlijnen in de sectie Commenting.

Documentatie

Elke variabele, functie, mixin en tijdelijke aanduiding die bedoeld is om overal in de codebase te worden hergebruikt, moet worden gedocumenteerd als onderdeel van de globale API met behulp van SassDoc.

/// Verticale ritme-basislijn die overal in de codebase wordt gebruikt.
/// @type Length
$vertical-rhythm-baseline: 1.5rem;
/// Verticale ritme-basislijn die overal in de codebase wordt gebruikt.
/// @type Length
$vertical-rhythm-baseline: 1.5rem

Drie schuine strepen (/) vereist.

SassDoc heeft twee hoofdrollen:

  • gestandaardiseerde commentaar afdwingen met behulp van een op annotaties gebaseerd systeem voor alles wat deel uitmaakt van een openbare of privé-API;
  • een HTML-versie van de API-documentatie kunnen genereren met behulp van een van de SassDoc-eindpunten (CLI-tool, Grunt, Gulp, Broccoli, Node…).
Documentatie gegenereerd door SassDoc
Documentatie gegenereerd door SassDoc

Hier is een voorbeeld van een mixin uitgebreid gedocumenteerd met SassDoc:

/// Mixin helpt bij het gelijktijdig definiëren van zowel `width` als `height`.
///
/// @author Kitty Giraudel
///
/// @access public
///
/// @param {Length} $width - De `width` van het element
/// @param {Length} $height [$width] - De `height` van het element
///
/// @example scss - Gebruik
///   .foo {
///     @include size(10em);
///   }
///
///   .bar {
///     @include size(100%, 10em);
///   }
///
/// @example css - CSS-uitvoer
///   .foo {
///     width: 10em;
///     height: 10em;
///   }
///
///   .bar {
///     width: 100%;
///     height: 10em;
///   }
@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}
/// Mixin helpt bij het gelijktijdig definiëren van zowel `width` als `height`.
///
/// @author Kitty Giraudel
///
/// @access public
///
/// @param {Length} $width - De `width` van het element
/// @param {Length} $height ($width) - De `height` van het element
///
/// @example scss - Gebruik
///   .foo
///     +size(10em)
///
///   .bar
///     +size(100%, 10em)
///
/// @example css - CSS-uitvoer
///   .foo {
///     width: 10em;
///     height: 10em;
///   }
///
///   .bar {
///     width: 100%;
///     height: 10em;
///   }
=size($width, $height: $width)
  width: $width
  height: $height

Architectuur

Het ontwerpen van een CSS-project is waarschijnlijk een van de moeilijkste dingen die u in het leven van een project zult moeten doen. De architectuur consistent en zinvol houden is nog moeilijker.

Gelukkig is een van de belangrijkste voordelen van het gebruik van een CSS-preprocessor de mogelijkheid om de codebase over verschillende bestanden te splitsen zonder de prestaties te beïnvloeden (zoals de @import CSS-richtlijn zou doen). Dankzij de overbelasting van de @import-richtlijn door Sass is het volkomen veilig (en eigenlijk aanbevolen) om zoveel bestanden te gebruiken als nodig is bij de ontwikkeling, allemaal gecompileerd in een enkele stylesheet wanneer ze in productie gaan.

Bovendien kan ik de behoefte aan mappen niet genoeg benadrukken, zelfs niet bij kleinschalige projecten. Thuis laat u niet elk vel papier in dezelfde doos vallen. U gebruikt mappen; een voor het huis/appartement, een voor de bank, een voor rekeningen, enzovoort. Er is geen reden om anders te doen bij het structureren van een CSS-project. Splits de codebase in zinvolle gescheiden mappen, zodat u later gemakkelijk dingen kunt terugvinden wanneer u terug moet naar de code.

Er zijn veel populaire architecturen voor CSS-projecten zoals: OOCSS, Atomic Design, Bootstrap, Foundation… Ze hebben allemaal hun verdiensten, voor- en nadelen.

Zelf gebruik ik een benadering die vrij veel lijkt op SMACSS van Jonathan Snook, die zich richt op het eenvoudig houden en voor de hand liggend.

Ik heb geleerd dat architectuur meestal heel specifiek is voor het project. Voelt u vrij om de voorgestelde oplossing helemaal weg te gooien of aan te passen zodat u te maken krijgt met een systeem dat bij u past.

Componenten

Er is een groot verschil tussen het laten werken en het goed maken. Nogmaals, CSS is nogal een rommelige taal [citation needed]. Hoe minder CSS we hebben, hoe beter. We willen niet omgaan met megabytes aan CSS-code. Om stylesheets kort en efficiënt te houden—en dit zal u niet verbazen—is het meestal een goed idee om een interface te zien als een verzameling componenten.

Componenten kunnen van alles zijn, zolang ze:

  • maar één ding en slechts één ding doen;
  • herbruikbaar zijn en hergebruikt in het hele project;
  • onafhankelijk zijn.

Een zoekformulier moet bijvoorbeeld als een onderdeel worden behandeld. Het moet herbruikbaar zijn, op verschillende posities, op verschillende pagina’s, in verschillende situaties. Het mag niet afhangen van zijn positie in de DOM (voettekst, zijbalk, hoofdinhoud…).

De meeste van elke interface kunnen worden gezien als kleine componenten en ik raad u ten zeerste aan om bij dit paradigma te blijven. Dit verkort niet alleen de hoeveelheid CSS die nodig is voor het hele project, maar is ook veel gemakkelijker te onderhouden dan een chaotische puinhoop waarin alles in de war is.

Componentstructuur

Idealiter zouden componenten in hun eigen Sass-deel moeten bestaan (in de components/ map, zoals beschreven in het 7-1 patroon), zoals components/_button.scss. De stijlen die in elk componentbestand worden beschreven, zouden alleen betrekking moeten hebben op:

  • de stijl van de component zelf;
  • de stijl van de varianten, modificatoren en/of staten van de component;
  • de stijlen van de afstammelingen van het onderdeel (d.w.z. kinderen), indien nodig.

Als u wilt dat uw componenten extern een thema kunnen hebben (bijv. Vanuit een thema in de map themes/), beperk de verklaringen dan tot alleen structurele stijlen, zoals afmetingen (width/height), opvulling, marges, uitlijning, enz. Sluit stijlen uit zoals kleuren, schaduwen, lettertypevoorschriften, achtergrondregels, enz.

Een partiële component kan componentspecifieke variabelen, tijdelijke aanduidingen en zelfs mixins en functies bevatten. Houd er echter rekening mee dat u moet vermijden om te verwijzen naar componentbestanden (d.w.z. @import-en) van andere componentbestanden, aangezien dit de afhankelijkheidsgrafiek van uw project een onhoudbare, verwarde puinhoop kan maken.

Hier is een voorbeeld van een gedeeltelijke knopcomponent:

// Knopspecifieke variabelen
$button-color: $secondary-color;

// … inclusief alle knopspecifieke:
// - mixins
// - tijdelijke aanduidingen
// - functies

/**
 * Knoppen
 */
.button {
  @include vertical-rhythm;
  display: block;
  padding: 1rem;
  color: $button-color;
  // … etc.

  /**
   * Inline knoppen op grote schermen
   */
  @include respond-to('medium') {
    display: inline-block;
  }
}

/**
 * Pictogrammen binnen knoppen
 */
.button > svg {
  fill: currentcolor;
  // … etc.
}

/**
 * Inline-knop
 */
.button--inline {
  display: inline-block;
}
// Knopspecifieke variabelen
$button-color: $secondary-color

// ... inclusief alle knopspecifieke:
// - mixins
// - tijdelijke aanduidingen
// - functies

/**
 * Knoppen
 */
.button
  +vertical-rhythm
  display: block
  padding: 1rem
  color: $button-color
  // ... etc.

  /**
   * Inline knoppen op grote schermen
   */
  +respond-to('medium')
    display: inline-block
}

/**
 * Pictogrammen binnen knoppen
 */
.button > svg
  fill: currentcolor
  // ... etc.

/**
 * Inline-knop
 */
.button--inline
  display: inline-block

Met dank aan David Khourshid voor zijn hulp en expertise op dit gebied.

Het 7-1 patroon

Terug naar architectuur, zullen we? Ik ga meestal met wat ik het 7-1 patroon noem: 7 mappen, 1 bestand. Kortom, u hebt al uw delen in 7 verschillende mappen gestopt, en een enkel bestand op het root-niveau (meestal genaamd main.scss) dat ze allemaal importeert om te worden gecompileerd in een CSS-stylesheet.

  • base/
  • components/
  • layout/
  • pages/
  • themes/
  • abstracts/
  • vendors/

En uiteraard:

  • main.scss

Als u het 7-1 patroon wilt gebruiken, is er een boilerplate klaar op GitHub. Het moet alles bevatten wat u nodig hebt om met deze architectuur aan de slag te gaan.

Wallpaper van Julien He
Wallpaper van Julien He

Idealiter kunnen we zoiets bedenken:

sass/
|
| abstracts/
|   | _variables.scss    # Sass Variabelen
|   | _functions.scss    # Sass Functies
|   | _mixins.scss       # Sass Mixins
|   | _placeholders.scss # Sass Tijdelijke aanduidingen
|
| base/
|   | _reset.scss        # Reset/normaliseren
|   | _typography.scss   # Typografische regels
|                        # Etc.
|
| components/
|   | _buttons.scss      # Knoppen
|   | _carousel.scss     # Carrousel
|   | _cover.scss        # Hoes
|   | _dropdown.scss     # Dropdown
|                        # Etc.
|
| layout/
|   | _navigation.scss   # Navigatie
|   | _grid.scss         # Grid-systeem
|   | _header.scss       # Koptekst
|   | _footer.scss       # Voettekst
|   | _sidebar.scss      # Zijbalk
|   | _forms.scss        # Formulieren
|                        # Etc.
|
| pages/
|   | _home.scss         # Home-specifieke stijlen
|   | _contact.scss      # Contact-specifieke stijlen
|                        # Etc.
|
| themes/
|   | _theme.scss        # Standaard thema
|   | _admin.scss        # Beheerdersthema
|                        # Etc.
|
| vendors/
|   | _bootstrap.scss    # Bootstrap
|   | _jquery-ui.scss    # jQuery UI
|                        # Etc.
|
`– main.scss              # Hoofd Sass-bestand

Bestanden volgen dezelfde naamgevingsconventies als hierboven beschreven: ze zijn gescheiden door koppeltekens.

Base map

De base/ map bevat wat we de standaardcode (boilerplate) voor het project zouden kunnen noemen. Daarin vindt u misschien het reset-bestand, enkele typografische regels en waarschijnlijk een stylesheet die enkele standaardstijlen definieert voor veelgebruikte HTML-elementen (die ik graag _base.scss noem).

  • _base.scss
  • _reset.scss
  • _typography.scss

Als uw project veel CSS-animaties gebruikt, kunt u overwegen om een \ _animations.scss-bestand daarin toe te voegen met de @keyframes-definities van al uw animaties. Als u ze maar sporadisch gebruikt, laat ze dan leven langs de selectors die ze gebruiken.

Layout map

De layout/ map bevat alles dat een rol speelt bij het opmaken van de site of applicatie. Deze map kan stylesheets hebben voor de belangrijkste onderdelen van de site (koptekst, voettekst, navigatie, zijbalk…), het rastersysteem of zelfs CSS-stijlen voor alle formulieren.

  • _grid.scss
  • _header.scss
  • _footer.scss
  • _sidebar.scss
  • _forms.scss
  • _navigation.scss

De layout/ map kan ook partials/ worden genoemd, afhankelijk van wat u verkiest.

Components map

Voor kleinere componenten is er de map components/. Terwijl layout/ macro is (waarmee het globale draadframe wordt gedefinieerd), is components/ meer gericht op widgets. Het bevat allerlei specifieke modules zoals een slider, een lader, een widget en eigenlijk alles in die richting. Er zijn gewoonlijk veel bestanden in components/ aangezien de hele site/applicatie voornamelijk uit kleine modules zou moeten bestaan.

  • _media.scss
  • _carousel.scss
  • _thumbnails.scss

De components/ map kan ook modules/ worden genoemd, afhankelijk van wat u verkiest.

Pages map

Als u paginaspecifieke stijlen heeft, is het beter om deze in een pages/ map te plaatsen, in een bestand met de naam van de pagina. Het is bijvoorbeeld niet ongebruikelijk om zeer specifieke stijlen voor de startpagina te hebben, vandaar de behoefte aan een _home.scss-bestand in pages/.

  • _home.scss
  • _contact.scss

Afhankelijk van uw implementatieproces kunnen deze bestanden afzonderlijk worden aangeroepen om te voorkomen dat ze worden samengevoegd met de anderen in het resulterende stylesheet. Het hangt van u af.

Themes map

Op grote sites en applicaties is het niet ongebruikelijk om verschillende thema’s te hebben. Er zijn zeker verschillende manieren om met thema’s om te gaan, maar persoonlijk vind ik het prettig om ze allemaal in een themes/ map te hebben.

  • _theme.scss
  • _admin.scss

Dit is zeer projectspecifiek en zal bij veel projecten waarschijnlijk niet voorkomen.

Abstracts map

De abstracts/ map verzamelt alle Sass-tools en helpers die in het hele project worden gebruikt. Elke globale variabele, functie, mixin en tijdelijke aanduiding moet hier worden ingevoerd.

De vuistregel voor deze map is dat deze geen enkele regel CSS mag uitvoeren wanneer deze op zichzelf wordt gecompileerd. Dit zijn niets anders dan Sass-helpers.

  • _variables.scss
  • _mixins.scss
  • _functions.scss
  • _placeholders.scss

Als u aan een heel groot project werkt met veel abstracte hulpprogramma’s, kan het interessant zijn om ze te groeperen op onderwerp in plaats van op type, bijvoorbeeld typografie (_typography.scss), thema (_theming.scss), enz. Elk bestand bevat alle gerelateerde helpers: variabelen, functies, mixins en tijdelijke aanduidingen. Hierdoor kan de code gemakkelijker doorbladeren en onderhouden worden, vooral wanneer bestanden erg lang worden.

De abstracts/ map kan ook utilities/ of helpers/ worden genoemd, afhankelijk van wat u verkiest.

Vendors map

En last but not least hebben de meeste projecten een vendors/ map met alle CSS-bestanden van externe bibliotheken en frameworks - Normalize, Bootstrap, jQueryUI, FancyCarouselSliderjQueryPowered, enzovoort. Die opzij zetten in dezelfde map is een goede manier om te zeggen “Hé, dit is niet van mij, niet mijn code, niet mijn verantwoordelijkheid”.

  • _normalize.scss
  • _bootstrap.scss
  • _jquery-ui.scss
  • _select2.scss

Als u een sectie van een vendor moet overschrijven, raad ik u aan om een 8e map te hebben met de naam vendors-extensions/ waarin u mogelijk bestanden hebt die precies zijn vernoemd naar de leveranciers die ze overschrijven.

Bijvoorbeeld: vendors-extensions/_bootstrap.scss is een bestand met alle CSS-regels bedoeld om een deel van de standaard CSS van Bootstrap opnieuw te declareren. Dit is om te voorkomen dat de vendorbestanden zelf moeten worden bewerkt, wat over het algemeen geen goed idee is.

Hoofdbestand

Het hoofdbestand (meestal gelabeld met main.scss) zou het enige Sass-bestand van de hele codebase moeten zijn dat niet begint met een onderstrepingsteken. Dit bestand mag niets anders bevatten dan @import en commentaar.

Bestanden moeten worden geïmporteerd volgens de map waarin ze zich bevinden, de een na de ander in de volgende volgorde:

  1. abstracts/
  2. vendors/
  3. base/
  4. layout/
  5. components/
  6. pages/
  7. themes/

Om de leesbaarheid te behouden, moet het hoofdbestand deze richtlijnen respecteren:

  • één bestand per @import;
  • één @import per regel;
  • geen nieuwe regel tussen twee importen uit dezelfde map;
  • een nieuwe regel na de laatste import uit een map;
  • bestandsextensies en leidende onderstrepingstekens zijn weggelaten.
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';

@import 'vendors/bootstrap';
@import 'vendors/jquery-ui';

@import 'base/reset';
@import 'base/typography';

@import 'layout/navigation';
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';

@import 'components/buttons';
@import 'components/carousel';
@import 'components/cover';
@import 'components/dropdown';

@import 'pages/home';
@import 'pages/contact';

@import 'themes/theme';
@import 'themes/admin';
@import vendors/bootstrap
@import vendors/jquery-ui

@import utils/variables
@import utils/functions
@import utils/mixins
@import utils/placeholders

@import base/reset
@import base/typography

@import layout/navigation
@import layout/grid
@import layout/header
@import layout/footer
@import layout/sidebar
@import layout/forms

@import components/buttons
@import components/carousel
@import components/cover
@import components/dropdown

@import pages/home
@import pages/contact

@import themes/theme
@import themes/admin

Er is een andere manier om gedeeltelijke gegevens te importeren die ik ook geldig acht. Aan de andere kant maakt het het bestand beter leesbaar. Aan de andere kant maakt het het bijwerken ervan iets pijnlijker. Hoe dan ook, ik laat u beslissen wat het beste is, het maakt niet veel uit. Voor deze manier van doen, moet het hoofdbestand deze richtlijnen respecteren:

  • één @import per map;
  • een regeleinde na @import;
  • elk bestand op zijn eigen regel;
  • een nieuwe regel na de laatste import uit een map;
  • bestandsextensies en leidende onderstrepingstekens zijn weggelaten.
@import
  'abstracts/variables',
  'abstracts/functions',
  'abstracts/mixins',
  'abstracts/placeholders';

@import
  'vendors/bootstrap',
  'vendors/jquery-ui';

@import
  'base/reset',
  'base/typography';

@import
  'layout/navigation',
  'layout/grid',
  'layout/header',
  'layout/footer',
  'layout/sidebar',
  'layout/forms';

@import
  'components/buttons',
  'components/carousel',
  'components/cover',
  'components/dropdown';

@import
  'pages/home',
  'pages/contact';

@import
  'themes/theme',
  'themes/admin';
@import
  vendors/bootstrap,
  vendors/jquery-ui

@import
  utils/variables,
  utils/functions,
  utils/mixins,
  utils/placeholders

@import
  base/reset,
  base/typography

@import
  layout/navigation,
  layout/grid,
  layout/header,
  layout/footer,
  layout/sidebar,
  layout/forms

@import
  components/buttons,
  components/carousel,
  components/cover,
  components/dropdown

@import
  pages/home,
  pages/contact

@import
  themes/theme,
  themes/admin

Over “globbing”

Bij computerprogrammering specificeren “glob”-patronen sets bestandsnamen met jokertekens, zoals ‘*.scss’. “Globbing” betekent in het algemeen het matchen van een set bestanden op basis van een uitdrukking in plaats van een lijst met bestandsnamen. Wanneer toegepast op Sass, betekent dit het importeren van delen in het hoofdbestand met een “glob”-patroon in plaats van ze afzonderlijk op te sommen. Dit zou leiden tot een hoofdbestand dat er als volgt uitziet:

@import 'abstracts/*';
@import 'vendors/*';
@import 'base/*';
@import 'layout/*';
@import 'components/*';
@import 'pages/*';
@import 'themes/*';
@import 'abstracts/*'
@import 'vendors/*'
@import 'base/*'
@import 'layout/*'
@import 'components/*'
@import 'pages/*'
@import 'themes/*'

Sass ondersteunt out-of-the-box bestands”globbing” niet, omdat het een gevaarlijke functie kan zijn, aangezien bekend is dat CSS orderafhankelijk is. Bij het dynamisch importeren van bestanden (wat meestal in alfabetische volgorde verloopt), heeft men geen controle meer over de volgorde van de bron, wat kan leiden tot moeilijk te debuggen neveneffecten.

Dat gezegd hebbende, in een strikt op componenten gebaseerde architectuur met extra zorg om geen enkele stijl van de ene naar de andere partitie te lekken, zou de volgorde er niet echt toe doen, wat globale import mogelijk zou maken. Dit zou het gemakkelijker maken om gedeelten toe te voegen of te verwijderen, aangezien het zorgvuldig bijwerken van het hoofdbestand niet langer nodig is.

Als u Ruby Sass gebruikt, is er een Ruby-edelsteen genaamd sass-“globbing” die precies dat gedrag mogelijk maakt. Als u op node-sass draait, kunt u vertrouwen op Node.js, of op welke bouwtool ze ook gebruiken om de compilatie af te handelen (Gulp, Grunt, etc.).

Schaamtebestand

Er is een interessant concept dat populair is gemaakt door Harry Roberts, Dave Rupert en Chris Coyier die bestaat uit het plaatsen van alle CSS-verklaringen, hacks en dingen waar we niet trots op zijn in een schaamtebestand. Dit bestand, dramatisch getiteld _shame.scss, zou na elk ander bestand worden geïmporteerd, helemaal aan het einde van het stylesheet.

/**
 * Nav specificiteit fix.
 *
 * Iemand gebruikte een ID in de headercode (`#header a {}`) die de nav
 * selectors overtroeft (`.site-nav a {}`). Gebruik !Important om het
 * te negeren totdat ik tijd heb om de koptekst te refactoren.
 */
.site-nav a {
    color: #BADA55 !important;
}
/**
 * Nav specificiteit fix.
 *
 * Iemand gebruikte een ID in de headercode (`#header a {}`) die de nav
 * selectors overtroeft (`.site-nav a {}`). Gebruik !Important om het
 * te negeren totdat ik tijd heb om de koptekst te refactoren.
 */
.site-nav a
    color: #BADA55 !important

Responsive Web Design en Breekpunten

Ik denk niet dat we Responsive Web Design nog moeten introduceren nu het overal is. U zou u echter kunnen afvragen waarom is er een sectie over RWD in een Sass-stijlgids? Eigenlijk zijn er nogal wat dingen die kunnen worden gedaan om het werken met breekpunten gemakkelijker te maken, dus ik dacht dat het niet zo’n slecht idee zou zijn om ze hier te benoemen.

Breekpunten Benoemen

Ik denk dat het veilig is om te zeggen dat mediaquery’s niet aan specifieke apparaten moeten worden gekoppeld. Dit is bijvoorbeeld absoluut een slecht idee om specifiek op iPads of Blackberry-telefoons te richten. Mediaquery’s moeten zorgen voor een reeks schermformaten, totdat het ontwerp breekt en de volgende mediaquery het overneemt.

Om dezelfde redenen mogen breekpunten niet naar apparaten worden genoemd, maar naar iets algemener. Vooral omdat sommige telefoons nu groter zijn dan tablets, sommige tablets groter dan sommige computers met een klein scherm, enzovoort…

// Yep
$breakpoints: (
  'medium': (min-width: 800px),
  'large': (min-width: 1000px),
  'huge': (min-width: 1200px),
);

// Nope
$breakpoints: (
  'tablet': (min-width: 800px),
  'computer': (min-width: 1000px),
  'tv': (min-width: 1200px),
);
// Yep
$breakpoints: ('medium': (min-width: 800px), 'large': (min-width: 1000px), 'huge': (min-width: 1200px))

// Nope
$breakpoints: ('tablet': (min-width: 800px), 'computer': (min-width: 1000px), 'tv': (min-width: 1200px))

Op dit punt zal elke naamgevingsconventie die glashelder maakt dat een ontwerp niet nauw verbonden is met een specifiek apparaattype het lukken, zolang het een gevoel van omvang geeft.

$breakpoints: (
  'zaad': (min-width: 800px),
  'spruit': (min-width: 1000px),
  'plant': (min-width: 1200px),
);
$breakpoints: ('zaad': (min-width: 800px), 'spruit': (min-width: 1000px), 'plant': (min-width: 1200px))

In de vorige voorbeelden worden geneste maps gebruikt om breekpunten te definiëren, maar dit hangt er echt van af wat voor soort breekpunt manager u gebruikt. U zou kunnen kiezen voor tekenreeksen in plaats van innerlijke maps voor meer flexibiliteit (bijv. '(min-width: 800px)').

Breekpunt manager

Nadat u uw breekpunten naar wens hebt benoemd, hebt u een manier nodig om ze in daadwerkelijke mediaquery’s te gebruiken. Er zijn tal van manieren om dit te doen, maar ik moet zeggen dat ik een grote fan ben van de breekpuntmap die wordt gelezen door een getterfunctie. Dit systeem is zowel eenvoudig als efficiënt.

/// Responsieve breekpuntmanager
/// @access public
/// @param {String} $breakpoint - Breekpunt
/// @requires $breakpoints
@mixin respond-to($breakpoint) {
  $raw-query: map-get($breakpoints, $breakpoint);

  @if $raw-query {
    $query: if(
      type-of($raw-query) == 'string',
      unquote($raw-query),
      inspect($raw-query)
    );

    @media #{$query} {
      @content;
    }
  } @else {
    @error 'Geen waarde gevonden voor `#{$breakpoint}`. '
         + 'Zorg ervoor dat het is gedefinieerd in de `$breakpoints` map.';
  }
}
/// Responsieve breekpuntmanager
/// @access public
/// @param {String} $breakpoint - Breekpunt
/// @requires $breakpoints
=respond-to($breakpoint)
  $raw-query: map-get($breakpoints, $breakpoint)

  @if $raw-query
    $query: if(type-of($raw-query) == 'string', unquote($raw-query), inspect($raw-query))

    @media #{$query}
      @content

  @else
    @error 'Geen waarde gevonden voor `#{$breakpoint}`. '
         + 'Zorg ervoor dat het is gedefinieerd in de `$breakpoints` map.'

Dit is duidelijk een vrij simplistische breekpuntmanager. Als u een iets meer toegeeflijke versie nodig hebt, mag ik u aanraden het wiel niet opnieuw uit te vinden en iets te gebruiken dat bewezen effectief is, zoals Sass-MQ, Breakpoint of include-media.

Als u meer wilt lezen over het benaderen van Mediaquery’s in Sass, beide SitePoint (van mijzelf) en CSS-Tricks hebben hier leuke artikelen over.

Gebruik van Mediaquery’s

Nog niet zo lang geleden was er nogal een verhit debat over waar mediaquery’s moeten worden geschreven: horen ze binnen selectors (zoals Sass het toestaat) of strikt los van hen? Ik moet zeggen dat ik een fervent verdediger ben van het mediaquery’s-binnen-selectors-systeem, aangezien ik denk dat het goed speelt met de ideeën van componenten.

.foo {
  color: red;

  @include respond-to('medium') {
    color: blue;
  }
}
.foo
  color: red

  +respond-to('medium')
    color: blue

Dit leidt tot de volgende CSS-uitvoer:

.foo {
  color: red;
}

@media (min-width: 800px) {
  .foo {
    color: blue;
  }
}

U hoort wellicht dat deze conventie resulteert in dubbele mediaquery’s in de CSS-uitvoer. Dat klopt beslist. Hoewel er tests zijn gemaakt en het laatste woord is dat het er niet toe doet als Gzip (of een equivalent daarvan) zijn ding heeft gedaan:

… we hebben nagegaan of er prestatie-implicaties waren van het combineren van mediaquery’s versus verstrooiing en kwamen tot de conclusie dat het verschil, hoewel lelijk, in het slechtste geval minimaal is, op zijn best in wezen onbestaande.
— Sam Richards, over Breakpoint

Als u u echt zorgen maakt over dubbele mediaquery’s, kunt u nog steeds een tool gebruiken om ze samen te voegen, zoals dit pareltje, maar ik heb het gevoel dat ik u moet waarschuwen tegen mogelijke bijwerkingen van het verplaatsen van CSS-code. Vergeet niet dat de volgorde van de bronnen belangrijk is.

Variabelen

Variabelen zijn de essentie van elke programmeertaal. Ze stellen ons in staat om waarden te hergebruiken zonder ze steeds opnieuw te hoeven kopiëren. Het belangrijkste is dat ze het bijwerken van een waarde heel gemakkelijk maken. Nooit meer zoeken en vervangen of handmatig crawlen.

CSS is echter niets anders dan een enorme mand met al onze eieren. In tegenstelling tot veel talen zijn er geen echte bereiken in CSS. Daarom moeten we echt opletten bij het toevoegen van variabelen met het risico getuige te zijn van conflicten.

Mijn advies zou zijn om alleen variabelen te maken als dat zinvol is. Start niet zomaar nieuwe variabelen, het zal niet helpen. Er mag alleen een nieuwe variabele worden gemaakt als aan alle volgende criteria is voldaan:

  • de waarde wordt minstens twee keer herhaald;
  • de waarde wordt waarschijnlijk minstens één keer bijgewerkt;
  • alle gevallen van de waarde zijn gekoppeld aan de variabele (d.w.z. niet toevallig).

In feite heeft het geen zin om een variabele te declareren die nooit zal worden bijgewerkt of die alleen op één plaats wordt gebruikt.

Scoping

Variabele scoping in Sass is in de loop der jaren veranderd. Tot vrij recent waren variabeleverklaringen binnen regelsets en andere bereiken standaard lokaal. Als er echter al een globale variabele met dezelfde naam was, zou de lokale toewijzing de globale variabele veranderen. Sinds versie 3.4 pakt Sass het concept van bereiken nu correct aan en maakt in plaats daarvan een nieuwe lokale variabele.

De documenten praten over global variable shadowing. Bij het declareren van een variabele die al bestaat op het globale bereik in een innerlijke bereik (selector, functie, mixin…), wordt gezegd dat de lokale variabele de globale schaduwt. In feite overschrijft het het alleen voor het lokale bereik.

Het volgende codefragment legt het variable shadowing-concept uit.

// Initialiseer een globale variabele op rootniveau.
$variable: 'initial value';

// Maak een mixin die die globale variabele overschrijft.
@mixin global-variable-overriding {
  $variable: 'mixin value' !global;
}

.local-scope::before {
  // Maak een lokale variabele die de globale in de schaduw stelt.
  $variable: 'local value';

  // Voeg de mixin toe: deze overschrijft de globale variabele.
  @include global-variable-overriding;

  // Druk de waarde van de variabele af.
  // Het is de **lokale**, aangezien het de globale overschaduwt.
  content: $variable;
}

// Druk de variabele af in een andere selector die geen schaduwwerking heeft.
// Het is de **globale**, zoals verwacht.
.other-local-scope::before {
  content: $variable;
}
// Initialiseer een globale variabele op rootniveau.
$variable: 'initial value'

// Maak een mixin die die globale variabele overschrijft.
@mixin global-variable-overriding
  $variable: 'mixin value' !global

.local-scope::before
  // Maak een lokale variabele die de globale in de schaduw stelt.
  $variable: 'local value'

  // Voeg de mixin toe: deze overschrijft de globale variabele.
  +global-variable-overriding

  // Druk de waarde van de variabele af.
  // Het is de **lokale**, aangezien het de globale schaduw overschaduwt.
  content: $variable

// Druk de variabele af in een andere selector die geen schaduwwerking heeft.
// Het is de **globale**, zoals verwacht.
.other-local-scope::before
  content: $variable

!default flag

Bij het bouwen van een bibliotheek, een framework, een rastersysteem of een stukje Sass dat bedoeld is om te worden gedistribueerd en gebruikt door externe ontwikkelaars, moeten alle configuratievariabelen worden gedefinieerd met de !default flag zodat ze kunnen worden overschreven.

$baseline: 1em !default;
$baseline: 1em !default

Dankzij dit kan een ontwikkelaar zijn eigen $baseline-variabele definiëren voordat uw bibliotheek wordt geïmporteerd zonder dat hun waarde opnieuw wordt gedefinieerd.

// De eigen variabele van de ontwikkelaar
$baseline: 2em;

// Uw bibliotheek verklaart `$baseline`
@import 'your-library';

// $baseline == 2em;
// De eigen variabele van de ontwikkelaar
$baseline: 2em

// Uw bibliotheek verklaart `$baseline`
@import your-library

// $baseline == 2em

!global flag

De !global flag mag alleen worden gebruikt bij het overschrijven van een globale variabele van een lokaal bereik. Bij het definiëren van een variabele op rootniveau, moet de !global flag worden weggelaten.

// Yep
$baseline: 2em;

// Nope
$baseline: 2em !global;
// Yep
$baseline: 2em

// Nope
$baseline: 2em !global

Meerdere variabelen of maps

Het gebruik van maps heeft voordelen in plaats van meerdere verschillende variabelen. De belangrijkste is de mogelijkheid om over een map te lopen, wat niet mogelijk is met verschillende variabelen.

Een ander voordeel van het gebruik van een map is de mogelijkheid om een kleine getter-functie te maken om een vriendelijkere API te bieden. Overweeg bijvoorbeeld de volgende Sass-code:

/// Z-indexen map, waarbij alle Z-lagen van de applicatie worden verzameld
/// @access private
/// @type Map
/// @prop {String} key - Laagnaam
/// @prop {Number} value - Z-waarde toegewezen aan de sleutel
$z-indexes: (
  'modal': 5000,
  'dropdown': 4000,
  'default': 1,
  'below': -1,
);

/// Haal een z-indexwaarde op uit een laagnaam
/// @access public
/// @param {String} $layer - Laagnaam
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
  @return map-get($z-indexes, $layer);
}
/// Z-indexen map, waarbij alle Z-lagen van de applicatie worden verzameld
/// @access private
/// @type Map
/// @prop {String} key - Laagnaam
/// @prop {Number} value - Z-waarde toegewezen aan de sleutel
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)

/// Haal een z-indexwaarde op uit een laagnaam
/// @access public
/// @param {String} $layer - Laagnaam
/// @return {Number}
/// @require $z-indexes
@function z($layer)
  @return map-get($z-indexes, $layer)

Extend

De @extend-instructie is een krachtige functie die vaak verkeerd wordt begrepen. In het algemeen maakt het het mogelijk om Sass te vertellen een selector A te stylen alsof deze ook overeenkomt met selector B. Onnodig te zeggen dat dit een waardevolle bondgenoot kan zijn bij het schrijven van modulaire CSS.

Het echte doel van @extension is echter om de relaties (beperkingen) binnen uitgebreide selectors tussen regelsets te behouden. Wat houdt dit precies in?

  • Selectors hebben beperkingen (bijv. .Bar in .foo > .bar moet een ouder .foo hebben);
  • Deze beperkingen worden overgedragen naar de uitbreidende selector (bijv. .Baz { @extend .bar; } zal .foo > .bar, .foo > .baz produceren);
  • De verklaringen van de uitgebreide selector worden gedeeld met de uitbreidende selector.

Gegeven dat, het eenvoudig is om te zien hoe het uitbreiden van selectors met milde beperkingen kan leiden tot een explosie van selectors. Als .baz .qux de extensie .foo .bar uitbreidt, kan de resulterende selector .foo .baz .qux of .baz .foo .qux zijn, aangezien zowel .foo als .baz algemene voorouders. Dit kunnen ouders, grootouders enz. Zijn.

Probeer relaties altijd te definiëren via tijdelijke aanduidingen voor selectors, niet met daadwerkelijke selectors. Dit geeft u de vrijheid om elke naamgevingsconventie die u hebt voor uw selectors te gebruiken (en te wijzigen), en aangezien relaties maar één keer worden gedefinieerd binnen de tijdelijke aanduidingen, is de kans veel kleiner dat u onbedoelde selectors produceert.

Gebruik voor het erven van stijlen alleen @extend als de uitbreidende .class of %placeholder selector een soort van de uitgebreide selector is. Een .error is bijvoorbeeld een soort .warning, dus .error kan @extend .warning.

%button {
  display: inline-block;
  // … button styles

  // Relatie: een %button die een kind is van een %modal
  %modal > & {
    display: block;
  }
}

.button {
  @extend %button;
}

// Yep
.modal {
  @extend %modal;
}

// Nope
.modal {
  @extend %modal;

  > .button {
    @extend %button;
  }
}
%button
  display: inline-block
  // … button styles

  // Relatie: een %button die een kind is van een %modal
  %modal > &
    display: block

.button
  @extend %button

// Yep
.modal
  @extend %modal

// Nope
.modal
  @extend %modal

  > .button
    @extend %button

Er zijn veel scenario’s waarin uitbreidende selectors nuttig en de moeite waard zijn. Houd altijd rekening met deze regels, zodat u met zorg kunt @extend:

  • Gebruik primair extend voor %placeholders, niet voor daadwerkelijke selectors.
  • Bij het uitbreiden van klassen, breid dan alleen een klasse uit met een andere klasse, nooit een complexe selector.
  • Extend een %placeholder zo min mogelijk direct.
  • Vermijd uitbreiding van algemene selectors voor voorouders (bijv. .Foo .bar) of algemene selectors voor broers en zussen (bijv. .Foo ~ .bar). Dit is wat de selector-explosie veroorzaakt.

Er wordt vaak gezegd dat @extend helpt bij de bestandsgrootte omdat het selectors combineert in plaats van eigenschappen te dupliceren. Dat is waar, maar het verschil is te verwaarlozen zodra Gzip de compressie heeft uitgevoerd.

Dat gezegd hebbende, als u Gzip (of een equivalent daarvan) niet kunt gebruiken, kan het waardevol zijn om over te schakelen naar een @extend-benadering, vooral als het stylesheet-gewicht het knelpunt is voor uw prestaties.

Extend and mediaquery’s

U moet alleen selectors uitbreiden binnen hetzelfde mediabereik (@media-instructie). Beschouw een mediaquery als een andere beperking.

%foo {
  content: 'foo';
}

// Nope
@media print {
  .bar {
    // Dit werkt niet. Erger nog: het crasht.
    @extend %foo;
  }
}

// Yep
@media print {
  .bar {
    @at-root (without: media) {
      @extend %foo;
    }
  }
}

// Yep
%foo {
  content: 'foo';

  &-print {
    @media print {
      content: 'foo print';
    }
  }
}

@media print {
  .bar {
    @extend %foo-print;
  }
}
%foo
  content: 'foo'

// Nope
@media print
  .bar
    // Dit werkt niet. Erger nog: het crasht.
    @extend %foo

// Yep
@media print
  .bar
    @at-root (without: media)
      @extend %foo

// Yep
%foo
  content: 'foo'

  &-print
    @media print
      content: 'foo print'

@media print
  .bar
    @extend %foo-print

De meningen lijken extreem verdeeld te zijn over de voordelen en problemen van @extend tot het punt waarop veel ontwikkelaars, waaronder ikzelf, er tegen hebben gepleit, zoals u kunt lezen in de volgende artikelen:

Dat gezegd hebbende, en kort samengevat, zou ik adviseren om @extend alleen te gebruiken voor het onderhouden van relaties binnen selectors. Als twee selectors karakteristiek vergelijkbaar zijn, is dat de perfecte use-case voor @extend. Als ze niets met elkaar te maken hebben, maar enkele regels delen, kan een @mixin beter bij u passen. Meer over hoe u tussen de twee kunt kiezen in dit artikel.

Met dank aan David Khourshid voor zijn hulp en expertise op dit gebied.

Mixins

Mixins zijn een van de meest gebruikte functies van de hele Sass-taal. Ze zijn de sleutel tot herbruikbaarheid en DRY componenten. En niet voor niets: met mixins kunnen auteurs stijlen definiëren die in het hele stylesheet kunnen worden hergebruikt zonder toevlucht te hoeven nemen tot niet-semantische klassen zoals .float-left.

Ze kunnen volledige CSS-regels bevatten en vrijwel alles wat overal in een Sass-document is toegestaan. Ze kunnen zelfs argumenten aannemen, net als functies. De mogelijkheden zijn uiteraard eindeloos.

Maar ik denk dat ik u moet waarschuwen voor misbruik van de kracht van mixins. Nogmaals, het sleutelwoord hier is eenvoud. Het is misschien verleidelijk om extreem krachtige mixins te bouwen met enorme hoeveelheden logica. Het wordt over-engineering genoemd en de meeste ontwikkelaars hebben er last van. Denk niet te lang na over uw code en houd het vooral simpel. Als een mixin langer wordt dan 20 regels of zo, dan moet deze in kleinere stukken worden opgesplitst of volledig worden herzien.

Basics

Dat gezegd hebbende, mixins zijn buitengewoon handig en u zou er wat moeten gebruiken. De vuistregel is dat als u toevallig een groep CSS-eigenschappen ziet die altijd samen verschijnen om een reden (dat wil zeggen geen toeval), u ze in plaats daarvan in een mixin kunt plaatsen. De micro-clearfix hack van Nicolas Gallagher verdient het bijvoorbeeld om in een (argumentloze) mixin te worden gestopt.

/// Helper om innerlijke drijvers schoon te maken
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix {
  &::after {
    content: '';
    display: table;
    clear: both;
  }
}
/// Helper om innerlijke drijvers schoon te maken
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix
  &::after
    content: ''
    display: table
    clear: both

Een ander geldig voorbeeld is een mixin om een element op maat te maken, waarbij zowel width als height tegelijkertijd worden gedefinieerd. Het zou niet alleen de code lichter maken om te typen, maar ook gemakkelijker te lezen.

/// Helper om een element op maat te maken
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}
/// Helper om een element op maat te maken
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
=size($width, $height: $width)
  width: $width
  height: $height

Kijk voor meer complexe voorbeelden van mixins naar deze om CSS-driehoeken te genereren, deze om lange schaduwen te creëren of deze om CSS-verlopen voor oude browsers te maken.

Argumentloze mixins

Soms worden mixins alleen gebruikt om te voorkomen dat dezelfde groep declaraties steeds opnieuw wordt herhaald, maar hebben ze geen parameter nodig of hebben ze zinnige standaardwaarden zodat we niet per se argumenten hoeven door te geven.

In dergelijke gevallen kunnen we de haakjes veilig weglaten wanneer we ze noemen. Het @include sleutelwoord (of + teken in inspringende syntaxis) fungeert al als een indicator dat de lijn een mixin-aanroep is; er zijn hier geen extra haakjes nodig.

// Yep
.foo {
  @include center;
}

// Nope
.foo {
  @include center();
}
// Yep
.foo
  +center

// Nope
.foo
  +center()

Argumentenlijst

Gebruik bij het omgaan met een onbekend aantal argumenten in een mixin altijd een arglist in plaats van een lijst. Beschouw arglist als het 8e verborgen ongedocumenteerde gegevenstype van Sass dat impliciet wordt gebruikt bij het doorgeven van een willekeurig aantal argumenten aan een mixin of een functie waarvan de handtekening ... bevat.

@mixin shadows($shadows...) {
  // type-of($shadows) == 'arglist'
  // …
}
=shadows($shadows...)
  // type-of($shadows) == 'arglist'
  // …

Als u nu een mixin maakt die een handvol argumenten accepteert (begrijp er 3 of meer), denk dan twee keer na voordat u ze samenvoegt als een lijst of een map, denkend dat het gemakkelijker zal zijn dan ze allemaal een voor een door te geven.

Sass is eigenlijk best slim met mixins en functieverklaringen, zo erg zelfs dat u een lijst of een map als een arglist aan een functie/mixin kunt doorgeven, zodat het wordt geparseerd als een reeks argumenten.

@mixin dummy($a, $b, $c) {
  // …
}

// Yep
@include dummy(true, 42, 'kittens');

// Yep but nope
$params: (true, 42, 'kittens');
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3));

// Yep
$params: (true, 42, 'kittens');
@include dummy($params...);

// Yep
$params: (
  'c': 'kittens',
  'a': true,
  'b': 42,
);
@include dummy($params...);
=dummy($a, $b, $c)
  // …

// Yep
+dummy(true, 42, 'kittens')

// Yep but nope
$params: (true, 42, 'kittens')
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3))

// Yep
$params: (true, 42, 'kittens')
+dummy($params...)

// Yep
$params: ('c': 'kittens', 'a': true, 'b': 42,)
+dummy($params...)

Voor meer informatie over of het het beste is om meerdere argumenten, een lijst of een argumentenlijst te gebruiken, SitePoint heeft een mooi stuk over het onderwerp.

Mixins en vendorvoorvoegsels

Het kan verleidelijk zijn om aangepaste mixins te definiëren om prefixen van vendors af te handelen voor niet-ondersteunde of gedeeltelijk ondersteunde CSS-eigenschappen. Maar we willen dit niet doen. Ten eerste, als u Autoprefixer kunt gebruiken, gebruik dan Autoprefixer. Het verwijdert Sass-code uit uw project, is altijd up-to-date en zal noodzakelijkerwijs veel beter werk leveren dan u bij toevoegen van voorvoegsel.

Helaas is Autoprefixer niet altijd een optie. Als u ofwel Bourbon of Compass gebruikt, weet u misschien al dat ze allebei een verzameling mixins bieden die voorvoegsels van vendors verwerken voor jou. Gebruik die.

Als u Autoprefixer niet kunt gebruiken en noch Bourbon noch Compass kunt gebruiken, dan en alleen dan, kunt u uw eigen mixin hebben om CSS-eigenschappen voor te voegen. Maar. Bouw alstublieft geen mixin per eigenschap, maar druk elke vendor handmatig af.

// Nope
@mixin transform($value) {
  -webkit-transform: $value;
  -moz-transform: $value;
  transform: $value;
}
// Nope
=transform($value)
  -webkit-transform: $value
  -moz-transform: $value
  transform: $value

Doe het op een slimme manier.

/// Mixin-helper om voorvoegsels van leveranciers uit te voeren
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - CSS-eigenschap zonder prefix
/// @param {*} $value - Ruwe CSS-waarde
/// @param {List} $prefixes - Lijst met voorvoegsels die moeten worden uitgevoerd
@mixin prefix($property, $value, $prefixes: ()) {
  @each $prefix in $prefixes {
    -#{$prefix}-#{$property}: $value;
  }

  #{$property}: $value;
}
/// Mixin-helper om voorvoegsels van leveranciers uit te voeren
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - CSS-eigenschap zonder prefix
/// @param {*} $value - Ruwe CSS-waarde
/// @param {List} $prefixes - Lijst met voorvoegsels die moeten worden uitgevoerd
=prefix($property, $value, $prefixes: ())
  @each $prefix in $prefixes
    -#{$prefix}-#{$property}: $value

  #{$property}: $value

Dan zou het gebruik van deze mixin heel eenvoudig moeten zijn:

.foo {
  @include prefix(transform, rotate(90deg), ('webkit', 'ms'));
}
.foo
  +prefix(transform, rotate(90deg), ('webkit', 'ms'))

Houd er alstublieft rekening mee dat dit een slechte oplossing is. Het kan bijvoorbeeld niet omgaan met complexe polyfills zoals die nodig zijn voor Flexbox. In die zin zou het gebruik van Autoprefixer een veel betere optie zijn.

Voorwaardelijke instructies

U weet waarschijnlijk al dat Sass voorwaardelijke instructies geeft via de @if en @else richtlijnen. Tenzij u een middelmatige tot complexe logica in uw code hebt, zijn er geen voorwaardelijke instructies nodig in uw dagelijkse stylesheets. Eigenlijk bestaan ze vooral voor bibliotheken en frameworks.

Hoe dan ook, als u ooit merkt dat u ze nodig heeft, respecteer dan de volgende richtlijnen:

  • Geen haakjes tenzij ze nodig zijn;
  • Altijd een lege nieuwe regel voor @if;
  • Altijd een lijnonderbreking na de openingsaccolade ({);
  • @else-instructies op dezelfde regel als de vorige sluitaccolade (}).
  • Altijd een lege nieuwe regel na het laatste sluitaccolade (}) tenzij de volgende regel een sluitaccolade is (}).
// Yep
@if $support-legacy {
  // …
} @else {
  // …
}

// Nope
@if ($support-legacy == true) {
  // …
}
@else {
  // …
}
// Yep
@if $support-legacy
  // …
@else
  // …

// Nope
@if ($support-legacy == true)
  // …
@else
  // …

Gebruik bij het testen op een valse waarde altijd het not-sleutelwoord in plaats van te testen op false of null.

// Yep
@if not index($list, $item) {
  // …
}

// Nope
@if index($list, $item) == null {
  // …
}
// Yep
@if not index($list, $item)
  // …

// Nope
@if index($list, $item) == null
  // …

Zet altijd het variabele deel aan de linkerkant van de instructie, en het (on)verwachte resultaat aan de rechterkant. Omgekeerde voorwaardelijke instructies zijn vaak moeilijker te lezen, vooral voor onervaren ontwikkelaars.

// Yep
@if $value == 42 {
  // …
}

// Nope
@if 42 == $value {
  // …
}
// Yep
@if $value == 42
  // …

// Nope
@if 42 == $value
  // …

Als u voorwaardelijke instructies binnen een functie gebruikt om een ander resultaat te retourneren op basis van een bepaalde voorwaarde, zorg er dan altijd voor dat de functie nog steeds een @return-instructie heeft buiten een voorwaardelijk blok.

// Yep
@function dummy($condition) {
  @if $condition {
    @return true;
  }

  @return false;
}

// Nope
@function dummy($condition) {
  @if $condition {
    @return true;
  } @else {
    @return false;
  }
}
// Yep
@function dummy($condition)
  @if $condition
    @return true

  @return false;

// Nope
@function dummy($condition)
  @if $condition
    @return true
  @else
    @return false

Lussen

Omdat Sass complexe datastructuren biedt, zoals lijsten en maps, is het geen verrassing dat het ook een manier biedt voor auteurs om deze entiteiten te herhalen.

De aanwezigheid van lussen impliceert echter meestal matig complexe logica die waarschijnlijk niet tot Sass behoort. Voordat u een lus gebruikt, moet u ervoor zorgen dat deze logisch is en dat deze daadwerkelijk een probleem oplost.

Each

De @each-lus is absoluut de meest gebruikte van de drie lussen die door Sass worden aangeboden. Het biedt een schone API om een lijst of een map te herhalen.

@each $theme in $themes {
  .section-#{$theme} {
    background-color: map-get($colors, $theme);
  }
}
@each $theme in $themes
  .section-#{$theme}
    background-color: map-get($colors, $theme)

Gebruik bij iteratie op een map altijd $key en $value als variabelenamen om consistentie af te dwingen.

@each $key, $value in $map {
  .section-#{$key} {
    background-color: $value;
  }
}
@each $key, $value in $map
  .section-#{$key}
    background-color: $value

Zorg er ook voor dat u deze richtlijnen respecteert om de leesbaarheid te behouden:

  • Altijd een lege nieuwe regel voor @each;
  • Altijd een lege nieuwe regel na het sluitaccolade (}) tenzij de volgende regel een sluitaccolade is (}).

For

De @for-lus kan handig zijn in combinatie met CSS’ :nth-* pseudo-klassen. Behalve voor deze scenario’s, geeft u de voorkeur aan een @each-lus als u over iets moet herhalen.

@for $i from 1 through 10 {
  .foo:nth-of-type(#{$i}) {
    border-color: hsl($i * 36, 50%, 50%);
  }
}
@for $i from 1 through 10
  .foo:nth-of-type(#{$i})
    border-color: hsl($i * 36, 50%, 50%)

Gebruik altijd $i als een variabelenaam om vast te houden aan de gebruikelijke conventie en tenzij u een echt goede reden hebt, gebruik nooit het to trefwoord: gebruik altijd through. Veel ontwikkelaars weten niet eens dat Sass deze variant aanbiedt; het gebruik ervan kan tot verwarring leiden.

Zorg er ook voor dat u deze richtlijnen respecteert om de leesbaarheid te behouden:

  • Altijd een lege nieuwe regel voor @for;
  • Altijd een lege nieuwe regel na het sluitaccolade (}) tenzij de volgende regel een sluitaccolade is (}).

While

De @while-lus heeft absoluut geen use-case in een echt Sass-project, vooral omdat er geen manier is om een lus van binnenuit te doorbreken. Gebruik het niet.

Waarschuwingen en fouten

Als er een functie is die vaak over het hoofd wordt gezien door Sass-ontwikkelaars, is het de mogelijkheid om dynamisch waarschuwingen en fouten uit te voeren. Sass wordt inderdaad geleverd met drie aangepaste richtlijnen om inhoud af te drukken in het standaard uitvoersysteem (CLI, compileer-app …):

  • @debug;
  • @warn;
  • @error.

Laten we @debug opzij zetten, aangezien het duidelijk bedoeld is om SassScript te debuggen, wat hier niet ons punt is. We blijven dan achter met @warn en @error die merkbaar identiek zijn, behalve dat de ene de compiler stopt en de andere niet. Ik laat u raden wat wat doet.

Nu is er in een Sass-project veel ruimte voor waarschuwingen en fouten. In principe kan elke mixin of functie die een specifiek type of argument verwacht, een fout genereren als er iets misgaat, of een waarschuwing weergeven bij het doen van een aanname.

Waarschuwingen

Neem deze functie van Sass-MQ die een px-waarde naar em probeert te converteren, bijvoorbeeld:

@function mq-px2em($px, $base-font-size: $mq-base-font-size) {
  @if unitless($px) {
    @warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.';
    @return mq-px2em($px + 0px);
  } @else if unit($px) == em {
    @return $px;
  }
   @return ($px / $base-font-size) * 1em;
}
@function mq-px2em($px, $base-font-size: $mq-base-font-size)
  @if unitless($px)
    @warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.'
    @return mq-px2em($px + 0px)
  @else if unit($px) == em
    @return $px
   @return ($px / $base-font-size) * 1em

Als de waarde een eenheidloos is, gaat de functie ervan uit dat de waarde bedoeld is om in pixels te worden uitgedrukt. Op dit punt kan een aanname riskant zijn, dus de gebruiker moet worden gewaarschuwd dat de software iets heeft gedaan dat als onverwacht kan worden beschouwd.

Fouten

Fouten, in tegenstelling tot waarschuwingen, voorkomen dat de compiler verder gaat. In feite stoppen ze de compilatie en geven ze een bericht weer in de uitvoerstroom, evenals de stacktracering, wat handig is voor foutopsporing. Daarom zouden er fouten moeten worden gegenereerd als het programma niet kan blijven draaien. Probeer indien mogelijk het probleem te omzeilen en in plaats daarvan een waarschuwing weer te geven.

Stel dat u een getter-functie bouwt om toegang te krijgen tot waarden van een specifieke kaart. U zou een fout kunnen genereren als de gevraagde sleutel niet op de kaart voorkomt.

/// Z-indexen map, waarbij alle Z-lagen van de applicatie worden verzameld
/// @access private
/// @type Map
/// @prop {String} key - Laagnaam
/// @prop {Number} value - Z-waarde toegewezen aan de sleutel
$z-indexes: (
  'modal': 5000,
  'dropdown': 4000,
  'default': 1,
  'below': -1,
);

/// Haal een z-indexwaarde op uit een laagnaam
/// @access public
/// @param {String} $layer - Laagnaam
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
  @if not map-has-key($z-indexes, $layer) {
    @error 'There is no layer named `#{$layer}` in $z-indexes. '
         + 'Layer should be one of #{map-keys($z-indexes)}.';
  }

  @return map-get($z-indexes, $layer);
}
/// Z-indexen map, waarbij alle Z-lagen van de applicatie worden verzameld
/// @access private
/// @type Map
/// @prop {String} key - Laagnaam
/// @prop {Number} value - Z-waarde toegewezen aan de sleutel
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)

/// Haal een z-indexwaarde op uit een laagnaam
/// @access public
/// @param {String} $layer - Laagnaam
/// @return {Number}
/// @require $z-indexes
@function z($layer)
  @if not map-has-key($z-indexes, $layer)
    @error 'There is no layer named `#{$layer}` in $z-indexes. '
         + 'Layer should be one of #{map-keys($z-indexes)}.'

  @return map-get($z-indexes, $layer)

Voor meer informatie over hoe u @error efficiënt kunt gebruiken, zou deze inleiding over foutafhandeling u moeten helpen.

Tools

Wat leuk is aan een CSS-preprocessor zo populair als Sass is dat het wordt geleverd met een geheel ecosysteem van frameworks, plug-ins, bibliotheken en tools. Na 8 jaar bestaan zijn we dichter en dichter bij het punt waar alles in Sass kan worden geschreven in Sass.

Mijn advies zou echter zijn om het aantal dependencies tot het strikte minimum te verlagen. Het beheren van dependencies is een soort hel waar u niet deel van wilt maken. Bovendien is er weinig tot geen behoefte aan externe dependencies als het gaat om SASS.

Compass

Compass is de hoofd Sass Framework. Ontwikkeld door Chris Eppstein, een van de twee kernontwerpers van Sass, ik zie het niet drastisch verliezen in populariteit voor een tijdje, als u mijn mening wilt.

Toch, ik gebruik Compass niet meer, de belangrijkste reden is dat het veel vertraagt. Ruby Sass is vrij langzaam op zich, dus het toevoegen van meer Ruby en meer Sass erbovenop helpt niet echt.

Het ding is, we gebruiken heel weinig van het hele framework. Compass is enorm. Cross-Browser compatibiliteit Mixins is slechts het topje van de ijsberg. Wiskundige functies, beeldhelpers, spriting… Er is zoveel dat kan worden gedaan met dit geweldige stukje software.

Helaas is dit allemaal suiker en is er geen moordende functie. Een uitzondering kan worden gemaakt van de sprite builder die echt geweldig is, maar grunticon en Grumpicon doen het werk ook, en hebben het voordeel van plugbaar in het bouwproces.

Hoe dan ook, ik verbied niet het gebruik van Compass, hoewel ik het ook niet zou aanraden, vooral omdat het niet LibSass-compatibel is (zelfs als inspanningen in die richting zijn gemaakt). Als u het fijner vindt om het te gebruiken, fair enough, maar ik denk niet dat u er veel van krijgt aan het einde van de dag.

Ruby Sass gaat momenteel onder enkele uitstekende optimalisaties die specifiek zijn gericht op logica-zware stijlen met veel functies en mixins. Ze moeten de prestaties drastisch verbeteren tot het punt waar Compass en andere frameworks Sass misschien niet meer vertragen.

Rastersystemen

Het gebruik van een rastersysteem is geen optie nu dat Responsive Web Design overal is. Om ontwerpen te maken die consistent en solide in alle maten lijken, gebruiken we een soort raster om de elementen op te leggen. Om het coderen van dit rastersysteem elke keer te vermijden, maakten enkele briljante mensen hun systeem herbruikbaar.

Laat me dit recht zetten: ik ben geen grote fan van rastersystemen. Natuurlijk zie ik het potentieel, maar ik denk dat de meesten van hen volledig overdreven zijn en meestal worden gebruikt om rode kolommen op een witte achtergrond in de sprekerdecks van nerdy ontwerpers te tekenen. Wanneer was de laatste keer dat u dacht God-zij-dank-ik-heb-deze-tool-om-deze-2-5-3.1-π-grid-te-bouwen? Dat klopt, nooit. Want in de meeste gevallen wilt u gewoon het gebruikelijke normale rooster van 12 kolommen, niets bijzonders.

Als u een CSS-framework gebruikt voor uw project zoals Bootstrap of Foundation, is de kans groot dat het al een rastersysteem bevat in welk geval Ik zou aanraden om het te gebruiken om te voorkomen dat ik met nog een andere dependency zou moeten dealen.

Als u niet gebonden bent aan een specifiek rastersysteem, zult u blij zijn te weten dat er twee eersteklas door Sass aangedreven rastermotoren zijn: Susy en Singularity . Beide doen veel meer dan u ooit nodig zult hebben, dus u kunt degene kiezen die u verkiest tussen deze twee en er zeker van zijn dat al uw edge cases—zelfs de handigste—worden gedekt. Als u het mij vraagt, heeft Susy een iets betere gemeenschap, maar dat is mijn mening.

Of u kunt naar iets meer casual gaan, zoals csswizardry-grids. Al met al heeft de keuze niet veel invloed op uw coderingsstijl, dus dit is op dit moment vrijwel aan u.

SCSS-lint

Code linting is erg belangrijk. Gewoonlijk helpt het volgen van de richtlijnen van een stijlgids om het aantal fouten in de codekwaliteit te verminderen, maar niemand is perfect en er zijn altijd dingen die verbeterd kunnen worden. U zou dus kunnen zeggen dat code linting net zo belangrijk is als commentaar geven.

SCSS-lint is een hulpmiddel om uw SCSS-bestanden schoon en leesbaar te houden. Het is volledig aanpasbaar en gemakkelijk te integreren met uw eigen tools.

Gelukkig lijken de SCSS-lint-aanbevelingen sterk op de aanbevelingen die in dit document worden beschreven. Om SCSS-lint te configureren volgens de Sass-richtlijnen, kan ik de volgende configuratie aanbevelen:

linters:

  BangFormat:
    enabled: true
    space_before_bang: true
    space_after_bang: false

  BemDepth:
    enabled: true
    max_elements: 1

  BorderZero:
    enabled: true
    convention: zero

  ChainedClasses:
    enabled: false

  ColorKeyword:
    enabled: true

  ColorVariable:
    enabled: false

  Comment:
    enabled: false

  DebugStatement:
    enabled: true

  DeclarationOrder:
    enabled: true

  DisableLinterReason:
    enabled: true

  DuplicateProperty:
    enabled: false

  ElsePlacement:
    enabled: true
    style: same_line

  EmptyLineBetweenBlocks:
    enabled: true
    ignore_single_line_blocks: true

  EmptyRule:
    enabled: true

  ExtendDirective:
    enabled: false

  FinalNewline:
    enabled: true
    present: true

  HexLength:
    enabled: true
    style: short

  HexNotation:
    enabled: true
    style: lowercase

  HexValidation:
    enabled: true

  IdSelector:
    enabled: true

  ImportantRule:
    enabled: false

  ImportPath:
    enabled: true
    leading_underscore: false
    filename_extension: false

  Indentation:
    enabled: true
    allow_non_nested_indentation: true
    character: space
    width: 2

  LeadingZero:
    enabled: true
    style: include_zero

  MergeableSelector:
    enabled: false
    force_nesting: false

  NameFormat:
    enabled: true
    convention: hyphenated_lowercase
    allow_leading_underscore: true

  NestingDepth:
    enabled: true
    max_depth: 1

  PlaceholderInExtend:
    enabled: true

  PrivateNamingConvention:
    enabled: true
    prefix: _

  PropertyCount:
    enabled: false

  PropertySortOrder:
    enabled: false

  PropertySpelling:
    enabled: true
    extra_properties: []

  PropertyUnits:
    enabled: false

  PseudoElement:
    enabled: true

  QualifyingElement:
    enabled: true
    allow_element_with_attribute: false
    allow_element_with_class: false
    allow_element_with_id: false

  SelectorDepth:
    enabled: true
    max_depth: 3

  SelectorFormat:
    enabled: true
    convention: hyphenated_lowercase
    class_convention: '^(?:u|is|has)\-[a-z][a-zA-Z0-9]*$|^(?!u|is|has)[a-zA-Z][a-zA-Z0-9]*(?:\-[a-z][a-zA-Z0-9]*)?(?:\-\-[a-z][a-zA-Z0-9]*)?$'

  Shorthand:
    enabled: true

  SingleLinePerProperty:
    enabled: true
    allow_single_line_rule_sets: false

  SingleLinePerSelector:
    enabled: true

  SpaceAfterComma:
    enabled: true

  SpaceAfterPropertyColon:
    enabled: true
    style: one_space

  SpaceAfterPropertyName:
    enabled: true

  SpaceAfterVariableColon:
    enabled: true
    style: at_least_one_space

  SpaceAfterVariableName:
    enabled: true

  SpaceAroundOperator:
    enabled: true
    style: one_space

  SpaceBeforeBrace:
    enabled: true
    style: space
    allow_single_line_padding: true

  SpaceBetweenParens:
    enabled: true
    spaces: 0

  StringQuotes:
    enabled: true
    style: single_quotes

  TrailingSemicolon:
    enabled: true

  TrailingZero:
    enabled: true

  TransitionAll:
    enabled: false

  UnnecessaryMantissa:
    enabled: true

  UnnecessaryParentReference:
    enabled: true

  UrlFormat:
    enabled: false

  UrlQuotes:
    enabled: true

  VariableForProperty:
    enabled: false

  VendorPrefixes:
    enabled: true
    identifier_list: base
    include: []
    exclude: []

  ZeroUnit:
    enabled: true

Als u niet overtuigd bent van de noodzaak om SCSS-lint te gebruiken, raad ik u aan deze geweldige artikelen te lezen: Clean Up your Sass with SCSS-lint, Improving Sass code quality on theguardian.com en An Auto-Enforceable SCSS Styleguide.

Als u SCSS-lint in uw Grunt-buildproces wilt aansluiten, zult u blij zijn te weten dat er een Grunt-plug-in voor is genaamd grunt-scss-lint.

En als u op zoek bent naar een handige applicatie die werkt met SCSS-lint en dergelijke, kunnen de mensen van Thoughtbot (Bourbon, Neat…) werken aan Hound.

Too Long; Didn’t read

Deze richtlijnen zijn vrij lang en soms is het goed om ze in een kortere versie op te sommen. Hieronder vindt u deze samenvatting.

Basisprincipes

  • Bij het hebben van een stijlgids draait alles om consistentie. Als u het niet eens bent met sommige regels uit de Sass-richtlijnen, is dat redelijk, zolang u maar consistent bent.
  • Sass moet zo eenvoudig mogelijk worden gehouden. Bouw geen complexe systemen, tenzij dit absoluut noodzakelijk is.
  • Houd er rekening mee dat KISS (Keep It Simple, Stupid) soms beter is dan DRY (Don’t Repeat Yourself).

Syntaxis en Opmaak

  • Een inspringing bestaat uit twee (2) spaties, geen tabs.
  • Regels moeten zoveel mogelijk korter zijn dan 80 tekens. Voelt u zich vrij om ze indien nodig op te splitsen in verschillende regels.
  • CSS moet correct worden geschreven, mogelijk volgens de CSS Guidelines van Harry Roberts.
  • Witruimte is gratis, gebruik het om items, regels en verklaringen te scheiden. Aarzel niet om lege regels achter te laten, het doet nooit pijn.

tekenreeksen

  • Het wordt ten zeerste aanbevolen om de @charset-richtlijn bovenaan het stylesheet te verklaren.
  • Tenzij toegepast als CSS-ID’s, moeten tekenreeksen tussen enkele aanhalingstekens worden geplaatst. URL’s moeten ook worden geciteerd.

Getallen

  • Sass maakt geen onderscheid tussen getallen, gehele getallen en floats, dus achterliggende nullen (0) moeten worden weggelaten. Voorloopnullen (0) helpen echter de leesbaarheid en moeten worden toegevoegd.
  • Een lengte van nul (0) mag geen eenheid hebben.
  • Het manipuleren van eenheden moet worden gezien als rekenkundige bewerkingen, niet als tekenreeksbewerkingen.
  • Om de leesbaarheid te verbeteren, moeten berekeningen op het hoogste niveau tussen haakjes worden geplaatst. Ook kunnen complexe wiskundige bewerkingen worden opgesplitst in kleinere delen.
  • Magische getallen hebben een dramatische invloed op de onderhoudbaarheid van de code en moeten te allen tijde worden vermeden. Leg bij twijfel uitgebreid de twijfelachtige waarde uit.

Kleuren

  • Kleuren moeten indien mogelijk worden uitgedrukt in HSL, dan RGB en dan hexadecimaal (in kleine letters en verkorte vorm). Kleurzoekwoorden moeten worden vermeden.
  • Geef de voorkeur aan mix(..) in plaats van darken(..) en lighten(..) bij het lichter of donkerder maken van een kleur.

Lijsten

  • Tenzij ze worden gebruikt als een directe toewijzing aan door spaties gescheiden CSS-waarden, moeten lijsten worden gescheiden met komma’s.
  • Het omhullen van haakjes moet ook worden overwogen om de leesbaarheid te verbeteren.
  • Inline lijsten mogen geen komma hebben, meerregelige lijsten zouden deze moeten hebben.

Maps

  • Maps die meer dan één paar bevatten, worden op meerdere regels geschreven.
  • Om de onderhoudbaarheid te bevorderen, moet het laatste paar van een map een komma hebben.
  • Mapsleutels die toevallig tekenreeksen zijn, moeten als elke andere tekenreeks worden aangehaald.

Verklaringsortering

  • Het systeem dat wordt gebruikt voor het sorteren van verklaringen (alfabetisch, op type, etc.) doet er niet toe, zolang het maar consistent is.

Selector nesten

  • Vermijd het nesten van selectors wanneer dit niet nodig is (wat de meeste gevallen vertegenwoordigt).
  • Gebruik selector nesten voor pseudo-klassen en pseudo-elementen.
  • Mediaquery’s kunnen ook in hun relevante selector worden genest.

Naamgevingsconventies

  • Het is het beste om vast te houden aan CSS-naamgevingsconventies die (behalve een paar fouten) in kleine letters en met koppeltekens worden gescheiden.

Commentaar geven

  • CSS is een lastige taal; aarzel niet om zeer uitgebreide opmerkingen te schrijven over dingen die er niet uitzien (of zijn).
  • Gebruik SassDoc-opmerkingen voor variabelen, functies, mixins en tijdelijke aanduidingen die een openbare API opzetten.

Variabelen

  • Gebruik de !default flag voor elk variabel deel van een openbare API dat veilig kan worden gewijzigd.
  • Gebruik de !global flag niet op rootniveau, aangezien dit in de toekomst een schending van de Sass-syntaxis kan vormen.

Extend

  • Blijf bij het verlengen van tijdelijke aanduidingen, niet bij bestaande CSS-selectors.
  • Verleng een tijdelijke aanduiding zo vaak mogelijk om bijwerkingen te voorkomen.
Terug naar boven