Sass
Sass is a pre-processor that compiles code to CSS
Install Sass
Use “npm install -g sass” to install Sass.
$color-primary: hotpink;
body {
background: $color-primary
}
Use "sass styles.scss styles.css" to compile the SCSS file to CSS
Use the command "sass --watch styles.scss styles.css" to start an event listener that watches for file changes and automatically compiles the Sass.
Nesting
.primary {
padding: 1rem;
ul {
display: flex;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
a {
text-transform: uppercase;
text-decoration: none;
}
}
.primary {
padding: 1rem;
}
.primary ul {
display: flex;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
.primary a {
text-transform: uppercase;
text-decoration: none;
}
Nesting allows you to put selectors inside of other selectors.
.card {
padding: 1rem;
box-shadow: 0 0 1rem #fff;
&-title {
font-size: 2rem;
&::after {
content: '';
display: block;
height: 2px;
width: 100%;
background: green;
}
}
}
.card {
padding: 1rem;
box-shadow: 0 0 1rem #fff;
}
.card-title {
font-size: 2rem;
}
.card-title::after {
content: "";
display: block;
height: 2px;
width: 100%;
background: green;
}
The parent selector & lets you combine selectors together. For example “.card” and “&-title” are combined into “.card-title”.
a {
text: {
transform: uppercase;
decoration: none;
}
}
a {
text-transform: uppercase;
text-decoration: none;
}
You can also nest CSS properties.
.card {
padding: 1rem;
&__title {
font-size: 2rem;
}
}
.card {
padding: 1rem;
}
.card__title {
font-size: 2rem;
}
Block Element Modifier (BEM) is a popular naming convention, it’s uses a double underscore e.g. “.card__title”.
.nav-link {
font-size: 2rem;
div & {
font-size: 0.925rem;
}
}
.nav-link {
font-size: 2rem;
}
div .nav-link {
font-size: 0.925rem;
}
If you put the parent selector add the end of a child selector, you can swap the two selectors around e.g. “.nav-link div” becomes “div .nav-link”.
.card {
padding: 1rem;
border-radius: .5rem;
@media (min-width: 400px) {
padding: 0.5rem;
}
}
.card {
padding: 1rem;
border-radius: 0.5rem;
}
@media (min-width: 400px) {
.card {
padding: 0.5rem;
}
}
If you nest a media query, then Sass will put the parent selector inside of the media query.
Variables
$color-red: firebrick;
.title {
color: $color-red;
}
.title {
color: firebrick;
}
In Sass variables are defined using a dollar sign $ e.g. “$color-red: firebrick”
$color-blue: navy;
$color-primary: $color-blue;
div {
color: $color-primary;
}
You can assign variables to other variables.
$color-primary: #ff00ee;
$color-secondary: #ff99ee;
$gradient: linear-gradient(90deg, $color-primary, $color-secondary);
You can assign CSS properties to variables.
.title {
$color-primary: navy !global;
}
Variables defined outside a selector are already global. Variables defined inside of a selector are local scope, you can make them global using “!global” keyword.
Extends
Extends allow you to copy all of the CSS properties from one selector to inside another.
.dark {
background: grey;
padding: 1rem;
}
.card {
@extend .dark;
color: white
}
.dark, .card {
background: grey;
padding: 1rem;
}
.card {
color: white;
}
“@extends .dark” adds all of the CSS styles from “.dark” to “.card”. This results in all the common styles between the two selectors being grouped into a single selector “.dark, .card”.
.card {
font-family: Arial;
.title {
@extend .card;
color: white;
}
}
.card, .card .title {
font-family: Arial;
}
.card .title {
color: white;
}
From a nested child you can extend the styles of parent element, here “.title” is inheriting the “font-family: Arial” style from “.card” using an extend.
.card {
font-family: Arial;
.title {
@extend .card;
color: white;
}
p {
display: block;
@extend .title;
}
}
.card, .card .title,
.card p, .card .title p,
.card p p {
font-family: Arial;
}
.card .title, .card p,
.card .title p, .card p p {
color: white;
}
.card p, .card .title p,
.card p p, .card p p p {
display: block;
}
Extends have an issue they cascade, e.g. “p” inherits from “.title”, which then inherits from “.card”. All of the CSS properties up the chain of extends are being applied, this can result in some very complicated selectors. To prevent this avoid using extends inside of nested selectors.
Placeholders
%styles {
display: block;
font-family: Arial;
text-transform: uppercase;
}
.card {
@extend %styles;
}
.card {
display: block;
font-family: Arial;
text-transform: uppercase;
}
Placeholders allow you to create a group of styles that aren’t compiled into CSS. These styles are only added to the CSS when you call the placeholder using an extend.
Mixins
They are a bit like functions.
@mixin uppercase {
text-transform: uppercase;
font-weight: bold;
}
.card {
font-family: Arial;
.title {
@include uppercase;
color: white;
}
}
.card {
font-family: Arial;
}
.card .title {
text-transform: uppercase;
font-weight: bold;
color: white;
}
Mixins work similar to placeholders, they allow you to add a group of styles. Expends will combine multiple different selectors together that all use common CSS properties into one large selector, whereas Mixins will repeat CSS selectors if needed.
@mixin mixin1 {
font-family: Arial;
&__title {
font-size: 2.5rem;
color: #ff00ee;
}
}
.card {
@include mixin1;
}
.card {
font-family: Arial;
}
.card__title {
font-size: 2.5rem;
color: #ff00ee;
}
You can include selectors inside of Mixins.
@mixin button($color) {
border: 15px solid red;
background: $color;
}
.btn {
color: white;
@include button(blue);
}
.btn {
color: white;
border: 15px solid red;
background: blue;
}
Mixins can accept arguments, here the colour blue is passed into the button mixin as an argument.
@mixin button($color, $text) {
border: 15px solid red;
background: $color;
&::before {
content: $text;
position: absolute;
}
}
.btn {
color: white;
@include button(
$text: 'Hello',
$color: blue
)
}
.btn {
color: white;
border: 15px solid red;
background: blue;
}
.btn::before {
content: "Hello";
position: absolute;
}
You can pass multiple arguments to a mixin. You can also specify the arguments name e.g. “$color: blue”.
@mixin button($color) {
color: $color;
}
.btn {
@include button(50 + 5)
}
.btn-2 {
@include button(Hello World);
}
.btn {
color: 55;
}
.btn-2 {
color: Hello World;
}
Sass does not use error checking on mixin arguments, “55” is not a valid colour but Sass will still compile it.
@mixin button($color: blue, $text) {
background: $color;
&::before {
content: $text;
position: absolute;
}
}
.btn {
color: white;
@include button($text: 'Hello')
}
.btn {
color: white;
background: blue;
}
.btn::before {
content: "Hello";
position: absolute;
}
You can make arguments optional by giving them a default value, here “$color” is optional because it has a default value of “blue”, but “$text” is required.
Interpolation
$color-primary: navy;
.btn.#{$color-primary} {
color: $color-primary;
}
.btn.navy {
color: navy;
}
Interpolation lets you use a variable value as a selector, for example “.btn.#{$color-primary}” gives “.btn.navy”.
$width: 1920;
$height: 1080;
.res-#{$width * $height} {
background: blue;
}
.res-2073600 {
background: blue;
}
You can do maths with variables inside of interpolation.
$width: 100;
@mixin btn($color, $px) {
&-#{$color}-#{$px} {
background: $color;
width: #{$px}px;
aspect-ratio: 1 / 1;
}
}
.button {
@include btn(red, $width);
@include btn(green, $width + 50);
@include btn(blue, $width + 100);
}
.button-red-100 {
background: red;
width: 100px;
aspect-ratio: 1/1;
}
.button-green-150 {
background: green;
width: 150px;
aspect-ratio: 1/1;
}
.button-blue-200 {
background: blue;
width: 200px;
aspect-ratio: 1/1;
}
Here a mixin is used to create 3 buttons, and interpolation is used to create the button selectors e.g. “.button-green-150px”
Standard Library
@use 'sass:color';
@use 'sass:math';
$color: #35ef12;
.btn {
background: color.scale(
$color, $lightness: -20%
);
border:
math.abs(
math.sin(math.$pi + math.$e)
)
solid
black;
}
.btn {
background: #29c10d;
border: 0.4107812905 solid black;
}
Sass has various modules in its standard library which you can import via “@use”.
Loops
@use 'sass:math';
$total: 4;
@for $i from 1 through $total {
.col-#{$i} {
width: math.div(100%,$total)*$i;
}
}
.col-1 {
width: 25%;
}
.col-2 {
width: 50%;
}
.col-3 {
width: 75%;
}
.col-4 {
width: 100%;
}
For loops allow you to repeat styling. Here a for loop creates 4 columns, each col width is +25%
“through” will include the last number where as “to” won't.
@for $n from 4 to 1 {
.btn {
width: $n;
}
}
.btn {
width: 4;
}
.btn {
width: 3;
}
.btn {
width: 2;
}
You can also count backwards.
@each $clr in pink, cyan, yellow {
.color-#{$clr} {
color: $clr;
}
}
.color-pink {
color: pink;
}
.color-cyan {
color: cyan;
}
.color-yellow {
color: yellow;
}
The “@each” loop allows you to loop through a list of items.
$people: (
('Jared', 22),
('Tom', 26),
('John', 15)
);
@each $name, $age in $people {
.person {
border: $name;
border: $age;
}
}
.person {
border: "Jared";
border: 22;
}
.person {
border: "Tom";
border: 26;
}
.person {
border: "John";
border: 15;
}
You can also loop through nested lists.
IF, ELSE
@use 'sass:color';
$colors: (
(primary, #ff00ee),
(secondary, #00ffaa),
(main, #8833ff)
);
@each $theme, $color in $colors {
.btn-#{$theme} {
background: $color;
$l: color.lightness($color);
@if ($l > 50) {
color: white;
}
}
}
.btn-primary {
background: #ff00ee;
}
.btn-secondary {
background: #00ffaa;
}
.btn-main {
background: #8833ff;
color: white;
}
IF statements can be used to compare values. For example here we loop through a list of colours, then check if the “$color” HSL lightness is > 50, if it is then we change the text colour to white.