Overview
Natours uses the modern Sass module system with @use and @forward directives, providing better encapsulation and namespace management compared to the legacy @import syntax.
The @use directive was introduced in Dart Sass 1.23.0 and is now the recommended way to load Sass files. It provides better performance and prevents accidental global namespace pollution.
The Module System
Main Entry Point
The main.scss file acts as the orchestrator, loading all modules in the correct order:
@use "./abstracts/functions" ;
@use "./abstracts/mixins" ;
@use "./abstracts/variables" ;
@use "./base/animations" ;
@use "./base/base" ;
@use "./base/typography" ;
@use "./base/utilities" ;
@use "./components/button" ;
@use "./components/composition" ;
@use "./components/feature-box" ;
@use "./components/card" ;
@use "./components/story" ;
@use "./components/bg-video" ;
@use "./components/form" ;
@use "./components/popup" ;
@use "./components/layout/navigation" ;
@use "./components/layout/header" ;
@use "./components/layout/grid" ;
@use "./components/layout/footer" ;
@use "./components/pages/home" ;
Load Abstracts First
Variables, functions, and mixins are loaded first because other modules depend on them.
Apply Base Styles
Global resets, typography, and utilities are loaded to establish the foundation.
Import Components
Individual UI components are loaded in any order since they don’t depend on each other.
Add Layout Modules
Layout-specific styles for header, footer, grid, and navigation are loaded.
Include Page Styles
Page-specific styles are loaded last to allow for overrides if needed.
Abstracts Layer
The abstracts folder contains Sass code that doesn’t output CSS directly but provides tools for other files.
Variables
The _variables.scss file defines all global constants:
sass/abstracts/_variables.scss
// COLORS
$color-primary : #55C57A ;
$color-primary-light : #7ED56F ;
$color-primary-dark : #28B485 ;
$color-secondary-light : #FFB900 ;
$color-secondary-dark : #FF7730 ;
$color-tertiary-light : #2998FF ;
$color-tertiary-dark : #5643FA ;
$color-grey-light-1 : #F7F7F7 ;
$color-grey-light-2 : #EEE ;
$color-grey-dark-1 : #777 ;
$color-grey-dark-2 : #999 ;
$color-grey-dark-3 : #333 ;
$color-white : #FFF ;
$color-black : #000 ;
// FONT
$default-font-size : 1.6 rem ;
// GRID
$grid-width : 114 rem ;
$gutter-vertical : 8 rem ;
$gutter-horizontal : 6 rem ;
Variables use semantic naming that describes their purpose (e.g., $color-primary) rather than their value (e.g., $green). This makes the code more maintainable when design changes occur.
Mixins
The _mixins.scss file contains reusable style patterns:
sass/abstracts/_mixins.scss
@mixin clearfix {
& ::after {
content : "" ;
display : table ;
clear : both ;
}
}
@mixin absCenter {
position : absolute ;
top : 50 % ;
left : 50 % ;
transform : translate ( -50 % , -50 % );
}
// MEDIA QUERY MANAGER
@mixin respond ( $breakpoint ) {
@if $breakpoint == phone {
@media ( max-width : 37.5 em ) { @content }; //600px
}
@if $breakpoint == tab - port {
@media ( max-width : 56.25 em ) { @content }; //900px
}
@if $breakpoint == tab - land {
@media ( max-width : 75 em ) { @content }; //1200px
}
@if $breakpoint == big - desktop {
@media ( min-width : 112.5 em ) { @content }; //1800px
}
}
Functions
The _functions.scss file is currently empty but ready for custom Sass functions:
sass/abstracts/_functions.scss
// Custom Sass functions can be added here
// Example:
// @function strip-unit($number) {
// @return $number / ($number * 0 + 1);
// }
Using Modules in Components
Importing with Namespace
By default, @use creates a namespace based on the filename:
@use "../abstracts/variables" ;
.btn {
color : variables . $color-primary ; // Access with namespace
}
Importing Without Namespace
Use as * to import without a namespace:
@use "../abstracts/variables" as * ;
@use "../abstracts/mixins" as * ;
.btn {
font-size : $default-font-size ; // Direct access
& --white {
background-color : $color-white ;
}
}
While as * is convenient, use it carefully to avoid naming conflicts. It’s safe for abstracts since they’re used across many files and their names are chosen to be unique.
Base Layer
The base layer establishes global styles that apply throughout the project.
Base Resets
@use "../abstracts/mixins" as * ;
* ,
* ::after ,
* ::before {
margin : 0 ;
padding : 0 ;
box-sizing : inherit ;
}
html {
font-size : 62.5 % ; // 1rem = 10px
scroll-behavior : smooth ;
@include respond (tab - land) {
font-size : 56.25 % ; // 1rem = 9px
}
@include respond (tab - port) {
font-size : 50 % ; // 1rem = 8px
}
@include respond (big - desktop) {
font-size : 75 % ; // 1rem = 12px
}
}
body {
box-sizing : border-box ;
}
The font-size: 62.5% trick on the html element makes 1rem equal to 10px (62.5% of 16px), making rem calculations easier while still being relative to user preferences.
Typography
sass/base/_typography.scss
@use "../abstracts/variables" as * ;
body {
font-family : 'Lato' , sans-serif ;
font-weight : 400 ;
line-height : 1.7 ;
color : $color-grey-dark-1 ;
padding : 2 rem ;
}
.heading-primary {
color : $color-white ;
text-transform : uppercase ;
backface-visibility : hidden ;
margin-bottom : 6 rem ;
& --main {
display : block ;
font-size : 6 rem ;
font-weight : 400 ;
letter-spacing : 3.5 rem ;
animation : moveInLeft 1 s ease ;
}
& --sub {
display : block ;
font-size : 2 rem ;
font-weight : 400 ;
letter-spacing : 1.75 rem ;
animation : moveInRight 1 s ease ;
}
}
Animations
sass/base/_animations.scss
@keyframes moveInLeft {
0% {
opacity : 0 ;
transform : translateX ( -100 px );
}
80% {
transform : translateX ( 10 px );
}
100% {
opacity : 1 ;
transform : translateX ( 0 );
}
}
@keyframes moveInRight {
0% {
opacity : 0 ;
transform : translateX ( 100 px );
}
80% {
transform : translateX ( -10 px );
}
100% {
opacity : 1 ;
transform : translateX ( 0 );
}
}
Utilities
Utility classes provide single-purpose helpers:
sass/base/_utilities.scss
.u-center-text { text-align : center !important ; }
.u-margin-bottom-small { margin-bottom : 1.5 rem !important ; }
.u-margin-bottom-medium { margin-bottom : 4 rem !important ; }
.u-margin-bottom-big { margin-bottom : 8 rem !important ; }
.u-margin-bottom-huge { margin-bottom : 10 rem !important ; }
.u-margin-top-small { margin-top : 1.5 rem !important ; }
.u-margin-top-medium { margin-top : 4 rem !important ; }
.u-margin-top-big { margin-top : 8 rem !important ; }
.u-margin-top-huge { margin-top : 10 rem !important ; }
Utility classes use the u- prefix and !important to ensure they override component styles, making them reliable for quick adjustments.
Component Structure
Each component follows a consistent pattern:
Example: Feature Box Component
sass/components/_feature-box.scss
@use "../abstracts/variables" as * ;
.feature-box {
background-color : rgba ( $color-white , .8 );
font-size : 1.5 rem ;
padding : 2.4 rem ;
text-align : center ;
border-radius : 4 px ;
box-shadow : 0 1.5 rem 4 rem rgba ( $color-black , .15 );
cursor : default ;
transition : transform .3 s ease ;
& __icon {
font-size : 6 rem ;
margin-bottom : .5 rem ;
display : inline-block ;
background-image : linear-gradient (
to right ,
$color-primary-light ,
$color-primary-dark
);
-webkit-background-clip : text ;
background-clip : text ;
color : transparent ;
}
& :hover {
transform : translateY ( -6 px ) scale ( 1.03 );
}
}
BEM Naming Components use BEM (Block Element Modifier) naming with &__ for elements and &-- for modifiers.
Single Responsibility Each component file contains styles for one UI component and its variations.
Layout Structure
Grid System
The grid system demonstrates advanced Sass usage:
sass/components/layout/_grid.scss
@use "../../abstracts/variables" as * ;
@use "../../abstracts/mixins" as * ;
.row {
max-width : $grid-width ;
margin : 0 auto ;
& :not ( :last-child ) {
margin-bottom : $gutter-vertical ;
}
@include clearfix ;
[ class ^= " col- " ] {
float : left ;
& :not ( :last-child ) {
margin-right : $gutter-horizontal ;
}
}
.col-1-of-2 {
width : calc (( 100 % - #{$gutter-horizontal} ) / 2 );
}
.col-1-of-3 {
width : calc (( 100 % - 2 * #{$gutter-horizontal} ) / 3 );
}
.col-1-of-4 {
width : calc (( 100 % - 3 * #{$gutter-horizontal} ) / 4 );
}
}
Notice the ../../ path to access abstracts from the nested layout folder. The module system uses relative paths based on file location.
Compilation Process
Entry Point
Sass compiler reads sass/main.scss
Resolve Dependencies
Processes all @use directives recursively
Evaluate Abstracts
Resolves variables, mixins, and functions
Generate CSS
Outputs compiled CSS to css/style.css
npm run compile:sass
# Runs: sass sass/main.scss css/style.css -w
The -w flag enables watch mode. The compiler will recompile automatically whenever any .scss file changes.
Best Practices
Consistent Imports Always import abstracts at the top of component files using as * for convenience.
Partial Files All Sass files except main.scss start with underscore (_) to mark them as partials.
Relative Paths Use relative paths in @use directives. Navigate up with ../ as needed.
Load Order Import abstracts before base, base before components. Order matters for dependencies.
Next Steps
Architecture Learn about the overall project architecture
Responsive Design Explore the responsive design system