What is Sass(SCSS)?
Sass is a preprocessor scripting language that is interpreted or compiled into Cascading Style Sheets(CSS).
Browser wouldn't load Sass but it will be written in Sass then will be exported to CSS.(It's because browser cannot read Sass, it needs to be compiled)
Sass and SCSS
There are two syntaxes available for Sass.
SCSS example
It's more similar to CSS because it uses brackets like CSS. The files using this syntax have the .scss
extension.
//SCSS
$font-stack: Helvetica, sans-serif;
$primary-color : #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
Sass example
Sass uses indentation rather than brackets to indicate nesting of selectors, and newlines rather than semicolons to separate properties. Files using this syntax hav the .sass
extension.
//Sass
$font-stack: Helvetica, sans-serif
$primary-color : #333
body
font: 100% $font-stack
color: $primary-color
Setting
I've used Sass(SCSS) previously by myself and the way I used it was through node-sass. I installed it through npm but at the class we learnt using ruby-sass and used VSC extension called Live Sass Compiler
Install this and then restart VS code. (If you are going to use node-sass, should install node-sass)
Separating files and writing comments
You can have separate files for each parts like _header.scss
, _home.scss
or _variable.scss
, _mixin.scss
. It's totally upto you but then you should import those separated scss files to one file which is style.scss
If you separates files by its function or layout, it's easy to maintain and reuse code.
Reason that there is underscore_ in front of file name.
If you don't add underscore in front of the file name, every separated scss files will be compiled and they will be saved on separated css file because of that.
But, if you add underscore in front of the file name, you can let sass know that it is part of main file and that file won't be compiled and you can import that using @import
Comments
/* This comment will be visible in CSS even after compiling. */
// This won't be compiled, only visible in Scss
Nesting
I personally think this is one of the nice things of SCSS.
You can see the structure of CSS code like html if by nesting these code. It makes the code more readable.
nav {
background : #C39BD3;
padding : 10px;
height: 50px;
ul {
display: flex;
list-style : none;
justify-content: flex-end;
li {
color: white;
margin-right: 10px;
}
}
}
Why use nesting?
With CSS, if you'd like to give style to an inherited element of it's parent element, you have to select the parent every time when you want to.
Example CSS
.info-list div {
display: flex;
font-size: 14px;
color: #4f4f4f;
}
.info-list div dt {
font-weight: 700;
margin-right: 7px;
}
But you can do this like below in SCSS
.info-list {
div {
display: flex;
font-size: 14px;
color: #4f4f4f;
dt {
font-weight: 700;
margin-right: 7px;
}
}
}
** Note! Avoid nesting in depth way too much.(Try not to get more than 3 levels deep if possible. If it's more than 3 levels deep, it's not so readable and it uses unnecessary selectors when it's compiled to CSS)
Nesting properties
You can also nest properties not only selectors.
It's to give background style to class .add-icon
You can nest properties that has background
name like background-image
, background-position
, and etc.
Also, you have to use colon(:) to nest properties.
add-icon {
background : {
image: url("./assets/arrow-right-solid.svg");
position: center center;
repeat: no-repeat;
size: 14px 14px;
}
}
Then the code above will be compiled to CSS like this below.
.add-icon {
background-image: url("./assets/arrow-right-solid.svg");
background-position: center center;
background-repeat: no-repeat;
background-size: 14px 14px;
}
& (Ampersand)
& refers to the outer selector. You can also add pseudo element like after, hover, pseudo element or add a selector the before parent.
SCSS
.box {
// pseudo classes
&:focus{}
&:hover{}
&:active{}
&:first-child{}
&:nth-child(2){}
// pseudo elements
&::after{}
&::before{}
}
CSS
.box:focus{}
.box:hover{}
.box:active{}
.box:frist-child{}
.box:nth-child(2){}
.box::after{}
.box::before{}
Example - giving style to li
and it's pseudo element and pseudo class.
ul {
li {
//pseudo element
&:hover {
background: white;
cursor: pointer;
}
//pseudo class
&:last-child {
border-bottom: 2px solid black;
}
}
}
Also, you can nest classes if they start with the same word like box-yellow or box-red. "box" is the common word used so you can do this way.
SCSS
.box {
&-yellow {
background: #ff6347;
}
&-red {
background: #ffd700;
}
&-green {
background: #9acd32;
}
}
CSS
.box-yellow {
background: #ff6347;
}
.box-red {
background: #ffd700;
}
.box-green {
background: #9acd32;
}
@at-root
You can get out of the nested code using @at-root
Everything within it to be emitted at the root of the document instead of using the normal nesting.
SCSS
.article {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
.article-content {
font-size: 14px;
opacity: 0.7;
@at-root i {
opacity: 0.5;
}
}
}
CSS
.article {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.article .article-content {
font-size: 14px;
opacity: 0.7;
}
/* You can see this isn't nested. It's separated from the nested code. */
i {
opacity: 0.5;
}
Variable
Being able to give variable means that you don't have to change the values one by one. It makes much easier to maintain the code.
** Note! Be aware that it can crash if you declare variables indiscriminately. Declare variables only when it has a good reason for. If you are in a team, you need to talk about these enough before declaring variables.
When to use variables?
- If the value is going to be repeatedly used. (You can style elements without remembering the value but just with the variable.)
- If you need to change existing value to something else.(It it's used in many different elements/properties without variable, you have to change one by one which is time consuming but if you set the value to variable, you only need to change the value of the variable which takes much shorter time.)
Declaring variable in Sass
/* bg */
$bgColor : #FFF
If there are repeatedly used values, you can style them easily by using variables.
// colour
$red: #ee4444;
$black: #222;
$bg-color: #3e5e9e;
$link-color: red;
$p-color: #282A36;
// font-size
$font-p: 13px;
$font-h1: 28px;
// font
$base-font: 'Noto Sans KR', sans-serif;
body {
background-color : $bg-color;
font-size : $font-p;
font-family : $base-font;
}
h1 {
font-size: $font-h1;
color: $black;
}
p {
font-size: $font-p;
color: $black;
}
a {
color: $link-color;
}
Type of variables
- number (eg. 1, .82, 20px, 2em, ...)
- string (eg. "./img/cutedog.png", bold, left, uppercase, ...)
- colour (eg. green, #fff, rgba(255,0,0,.5), ...)
- boolean (true, false)
- null
- list
$font-size : 10px 12px 16px; // list of font-size
$image-file : photo_01, photo_02, photo_03 // list of image-file
// can also use this way - ruby sass
// it iterates from index 1 in sass(*** not 0)
nth(10px 12px 16px, 2); // 2nd value of $font-size is 12px
nth([line1, line2, line3], -1); // if it's negative, it iterates from right to left. Therefore, -1 of $image-file is line3
- map
$font-weights: ("regular": 400, "medium": 500, "bold": 700); // map of font-weights. (key-value pair)
// use this way - ruby sass
map-get($font-weights, "medium"); // 500
map-get($font-weights, "extra-bold"); // null
More about List and Map
List
// You can declare value of list using , or whitespace
$sizes: 40px, 50px, 80px;
// above code works the same with $sizes: 40px 50px 80px;
$valid-sides: top, bottom, left, right;
*** index of list starts from 1
Built-in List function
-
append(list,value,[s])
: function that adds value to list. -
index(list, value)
: function that returns index of list's value. -
nth(list, n)
: function that returns the value of list's index. Example
// Scss
$valid-sides: left, center, right;
.screen-box {
text-align : nth($valid-sides, 1);
}
/* CSS */
.screen-box {
text-align: left;
}
Map
Map saves the value as key:value pair inside the bracket(). Key needs to be unique!
Built-in Map function
-
map-get(map, key)
: function that returns the value of its key. -
map-get(map)
: function that returns keys of map -
map-values(map)
: function that returns values of map Example
// Scss
$font-sizes: ("h1": 45px, "h2": 19px, "p": 16px);
section {
h2 {
font-size : map-get($font-sizes, "h2");// 19px
}
}
map-get($font-size, "h3");// null
/* CSS */
section h2 {
font-size : 19px;
}
- string and number also have functions. Find more about string functions in Sass
Scope
There are local variable and global variable.
Local variable
.info{
// local variable
$line-normal : 1.34;
font-size : 15px;
line-height : $line-normal;
text-align : right;
span{
line-height : $line-normal;
}
}
Global variable
//Scss
// global variable
$font-p : 15px;
.main-box{
p {
font-size : $font-p;
}
a {
font-size : $font-p;
color : blue;
text-decoration : none;
}
}
.main-box p {
font-size: 15px;
}
.main-box a {
font-size: 15px;
color: blue;
text-decoration: none;
}
You can also use !global to make local variable to global variable.
$mycolor: #ffffff !global;
More about variables in Sass
Operator
-
a < b
: check if a is smaller than b -
a <= b
: check if a is the same with b or smaller than b -
a > b
: check if a is greater than be -
a >= b
: check if a is greater than be or the same with b
@debug 100 > 50; // true
@debug 10px < 17px; // true
@debug 96px >= 1in; // true
@debug 1000ms <= 1s; // true
ERROR
If they both have units and those units aren't the same, it causes the error.
BUT! it's fine when you compare it with number and number with unit.
Example
@debug 100px > 10s;
// Error: Incompatible units px and s
@debug 100 > 50px; // true
@debug 10px < 17; // true
// Not Error
-
a == b
: check if a and b are the same. -
a !== b
: check if a and be aren't the same.
Example
// number
@debug 1px == 1px; // true
@debug 1px != 1em; // true
@debug 1 != 1px; // true
@debug 96px == 1in; // true
// string
@debug "Poppins" == Poppins; // true
@debug "Open Sans" != "Roboto"; // true
// colour
@debug rgba(53, 187, 169, 1) == #35bba9; // true
@debug rgba(179, 115, 153, 0.5) != rgba(179, 115, 153, 0.8); // true
// list
@debug (5px 7px 10px) != (5px, 7px, 10px); // true
@debug (5px 7px 10px) != [5px 7px 10px]; // true
@debug (5px 7px 10px) == (5px 7px 10px); // true
-
a + b
a - b
a * b
a / b
-
a % b
: remainder of a/b
@debug 10s + 15s; // 25s
@debug 1in - 10px; // 0.8958333333in
@debug 5px * 3px; // 15px*px
@debug 1in % 9px; // 0.0625in (1in == 96px)
Error
@debug 100px + 10s;
// Error: Incompatible units px and s.
@debug 100px / 2;
// 50px (Not Error)
String a + b
If there is + operator and a, b are all string, it combines a, b and returns combined string.
Even if one of them isn't string, it makes all of them to string and combine.
@debug "Helvetica" + " Neue"; // "Helvetica Neue"
@debug sans- + serif; // sans-serif
@debug sans - serif; // sans-serif
@debug "Elapsed time: " + 10s; // "Elapsed time: 10s";
@debug true + " is a boolean value"; // "true is a boolean value";
Boolean
-
not
: If true, return false. If false, return true. -
and
: Return true when both are true. Return false, if one of them is false. -
or
: Return false if both are false. Return true if one of them is. true.
@debug not true; // false
@debug not false; // true
@debug true and true; // true
@debug true and false; // false
@debug true or false; // true
@debug false or false; // false
Top comments (6)
Very nice, well done
Se detailed! love it
Thanks for the well-explained and comprehensive article.
Nice, to simple and to good... Tks a lot.
I love people who is Korean and especially is a programmer. Thanks a lot for sharing these great information. From Vietnam with respects.
Thanks! it was cool!