donuts.js
FIGHT!
FIGHT!
$box-model: border-box
html
box-sizing: $box-model
*, *::before, *::after
box-sizing: inherit
$box-model: border-box;
html {
box-sizing: $box-model;
}
*, *::before, *::after {
box-sizing: inherit;
}
Variables begin with $.
assignment is done like a CSS rule:
$variable-name: value;
A variable can be assigned any SASS type: string, number, bool, color, list, map or null.
SASS variables can have one of two scopes: selector level and global.
A variable defined within a selector is scoped to that selector only if there is not an existing global variable with the same name. If there is, the local assignment overrides the global value.
When naming variables, they should use the type as the block and the identifier as modifier.
Be descriptive in your names so you know what they mean.
Sometimes adding an additional layer of abstraction gives greater flexibility.
//Colors
//Named colors
$color--rebecca-purple: #663399;
$color--bad-green: #hsl(74, 64.2512%, 59.4118%);
//Color Purposes
$color--primary: $color--rebecca-purple;
$color--secondary: $color--bad-green;
Any variable that is not component specific should be in a vars.scss
Group your variables.
colors
typography
media queries
etc.
//vars.scss
//Colors
//Named colors
$color--rebecca-purple: #663399;
$color--bad-green: #hsl(74, 64.2512%, 59.4118%);
$color--black: hsl(0, 10%, 14%);
$color--white: hsl(0, 20%, 98%);
//Color Purposes
$color--primary: $color--rebecca-purple;
$color--secondary: $color--bad-green;
//Typography
$font--body: Helvetica, sans;
$font--title: Josephine, serif;
$text-size--title: 2.4em;
//Media Queries
$mq--small: only screen and (min-width: 42em);
$mq--med: only screen and (min-width: 47.5em);
$mq--large: only screen and (min-width: 56.25em);
import your component files into your main.scss
Why not sass-globbing?
node-sass does not support sass-globbing. The ruby requires a specific unmerged pull request.
//main.scss
@import 'vars';
@import 'functions';
@import 'mixins';
@import 'componentA';
@import 'componentB';
(those with weak constitutions may want to avert their eyes)
html {
body {
main {
article {
&::before {
content: "Sweet fancy musturd,
WHY! My eyes!
It hurts my EYES!";
}
&::after {
content: "Several kittens &
puppies died as a
result of writing
this example.";
}
}
}
}
}
html body main article::before {
content: "Sweet fancy mustard,
WHY! My eyes!
It hurts my EYES!";
}
html body main article::after {
content: "Many kittens and
puppies died as a
result of writing
this example.";
}
I told you we'd be going in depth ;)
The flatter the better, but as a rule, keep your nesting to a strict maximum depth of 3.
//BAD
.dialog {
max-width: 80vw;
max-height: 80vh;
.dialog__backdrop {
display: none;
&.dialog__backdrop--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
}
}
//Processed BAD
.dialog {
max-width: 80vw;
max-height: 80vh;
}
.dialog__backdrop {
display: none;
}
.dialog__backdrop.dialog__backdrop--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
Typically this means if you're writing BEM, you won't need any nesting at all.
//LESS BAD
$max-dialog-size: 80;
.dialog {
max-width: $max-dialog-size * 1vw;
max-width: $max-dialog-size * 1vh;
}
.dialog__backdrop {
display: none;
}
.dialog__backdrop--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
//Processed LESS BAD
.dialog {
max-width: 80vw;
max-height: 80vh;
}
.dialog__backdrop {
display: none;
}
.dialog__backdrop--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
The ampersand ("&") SASS operator gives us a way to nest in an intuitive way that resolves to really flat CSS selectors.
"&" acts as a representation of the fully expanded parent selector string.
//HOTNESS
$max-dialog-size: 80;
.dialog {
max-width: $max-dialog-size * 1vw;
max-width: $max-dialog-size * 1vh;
&__backdrop {
display: none;
&--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
}
}
//Processed HOTNESS
.dialog {
max-width: 80vw;
max-height: 80vh;
}
.dialog__backdrop {
display: none;
}
.dialog__backdrop--open {
display: block;
background-color: hsla(0, 0%, 0%, .2);
position: fixed;
width: 100vw;
height: 100vh;
}
#{expression}
Interpolation lets one use the value of a variable or expression in places other than as a CSS property value.
Here we're using it in three unique places to build our our media queries.
Can you find them all?
//Media Queries
$mq-size--small: 42em;
$mq-size--med: 47.5em;
$mq-size--large: 56.25em;
$mq-dir: "min-width";
$mq--small: "(#{$mq-dir}: #{$mq-size--small})";
$mq--med: "(#{$mq-dir}: #{$mq-size--med})";
$mq--large: "(#{$mq-dir}: #{$mq-size--large})";
@media #{$mq--med} {
.sidebar {
width: 33.3%;
}
}
@media (min-width: 47.5em) {
.sidebar {
width: 33.3%;
}
}
Sass supports + - * / and %.
As with any applied math, the gotcha is with units. The resultant unit must be a valid CSS unit.
$size: 10em;
$margin: 2em;
$size--plus: $size + 2em; // 12em
$size--double: $size * 2; // 20em
$size--square: $size * $size; // WAT? em^2 is not valid
$size--margin-adjust: 100% - $margin; // Works with CSS calc(), not in a preprocessor
$size--half: $size * 50%; // Nope. SASS doesn't know how to multiply em * %
$size--half: $size * .5; // But this works: 5em
(assuming we're not using flexbox -- which we should be)
Let SASS do the math for space between grid items.
extend the rules of a selector into others.
Placeholders work the same as regular selectors except they are intended to only be extended.
They render nothing themselves, only when they are extended.
The @mixin directive defines a mixin.
Mixins are like function in that they can take arguments. Arguments can also have default values.
The @include directive "invokes" a mixin.
rgb(a), hsl(a)
red, green, blue
hue, saturation, lightness
adjust-hue
lighten, darken
saturate, desaturate,
complement, invert,
opacify, transparentize
mix
ie-hex-str
quote/unquote, str-length, str-insert, str-index, str-slice, to-upper-case, to-lower-case
percentage, round, ceil, floor, abs, min, max, random
length, nth, set-nth, join, append, zip, index, list-seperator
map-get, map-merge, map-remove, map-keys, map-value, map-has-key, keywords
selector-nest
selector-append
selector-extend
selector-replace
selector-unify
is-superselector
simple-selector
selector-parse
feature-exists
variable-exists
global-variable-exists
function-exists
mixin-exists
inspect
type-of
unit
unitless
comparable
call
More in-depth:
@function directive
Accepts arguments
Returns a single value
@return directive
@if for conditionals
@if else also
@for for loops
@each for iterables
@warn to message to std out
@function social-selector-gen($social) {
$base: '.social--';
@return str-insert($base, $social, str-length($base) + 1);
}
A list in SASS is a collection of values.
SASS is very permissive in type definitions so care should be taken.
SASS will type coherce so strings, numbers, etc. can be quoted or not. Even lists need not be braced.
List items can be comma separated or space* separated.
*provided there are no spaces in the value.
More in-depth:
A Map in SASS is simply a list of key-value pairs.
Both keys & values can be of any SASS type, INCLUDING OTHER MAPS!
Get values using map-get
Set map entries with map-merge
More in-depth: