Sass Guidelines

En subjektiv styleguide til at skrive fornuftigt, vedligeholdelsesvenligt og skalerbart Sass.

You are viewing the Danish translation by Anders Schmidt Hansen of the original Sass Guidelines from Kitty Giraudel.

This version is exclusively maintained by contributors without the review of the main author, therefore might not be completely authentic, especially since it is currently in version 1.1 while the English version is in version 1.3.

Åbn panelet muligheder

Om forfatteren

Mit navn er Kitty Giraudel, jeg er en fransk front-end udvikler med base i Berlin, Tyskland. Jeg har skrevet Sass i over to år nu, og er forfatteren af Sass-relaterede projekter såsom SassDoc og Sass-Compatibility. Jeg har også skrevet en bog om CSS (på fransk) med titlen CSS3 Pratique du Design Web.

Jeg har også skrevet en række Sass-biblioteker, egentlig mest bare fordi: SassyJSON, SassyLists, SassySort, SassyCast, SassyMatrix, SassyBitwise, SassyIteratorsGenerators, SassyLogger, SassyStrings og SassyGradients.

Kontribuering

Sass Guidelines er et gratis projekt, som jeg vedligeholder i min fritid. Jeg behøver ikke sige, at det er et ret stort arbejde at holde alt opdateret, dokumenteret og relevant. Det er dog åbenlyst, at bare det at vide, at du kunne lide denne styleguide allerede er meget værdsat!

Hvis du føler for at kontribuere, så skal du vide at bare det at tweete om det, sprede ordet eller fikse en mindre tastefejl ved at åbne et issue eller en pull request på GitHub repository’et vil være fedt!

Sidst, men ikke mindst, før vi går i gang: hvis du har nydt dokumentet, eller hvis det er brugbart for dig eller dit team, så overvej venligst at støtte det!

Om Sass

Sådan beskriver Sass sig selv i dets dokumentation:

Sass er en forlængelse af CSS, der tilføjer kraft og elegance til det basale sprog.

Sass’ ultimative mål er at fikse CSS’ skønhedsfejl. CSS, som vi alle kender det, er ikke det bedste sprog i verden [citation mangler]. På trods af at det er simpelt at lære, så kan det hurtigt blive ret rodet, især i store projekter.

Det er her hvor Sass kommer ind, som et metasprog, til at forbedre CSS’ syntaks på en måde der tilføjer ekstra funktionaliteter og brugbare værktøjer. Samtidig, så ønsker Sass at være konservativ når det kommer til CSS-sproget.

Pointen er ikke at transformere CSS til et fuldt udstyret programmeringssprog; Sass ønsker kun at hjælpe dér hvor CSS fejler. På grund af det, så er det at komme i gang med Sass ikke sværere end at lære CSS: det tilføjer blot et par ekstra funktionaliteter ovenpå det.

Når det er sagt, så er der mange måde at bruge disse funktionaliteter på. Nogle gode, nogle dårlige, nogle underlige. Disse retningslinjer er tiltænkt at give dig en konsistent og dokumenteret tilgang til at skrive Sass kode.

Videre læsning:

Ruby Sass eller LibSass

Sass’s første commit går helt tilbage til sen-2006, over 8 år siden. Det er derfor overflødigt at sige, at det er kommet ret langt siden da. Originalt udviklet i Ruby, så poppede variationer op her og der. Den mest succesfulde, LibSass (skrevet i C/C++), er nu tæt på at være fuldt kompatibel med den originale Ruby-version.

I 2014 besluttede holdene bag Ruby Sass og LibSass at vente på at begge versioner kunne synkronisere, før de bevægede sig videre fremad. Siden da har LibSass været meget aktiv i at udgive versioner, der har funktionalitets-paritet med dets storebror. De sidste tilbageblivende inkonsistenser har jeg samlet og listet under projektet Sass-Compatibility. Hvis du er blevet opmærksom på en inkompatibilitet mellem de to versioner, så vær rar at åbne et issue.

For at vende tilbage til valget om din compiler. Det hele afhænger rent faktisk af dit projekt. Hvis dit projekt er et Ruby on Rails projekt, så bør du bruge Ruby Sass, der er perfekt velegnet til en sådan situation. Vær også opmærksom på at Ruby Sass altid vil være implementationsreferencen, og vil derfor altid være foran LibSass når det kommer til funktionaliteter.

Ved ikke-Ruby projekter, der har behov for en workflow integration, så er LibSass højest sandsynlig en bedre idé, da den for det meste er dedikeret til at blive indpakket. Så hvis du ønsker at bruge f.eks. Node.js, så er node-sass det klare valg.

Videre læsning:

Sass eller SCSS

Der er eksisterer megen forvirring omkring semantikken ved navnet Sass, og af god grund: Sass betyder både preprocessoren og dens egen syntaks. Ikke særlig hensigtsmæssigt, vel?

Ser du, Sass blev originalt beskrevet som en syntaks hvoraf de definerende karaktertræk var dets sensitivitet overfor indentering. Inden længe besluttede holdet bag Sass at lukke hullet mellem Sass og CSS ved at tilbyde en CSS-venlig syntaks kaldet SCSS, som står for Sassy CSS. Dets motto er: hvis det er valid CSS, så er det valid SCSS.

Siden da har Sass (preprocessoren) tilbudt to forskellige syntakser: Sass (uden store bogstaver, tak), også kendt som den indenterede syntaks, og SCSS. Hvilken en du bruger er faktisk helt op til dig, da de er fuldstændigt ens funktionalitetsmæssigt. Her er det kun et spørgsmål om æstetik.

Sass’ whitespace-sensitive syntaks afhænger af indentering for at fjerne klammer, semi-kolonner og andre tegnsætningssymboler, hvilket leder til en slankere og kortere syntaks. Samtidig, så er SCSS nemmere at lære da det egentlig bare er CSS med lidt ekstra ovenpå.

Jeg selv foretrækker SCSS frem for Sass, fordi det er tættere på CSS og rarere for de fleste udviklere. På grund af det, så er SCSS standard-syntaksen for disse retningslinjer. Du kan skifte til indenteret Sass syntaks via .

Videre læsning:

Andre preprocessorer

Sass er en preprocessor blandt mange andre. Dens mest seriøse konkurrent må være LESS, en Node.js-baseret preprocessor, der er blevet ret populært fordi det kendte CSS framework Bootstrap anvender det. Der findes også Stylus - som er den nørdede, ubegrænsede version af LESS - hvor du kan gøre praktisk taget lige hvad du vil, da den nærmest transformerer CSS om til et programmeringssprog.

Hvorfor vælge Sass frem for LESS eller en anden preprocessor?, er et godt spørgsmål selv i dag. For ikke så længe siden anbefalede vi Sass til Ruby-baserede projekter, fordi det først var skrevet i Ruby og fungerede godt med Ruby on Rails. Nu hvor LibSass (næsten) er på samme niveau som det originale Sass, så er anbefalingen ikke længere relevant.

Hvad jeg godt kan lide ved Sass er dets konservative tilgang til CSS. Sass’ design er baseret på stærke principper: meget af designtilgangen kommer naturligt fra hovedteamets overbevisninger om, at a) tilføjelse af ekstra funktionaliteter har en kompleksitetsudgift, som skal retfærdiggøres på baggrund af brugbarhed, og b) at det skal være nemt at argumentere for hvad en given blok af styles laver ud fra at se på blokken alene. Dertil, så har Sass et meget skarpere øje for detaljer end de andre preprocessorer. Så vidt jeg ved bekymrer hovedteamet sig meget om at støtte hver eneste edge-case af CSS-kompatibilitet, og sikrer sig at hver enkelt generel adfærd er konsistent.

Med andre ord, så er Sass ikke en preprocessor der er målrettet mod at please nørdede wannabe-programmører som mig, ved at tilføje særlige funktionaliteter ovenpå et sprog der ikke er tiltænkt at skulle understøtte nogen logiske brugssituationer. Det er et stykke software målrettet mod at løse aktuelle problemer; at hjælpe med at tilføje brugbar funktionalitet til CSS, dér hvor CSS kommer til kort.

Lad os lægge preprocessorerne til side, da vi også bør nævne postprocessorer, der har modtaget nævneværdig eksponering de sidste par måneder, hovedsageligt på grund af PostCSS og cssnext. Postprocessorer er rimeligt meget det samme som preprocessorer bortset fra at de ikke tilføjer andet end den kommende CSS syntax.

Du kan tænke på postprocessorer som en slags polyfill for ikke-understøttede CSS funktionaliteter. For eksempel, så ville du skrive variabler som de beskrives i CSS specifications, dernæst kompilere dine stylesheets med en postprocessor for derefter at opleve at hver variabel bliver erstattet med dets værdi, ligesom Sass ville gøre.

Idéen bag postprocessorer er, at når browsere støtter nye funktionaliteter (f.eks. CSS variabler), så vil postprocessoren ikke kompilere dem længere og lade browserne tage over.

Selvom det at give os morgendagens syntaks i dag er en nobel idé, så bliver jeg nødt til at sige at jeg stadig foretrækker at anvende Sass til de fleste opgaver. Dog er der situationer, hvor jeg tror at postprocessorer er mere velegnet end Sass og lignende - CSS præ-fiksing for eksempel - men dette vender vi tilbage til.

Videre læsning:

Indledning

Hvorfor en styleguide

En styleguide er ikke bare hyggelæsning, der maler et ideelt billede af din kode. Det er et vigtigt dokument i et projekts liv, der beskriver hvordan og hvorfor kode bør blive skrevet. Det kan se overdrevet ud til små projekter, men det hjælper meget med at holde kodebasen ren, skalérbar og let at vedligeholde.

Det er unnødvendigt at sige, at jo flere udviklere der er involveret i et projekt desto flere kode-retningslinjer er nødvendige. I samme dur, så jo større et projekt desto større er kravet for en styleguide.

Harry Roberts forklarer dette meget godt i CSS Guidelines:

En programmeringsstyleguide (bemærk, ikke en visuel styleguide) er et værdifuldt værktøj for teams som:

  • bygger og vedligeholder produkter over en rimelig mængde tid;
  • har udviklere med forskellige evner og specialiseringer;
  • har et antal af forskellige udviklere, der arbejder på et produkt på ethvert givent tidspunkt;
  • oplærer nye ansatte regelmæssigt;
  • har et antal af kodebaser, som udviklere skal dykke ned i og op ad.

Disclaimer

Først og fremmest: dette er ikke en CSS styleguide. Dette dokument vil ikke diskutere konventioner for navngivning af CSS-klasser, modulære mønstre og spørgsmålet om ID’er i CSS-verdenen. Disse retningslinjer fokuserer kun på hvordan man arbejder med Sass-specifikt indhold.

Dertil, så er denne styleguide min egen og den er derfor meget farvet. Tænk på denne som en samling af metodologier og råd, som jeg har finpudset og givet over årene. Det har også givet mig muligheden for at linke til en håndful indsigtsfulde resourcer, så vær sikker på at tjekke Videre læsning ud.

Det er åbenlyst at dette selvfølgelig ikke er den eneste måde at gøre tingene på, og vil enten passe eller ikke passe til dit projekt. Vær velkommen til at udvælge hvad du kan bruge, og tilpasse det til dine behov. Hver sin smag, som vi siger.

Nøgleprincipper

Når alt kommer til alt, så hvis der er noget jeg gerne vil have at du tager med dig fra hele denne styleguide, så er det at Sass bør holdes så enkelt som det kan blive.

Takket være mine fjollede eksperimenter, såsom bitwise operatører, iteratorer og generatorer og en JSON parser i Sass, så er vi alle meget klare over hvad man kan gøre med denne preprocessor.

I mellemtiden, så er CSS et simpelt sprog. Sass, som tiltænkt til at skrive CSS, bør ikke blive meget mere kompleks end almindelig CSS. KISS princippet (Keep It Simple Stupid) er nøglen her, og kan endda være vigtigere end DRY principle (Don’t Repeat Yourself) i nogle tilfælde.

Sommetider er det bedre at gentage sig selv en smule for at holde koden vedligeholdelsesvenlig, fremfor at bygge et meget tungt, uhåndterbart og unnødvendigt kompliceret system, der er fuldstændig umulig at vedligeholde fordi det er alt for komplekst.

Dertil, så lad mig citere Harry Roberts endnu engang, pragmatisme trumfer perfektion. På et tidspunkt, så vil du højest sandsynlig finde dig selv i en situation hvor du går imod reglerne, som står beskrevet her. Hvis det giver mening, og hvis det føles rigtigt, så gør det. Kode er kun et middel, ikke målet.

Videre læsning:

Syntaks & formatering

Hvis du spørger mig, så er noget af det allerførste en styleguide bør gøre, er at beskrive måden hvordan vi vil have vores kode til at se ud.

Når flere udviklere er involveret i at skrive CSS på de(t) samme projekt(er), så er det kun et spørgsmål om tid før en af dem begynder at gøre tingene på deres egen måde. Retningslinjer for kode, der fremmer konsistens, er ikke blot med til at undgå dette, men hjælper også når det kommer til at læse og opdatere koden.

Groft sagt, så ønsker vi (skamløst inspireret af CSS Guidelines):

  • indentering á to (2) mellemrum, ingen tabs;
  • 80-karakterer brede linjer, ideelt set;
  • ordentligt skrevede, multi-linje CSS-regler;
  • meningsfuld brug af whitespace.
// Yep
.foo {
  display: block;
  overflow: hidden;
  padding: 0 1em;
}

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

    padding: 0 1em;
}
// Since Sass indented-syntax forces those coding standards
// There is no wrong way of proceeding
.foo
  display: block
  overflow: hidden
  padding: 0 1em

Vi vil ikke tackle spørgsmålet omkring filorganisering i denne sektion. Det er formålet for en anden sektion.

Strenge

Tro det eller ej, så spiller strenge en ret stor rolle i økosystemerne for både CSS og Sass. De fleste CSS-værdier er enten længder eller strenge (ofte uciterede), så det er faktisk ret vigtigt at holde sig til nogle retningslinjer når man arbejder med strenge i Sass.

Encoding

For at undgå potentielle problemer med karakter-encoding, så anbefales det kraftigt at tvinge UTF-8 encoding i hoved-stylesheetet ved at anvende @charset direktivet. Vær sikker på at det er det allerførste element i stylesheetet, og at der ikke er nogen form for karakterer før det.

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

Citationstegn

CSS kræver ikke at strenge bliver citerede, ikke engang dem der indeholder mellemrum. Tag font-family navne som eksempel: for CSS parseren gør det ingen forskel hvorvidt du pakker dem ind i citationstegn.

På grund af det, så kræver Sass heller ikke at strenge citeres. Endnu bedre er (og heldigvis, vil du nok indrømme), at en citeret streng er fuldstændig den samme som dens uciterede tvilling (f. eks. er 'abc' fuldstændig det samme som abc).

Med det sagt, så er sprog der ikke kræver at strenge bliver citeret klart en minoritet, og derfor bør strenge altid indpakkes i enkelte citationstegn (') i Sass (enkelte citationstegn er nemmere at taste end dobbelte på qwerty tastaturer). Foruden konsistens med andre sprog, inklusiv CSS’ kusine JavaScript, er der flere grunde bag dette valg:

  • farvenavne behandles på samme måde som uciterede farver, hvilket kan lede til alvorlige problemer;
  • de fleste syntax highlighters får sure opstød af uciterede strenge;
  • det hjælper med generel læsbarhed;
  • der er ingen god grund til ikke at citere strenge.
// Yep
$direction: 'left';

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

// Nope
$direction: left

Strenge som CSS værdier

Specifikke CSS værdier, såsom initial eller sans-serif kræver ikke at blive citeret. Det er klart, at font-family: 'sans-serif' vil fejle i stilhed fordi CSS forventer en identifier og ikke en citeret streng. På grund af dette, så citerer vi ikke disse værdier.

// 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')

Dermed kan vi lave en distinktion mellem strenge der har til hensigt at blive brugt som CSS værdier (CSS identifiers), som i det forrige eksempel, og strenge der holder sig til Sass’ datatype, som for eksempel map-nøgler.

Vi citerer ikke den førstnævnte, men vi indpakker den sidstnævnte i enkelte citationstegn.

Strenge der indeholder citationstegn

Hvis en streng indeholder en eller flere citationstegn, så kan man overveje at indpakke strengen i dobbelte citationstegn (") i stedet, for at undgå at escape for mange karakterer inden i strengen.

// 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’er

URL’er bør også blive citeret af de samme grunde som ovenfor:

// 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)

Videre læsning:

Tal

I Sass er tal en datatype der inkluderer alt lige fra enhedsløse numre til længder, varigheder, frekvenser, vinkler og så videre. Dette tillader udførelse af udregninger på sådanne målinger.

Nuller

Tal bør vise foranstillede nuller før en decimalværdi, der er mindre end et. Vis aldrig efterstillede nuller.

// 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

Enheder

Når du arbejder med længder, så bør en værdi af 0 aldrig have en enhed.

// Yep
$length: 0;

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

// Nope
$length: 0em

Den mest typiske fejl jeg kan komme i tanke om, i relation til tal i Sass, er at tænke på enheder som kun værende strenge der trygt kan tilføjes til et tal. Selvom det lyder sandt, så er det absolut ikke sådan enheder virker. Tænk på enheder som algebraiske symboler. For eksempel, som i den virkelig verden, hvis du ganger 5 tommer med 5 tommer så får du 25 kvadrattommer. Den samme logik gælder ved Sass.

For at tilføje en enhed til et tal, så er du nødt til at gange dette tal med 1 enhed.

$value: 42;

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

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

// Yep
$length: $value * 1px

// Nope
$length: $value + px

Bemærk at tilføjelse af 0 medlem af samme enhed også virker, men jeg vil hellere anbefale den førnævnte metode, siden 0 enhed kan være en anelse forvirrende. Det er klart, at når man forsøger at konvertere et tal til en anden kompatibel enhed, så vil tilføjelse af 0 ikke være nok.

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

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

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

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

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

Når alt kommer til alt, så afhænger det af hvad du forsøger at opnå. Bare hold det i tankerne, at tilføjelse af en enhed til en streng ikke altid er en god fremgangsmåde.

For at fjerne en værdis enhed, så er du nødt til at dividere den med en enhed af dets slags.

$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)

Tilføjelse af en enhed som en streng til et tal resulterer i en streng, hvilket forhindrer enhver yderligere operation på værdien. At opdele den numeriske del af et tal med en enhed resulterer også i en streng. Dette er ikke hvad du ønsker.

Kalkulationer

Numeriske kalkulationer på top-niveau bør altid indpakkes i paranteser. Ikke alene forbedrer dette krav læsbarheden dramatisk, det forhindrer også særtilfælde ved at tvinge Sass til at evaluere indholdet af paranteserne.

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

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

// Nope
.foo
  width: 100% / 3

Magiske tal

“Magiske tal” er et old school programmeringsterm for unavngivne numeriske konstanter. Basalt set, så er det et tilfældigt tal der bare virker™, dog uden at være forbundet til nogen logisk forklaring.

Selvfølgelig er magiske tal en plage og bør undgås for enhver pris. Når du ikke kan finde en fornuftig forklaring for hvorfor et tal virker, så tilføj en uddybende kommentar der forklarer hvordan du er nået hertil, og hvorfor du tror det virker. At indrømme at du ikke ved hvorfor noget virker er stadig mere hjælpsomt for den næste udvikler, end at få dem til regne ud hvad det er der sker fra bunden af.

/**
 * 1. Magic number. This value is the lowest I could find to align the top of
 * `.foo` with its parent. Ideally, we should fix it properly.
 */
.foo {
  top: 0.327em; /* 1 */
}
/**
 * 1. Magic number. This value is the lowest I could find to align the top of
 * `.foo` with its parent. Ideally, we should fix it properly.
 */
.foo
  top: 0.327em /* 1 */

Videre læsning:

Farver

Farver har en vigtig plads i CSS-sproget. Sass bliver derfor naturligt en værdifuld allieret når det kommer til manipulation af farver, mest fordi det giver os en håndfuld kraftfulde funktioner.

Farveformater

For at holde farver så simple som muligt, så vil mit råd være at respektere den følgende rækkefølge for farveformater:

  1. CSS farve-nøgleord;
  2. HSL notation;
  3. RGB notation;
  4. Hexadecimal notation. Små bogstaver og forkortet, hvis muligt, er at foretrække.

Som udgangspunkt, så taler nøgleord ofte for sig selv. HSL-repræsentationen er ikke kun den nemmeste for den menneskelige hjerne at forstå [citation mangler], den er også nemmere for forfattere af stylesheets når det kommer til at fintune farven ved at justere nuance, mætning og lyshed hver for sig. RGB har stadig en fordel ved med det samme at vise om farven er mere en blå, en grøn eller en rød, men den gør det ikke nemmere at bygge en farve ud af de tre dele. Til sidst, så er hexidecimaler tættest på at være uforståeligt for det menneskelige sind.

// 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

Når man anvender HSL eller RGB, så tilføj altid et enkelt mellemrum efter et komma (,) og ingen mellemrum mellem paranteser ((, )) og indhold.

// 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% )

Farver og variabler

Når en farve anvendes mere end én gang, så gem den i en variabel med et meningsfuldt navn, der repræsenterer farven.

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

Du står dig nu frit for at anvende denne variabel hvorend du vil. Dog, hvis din brug er tæt koblet til et tema, så vil jeg fraråde at anvende variablen som den er. Gem den i stedet i en anden variabel med et navn der forklarer hvordan den bør bruges.

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

Ved at gøre det på denne måde, forhindrer du at tema-ændringer fører til ting som $sass-pink: blue.

Lysning og mørkning af farver

Både lighten og darken er funktioner til manipulation af lysstyrken af en farve i HSL-rum ved at tilføje eller fratrække lysstyrken i HSL-rummet. Basalt set er de intet andet end aliaser for $lightness parametret af adjust-color funktionen.

Sagen er den, at disse funktioner ofte ikke giver det forventede resultat. På den anden side, så er mix funktionen en god måde at lysne eller mørkne en farve på, ved at mikse den med enten white eller black.

Fordelen ved at anvende mix i stedet for at en af de to førnævnte funktioner er, at det den vil progressivt gå mod sort (eller hvid) efterhånden som du reducerer farvens proportion, hvoraf darken og lighten hurtigt vil kaste en farve helt mod sort eller hvid.

Illustration af forskellen mellem lighten/darken og mix af KatieK
Illustration af forskellen mellem lighten/darken og mix af KatieK

Hvis du ikke ønsker at skrive mix funktionen hver gang, så kan du skabe to letanvendelige funktioner kaldet tint og shade (der også er en del af Compass), til at udføre den samme ting:

/// Slightly lighten a color
/// @access public
/// @param {Color} $color - color to tint
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function tint($color, $percentage) {
  @return mix(white, $color, $percentage);
}

/// Slightly darken a color
/// @access public
/// @param {Color} $color - color to shade
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function shade($color, $percentage) {
  @return mix(black, $color, $percentage);
}
/// Slightly lighten a color
/// @access public
/// @param {Color} $color - color to tint
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function tint($color, $percentage)
  @return mix($color, white, $percentage)

/// Slightly darken a color
/// @access public
/// @param {Color} $color - color to shade
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function shade($color, $percentage)
  @return mix($color, black, $percentage)

scale-color funktionen er designet til at skalere egenskaber mere flydende ved at tage hvor høje og lave de allerede er med i betragtning. Den bør give resultater der er ligeså gode som mix' men med en klarere konvention for kald. Skaleringsfaktoren er dog ikke helt den samme.

Videre læsning:

Lister

Lister er Sass’ svar på arrays. En liste er en flad datastruktur (modsat maps), der har til hensigt at gemme værdier af enhver type (inklusiv lister, hvilket leder til indlejrede lister).

Lister bør respektere de følgende retningslinjer:

  • enten indlejrede eller i flere linjer;
  • nødvendigvis i flere linjer, hvis for lang til at passe ind i linje på 80-karakterer;
  • medmindre brugt som den er til CSS formål, skal det altid være komma-separeret;
  • altid indpakked i paranteser;
  • efterstillede kommaer hvis flere linjer, ikke hvis indlejret.
// 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,)

Når du tilføjer nye artikler til en liste, så brug altid den medfølgende API. Forsøg ikke at tilføje nye artikler manuelt.

$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

Videre læsning:

Maps

Siden Sass 3.3 kan stylesheet forfattere definere maps — Sass-termet for et associativ array, hashes eller endda JavaScript objekter. Et map er en datastruktur til forbinde nøgler (der kan være af enhver datatype, inklusiv maps, selvom jeg ikke anbefaler det) til værdier af enhver type.

Maps bør altid blive skrevet som følgende:

  • mellemrum efter kolon (:);
  • åbnende klamme (() på samme linje som kolonet (:);
  • citerede nøgler, hvis de er strenge (hvilket repræsenterer 99% af situationerne);
  • hver nøgle/værdi par er på dets egen, nye linje;
  • efterstillet komma (,) på den sidste artikel gør det lettere at tilføje, fjerne eller omarrangere artikler;
  • afsluttende klamme ()) på hver sin, nye linje;
  • intet mellemrum eller ny linje mellem en afsluttende klamme ()) og semikolon (;).

Illustration:

// 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,
)

Debugging af et Sass map

Hvis du nogensinde har følt dig fortabt, og tænkt hvilken skør magi der foregår i et Sass map, så fortvivl ikke, der stadig er en måde at blive reddet på.

@mixin debug-map($map) {
  @at-root {
    @debug-map {
      __toString__: inspect($map);
      __length__: length($map);
      __depth__: if(function-exists('map-depth'), map-depth($map), null);
      __keys__: map-keys($map);
      __properties__ {
        @each $key, $value in $map {
          #{'(' + type-of($value) + ') ' + $key}: inspect($value);
        }
      }
    }
  }
}
=debug-map($map)
  @at-root
    @debug-map
      __toString__: inspect($map)
      __length__: length($map)
      __depth__: if(function-exists('map-depth'), map-depth($map), null)
      __keys__: map-keys($map)
      __properties__
        @each $key, $value in $map
          #{'(' + type-of($value) + ') ' + $key}: inspect($value)

Hvis du er interesseret i at vide dybden af map’et, så tilføj følgende funktion. Mixin’en vil vise det automatisk.

/// Compute the maximum depth of a map
/// @param {Map} $map
/// @return {Number} max depth of `$map`
@function map-depth($map) {
  $level: 1;

  @each $key, $value in $map {
    @if type-of($value) == 'map' {
      $level: max(map-depth($value) + 1, $level);
    }
  }

  @return $level;
}
/// Compute the maximum depth of a map
/// @param {Map} $map
/// @return {Number} max depth of `$map`
@function map-depth($map)
  $level: 1

  @each $key, $value in $map
    @if type-of($value) == 'map'
      $level: max(map-depth($value) + 1, $level)

  @return $level;

Videre læsning:

CSS Regelsæt

På dette tidspunkt, hvilket mest er en opsummering af hvad alle ved, men her er måden hvordan et CSS regelsæt bør blive skrevet (i det mindste ifølge de fleste retningslinjer, inklusiv CSS Guidelines):

  • relaterede selektorer på samme linje; urelaterede selektorer på nye linjer;
  • den åbnende klamme ({) har afstand fra den sidste selektor med et enkelt mellemrum;
  • hver deklaration på dets egen, nye linje;
  • et mellemrum efter kolonet (:);
  • et efterstillet semikolon (;) ved enden af alle deklarationer;
  • den afsluttende klamme (}) på sin egen, nye linje;
  • en ny linje efter den afsluttende klamme }.

Illustration:

// 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

Ifølge disse CSS-relaterede retningslinjer, så ønsker vi at være opmærksomme på:

  • at lokale variabler bliver deklareret før alle andre deklarationer, for derefter at have afstand til deklarationer via en ny linje;
  • at mixin-kald uden nogen @content kommer efter enhver deklaration;
  • at indlejrede selektorer altid kommer efter en ny linje;
  • at mixin-kald med @content kommer efter enhver indlejret selektor;
  • at der ikke er nogen ny linje før en afsluttende klamme (}).

Illustration:

.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

Videre læsning:

Sortering af Deklarationer

Jeg kan ikke komme på mange emner, hvor meninger er så splittede som de er når det kommer til sortering af deklarationer i CSS. Helt konkret, så er to fraktioner på spil her:

  • at holde sig til den alfabetiske rækkefølge;
  • at arrangere deklarationerne efter type (position, display, farver, skrifttype, diverse…).

Der er fordele og ulemper ved begge tilgange. På den ene side, så er alfabetisk sortering universelt (i det mindste for sprog, der anvender det latinske alfabet), så der er ikke noget argument om at sortere en egenskab efter en anden. Dog finder jeg det ekstremt mærkeligt ikke at se værdier som bottom og top lige ved siden af hinanden. Hvorfor skulle animationer komme før display-typen? Der er mange særheder ved en alfabetisk arrangering.

.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

På den anden side, giver arrangering af egenskaber efter type perfekt mening. Enhver skrifttype-relateret deklaration bliver samlet, top og bottom er genforenet, og at læse et regelsæt føles lidt ligesom at læse en kort historie. Men medmindre du holder til konventioner såsom Idiomatic CSS, så opstår der en masse plads til fortolkning ved denne måde. Hvor bør white-space være: font eller display? Hvor hører overflow til helt præcist? Hvad er rækkefølgen for egenskaber i en gruppe (det kunne være alfabetisk, ironisk nok)?

.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

Der findes også en helt anden, interessant underart af type-sortering kaldet Concentric CSS, der virker til også at være ret populær. Grundlæggende, så læner Concentric CSS sig op ad box-modellen for at definere en rækkefølge: den starter udefra og bevæger sig indad.

.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

For at tale for mig selv, så kan jeg ikke beslutte mig. En nylig afstemning på recent poll on CSS-Tricks konkluderede, at over 45% af udviklerne arrangerer deres deklarationer efter type imod 14%, der gør det alfabetisk. Dertil, så går 39% fuldstændig tilfældig til værks, inklusiv mig selv.

Diagram der viser hvordan udviklere arrangerer deres CSS deklarationer
Diagram der viser hvordan udviklere arrangerer deres CSS deklarationer

På grund af det, så vil jeg ikke pålægge dig et valg i denne styleguide. Vælg den tilgang du foretrækker, så længe du er konsistent gennem dine stylesheets (ikke den tilfældige tilgang, for eksempel).

Et nyligt studie viser at ved at anvende CSS Comb (der anvender type-arrangering til sortering af CSS deklarationer, så afkortes gennemsnitsfilen under Gzip kompression med 2.7%, sammenligned med 1.3% når der sorteres alfabetisk.

Videre læsning:

Indlejring af selektorer

En særlig funktionalitet som Sass giver, der bliver misbrugt alt for meget af mange udviklere er indlejring af selektorer. Indlejring af selektorer giver stylesheet forfattere en måde at beregne lange selektorer ved at indlejre kortere selektorer inde i hinanden.

Generel regel

For eksempel, så vil den følgende Sass indlejring:

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

… generere denne CSS:

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

På samme måde er det siden Sass 3.3 muligt at anvende den nuværende selektor-reference (&) til at generere avancerede selektorer. For eksempel:

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

… vil generere denne CSS:

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

Denne metode anvendes ofte sammen med navnekonventionerne for BEM ti at generere .block__element og .block--modifier selektorer, baseret på den oprindelige selektor (f. eks. .block i dette tilfælde).

Selvom det måske er anekdotisk, så når nye selektorer genereres fra den nuværende selektor-reference (&), så gør dét disse selektorer usøgbare i kodebasen, da egentlig ikke længere eksisterer.

Problemet med indlejring af selektorer er at det i sidste ende gør koden sværere at læse. Man skal mentalt beregne den endelige selektor ud fra indenteringsniveauer; det er derfor ikke altid særlig åbenlyst hvad CSS’en vil ende ud som.

Dette udsagn bliver mere sandt efterhånden som selektorer og referencer til den nuværende selektor (&) bliver hyppigere. På dette tidspunkt bliver risikoen for at miste overblikket, og at være ude af stand til at forstå hvad der sker, så høj at det ikke er dét værd.

For at undgå en sådan situation, så undgår vi indlejring af selektorer så meget som muligt. Dog er der åbenlyst nogle få undtagelser til denne regel.

Undtagelser

Til at starte med, så er det tilladt og endda anbefalet at indlejre pseudo-klasser og pseudo-elementer inden i den indledende selektor.

.foo {
  color: red;

  &:hover {
    color: green;
  }

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

  &:hover
    color: green

  &::before
    content: 'pseudo-element'

At anvende selektor-indlejring til pseudo-klasser og pseudo-elementer giver ikke alene mening (fordi det håndterer tæt relaterede selektorer), det hjælper også med at holde alt omkring et komponent på det samme sted.

Dertil, så når komponent-agnostiske tilstandsklasser såsom .is-active anvendes, så er det helt i orden at indlejre det under komponentets selektor for at holde tingene pæne.

.foo {
  // …

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

  &.is-active
    font-weight: bold

Sidst, men ikke mindst, så når et element styles fordi det eksisterer inden i et andet specifikt element, så er det også fint at bruge indlejring til at holde alt omkring komponentet på det samme sted.

.foo {
  // …

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

  .no-opacity &
    display: none

Når der arbejdes med uerfarne udviklere, så kan en selektor såsom .no-opacity & virke en anelse underlig. For at undgå enhver forvirring, så kan du bygge en meget kortfattet mixin, der transformerer denne underlige syntaks om til en eksplicit API.

/// Helper mixin to provide simple API to selector nesting
/// @param {String} $selector - Selector
@mixin when-inside($selector) {
  #{$selector} & {
    @content;
  }
}
/// Helper mixin to provide simple API to selector nesting
/// @param {String} $selector - Selector
=when-inside($selector) {
  #{$selector} &
    @content
}

Ved at genskrive vores tidligere eksempel, så vil det se ud som dette:

.foo {
  // …

  @include when-inside('.no-opacity') {
    display: none;
  }
}
.foo
  // …

  +when-inside('.no-opacity')
    display: none

Som med alting, så er det specifikke rimelig irrelevant, da det er konsistens der er det vigtige. Hvis du føler dig fuldstændig sikker på selektor-indlejring, så brug selektor-indlejring. Bare sikr dig, at hele dit team er med på det.

Videre læsning:

Konventioner for navngivelse

I denne sektion vil vi ikke behandle hvad de bedste CSS navgivningskonventioner er for vedligeholdelse og skalering; det er ikke alene op til dig, det er også uden for rammerne af en Sass styleguide. Jeg foreslår disse, anbefalet af CSS Guidelines.

Der er få ting du kan navngive i Sass, og det er vigtigt at navngive dem ordentligt så hele kodebasen både ser konsistent ud og er let at læse:

  • variabler;
  • funktioner;
  • mixins.

Sass-placeholdere er bevidst fjernet fra denne liste, siden de kan betragtes som almindelige CSS selektorer, hvilket følger de samme mønstre for navngivning som klasser.

Når det kommer til variabler, funktioner og mixins, så holder vi os til noget meget CSS-agtigt: små bogstaver og afgrænset med bindestreg, og først og fremmest meningsfuldt.

$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)
  // …

Videre læsning:

Konstanter

Hvis du tilfældigvis er en framework-udvikler eller biblioteksforfatter, så finder du muligvis dig selv i færd med at behandle variabler, der ikke er tiltænkt at blive opdateret under nogen omstændigheder: konstanter. Desværre (eller heldigvis?), så giver Sass ikke nogen måde at definere denne slags enheder på, så vi er nødt til at holde os til strikse navngivningskonventioner for at slå vores pointe fast.

Som ved mange sprog, så anbefaler jeg variabelnavne i store bogstaver, med underscore som mellemrum når de er konstanter. Det er ikke blot en meget gammel konvention, men det giver også en god kontrast til de sædvanlige “små bogstaver med bindestreger som mellemrum”-variabler.

// 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)

Videre læsning:

Namespace

Hvis du har til hensigt at distribuere din Sass kode, i tilfældet af et bibliotek, et framework, et gittersystem eller hvadend det kunne være, så bør du muligvis overveje at namespace alle dine variabler, funktioner, mixins og placeholdere så de ikke kolliderer med nogen andens kode.

For eksempel, hvis du arbejder på et Sassy Unicorn projekt, der er tænkt som at blive brugt af udviklere over hele verden (hvem ville ikke det, ikk?), så kunne du overveje at bruge su- som et namespace. Det er specifikt nok til at forebygge enhver navnekollision og er kort nok til at ikke at være træls at skrive.

$su-configuration: (  );

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

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

Bemærk, at automatisk namespacing absolut er et designmål for den kommende @import opdatering fra Sass 4.0. Efterhånden som det kommer tættere på at være realitet, så vil det blive mindre og mindre brugbart at foretage manuel namespacing; efterhånden vil manuelt namespacede biblioteker muligvis blive sværere at bruge.

Videre læsning:

Kommentering

CSS er et udfordrende sprog, fyldt med hacks og mærkværdigheder. På grund af det, så bør det blive kraftigt kommenteret, især hvis du eller andre har til hensigt at læse eller opdatere koden 6 måneder, eller 1 år, fra nu. Lad ikke dig selv eller andre komme i en situation af Jeg-har-ikke-skrevet-det-her-åh-gud-hvorfor.

Så simpelt som CSS kan blive, så er der stadig masser af plads til kommentarer. Disse kunne forklare:

  • strukturen af/eller rollen af en fil;
  • målet med et regelsæt;
  • idéen bag et magisk tal;
  • begrundelsen for en CSS deklaration;
  • rækkefølgen af CSS deklarationer;
  • tankeprocessen bag måde at gøre ting på;

Og jeg glemte sikkert en masse andre grunde. Kommentering tager meget lidt tid når det gøres samtidig med koden, så gør det på det rigtige tidspunkt. At vende tilbage til et stykke kode for at kommentere det er ikke blot urealistisk, men også ekstremt irriterende.

At skrive kommentarer

Ideelt set, så bør alle CSS regelsæt foranstilles med en C-stil kommentar, der forklarer grunden bag CSS-blokken. Denne kommentar indeholder nummererede forklaringer, der vedrører specifikke dele af regelsættet. For eksempel:

/**
 * Helper class to truncate and add ellipsis to a string too long for it to fit
 * on a single line.
 * 1. Prevent content from wrapping, forcing it on a single line.
 * 2. Add ellipsis at the end of the line.
 */
.ellipsis {
  white-space: nowrap; /* 1 */
  text-overflow: ellipsis; /* 2 */
  overflow: hidden;
}
/**
 * Helper class to truncate and add ellipsis to a string too long for it to fit
 * on a single line.
 * 1. Prevent content from wrapping, forcing it on a single line.
 * 2. Add ellipsis at the end of the line.
 */
.ellipsis
  white-space: nowrap /* 1 */
  text-overflow: ellipsis /* 2 */
  overflow: hidden

Alt, der basalt set ikke er åbenlyst ved første øjekast, bør blive kommenteret. Der er ikke noget der hedder for meget dokumentation. Husk, at du kan ikke kommentere for meget, så kom i gang og skriv kommentarer til alt der gør sig fortjent til det.

Når du kommenterer en Sass-specifik sektion, så anvend indlejrede Sass-kommentarer i stedet for en C-stil blok. Dette gør kommentaren usynlig for outputtet, selv ved udvidet tilstand under udvikling.

// Add current module to the list of imported modules.
// `!global` flag is required so it actually updates the global variable.
$imported-modules: append($imported-modules, $module) !global;
// Add current module to the list of imported modules.
// `!global` flag is required so it actually updates the global variable.
$imported-modules: append($imported-modules, $module) !global

Videre læsning:

Dokumentation

Hver variabel, funktion, mixin og placeholder, der har til hensigt at blive genbrugt igennem hele kodebasen, bør dokumenteres som en del af den globale API ved at anvende SassDoc.

/// Vertical rhythm baseline used all over the code base.
/// @type Length
$vertical-rhythm-baseline: 1.5rem;
/// Vertical rhythm baseline used all over the code base.
/// @type Length
$vertical-rhythm-baseline: 1.5rem

Tre skråstreger (/) påkrævet.

SassDoc har to overordnede roller:

  • at tvinge standardiserede kommentarer ved anvendelse af et annotations-baseret system til alt der er en del af en offentlig eller privat API;
  • at være i stand til at generere en HTML version af API-dokumentationen ved hjælp af SassDoc endpoints (CLI værktøjer, Grunt, Gulp, Broccoli, Node…)
Dokumentation genereret af SassDoc
Dokumentation genereret af SassDoc

Her er et eksempel af en mixin, der er omfattende dokumenteret med SassDoc:

/// Mixin helping defining both `width` and `height` simultaneously.
///
/// @author Kitty Giraudel
///
/// @access public
///
/// @param {Length} $width - Element’s `width`
/// @param {Length} $height [$width] - Element’s `height`
///
/// @example scss - Usage
///   .foo {
///     @include size(10em);
///   }
///
///   .bar {
///     @include size(100%, 10em);
///   }
///
/// @example css - CSS output
///   .foo {
///     width: 10em;
///     height: 10em;
///   }
///
///   .bar {
///     width: 100%;
///     height: 10em;
///   }
@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}
/// Mixin helping defining both `width` and `height` simultaneously.
///
/// @author Kitty Giraudel
///
/// @access public
///
/// @param {Length} $width - Element’s `width`
/// @param {Length} $height ($width) - Element’s `height`
///
/// @example scss - Usage
///   .foo
///     +size(10em)
///
///   .bar
///     +size(100%, 10em)
///
/// @example css - CSS output
///   .foo {
///     width: 10em;
///     height: 10em;
///   }
///
///   .bar {
///     width: 100%;
///     height: 10em;
///   }
=size($width, $height: $width)
  width: $width
  height: $height

Videre læsning:

Arkitektur

At konstruere et CSS projekt er højest sandsynlig noget af det sværeste du kommer til at lave i et projekts levetid. At holde arkitekturen konsistent og meningsfuld er endnu sværere.

Heldigvis er en af hovedfordelene ved at have en CSS preprocessor evnen til at kunne splitte kodebasen i flere filer, uden at det påvirker performance (som @import CSS-direktivet ville gøre). Takket være Sass’ overload af @import direktivet, så er det fuldstændig sikkert (og faktisk anbefalet) at bruge så mange filer som nødvendigt i udvikling, og derefter samle alle i ét enkelt stylesheet når man går i produktion.

Oven på det, så kan jeg ikke udtrykke nødvendigheden for mapper nok, selv ved mindre projekter. Du smider ikke alle dine papirark i den samme kasse derhjemme. Du bruger mapper; en til huset/lejligheden, en til banken, en til regningerne og så videre. Der er ingen grund til ikke at strukturere et CSS projekt på samme måde. Split kodebasen i meningsfulde mapper, så det er nemt at finde tingene senere når du er nødt til at vende tilbage til koden.

Der er mange populære arkitekturer for CSS-projekter: OOCSS, Atomic Design, Bootstrap-lignende, Foundation-lignende… De har alle deres meritter, fordele og ulemper.

Jeg selv bruger en tilgang der har vist sig at være meget lig SMACSS fra Jonathan Snook, der fokuserer på at holde tingene simple og åbenlyse.

Jeg har lært at arkitetur, for det meste, er meget specifik til projektet. Det står dig frit for helt at afskrive eller tilpasse løsningsforslaget, så du står med et system der dækker dine behov.

Videre læsning:

Komponenter

Der er en kæmpe forskel mellem at få noget til at virke, og at få noget til at blive godt. Igen, så er CSS et ret rodet sprog [citation mangler]. Jo mindre CSS vi har, jo bedre. Vi ønsker ikke at håndtere megabytes af CSS-kode. For at holde dine stylesheets korte og effektive—og det her vil ikke komme som en overraskelse for dig—så det er tit en god idé at tænke på et interface som en samling af komponenter.

Komponenter kan være hvad som helst, så længe de:

  • gør én ting, og kun én ting;
  • er genbrugelige og genbrugt på tværs af projektet;
  • er uafhængige.

For eksempel bør en søgeformular behandles som et komponent. Det bør være genbrugeligt ved forskellige positioner, på forskellige sider og i forskellige situationer. Den bør ikke være afhængig af dens position i DOM’en (footer, sidebar, hovedindhold…).

Størstedelen af ethvert interface kan tænkes som små komponenter, og jeg anbefaler kraftigt at du holder dig til dette paradigme. Det vil ikke kun forkorte mængden af CSS der skal bruges til hele projektet, men det gør det også meget nemmere at håndtere end et kaotisk rod, hvor alting flyder rundt.

7-1 Mønstret

Lad os vende tilbage til arkitektur. Jeg arbejder typisk med hvad jeg kalder 7-1 mønstret: 7 mapper, 1 fil. Basalt set, så har du alle dine partials pakket ned i 7 forskellige mapper, og en enkelt fil på rod-niveauet (oftest kaldet main.scss) der importerer dem alle til at blive kompileret til ét CSS stylesheet.

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

Og selvfølgelig:

  • main.scss
Baggrund af Julien He
Baggrund af Julien He

Ideelt set, så kan vi ende med noget som dette:

sass/
|
| abstracts/
|   | _variables.scss    # Sass Variables
|   | _functions.scss    # Sass Functions
|   | _mixins.scss       # Sass Mixins
|   | _placeholders.scss # Sass Placeholders
|
| base/
|   | _reset.scss        # Reset/normalize
|   | _typography.scss   # Typography rules
|                        # Etc.
|
| components/
|   | _buttons.scss      # Buttons
|   | _carousel.scss     # Carousel
|   | _cover.scss        # Cover
|   | _dropdown.scss     # Dropdown
|                        # Etc.
|
| layout/
|   | _navigation.scss   # Navigation
|   | _grid.scss         # Grid system
|   | _header.scss       # Header
|   | _footer.scss       # Footer
|   | _sidebar.scss      # Sidebar
|   | _forms.scss        # Forms
|                        # Etc.
|
| pages/
|   | _home.scss         # Home specific styles
|   | _contact.scss      # Contact specific styles
|                        # Etc.
|
| themes/
|   | _theme.scss        # Default theme
|   | _admin.scss        # Admin theme
|                        # Etc.
|
| vendors/
|   | _bootstrap.scss    # Bootstrap
|   | _jquery-ui.scss    # jQuery UI
|                        # Etc.
|
`– main.scss              # Main Sass file

Filer følger de samme konventioner for navngivelse beskrevet ovenfor: afgrænset med en bindestreg.

Base mappen

base/ mappen holder på alt hvad vi kan kalde boilerplate-kode for projektet. Derinde finder du typisk reset-filen, nogle typografiske regler, og højest sandsynlig et stylesheet (som jeg er vant til at kalde _base.scss), der definerer nogle standard styles for de oftest anvendte HTML-elementer.

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

Layout mappen

layout/ mappen indeholder alt der omhandler layoutet af siden eller applikationen. Denne mappe kan have stylesheets for hoveddelene af siden (header, footer, navigation, sidebar…), gitter-systemet eller endda CSS styles for alle formularerne.

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

Layout/ mappen kan også kaldes partials/, afhængigt af hvad du foretrækker.

Components mappen

Til mindre komponenter er der components/ mappen. Mens layout/ er makro (der definerer den globale wireframe), så fokuserer components/ mere på widgets. Den indeholder alle slags specifikke moduler såsom en slider, en loader, et widget og basalt set alt derimellem. Der er ofte en masse filer i components/, da hele siden/applikationen stort set bør bestå hovedsageligt af bittesmå moduler.

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

Components/ mappen kan også kaldes modules/, afhængigt af hvad du foretrækker.

Pages mappen

Hvis du har side-specifikke styles, så er det bedre at have dem i en pages/ mappe, i en fil der er navngivet efter siden. For eksempel, så er det ikke unormalt at have meget specifikke styles for forsiden og derfor vil der være et behov for en _home.scss fil i pages/.

  • _home.scss
  • _contact.scss

Afhængigt af din implementeringsproces, så kan disse filer også blive kaldt enkeltvis, for at undgå at de bliver merged med andre i det samlede stylesheet. Det er helt op til dig.

Themes mappen

Ved store sider og applikationer, så er det ikke unormalt at have forskellige temaer. Der er absolut forskellige måder at håndtere temaer, men personligt foretrækker jeg at have dem alle samlet i en themes/ mappe.

  • _theme.scss
  • _admin.scss

Denne er meget projekt-specifik, og er ofte ikke-eksisterende i mange projekter.

Utils mappen

utils/ mappen samler alle de Sass værktøjer og hjælpere, der anvendes på tværs af projektet. Enhver global variabel, funktion, mixin og placeholder bør puttes herind.

Tommelfingerreglen for denne mappe er, at den ikke bør outputte en enkelt linje CSS når den kompileres for sig selv. De er intet andet end Sass hjælpere.

  • _variables.scss
  • _mixins.scss
  • _functions.scss
  • _placeholders.scss (oftest navngivet _helpers.scss)

Utils/ mappen kan også kaldes helpers/, sass-helpers/ eller sass-utils/, afhængigt af hvad du foretrækker.

Vendors mappen

Og sidst, men ikke mindst, så vil de fleste projekter have en vendors/ mappe der indeholder alle CSS filerne fra eksterne biblioteker og frameworks - Normalize, Bootstrap, jQueryUI, FancyCarouselSliderjQueryPowered, og så videre. At putte dem til side i den samme mappe er en god måde at sige “Hey, det her er ikke fra mig, ikke min kode, ikke mit ansvar”.

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

Hvis du er nødt til at overskrive en sektion fra en udbyder, anbefaler jeg at du har en ottende mappe kaldet vendors-extensions/, hvori du kan have filer der er navngivet præcist efter de udbydere du overskriver.

For eksempel, vendors-extensions/_bootstrap.scss er en fil der indeholder alle de CSS regler, der har til hensigt at redeklarere noget af Bootstraps originale CSS. Det er for at undgå at redigere i selve udbyderfilerne, hvilket generelt ikke er en god idé.

Main filen

Main filen (oftest navngivet main.scss) bør være den eneste Sass fil i hele kodebasen, der ikke starter med et underscore. Denne fil bør ikke indeholde andet end @import og kommentarer.

Filer bør blive importeret i forhold til den mappe de lever i, én efter én, i følgende rækkefølge:

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

For at bevare læsbarheden, bør main filen respektere følgende retningslinjer:

  • en fil per @import;
  • en @import per linje;
  • ingen ny linje mellem to imports fra samme mappe;
  • en ny linje efter den sidste import fra en mappe;
  • filtyper og ledende underscores udeladt.
@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

Der er en anden måde at importerer partials, som jeg også anser som værende i orden. På den lyse side, så gør det filen mere læsbar. På den anden side, så gør dét det mere smertefuldt at opdatere. Under alle omstændigheder, så vil jeg lade dig om at beslutte hvad der er bedst, da det ikke betyder særlig meget. For denne måde, bør main filen respektere følgende guidelines:

  • en @import per mappe;
  • et linjeskift efter @import;
  • en fil på sin egen linje;
  • en ny linje efter den sidste import fra en mappe;
  • filtyper og ledende underscores udeladt.
@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

For ikke at skulle importere hver fil manuelt, så findes der en udvidelse til Ruby Sass kaldet sass-globbing, der gør det muligt at anvende glob-mønstre i Sass @import som eksempelvis @import "components/*".

Med det sagt, så vil jeg ikke anbefale det fordi den importerer filerne i alfabetisk rækkefølge, hvilket typisk ikke er hvad du ønsker, især når du arbejder med et sprog der er afhængigt af en særlig kilde-rækkefølge.

Shame filen

Der findes et interessant koncept, der allerede er blevet gjort populært af Harry Roberts, Dave Rupert og Chris Coyier, hvilket involverer at alle CSS-deklarationer, hacks og ting vi ikke er stolte af, bliver smidt i en shame fil. Denne fil, med den dramatiske titel _shame.scss, bliver så importeret efter alle andre filer, til sidst i stylesheetet.

/**
 * Nav specificity fix.
 *
 * Someone used an ID in the header code (`#header a {}`) which trumps the
 * nav selectors (`.site-nav a {}`). Use !important to override it until I
 * have time to refactor the header stuff.
 */
.site-nav a {
    color: #BADA55 !important;
}
/**
 * Nav specificity fix.
 *
 * Someone used an ID in the header code (`#header a {}`) which trumps the
 * nav selectors (`.site-nav a {}`). Use !important to override it until I
 * have time to refactor the header stuff.
 */
.site-nav a
    color: #BADA55 !important

Videre læsning:

Responsivt Web Design og breakpoints

Jeg tror ikke at vi stadig behøver at introducere Responsivt Web Design, nu hvor det er overalt. Dog spørger du muligvis dig selv hvorfor er der en sektion omkring RWD i en Sass styleguide? Rent faktisk er der en del ting som kan gøres, for at gøre arbejdet med breakpoints nemmere, så jeg tænkte at det ikke ville være en dårlig idé at liste dem her.

Jeg tænker at det er sikkert at sige, at media queries ikke bør være forbundet til specifikke enheder. For eksempel, så er det klart en dårlig idé at forsøge at ramme iPads og Blackberry telefoner alene. Media queries bør tage sig af en række af skærmstørrelser indtil designet bryder sammen, hvorefter den næste media query tager over.

Af de samme grunde, så bør breakpoints ikke blive navngivet efter enheder men efter noget mere generelt. Især fordi at nogle telefoner nu er større end tablets, nogle tablets større en nogle små skærmcomputere, og så videre…

// 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))

Hertil vil enhver navngivningskonvention, der gør det krystalklart at et design ikke er tæt forbundet til en specifik enhedstype, gøre arbejdet godt så længe det giver en slags fornemmelse for størrelsesorden.

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

De forrige eksempler anvender indlejrede maps til at definere breakpoints, men dette afhænger faktisk af hvilken slags breakpoint-manager du anvender. Du kunne gå efter strenge fremfor indre maps for mere fleksibilitet (e.g. '(min-width: 800px)').

Videre læsning:

Breakpoint manager

Når du har navngivet dine breakpoints som du ønsker, så har du brug for en måde til rent faktisk at bruge dem i egentlige media queries. Der findes rigeligt med måder at gøre dette på, men jeg må sige at jeg er stor fan af et breakpoint map, der læses af en getter funktion. Denne tilgang er både enkel og effektiv.

/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @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 'No value found for `#{$breakpoint}`. '
         + 'Please make sure it is defined in `$breakpoints` map.';
  }
}
/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @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 'No value found for `#{$breakpoint}`. '
         + 'Please make sure it is defined in `$breakpoints` map.'

Det er åbenlyst, at dette er en rimelig simpel breakpoint manager. Hvis du har behov for en mere eftergivende en, så anbefaler jeg at du ikke genopfinder hjulet og bruger noget som er bevist effektivt, såsom Sass-MQ, Breakpoint eller include-media.

Videre læsning:

Brug af Media Queries

For ikke så længe siden var der en ret ophedet debat omkring hvorhenne media queries bør blive skrevet: hører de til indeni selektorer (som Sass tillader det), eller skal de være helt afkoblet fra dem? Jeg bliver nødt til at sige, at jeg er en stærk forsvarer af media-queries-indeni-selektorer-tilgangen, da jeg synes at det spiller godt sammen med idéen om komponenter.

.foo {
  color: red;

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

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

Hvilket leder til det følgende CSS output:

.foo {
  color: red;
}

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

Du har muligvis hørt at denne konvention resulterer i duplikerede media queries i CSS-outputtet. Det er helt klart sandt. Dog, så er der blevet foretaget tests og det sidste ord i denne diskussion er, at det ikke betyder noget så snart Gzip (eller lignende) har gjort sit arbejde:

… vi undersøgte hvorvidt der var performance-påvirkninger ved kombinering vs spredning af Media Queries, og kom frem til konklusionen at forskellen, selvom den er grim, er minimal når den er værst, og grundlæggende ikke-eksisterende når den er bedst.
Sam Richards, vedrørende Breakpoint

Så hvis du virkelig er bekymret for duplikerede media queries, så kan du stadig bruge et værktøj til at forene dem, såsom denne gem, dog føler jeg at jeg bliver nødt til at advare dig om de mulige bivirkninger af at flytte CSS kode rundt. Du ved allerede, at kildekodens rækkefølge er vigtig.

Videre læsning:

Variabler

Variabler er essencen af ethvert programmeringssprog. De tillader os at genbruge værdier uden at være nødsaget til at kopiere dem igen og igen. Vigtigst er dog at de gør opdateringen af en værdi meget nem. Slut med søg og erstat, eller manuel gennemgang.

Dog er CSS intet andet end en kæmpe kurv, der indeholder alle vores æg. Modsat mange sprog, så er der ikke nogen egentlige scopes i CSS. På grund af det er vi nødt til at holde særligt øje, når vi tilføjer variabler med risiko for at opleve konflikter.

Mit råd vil være, kun at oprette variabler når det giver mening. Lad være med at initialisere nye variabler bare fordi du kan, da det ikke vil hjælpe. En ny variabel bør kun blive skabt når alle følgende kriterier er mødt:

  • værdien bliver gentaget mindst to gange;
  • værdien vil sandsynligvis blive opdateret mere end én gang;
  • alle tilfælde af værdien er forbundet til variablen (f. eks. ikke ved et tilfælde);

Basalt set, er der ikke nogen grund til at deklarere en variabel der aldrig vil blive opdateret eller kun anvendes et enkelt sted.

Scoping

Variabel-scoping i Sass har ændret sig med årene. Indtil for nylig har variabel-deklarationer inden for regelsæt og andre scopes været lokale, som udgangspunkt. Dog, når der allerede var en global variabel med det samme navn, så ændrede den lokale anvisning den globale variabel. Siden version 3.4, har Sass tacklet konceptet af scopes korrekt, og skaber en ny lokal variabel i stedet.

Dokumentationen taler om overskygning af globale variabler. Når en variabel, der allerede eksisterer i det globale scope, deklareres i et indre scope (selektor, funktion, mixin…), så siger man at den lokale variable overskygger den globale. Basalt set, så overskriver den kun for det lokale scope.

Følgende kodestykke forklarer konceptet bag overskygning af variabler.

// Initialize a global variable at root level.
$variable: 'initial value';

// Create a mixin that overrides that global variable.
@mixin global-variable-overriding {
  $variable: 'mixin value' !global;
}

.local-scope::before {
  // Create a local variable that shadows the global one.
  $variable: 'local value';

  // Include the mixin: it overrides the global variable.
  @include global-variable-overriding;

  // Print the variable’s value.
  // It is the **local** one, since it shadows the global one.
  content: $variable;
}

// Print the variable in another selector that does no shadowing.
// It is the **global** one, as expected.
.other-local-scope::before {
  content: $variable;
}
// Initialize a global variable at root level.
$variable: 'initial value'

// Create a mixin that overrides that global variable.
@mixin global-variable-overriding
  $variable: 'mixin value' !global

.local-scope::before
  // Create a local variable that shadows the global one.
  $variable: 'local value'

  // Include the mixin: it overrides the global variable.
  +global-variable-overriding

  // Print the variable’s value.
  // It is the **local** one, since it shadows the global one.
  content: $variable

// Print the variable in another selector that does no shadowing.
// It is the **global** one, as expected.
.other-local-scope::before
  content: $variable

!default flaget

Når du bygger et bibliotek, et framework, et gittersystem, eller ethvert andet stykke Sass der er tiltænkt at blive distribueret og anvendt af eksterne udviklere, bør alle konfigurations-variabler være defineret med !default flaget, så de kan blive overskrevet.

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

Takket være dette, så kan en udvikler definere hans egen $baseline variabel før han importerer dit bibliotek, uden at se hans værdi blive redefineret.

// Developer’s own variable
$baseline: 2em;

// Your library declaring `$baseline`
@import 'your-library';

// $baseline == 2em;
// Developer’s own variable
$baseline: 2em

// Your library declaring `$baseline`
@import your-library

// $baseline == 2em

!global flaget

!global flaget bør kun anvendes når en global variabel fra et lokalt scope overskrives. Når en variabel på root-niveauet defineres, bør !global flaget udelades.

// Yep
$baseline: 2em;

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

// Nope
$baseline: 2em !global

Flere variabler eller maps

Der er fordele ved at bruge maps frem for flere, særskilte variabler. Den primære er evnen til at iterere over et map, hvilket ikke er muligt med enkeltstående variabler.

En anden fordel ved at bruge et map er evnen til at skabe en lille getter-funktion der giver en lettere tilgængelig API. For eksempel, overvej følgende Sass kode:

/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: (
  'modal': 5000,
  'dropdown': 4000,
  'default': 1,
  'below': -1,
);

/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer’s name
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
  @return map-get($z-indexes, $layer);
}
/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)

/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer’s name
/// @return {Number}
/// @require $z-indexes
@function z($layer)
  @return map-get($z-indexes, $layer)

Extend

@extend direktivet er en af de funktionaliteter der har gjort Sass så populært for et par år siden. Som en påmindelse, så er det muligt at fortælle Sass at det skal style element A præcis som hvis det også matchede selektor B. Det er derfor unnødvendigt at sige, at det kan ende med at blive en ret værdifuld allieret når der skal skrives modulært CSS.

Når der er sagt, så føler jeg, at jeg bør advare dig imod denne funktionalitet. Selvom den er smart, så er @extend stadig et ret udfordrende koncept, der kan gøre mere skade end gavn, især hvis anvendt forkert. Sagen er den, at når en selektor udvides, så har du lidt til ingen måde at at svare på disse spørgsmål uden at have dyb kendskab til hele kodebasen:

  • hvor vil min nuværende selektor blive tilføjet?
  • er der sandsynlighed for at jeg skaber uønskede bivirkninger?
  • hvor stor er den genererede CSS, der skabes af denne enkelte extend?

Ud fra hvad du ved, så kunne resultatet variere fra at gøre ingenting til at forårsage katastrofale bivirkninger. Derfor er mit første råd helt at undgå @extend-direktivet. Det lyder måske brutalt, men når alt kommer til alt, så kan det redde dig fra et par hovedpiner og problemer.

