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.
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:
- How to Programmatically Go From One Color to Another
- Using Sass to Build Color Palettes
- Dealing with Color Schemes in Sass
Kleurformaten
Om kleuren zo eenvoudig mogelijk te maken, zou mijn advies zijn om de volgende voorkeursvolgorde voor kleurformaten te respecteren:
- HSL-notatie;
- RGB-notatie;
- 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.
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.
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.
Als je Sass Guidelines leuk vindt, overweeg dan om ze te steunen.
Ondersteun Sass GuidelinesNaamgevingsconventies
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.
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.
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:
abstracts/
vendors/
base/
layout/
components/
pages/
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.
Als je Sass Guidelines leuk vindt, overweeg dan om ze te steunen.
Ondersteun Sass GuidelinesVariabelen
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:
- Wat niemand u heeft verteld over Sass Extend
- Waarom u verlenging moet vermijden
- Breid jezelf niet te veel uit
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
Als je Sass Guidelines leuk vindt, overweeg dan om ze te steunen.
Ondersteun Sass GuidelinesLussen
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 vandarken(..)
enlighten(..)
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.
Als je Sass Guidelines leuk vindt, overweeg dan om ze te steunen.
Ondersteun Sass Guidelines
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:
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:
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.
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.
Drie schuine strepen (
/
) vereist.SassDoc heeft twee hoofdrollen:
Hier is een voorbeeld van een mixin uitgebreid gedocumenteerd met SassDoc: