DEV Community

Dahye Ji
Dahye Ji

Posted on

Sass(SCSS) for beginners

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
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.
scss files

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
Enter fullscreen mode Exit fullscreen mode

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;
        } 
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

** 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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

& (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{} 
}
Enter fullscreen mode Exit fullscreen mode

CSS

.box:focus{} 
.box:hover{}
.box:active{}
.box:frist-child{}
.box:nth-child(2){}
.box::after{}
.box::before{}
Enter fullscreen mode Exit fullscreen mode

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;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

CSS

.box-yellow {
  background: #ff6347;
}
.box-red {
  background: #ffd700;
}
.box-green {
  background: #9acd32;
}
Enter fullscreen mode Exit fullscreen mode

@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;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

*** 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);
}
Enter fullscreen mode Exit fullscreen mode
/* CSS */
.screen-box {
  text-align: left;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
/* CSS */
section h2 {
    font-size : 19px;
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode
.main-box p {
  font-size: 15px; 
}

.main-box a {
  font-size: 15px;
  color: blue;
  text-decoration: none; 
}
Enter fullscreen mode Exit fullscreen mode

You can also use !global to make local variable to global variable.

$mycolor: #ffffff !global;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • 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)
Enter fullscreen mode Exit fullscreen mode

Error

@debug 100px + 10s;
// Error: Incompatible units px and s.

@debug 100px / 2;
// 50px (Not Error)
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Discussion (6)

Collapse
bogdanbatsenko profile image
bogdanbatsenko

Very nice, well done

Collapse
thetrendycoder profile image
Sara Ounissi

Se detailed! love it

Collapse
imiahazel profile image
Imia Hazel

Thanks for the well-explained and comprehensive article.

Collapse
mafeal profile image
Marcelo Alves

Nice, to simple and to good... Tks a lot.

Collapse
githubtuankiet profile image
Tuan Kiet Tran

I love people who is Korean and especially is a programmer. Thanks a lot for sharing these great information. From Vietnam with respects.

Collapse
solar5503 profile image
Vadim

Thanks! it was cool!