Med det sagt, så kender du ordsproget:

Aldrig sig aldrig.
— Tilsyneladende, ikke Beyonce.

Der er scenarier, hvor at udvide selektorer kan være hjælpsomt og tiden værd. Hav dog altid disse regler for øje, så du ikke kommer i problemer:

  • Brug extend inden i et modul, ikke på tværs af forskellige moduler.
  • Brug extend udelukkende på placeholdere, ikke på egentlige selektorer.
  • Vær sikker på at placeholderen, du udvider, er så lidt til stede som muligt i stylesheetet.

Hvis du skal til at anvende extend, så lad mig minde dig om at den ikke fungerer godt sammen med @media blokke. Som du muligvis ved, så er Sass ikke i stand til at udvide en ydre selektor inden i en media query. Når du gør det, så bryder compileren simpelthen ned, og fortæller dig at du ikke kan gøre sådan. Ikke så fedt. Især da media queries nu næsten er alt hvad vi laver.

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

  // Relationship: a %button that is a child of a %modal
  %modal > & {
    display: block;
  }
}

.button {
  @extend %button;
}

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

// Nope
.modal {
  @extend %modal;

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

  // Relationship: a %button that is a child of a %modal
  %modal > &
    display: block

.button
  @extend %button

// Yep
.modal
  @extend %modal

// Nope
.modal
  @extend %modal

  > .button
    @extend %button

Du bør ikke @extend’e en ydre selektor indefra @media.
Du bør kun @extend’e selektorer inden for det samme direktiv.

Ofte siges det, at @extend hjælper med filstørrelsen, siden den kombinerer selektorer fremfor at duplikere egenskaber. Det er sandt, dog er forskellen minimal når først Gzip er færdig med sin kompression.

Når det er sagt, så hvis du ikke kan bruge Gzip (eller noget lignende), så kan det at skifte til en @extend tilgang muligvis ikke være så slem når du ved hvad du laver.

For at opsummere, så vil jeg anbefale imod brugen af @extend direktivet, medmindre under særlige omstændigheder, men jeg vil ikke gå så langt som at forbyde det.

Videre læsning:

Mixins

Mixins er en af de mest anvendte funktionaliteter fra hele Sass sproget. De er nøglen til genbrugelighed og DRY komponenter. Og af en god grund: mixins tillader forfattere at definere styles der kan genbruges igennem stylesheetet uden at skulle tøve til ikke-semantiske klasser såsom .float-left.

De kan indeholde hele CSS-regler og faktisk alt hvad der er tilladt overalt i et Sass dokument. De kan endda tage argumenter, præcis som funktioner. Det er unnødvendigt at sige, at mulighederne er uendelige.

Men jeg føler, at jeg må advare dig imod at misbruge magten ved mixins. Igen, simplicitet er nøgleordet her. Det kan være fristende at bygge ekstremt kraftulde mixins med massive mængder logik. Dette er at overkomplicere tingene, og de fleste udviklere lider af det. Lad være med at overtænke din kode, og hold den først og fremmest simpel. Hvis en mixin ender med at være mere end 20 linjer eller deromkring, så bør den enten blive splittet op i mindre stykker eller blive fuldstændig revideret.

Det grundlæggende

Med det på plads, så er mixins ekstremt brugbare og du bør bruge et par stykker. Tommelfingerreglen er, at hvis det hænder for dig at du opdager en gruppe CSS egenskaber, der altid opstår som værende sammen af en grund (og ikke af tilfældighed), så kan du putte dem i en mixin i stedet. Mikro-clearfix hacket fra Nicolas Gallagher fortjener at blive puttet i en (argumentløs) mixin, for eksempel.

/// Helper to clear inner floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix {
  &::after {
    content: '';
    display: table;
    clear: both;
  }
}
/// Helper to clear inner floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix
  &::after
    content: ''
    display: table
    clear: both

Et andet validt eksempel ville være en mixin til at definere størrelsen på et element, der definerer både width og height på samme tid. Ikke alene vil det gøre koden meget lettere at skrive, men også nemmere at læse.

/// Helper to size an element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}
/// Helper to size an element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
=size($width, $height: $width)
  width: $width
  height: $height

Videre læsning:

Argumentliste

Når du står overfor et ukendt antal af argumenter i en mixin, så brug altid en arglist fremfor en liste. Tænk på arglist som den 8. skjulte, udokumenterede datatype fra Sass der anvendes implicit når et arbitrært antal af argumenter bliver videregivet til en mixin eller en funktion, hvis signatur indeholder ....

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

Når du bygger en mixin, der accepterer en håndfuld argumenter (3 eller flere), så tænk to gange før du forener dem som en liste eller et map, i den tro at det vil være nemmere end at videregive dem alle en for en.

Sass er faktisk ret smart med mixins og funktions-deklarationer, så smart at du faktisk kan give den en liste eller et map som en arglist til en funktion/mixin, således at det bliver parset som en serie af argumenter.

@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...)

Videre læsning:

Mixins og vendor-præfikser

Det er fristende at definere skræddersyede mixins til at håndtere udbyder-præfikser for ikke-understøttede eller delvist understøttede CSS egenskaber. Men det ønsker vi ikke at gøre. Først og fremmest, hvis du kan bruge Autoprefixer, så brug Autoprefixer. Det vil fjerne Sass kode fra dit projekt, det vil altid være up-to-date og vil højest sandsynlig gøre et bedre arbejde med at præfikse ting end dig.

Desværre er Autoprefixer ikke altid en mulighed. Hvis du bruger enten Bourbon eller Compass, så ved du sikkert at de begge giver dig en samling af mixins der håndterer præfikser for dig. Brug disse.

Hvis du ikke kan bruge Autoprefixer og hverken kan bruge Bourbon eller Compass, så da, og kun da, kan du have dine egne mixins til at præfikse CSS egenskaber. Men. Lad venligst være med at bygge en mixin per enhed, der manuelt udskriver hver udbyder.

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

Gør det på den smarte måde.

/// Mixin helper to output vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Raw CSS value
/// @param {List} $prefixes - List of prefixes to output
@mixin prefix($property, $value, $prefixes: ()) {
  @each $prefix in $prefixes {
    -#{$prefix}-#{$property}: $value;
  }

  #{$property}: $value;
}
/// Mixin helper to output vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Raw CSS value
/// @param {List} $prefixes - List of prefixes to output
=prefix($property, $value, $prefixes: ())
  @each $prefix in $prefixes
    -#{$prefix}-#{$property}: $value

  #{$property}: $value

Derfra vil brugen af denne mixin være meget ligetil:

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

Hav venligst for øje, at dette er en ringe løsning. For eksempel kan den ikke håndtere komplekse polyfills som dem der kræves til Flexbox. I den situation vil Autoprefixer være et langt bedre valg.

Videre læsning:

Betingede udsagn

Du kender sikkert allerede til at Sass tilbyder betingede udsagn via @if og @else direktiverne. Medmindre du har rimelig kompleks logik i din kode, så er der ikke behov for betingede udsagn i dine hverdags-stylesheets. Faktisk, så eksisterer de hovedsageligt for biblioteker og frameworks.

Under alle omstændigheder, hvis du nogensinde finder behovet for dem, så respektér venligst følgende guidelines:

  • Ingen paranteser medmindre de er nødvendige;
  • Hav altid en ny, tom linje før @if;
  • Hav altid et linjeskift efter den åbnende klamme ({);
  • @else udsagn skal være på den samme linje som den forrige, lukkende klamme (}).
  • Hav altid en ny, tom linje efter den sidste, lukkende klamme (}), medmindre den næste linje er en lukkende klamme (}).
// Yep
@if $support-legacy {
  // …
} @else {
  // …
}

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

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

Når du tester en falsk værdi, skal du altid bruge not keywordet i stedet for at teste det imod false eller 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
  // …

Læg altid variabel-delen på den venstre side af et udsagn, og det (u)forventede resultat på den højre side. Omvendte betingede udsagn er ofte sværere at læse, især for uerfarne udviklere.

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

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

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

Når du anvender betingede udsagn inden for en funktion, for at returnere et forskelligt resultat baseret på nogle betingelser, så vær altid sikker på at funktionen stadig har et @return udsagn uden for enhver betinget 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

Løkker

Fordi Sass giver os komplekse datastrukturer såsom lister og maps, så er det ikke nogen overraskelse, at det også giver forfattere en måde at iterere over disse enheder.

