Introduction to Sass in Astro

Introduction to Sass in Astro

How to improve CSS with preprocessors
Ferenc Almasi β€’ 2024 January 29 β€’ Read time 14 min read
Learn why to use Sass and what it has to offer on top of CSS. We'll examine its core concepts and how to use Sass features.
  • twitter
  • facebook
CSS

This lesson is a preview from our interactive course

Sass is a powerful CSS preprocessor that adds various extra functionalities on top of CSS.

A preprocessor is a program that processes input data (in our case, a Sass file) and produces an output (a CSS file) that can be used as input elsewhere (in our HTML documents).


Why Sass?

Sass comes with many benefits over regular CSS. First of all, Sass is completely compatible with all versions of CSS. This means any valid CSS file is also a valid Sass file. This results in a shallow learning curve, as most of its syntax is regular CSS. Apart from compatibility, it also comes with the following benefits:


Installing Sass

To get started with Sass, we first need to install it. Astro supports the most widely used CSS preprocessors out of the box. Apart from Sass, Stylus, and Less are also supported. This means we only need to install the dependency, then we can start using Sass right away. We can install Sass by running the following in the terminal:

Copied to clipboard!
npm i sass

Sass has already been installed for your convenience in this project. Open the package.json file to verify that Sass is available as a dependency. That's everything we have to do. Now we can start using Sass in Astro by specifying the lang attribute on style tags in our component:

Copied to clipboard! Playground
<!-- Regular CSS: -->
<style>...</style>

<!-- Sass: -->
<style lang="scss">...</style>
How to turn regular CSS into Sass
Looking to improve your skills? Master Astro + SEO from start to finish.
info Remove ads

Core Concepts of Sass

The core concept of Sass is to make CSS fun to write, easy to read and maintain, and also shorter most of the time. Sass has crucial features that CSS doesn't support out of the box, such as nesting, inheritance, advanced variables and functions, loops, and many more. Let's take a look at the ones we're going to use in this project, and you'll likely use them in any project where Sass is used.

Nesting

One of the most important benefits of using Sass is the ability to nest CSS rules. In HTML, we've gotten used to seeing a visual hierarchy, where child elements are nested inside parents. This is not possible in CSS. However, Sass supports nesting. Take a look at the following comparison:

Copied to clipboard! Playground
ul {
    columns: 2;
}

ul li {
    display: flex;
}

ul li img {
    margin-top: 2px;
}
Lack of nesting in CSS
Copied to clipboard!
ul {
    columns: 2;

    li {
        display: flex;

        img {
            margin-top: 2px;
        }
    }
}
Nesting in Sass

Using nesting, we can visually see which elements belong to which parent. Now we can understand at a glance that each style is only applicable within the ul.

As Astro scopes CSS to the components, we don't need to worry about specificity. Because of this, we'll mostly avoid nesting CSS to keep our styles flat, apart from a few exceptions.

Imports

Another great feature of Sass is that it allows the use of imports, also known as partials. This opens the possibility to modularize our CSS. For example, if we have global styles for certain elements, we can separate the styles for those elements into a distinct Sass file and import them in other places:

Copied to clipboard!
// Inside tooltip.scss
.tooltip { ... }

// Inside global.scss
@import './tooltip.scss';
How to use imports in Sass

Sass files use the .scss extension.

To import other SCSS files, we can use the @import at-rule. Each built-in functionality in Sass is prefixed with an @ and is called an at-rule. The statement must include a path to the CSS file, similar to how imports are used in JavaScript.

The .tooltip styles are now generated into the global.scss file. Note that we can also use // for comments inside SCSS files. The regular /**/ CSS syntax is also available.

Variables

Sass also supports the use of variables. Unlike CSS variables, Sass variables are prefixed with a $ sign, and they can contain any valid CSS unit. For example, we can use variables to collect brand colors in one place. This means if we need to change the colors of the site, we only need to do it in one place. Take the following as an example:

Copied to clipboard!
// Inside color-palette.scss
$primary: #2980b9;

// Inside resets.scss
@import 'color-palette.scss';

a {
    color: $primary;
}
How to use variables in Sass

Here we defined a $primary color variable inside a file called color-palette.scss. We can use the @import at-rule to import this file into any other SCSS file to use them. We can reference the variable using its name. In the above example, we assigned the $primary color to all anchors.

Lists and maps

Variables can also take the form of other Sass objects, such as lists and maps. A map is a collection of values represented by key-value pairs, just like an object in JavaScript. Values can include CSS units or even lists, which is another structured data type in Sass. Lists are comma-separated sequences of values:

Copied to clipboard!
// Lists in Sass:
$fontFamily: Inter, sans-serif;

// Map in Sass:
$fontSizes: (
    'xs':    12px,
    'sm':    14px,
    'md':    16px
);

// Using lists in maps:
$fontTypes: (
    'regular':  (Inter, sans-serif),
    'bold':     (InterBold, sans-serif)
);

// Reference lists and maps:
a {
    font-family: $fontFamily; // Referencing a list
    font-weight: map-get($fontTypes, 'regular'); // Referencing a map
}
Lists and maps in Sass

Mixins

So far, we only looked at how to work with variables, but Sass also supports the use of more complex functions, called mixins. Mixins in Sass are functions for encapsulating styles. Mixins are defined using the @mixin <mixinName> { ... } syntax. When a mixin is used, all CSS-related content within the mixin is generated into the stylesheets. Let's see an example:

Copied to clipboard!
@mixin media($size: 'xs') {
    $mediasizes: (
        'xs':   600px,
        'sm':   800px,
        'md':   1024px,
        'lg':   1200px
    );

    @media (min-width: #{map-get($mediasizes, $size)}) {
        @content;
    }
}
How to create a mixin

This mixin is called media. It can be used for using predefined media queries in CSS. As we can see, mixins can accept parameters just like JavaScript functions. In our case, it accepts a $size parameter, which is set to xs by default.

To create a mobile-first media query when the mixin is invoked, we can use the map-get function we've seen before to retrieve a value ($size) from the provided map ($mediasizes). Note that we need to use the #{} interpolation to include Sass functions in the CSS output. When the mixin is called, anything inside the mixin is placed in place of the @content keyword, which is called a content block. To call a mixin, we can use the @include at-rule:

Copied to clipboard!
@include media('xs') {
    // This will be placed in place of the @content keyword in the mixin
    ul {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

// The generated CSS output:
@media (min-width: 600px) {
    ul {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}
How to call a mixin in Sass

Here we called the media mixin and also passed xs as the parameter. Notice that since xs is the default parameter for the mixin, it's also possible to call this mixin without a parameter to get the same result.

Note that the generated @media is a regular CSS at-rule and not specific to Sass.


Adding Configuration Files

Now that we know everything we need to know about Sass, let's put theory into practice and set up the Sass configurations. To keep Sass files easy to manage, we'll create a couple of configuration files, each with a different purpose. Create a config folder inside the scss folder in the code editor, and add the following four new files:

Copied to clipboard!
src
β”œβ”€ scss
β”‚  β”œβ”€ config
β”‚  β”‚  β”œβ”€ color-palette.scss
β”‚  β”‚  β”œβ”€ mixins.scss
β”‚  β”‚  β”œβ”€ typography.scss
β”‚  β”‚  β”œβ”€ spacings.scss
The structure of the scss folder

Adding colors

For this landing page, we'll only work with six individual colors. Open the color-palette.scss file and add the following variables:

Copied to clipboard!
$primary: #2980b9;
$primary-light: #33AEFF;
$secondary: #d8a752;

$black: #111111;
$white: #FFF;
$off-white: #FAFAFA;
color-palette.scss
Add colors to color-palette.scss

Except for shades of black and white, it's best to avoid using color names for variables to prevent variable names from becoming meaningless and needing updates after a color change. For instance, if we initially name $primary as $blue and later change the primary color to purple, $blue would lose its meaning. On the other hand, $primary remains meaningful.

Adding typography

For typography, we want to define two font types: regular and bold, along with font weights and sizes for each. To achieve this, we can use maps. Open the typography.scss file and add the following variables:

Copied to clipboard!
$fontTypes: (
    'regular':  (Regular, sans-serif),
    'bold':     (Bold, sans-serif)
);

$fontSizes: (
    'xs':       12px,
    'sm':       14px,
    'md':       16px,
    'default':  18px,
    'lg':       21px,
    'xl':       24px,
    '2xl':      28px,
    '3xl':      32px
);
typography.scss
Create typographies

Here we combined a map with lists, similar to a previous example. For the $fontTypes map, each key references a list, which needs to be wrapped in parentheses for the correct syntax, otherwise it would be treated as regular CSS.

The $fontTypes variable references a custom font that we'll import into the project in the next lesson.

Adding spacings

For spacings.scss, we'll only need to define a map and return one of its values when the function is called. Open the spacings.scss file and add the following:

Copied to clipboard!
@use 'sass:map';

@function size($size: 'default') {
    $sizes: (
        'xs':      5px,
        'sm':      10px,
        'md':      15px,
        'default': 20px,
        'lg':      25px
    );

    @return map.get($sizes, $size);
}
spacings.scss
Add the spacings function

Note that this time, we use the @function at-rule, as opposed to @mixin. This is because we don't want any CSS rule to be generated by this function. Instead, we only want to return a value. When you need a function to generate CSS output, use a mixin. Otherwise, use @function. To return a value from the function, we can use the @return keyword.

Similar to how we used map-get in one of the previous examples, we can use the same functionality here to return a value from the map. However, we can also use map.get as shown here, which will replace map-get in future versions of Sass. They both have the same functionality.

When using map.get, however, we need to include the map object in the file using @use 'sass:map' at the top of our Sass file. This is because map-get is a global function, whereas map.get is only available through an import.

For now, both map-get and map.get can be used interchangeably. For future versions, prefer map.get as map-get will be deprecated in the long term.

Adding mixins

To easily use these typography rules, we'll create a couple of mixins. Inside the mixins.scss file, add the following three mixins:

Copied to clipboard!
@mixin media($size: 'xs') {
    $mediasizes: (
        'xs':   600px,
        'sm':   800px,
        'md':   1024px,
        'lg':   1200px
    );

    @media (min-width: #{map-get($mediasizes, $size)}) {
        @content;
    }
}

@mixin fontType($type: 'regular') {
    font-family: #{map-get($fontTypes, $type)};
}

@mixin fontSize($size: 'regular') {
    font-size: #{map-get($fontSizes, $size)};
}
mixins.scss
Add the mixins

CSS Resets

Now that all configurations are in place, let's focus on adding reset styles. To use these configurations, we need to import the files. However, to avoid importing them individually, create a config.scss file next to the empty resets.scss and add the following:

Copied to clipboard!
@import './config/color-palette';
@import './config/mixins';
@import './config/typography';
@import './config/spacings';
config.scss
Import everything from the config folder

We can import this file into resets.scss to automatically import other configurations for us. Open resets.scss and add an import for config.scss, along with the following CSS rules:

Copied to clipboard!
@import './config';

body {
    @include fontType('regular');
    @include fontSize('default');
    margin: 0;
    background: $white;
    color: $black;
}

div {
    box-sizing: border-box;
}

a {
    color: $primary;
}

h1,
h2 {
    margin: 0;
}

ul {
    margin: 0;
    padding: 0;
    list-style-type: none;
}

.container {
    position: relative;
    max-width: 1200px;
    margin: 0 auto;
    padding: 25px size('default') 0;
    z-index: 1;
}
resets.scss
Add CSS resets

Here we imported config.scss, which imports all other configuration files. This means we can use mixins, variables, and functions with a single import, while still maintaining them in different files. We also defined a common .container class that we can use across different sections on the page.

This file can be used to reset CSS styles or create common classes that can be used across different components. This file is imported into index.scss, which, in turn, is imported into our index.astro page. Note that we need to add the is:global directive on the style tag to make the styles global. Otherwise, they would be scoped to the component. And now we have everything set up from the CSS side of things!

  • twitter
  • facebook
CSS
Did you find this page helpful?
πŸ“š More Webtips
Mentoring

Rocket Launch Your Career

Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies:

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.