Dog indebærer tilstedeværelsen af løkker ofte en moderat, kompleks logik, der sandsynligvis ikke hører til Sass. Før en løkke anvendes bør man sikre sig at den giver mening, og faktisk løser et problem.

Each

@each løkken er klart en af de mest anvendte af de tre løkker Sass tilbyder. Den giver os en ren API til at iterere over en liste eller et map.

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

Når der itereres over et map, så anvend altid $key og $value som variabelnavne for at fastholde konsistens.

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

Sikr dig også, at du respekterer disse guidelines for at bevare læsbarhed:

  • Hav altid en tom, ny linje før @each;
  • Hav altid en tom, ny linje efter den afsluttende klamme (}), medmindre den næste linje er en afsluttende klamme (}).

For

@for løkken er brugbar når den kombineres med CSS’ :nth-* pseudo-klasser. Bortset fra disse scenarier, så foretræk en @each løkke hvis du er nødt til at iterere over noget.

@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%)

Anvend altid $i som variabelnavn, for at holde dig til den almene konvention, og medmindre du har en virkelig god grund til det, så brug aldrig to nøgleordet: brug altid through. Mange udviklere ved slet ikke at Sass tilbyder denne variation; at anvende den kan lede til forvirring.

Vær også sikker på, at respektere disse guidelines for at bevare læsbarhed:

  • Hav altid en tom, ny linje før @for;
  • Hav altid en tom, ny linje efter den afsluttende klamme (}), medmindre den næste linje er en afsluttende klamme (}).

While

@while løkken har absolut ingen brugssituation i et virkeligt Sass-projekt, især da der ikke er nogen måde at bryde løkken indefra. Brug den ikke.

Advarsler og Fejl

Hvis der er en funktionalitet, der ofte bliver overset af Sass udviklere, så er det evnen til dynamisk at outputte advarsler og fejl. Rent faktisk, så har Sass tre særlige direktiver til udprintning af indhold i gængse output-systemer (CLI, kompileringsapps…):

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

Lad os se bort fra @debug, da den åbenlyst er tænkt til debugging af SassScript, hvilket ikke er vores pointe her. Tilbage står vi med @warn og @error, der er bemærkelsesværdigt identiske bortset fra at den ene stopper compileren, mens den anden ikke gør. Jeg lader dig gætte hvilken der gør hvad.

Der er masser af plads i et Sass projekt til advarsler og fejl. Basalt set forventer enhver mixin eller funktion, at en specifik type eller argument kunne give en fejl hvis noget går galt, eller vise en advarsel når man udfører en antagelse.

Videre læsning:

Advarsler

Tag, for eksempel, denne funktion fra Sass-MQ, der forsøger at konvertere en px til em:

@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

Hvis værdien viser sig at være enhedsløs, så vil funktionen antage at værdien er ment som at skulle være udtrykt i pixels. Herved kan en antagelse være risikabel for brugeren og bør blive advaret om, at softwaren gjorde noget der kunne opfattes som uventet.

Fejl

Fejl, modsat advarsler, forhindrer compileren i at fortsætte. De stopper basalt set kompilering og viser en besked i både output-strømmen og i stack-tracen, hvilket er brugbart til debugging. På grund af dette, bør fejl gives når der ikke er nogen anden måde for programmet at fortsætte. Hvis muligt bør du prøve at arbejde rundt om problemet og vise en advarsel i stedet.

For eksempel, lad os sige at du er ved at bygge en getter funktion, der tilgår værdier fra et specifikt map. Du kunne give en fejl, hvis den anmodede nøgle ikke eksisterer i map’et.

/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: (
  'modal': 5000,
  'dropdown': 4000,
  'default': 1,
  'below': -1,
);

/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer's name
/// @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-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer's name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)

/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer's name
/// @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)

Værktøjer

Dét der er rart ved en så populær CSS preprocessor som Sass er, at den kommer med et helt økosystem af frameworks, plugins, biblioteker og værktøjer. Efter 8 års eksistens er vi ved at komme tættere og tættere på et punkt hvor alt der kan skrives i Sass er blevet skrevet i Sass.

Mit råd er dog, at sænke antallet af dependencies til det absolut nødvendige. At håndtere dependencies er en form for helvede du ikke ønsker at være en del af. Plus, der er begrænset til intet behov for eksterne dependencies når det kommer til Sass.

Compass

Compass er det primære Sass framework derude. Udviklet af Chris Eppstein, en af hoved-designerne bag Sass, og jeg ser det ikke tabe popularitet dramatisk det næste stykke tid, hvis du spørger mig.

Når det er sagt, så bruger jeg ikke Compass mere. Hovedårsagen er, at det gør Sass meget langsommere. Ruby Sass er ret langsomt i sig selv, så at tilføje mere Ruby og mere Sass ovenpå hjælper ikke rigtigt.

Sagen er, at vi bruger meget lidt fra hele frameworket. Compass er enormt. Mixins til kryds-browser kompatibilitet er bare toppen af isbjerget. Matematik-funktioner, billede-hjælpere, spriting… Der er så meget der kan klares med dette fantastiske stykke software.

Desværre er det hele sukker, og der er ikke nogen overvældende funktioner inde i pakken. En undtagelse kan gøres med sprite-byggeren, som er virkelig god, men Grunticon og Grumpicon klarer også jobbet, og har fordelen af at kunne tages ind og ud af build-processen.

Under alle omstændigheder, så afviser jeg ikke brugen af Compass selvom jeg heller ikke vil anbefale det, især siden det ikke er kompatibel med LibSass (selv hvis der skulle blive gjort indsats i den retning). Hvis du føler dig mere tilpas ved at bruge det, fair nok, men jeg tror ikke du får meget ud af det når alt kommer til alt.

Ruby Sass er p.t. ved at gennemgå nogle ekstraordinære optimering, som er specifikt målrettet mod logik-tunge styles med mange funktioner og mixins. De skulle forbedre effektiviteten dramatisk til et punkt hvor Compass og andre frameworks muligvis ikke længere vil sløve Sass.

Videre læsning:

Gitter-systemer

At undlade at anvende et gitter-system er ikke længere en mulighed, nu hvor Responsivt Web Design er overalt. For at få designs til at se konsistente og solide ud på tværs af alle skærmstørrelser, anvender vi en eller anden form for gitter til at layoute elementer. For at undgå at skulle kode dette gitter igen og igen, så har nogle geniale folk gjort deres genbrugelige.

Lad mig gøre det helt klart: Jeg er ikke den store fan af gitter-systemer. Selvfølgelig ser jeg et potentiale, men mest ser jeg dem som at skyde gråspurve med kanoner, og anvendes for det meste til at tegne røde kolonner på en hvid baggrund i nørdede designeres præsentationer. Hvornår tænkte du sidst gudskelov-at-jeg-har-det-her-værktøj-til-at-bygge-2-5-3-1-π-gitre? Aldrig, det er rigtigt. Fordi i de fleste tilfælde, så ønsker du bare det almindelige 12-kolonne gitter-system og ikke noget fancy.

Hvis du anvender et CSS framework til dit projekt, såsom Bootstrap eller Foundation, så er der stor sandsynlighed for at det allerede inkluderer et gitter-system, som jeg i det tilfælde vil anbefale at du bruger så du undgår at skulle håndtere endnu en dependency.

Hvis du ikke er tilknyttet til et specifikt gitter-system, så vil det nok glæde dig at vide at der findes to top-kvalitets gitter-motorer baseret på Sass derude: Susy og Singularity. Begge gør meget mere end du nogensinde vil få brug for, så du kan vælge den af dem du foretrækker og være sikker på at alle dine særtilfælde —selv de mest specielle af slagsen— vil være dækket. Hvis du spørger mig, så har Susy en anelse bedre community, men det er min holdning.

Alternativt kan du gå over til noget mere nede på jorden, såsom csswizardry-grids. Når alt kommer til alt, vil dit valg ikke have den store indvirkning på din kodestil, så det er faktisk mest op til dig.

Videre læsning:

SCSS-lint

Kode-linting er meget vigtigt. Ved at følge retningslinjer fra en styleguide, vil mængden af kodekvalitetsfejl normalt blive reduceret, men ingen er perfekt, og der er altid ting der kan forbedres. Derfor kan man sige, at dét linte kode er lige så vigtigt som at kommentere den.

SCSS-lint er et værktøj, der hjælper dig med at holde dine SCSS filer rene og læsbare. Det er fuldt tilpasseligt og nemt at integrere med dine egne værktøjer.

Heldigvis er anbefalinger for SCSS-lint meget lig de der beskrives i dette dokument. For at konfigurere SCSS-lint i forhold til Sass Guidelines, så anbefaler jeg følgende setup:

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

Hvis du vil koble SCSS lint ind i din Grunt build proces, så bliver du nok glad for at vide at der er et Grunt plugin til netop dét kaldet grunt-scss-lint.

Dertil, så hvis du er på jagt efter et smart program der virker både med SCSS-lint og lignende, så arbejder folkene hos Thoughtbot (Bourbon, Neat…) på Hound.

Videre læsning:

Too Long; Didn’t read

For at opsummere, så ønsker vi:

  • Indentering á to (2) mellemrum, ingen tabs;
  • 80-karakter brede linjer;
  • Ordentligt skrevet CSS, i flere linjer;
  • Meningsfuld brug af whitespace;
  • Citerede strenge (enkelt-citationstegn) & URL’er;
  • Intet efterstillet 0, obligatorisk førende 0;
  • Udregninger indpakket i paranteser;
  • Ingen magiske tal;
  • Farver udtrykt i nøgleord > HSL > RGB > hexadecimal;
  • Lister separeret af kommaer;
  • Ingen efterstillede kommaer i lister (fordi de er inlinede)
  • Efterstillede kommaer i maps;
  • Ingen selektor-indlejring undtagen pseudo-klasser og pseudo-elementer;
  • Bindestreg-afgrænset navngivning;
  • Omfattende kommentarer;
  • SassDoc-drevne API kommentarer;
  • Begrænset brug af @extend;
  • Simple mixins;
  • Så få løkker som muligt, ingen @while;
  • Begrænset antal af dependencies;
  • Meningsfuld anvendelse af advarsler og fejl;
Tilbage til toppen