Getting Started with SASS SCSS
SCSS (Sassy CSS) is a powerful extension of CSS that revolutionizes the way you write your stylesheets. As a CSS preprocessor, SCSS allows you to use variables, functions, and control structures to create more maintainable and efficient styles.
Educational objectives
- Understanding what SASS/SCSS is and its advantages over classic CSS
- Mastering the use of SCSS variables for better organization
- Learn how to create and use mixins to reuse code
- Discover the interrelationship of CSS rules and its best practices
- Knowing how to organize and structure an SCSS project with imports
What is SASS?
SASS (Syntactically Awesome StyleSheets) is a CSS preprocessor created in 2006 that extends the capabilities of traditional CSS. It exists in two syntaxes: SASS (with indentation) and SCSS (Sassy CSS, with curly braces). SCSS is more popular because its syntax more closely resembles classic CSS, making it easier for developers already familiar with CSS to learn.
The advantages of SCSS
SCSS brings several features missing from CSS: variables for storing reusable values, mixins to avoid code repetition, nesting for better rule organization, and functions for dynamic calculations. These tools allow for writing more maintainable, readable, and efficient code.
Key point SCSS must be compiled into CSS to be interpreted by web browsers.
Key points to remember
SCSS is a CSS preprocessor that adds advanced features like variables and mixins, requiring compilation to become standard CSS.
🎯 Mini-exercise: Your first SCSS file
Discover the difference between CSS and SCSS by creating a simple style with variables.
Reference code:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Introduction SCSS</title>
</head>
<body>
<header class="header">
<h1 class="header__title">Welcome to SCSS</h1>
<p class="header__subtitle">Discover the power of CSS preprocessors</p>
</header>
<main class="main">
<div class="card">
<h2 class="card__title">My first SCSS card</h2>
<p class="card__content">This content is styled with SCSS and its variables!</p>
</div>
</main>
</body>
</html>
// SCSS Variables - Color Definition $primary-color: #667eea; $secondary-color: #764ba2; $text-color: #333; $bg-color: #f8fafc; // Variables for spacing $spacing-small: 8px; $spacing-medium: 16px; $spacing-large: 24px; // Basic styles body { font-family: 'Arial', sans-serif; background-color: $bg-color; color: $text-color; margin: 0; padding: $spacing-large; } // Header with SCSS nesting .header { text-align: center; padding: $spacing-large; background: linear-gradient(135deg, $primary-color, $secondary-color); color:white; border-radius: 8px; margin-bottom: $spacing-large; &__title { font-size: 2rem; margin: 0 0 $spacing-small 0; } &__subtitle { font-size: 1.1rem; margin: 0; opacity: 0.9; } } // Card component .card { background: white; padding: $spacing-large; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); &__title { color: $primary-color; font-size: 1.5rem; margin: 0 0 $spacing-medium 0; } &__content { line-height: 1.6; margin: 0; } }
Monaco Editor v0.45
Syntax and use of variables
SCSS variables are declared with the dollar sign ($) followed by the variable name. They can store colors, sizes, fonts, or any other CSS value. For example: `$primary-color: #3498db;` or `$font-size: 16px;`. This approach allows you to centralize important values and easily modify them in one place.
Types of variables and best practices
SCSS accepts various types of variables: colors (hexadecimal, RGB, HSL), numbers with or without units, strings, booleans, and lists. It is recommended to name your variables descriptively (e.g., $button-primary-color rather than $blue) and to organize them at the beginning of the file or in a dedicated file (_variables.scss).
Key point : SCSS variables have a scope: they can be global or local to a selector.
Key points to remember
SCSS variables begin with $ and allow for the storage of reusable values, facilitating maintenance and design consistency.
🎯 Mini-exercise: Complete variable system
Create a variable system for the colors, typography, and spacing of a consistent theme.
Reference code:
<div class="theme-demo">
<div class="color-palette">
<h2>Color palette</h2>
<div class="color-grid">
<div class="color-swatch primary">
<span>Primary</span>
</div>
<div class="color-swatch secondary">
<span>Secondary</span>
</div>
<div class="color-swatch accent">
<span>Accent</span>
</div>
<div class="color-swatch neutral">
<span>Neutral</span>
</div>
</div>
</div>
<div class="typography-demo">
<h2>Typography</h2>
<h1 class="heading-xl">Title XL</h1>
<h2 class="heading-lg">Title Large</h2>
<h3 class="heading-md">Medium Title</h3>
<p class="body-text">Standard body text with the configured font</p>
<small class="caption">Smaller caption text</small>
</div>
<div class="spacing-demo">
<h2>Spacing system</h2>
<div class="box spacing-xs">XS</div>
<div class="box spacing-sm">SM</div>
<div class="box spacing-md">MD</div>
<div class="box spacing-lg">LG</div>
<div class="box spacing-xl">XL</div>
</div>
</div>
// === SCSS VARIABLE SYSTEM === // Color palette $color-primary: #2563eb; // Primary blue $color-secondary: #10b981; // Secondary green $color-accent: #f59e0b; // Accent orange $color-neutral: #6b7280; // Neutral gray // Derived colors $color-primary-light: lighten($color-primary, 20%); $color-primary-dark: darken($color-primary, 15%); $color-bg: #f8fafc; $color-text: #1f2937; $color-text-light: #9ca3af; // Typography $font-family-primary: 'Inter', 'Segoe UI', sans-serif; $font-family-mono: 'Fira Code', minivan; $font-size-xs: 0.75rem; // 12px $font-size-sm: 0.875rem; // 14px $font-size-base: 1rem; // 16px $font-size-lg: 1.125rem; // 18px $font-size-xl: 1.25rem; // 20px $font-size-2xl: 1.5rem; // 24px $font-size-3xl: 2rem; // 32px $font-weight-normal: 400; $font-weight-medium: 500; $font-weight-bold:700; // Spacing (system in multiples of 8px) $space-xs: 0.25rem; // 4px $space-sm: 0.5rem; // 8px $space-md: 1rem; // 16px $space-lg: 1.5rem; // 24px $space-xl: 2rem; // 32px $space-2xl: 3rem; // 48px // Border rays $radius-sm: 4px; $radius-md:8px; $radius-lg:12px; // === USE OF VARIABLES === body { font-family: $font-family-primary; font-size: $font-size-base; color: $color-text; background-color: $color-bg; margin: 0; padding: $space-lg; } .theme-demo { max-width: 800px; margin: 0 auto; h2 { font-size: $font-size-2xl; font-weight: $font-weight-bold; color: $color-primary; margin: $space-xl 0 $space-lg 0; } } // Color palette .color-palette { margin-bottom: $space-2xl; } .color-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: $space-md; } .color-swatch { height: 100px; border-radius: $radius-md; display:flex; align-items: center; justify-content: center; color:white; font-weight: $font-weight-medium; &.primary { background-color: $color-primary; } &.secondary { background-color: $color-secondary; } &.accent { background-color: $color-accent; } &.neutral { background-color: $color-neutral; } } // Typography .typography-demo { margin-bottom: $space-2xl; } .heading-xl { font-size: $font-size-3xl; font-weight: $font-weight-bold; color: $color-primary; margin: $space-md 0; } .heading-lg { font-size: $font-size-2xl; font-weight: $font-weight-bold; color: $color-text; margin: $space-md 0; } .heading-md { font-size: $font-size-xl; font-weight: $font-weight-medium; color: $color-text; margin: $space-sm 0; } .body-text { font-size: $font-size-base; line-height: 1.6; color: $color-text; margin: $space-sm 0; } .caption { font-size: $font-size-sm; color: $color-text-light; } // Spacing demo .spacing-demo .box { background: $color-primary; color:white; border-radius: $radius-sm; margin-bottom: $space-sm; display: inline-flex; align-items: center; justify-content: center; font-weight: $font-weight-medium; &.spacing-xs { padding: $space-xs; } &.spacing-sm { padding: $space-sm; } &.spacing-md { padding: $space-md; } &.spacing-lg { padding: $space-lg; } &.spacing-xl { padding: $space-xl; } }
Monaco Editor v0.45
Principle of nesting
SCSS nesting allows you to write CSS rules inside other rules, mirroring the HTML structure. Instead of writing ".nav", then ".nav ul", then ".nav ul li", you can nest these rules within each other. This approach makes the code more readable and maintains a clear visual hierarchy.
The parent selector (&) and its uses
The ampersand (&) references the parent selector in SCSS. It is particularly useful for pseudo-classes (&:hover), pseudo-elements (&::before), and class modifiers (&.active). This feature prevents repetition and keeps the code organized around the main component.
Key point Limit nesting to a maximum of 3-4 levels to avoid overly specific and difficult-to-maintain CSS.
Key points to remember
SCSS nesting allows you to organize CSS according to the HTML structure, using the & selector to reference the parent element.
🎯 Mini-exercise: Navigation with advanced nesting
Build a responsive navigation using SCSS nesting and the parent selector.
Reference code:
<nav class="navbar">
<div class="navbar__container">
<div class="navbar__brand">
<a href="#" class="navbar__logo">
<span class="navbar__logo-icon">🚀</span>
<span class="navbar__logo-text">MySite</span>
</a>
</div>
<button class="navbar__toggle" aria-label="Menu">
<span class="navbar__hamburger"></span>
<span class="navbar__hamburger"></span>
<span class="navbar__hamburger"></span>
</button>
<div class="navbar__menu">
<ul class="navbar__nav">
<li class="navbar__item">
<a href="#" class="navbar__link navbar__link--active">Welcome</a>
</li>
<li class="navbar__item">
<a href="#" class="navbar__link">Services</a>
</li>
<li class="navbar__item navbar__item--dropdown">
<a href="#" class="navbar__link">
Products
<span class="navbar__dropdown-arrow">▼</span>
</a>
<ul class="navbar__dropdown">
<li><a href="#" class="navbar__dropdown-link">Web Design</a></li>
<li><a href="#" class="navbar__dropdown-link">Development</a></li>
<li><a href="#" class="navbar__dropdown-link">Consulting</a></li>
</ul>
</li>
<li class="navbar__item">
<a href="#" class="navbar__link">Contact</a>
</li>
</ul>
<div class="navbar__actions">
<a href="#" class="navbar__btn navbar__btn--outline">Login</a>
<a href="#" class="navbar__btn navbar__btn--primary">Signup</a>
</div>
</div>
</div>
</nav>
<main style="padding: 2rem; text-align: center;">
<h1>SCSS navigation with nesting</h1>
<p>Test the dropdown menu and interactions!</p>
</main>
// Variables $primary-color: #3b82f6; $secondary-color: #1e40af; $white: #ffffff; $gray-100: #f3f4f6; $gray-500: #6b7280; $gray-800: #1f2937; $shadow: 0 4px 6px rgba(0, 0, 0, 0.1); $transition: all 0.3s ease; // Reset * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; } // Main navigation with SCSS nesting .navbar { background: $white; box-shadow: $shadow; position:sticky; top: 0; z-index: 1000; // Main container &__container { max-width: 1200px; margin: 0 auto; display:flex; align-items: center; justify-content: space-between; padding: 0 1rem; height: 70px; } // Logo/brand section &__brand { flex-shrink: 0; } &__logo { display: flex; align-items: center; text-decoration: none; color: $gray-800; font-weight: bold; font-size: 1.5rem; transition: $transition; // Hover effect on the full logo &:hover { color: $primary-color; transform: scale(1.05); } // Logo icon &-icon { margin-right: 0.5rem; font-size: 1.8rem; } // Logo text &-text { font-weight: 700; } } // Hamburger button (mobile) &__toggle { display: none; flex-direction: column; background:none; border:none; cursor: pointer; padding: 0.5rem; // Hamburger lines .navbar__hamburger { width: 25px; height: 3px; background: $gray-800; margin: 2px 0; transition: $transition; } // Animation hover hamburger &:hover .navbar__hamburger { background: $primary-color; } } // Menu container &__menu { display: flex; align-items: center; gap: 2rem; @media (max-width: 768px) { position: fixed; top: 70px; left: -100%; width: 100%; height: calc(100vh - 70px); background: $white; flex-direction: column; justify-content: flex-start; padding: 2rem; transition: left 0.3s ease; box-shadow: $shadow; // Open state (added via JS) &.active { left: 0; } } } // Navigation list &__nav { display: flex; list-style: none; gap: 1rem; @media (max-width: 768px) { flex-direction: column; width: 100%; gap: 0; } } // Navigation items &__item { position: relative; // Item with dropdown &--dropdown { // Display dropdown on hover &:hover .navbar__dropdown { opacity: 1; visibility: visible; transform: translateY(0); } // Animation of the arrow &:hover .navbar__dropdown-arrow { transform: rotate(180deg); } } @media (max-width: 768px) { width: 100%; border-bottom: 1px solid $gray-100; &:last-child { border-bottom: none; } } } // Navigation links &__link { display: flex; align-items: center; padding: 0.75rem 1rem; color: $gray-800; text-decoration: none; font-weight: 500; transition: $transition; border-radius: 6px; // Link states &:hover { color: $primary-color; background: rgba($primary-color, 0.1); } // Active link &--active { color: $primary-color; background: rgba($primary-color, 0.15); font-weight: 600; // No change to hover if already active &:hover { background: rgba($primary-color, 0.15); } } @media (max-width: 768px) { width: 100%; padding: 1rem; border-radius: 0; } } // Dropdown arrow &__dropdown-arrow { margin-left: 0.5rem; font-size: 0.8rem; transition: transform 0.3s ease; } // Dropdown menu &__dropdown { position: absolute; top: 100%; left: 0; background: $white; min-width: 200px; box-shadow: $shadow; border-radius: 8px; list-style: none; opacity: 0; visibility: hidden; transform: translateY(-10px); transition: all 0.3s ease; z-index: 1000; @media (max-width: 768px) { position: static; box-shadow: none; background: $gray-100; border-radius: 0; opacity: 1; visibility: visible; transform:none; margin-top: 0.5rem; } } // Dropdown links &__dropdown-link { display: block; padding: 0.75rem 1rem; color: $gray-800; text-decoration: none; transition: $transition; // First and last item &:first-child { border-radius: 8px 8px 0 0; } &:last-child { border-radius: 0 0 8px 8px; } // Hover dropdown &:hover { background: $gray-100; color: $primary-color; padding-left: 1.25rem; } @media (max-width: 768px) { padding: 0.5rem 1rem; &:first-child, &:last-child { border-radius: 0; } &:hover { padding-left: 1rem; background: rgba($primary-color, 0.1); } } } // Actions section (buttons) &__actions { display: flex; gap: 0.5rem; @media (max-width: 768px) { flex-direction: column; width: 100%; margin-top: 1rem; } } // Action buttons &__btn { padding: 0.5rem 1rem; border-radius: 6px; text-decoration: none; font-weight: 600; text-align: center; transition: $transition; // Button outline &--outline { color: $primary-color; border: 2px solid $primary-color; background: transparent; &:hover { background: $primary-color; color: $white; transform: translateY(-1px); } } // Primary button &--primary { background: $primary-color; color: $white; border: 2px solid $primary-color; &:hover { background: $secondary-color; border-color: $secondary-color; transform: translateY(-1px); box-shadow: 0 4px 12px rgba($primary-color, 0.3); } } @media (max-width: 768px) { padding: 0.75rem 1rem; margin: 0.25rem 0; } } // Responsive - hamburger display @media (max-width: 768px) { &__toggle { display: flex; } } }
Monaco Editor v0.45
Understanding Mixins
Mixins are reusable CSS code blocks defined with `@mixin` and used with `@include`. They help avoid code duplication and allow you to apply complex sets of properties in a single line. A mixin can contain any CSS declarations: properties, nested selectors, and even other mixins.
Mixins with parameters and default values
Mixins accept parameters for greater flexibility. For example, a button mixin can take color and size as parameters. You can define default values for these parameters: `@mixin button($color: blue, $size: medium)`. This approach allows you to create modular and customizable components.
Key point Use mixins for complex repetitive code, but prefer variables for simple values.
Key points to remember
Mixins (@mixin/@include) allow you to reuse complex CSS blocks with customizable parameters.
🎯 Mini-exercise: Utility Mixin Library
Create advanced mixins for buttons, flex layout and animations with customizable parameters.
Reference code:
<div class="demo-container">
<section class="buttons-demo">
<h2>Button Mixins</h2>
<div class="button-group">
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-success">Success</button>
<button class="btn btn-danger">Hazard</button>
</div>
<div class="button-group">
<button class="btn btn-outline-primary">Outline Primary</button>
<button class="btn btn-outline-secondary">Outline Secondary</button>
</div>
<div class="button-group">
<button class="btn btn-gradient">Gradient</button>
<button class="btn btn-glass">Glass Effect</button>
<button class="btn btn-neon">Neon Glow</button>
</div>
</section>
<section class="layout-demo">
<h2>Flexbox Layout Mixins</h2>
<div class="flex-center">
<div class="card">Centered H&V</div>
</div>
<div class="flex-between">
<div class="card">LEFT</div>
<div class="card">Center</div>
<div class="card">RIGHT</div>
</div>
<div class="flex-column">
<div class="card">Item 1</div>
<div class="card">Item 2</div>
<div class="card">Item 3</div>
</div>
</section>
<section class="animation-demo">
<h2>Animation Mixins</h2>
<div class="animation-grid">
<div class="animated-card bounce">Bounce</div>
<div class="animated-card slide">Slide</div>
<div class="animated-card fade">Bland</div>
<div class="animated-card rotate">Rotate</div>
<div class="animated-card pulse">Pulse</div>
<div class="animated-card shake">Shake</div>
</div>
</section>
</div>
// === SCSS UTILITY MIXIN LIBRARY === // Global variables $primary: #3b82f6; $secondary: #64748b; $success: #10b981; $danger: #ef4444; $white: #ffffff; $dark: #1e293b; // === BUTTON MIXINS === // Base mixin for buttons @mixin button-base($padding: 0.75rem 1.5rem, $border-radius: 8px) { display: inline-block; padding: $padding; border: none; border-radius: $border-radius; cursor: pointer; font-weight: 600; text-decoration: none; text-align: center; transition: all 0.3s ease; font-size: 1rem; line-height: 1.5; &:focus { outline: 2px solid rgba($primary, 0.5); outline-offset: 2px; } } // Mixin button solid @mixin button-solid($bg-color: $primary, $text-color: $white, $hover-darken: 10%) { @include button-base; background-color: $bg-color; color: $text-color; box-shadow: 0 2px 4px rgba($bg-color, 0.2); &:hover { background-color: darken($bg-color, $hover-darken); transform: translateY(-2px); box-shadow: 0 4px 8px rgba($bg-color, 0.3); } &:active { transform: translateY(0); box-shadow: 0 2px 4px rgba($bg-color, 0.2); } } // Mixin button outline @mixin button-outline($border-color: $primary, $text-color: $primary, $hover-bg: $primary, $hover-text: $white) { @include button-base; background: transparent; color: $text-color; border: 2px solid $border-color; &:hover { background-color: $hover-bg; color: $hover-text; transform: translateY(-1px); box-shadow: 0 4px 8px rgba($border-color, 0.2); } } // Mixin button gradient @mixin button-gradient($start-color, $end-color, $text-color: $white) { @include button-base; background: linear-gradient(135deg, $start-color 0%, $end-color 100%); color: $text-color; position: relative; overflow:hidden; &::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba($white, 0.2), transparent); transition: left 0.5s; } &:hover::before { left: 100%; } &:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba($start-color, 0.4); } } // Mixin glass effect @mixin button-glass($bg-color: rgba($white, 0.1), $border-color: rgba($white, 0.2)) { @include button-base; background: $bg-color; border: 1px solid $border-color; backdrop-filter: blur(10px); color: $dark; &:hover { background: rgba($white, 0.2); transform: translateY(-2px); box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); } } // Mixin neon effect @mixin button-neon($glow-color: $primary) { @include button-base; background: transparent; color: $glow-color; border: 2px solid $glow-color; text-shadow: 0 0 5px $glow-color; box-shadow: inset 0 0 5px rgba($glow-color, 0.1), 0 0 5px rgba($glow-color, 0.3); &:hover { background: rgba($glow-color, 0.1); box-shadow: inset 0 0 10px rgba($glow-color, 0.2), 0 0 15px rgba($glow-color, 0.5), 0 0 30px rgba($glow-color, 0.3); text-shadow: 0 0 10px $glow-color; } } // === MIXINS LAYOUT FLEXBOX === @mixin flex-center { display: flex; justify-content: center; align-items: center; } @mixin flex-between { display: flex; justify-content: space-between; align-items: center; } @mixin flex-column($gap: 1rem) { display: flex; flex-direction: column; gap: $gap; } @mixin flex-grid($columns: 3, $gap: 1rem) { display: grid; grid-template-columns: repeat($columns, 1fr); gap: $gap; } // === MIXINS ANIMATIONS === @mixin animate($name, $duration: 0.6s, $timing: ease, $iteration: infinite) { animation: #{$name} $duration $timing $iteration; } // Keyframes animations @keyframes bounceEffect { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-10px); } 60% { transform: translateY(-5px); } } @keyframes slideIn { from { transform: translateX(-20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes fadeInOut { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } } @keyframes rotateGlow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes pulseGrow { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } @keyframes shakeHorizontal { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } } // === USING MIXINS === * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', 'Segoe UI', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: $dark; min-height: 100vh; padding: 2rem; } .demo-container { max-width: 1000px; margin: 0 auto; section { background: rgba($white, 0.95); padding: 2rem; border-radius: 16px; margin-bottom: 2rem; backdrop-filter: blur(10px); h2 { margin-bottom: 1.5rem; color: $dark; text-align: center; } } } // Applying button mixins .btn { margin: 0.25rem; &-primary { @include button-solid($primary); } &-secondary { @include button-solid($secondary); } &-success { @include button-solid($success); } &-danger { @include button-solid($danger); } &-outline-primary { @include button-outline($primary); } &-outline-secondary { @include button-outline($secondary); } &-gradient { @include button-gradient($primary, darken($primary, 20%)); } &-glass { @include button-glass(); } &-neon { @include button-neon($success); } } .button-group { @include flex-center; flex-wrap:wrap; margin-bottom: 1rem; &:last-child { margin-bottom: 0; } } // Applying mixins layout .flex-center { @include flex-center; height: 100px; background: rgba($primary, 0.1); border-radius: 8px; margin-bottom: 1rem; } .flex-between { @include flex-between; padding: 1rem; background: rgba($secondary, 0.1); border-radius: 8px; margin-bottom: 1rem; } .flex-column { @include flex-column(0.5rem); padding: 1rem; background: rgba($success, 0.1); border-radius: 8px; } .card { background: $white; padding: 1rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); text-align: center; font-weight: 500; min-width: 100px; } // Applying animation mixins .animation-grid { @include flex-grid(3, 1rem); @media (max-width: 768px) { @include flex-grid(2, 1rem); } @media (max-width: 480px) { @include flex-grid(1, 1rem); } } .animated-card { background: $white; padding: 2rem; border-radius: 12px; text-align: center; font-weight: 600; cursor: pointer; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; &:hover { box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); } &.bounce:hover { @include animate(bounceEffect, 1s, ease-in-out, 3); } &.slide:hover { @include animate(slideIn, 0.8s, ease-out, 1); } &.fade:hover { @include animate(fadeInOut, 1.5s, ease-in-out, 3); } &.rotate:hover { @include animate(rotateGlow, 2s, linear, 1); } &.pulse:hover { @include animate(pulseGrow, 1s, ease-in-out, 3); } &.shake:hover { @include animate(shakeHorizontal, 0.5s, ease-in-out, 3); } } // Responsive @media (max-width: 768px) { .demo-container { padding: 1rem; section { padding: 1.5rem; } } .btn { font-size: 0.9rem; padding: 0.6rem 1.2rem; } }
Monaco Editor v0.45
SCSS file architecture
A well-organized SCSS structure organizes the code into several files according to their function: _variables.scss for variables, _mixins.scss for mixins, _base.scss for base styles, and files for each component (_buttons.scss, _navbar.scss). This modular approach facilitates maintenance and allows for efficient teamwork.
Imports and the @use rule
SCSS uses @import (the older method) or @use (the recommended method) to include files. Partial files begin with an underscore (e.g., _variables.scss) and are not compiled individually. The @use directive replaces @import because it avoids name conflicts and allows for better control of namespaces.
Key point : Create a main.scss file that imports all your partial files in the correct order (variables, mixins, base, components).
Key points to remember
Organize your SCSS files into modules with @use/@forward for a maintainable architecture and to avoid conflicts.
🎯 Mini-exercise: Complete SCSS Architecture
Simulate a modular SCSS architecture with organized variables, mixins, and components.
Reference code:
<!-- Simulation d'une application complète avec architecture SCSS modulaire -->
<div class="app">
<!-- Header avec navigation -->
<header class="header">
<div class="container">
<div class="header__brand">
<h1 class="logo">🎨 Design System</h1>
</div>
<nav class="navbar">
<ul class="navbar__list">
<li class="navbar__item">
<a href="#" class="navbar__link navbar__link--active">Welcome</a>
</li>
<li class="navbar__item">
<a href="#" class="navbar__link">Components</a>
</li>
<li class="navbar__item">
<a href="#" class="navbar__link">Documentation</a>
</li>
</ul>
</nav>
</div>
</header>
<!-- Section hero -->
<section class="hero">
<div class="container">
<div class="hero__content">
<h2 class="hero__title">Modular SCSS Architecture</h2>
<p class="hero__subtitle">
Discover how to organize your SCSS files for maintainable and scalable code.
</p>
<div class="hero__actions">
<button class="btn btn--primary">To start</button>
<button class="btn btn--secondary">Documentation</button>
</div>
</div>
</div>
</section>
<!-- Section composants -->
<section class="components">
<div class="container">
<h2 class="section__title">Design System Components</h2>
<div class="grid grid--3-col">
<article class="card">
<div class="card__header">
<span class="card__icon">🔘</span>
<h3 class="card__title">Buttons</h3>
</div>
<div class="card__content">
<p>Collection of buttons with different states and variations.</p>
<div class="card__buttons">
<button class="btn btn--small btn--primary">Primary</button>
<button class="btn btn--small btn--outline">Outline</button>
</div>
</div>
</article>
<article class="card">
<div class="card__header">
<span class="card__icon">📝</span>
<h3 class="card__title">Forms</h3>
</div>
<div class="card__content">
<p>Stylish and consistent input fields.</p>
<div class="form-group">
<input type="text" class="input" placeholder="Example of input">
<input type="email" class="input input--success" placeholder="Email verified" readonly value="user@example.com">
</div>
</div>
</article>
<article class="card">
<div class="card__header">
<span class="card__icon">🎨</span>
<h3 class="card__title">Alerts</h3>
</div>
<div class="card__content">
<p>Information messages for the user.</p>
<div class="alert alert--success">
✅ Operation successful!
</div>
<div class="alert alert--warning">
⚠️ Attention required
</div>
</div>
</article>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer__content">
<div class="footer__section">
<h4>SCSS Architecture</h4>
<ul>
<li><a href="#">Variables</a></li>
<li><a href="#">Mixins</a></li>
<li><a href="#">Components</a></li>
</ul>
</div>
<div class="footer__section">
<h4>Resources</h4>
<ul>
<li><a href="#">Documentation</a></li>
<li><a href="#">Style guide</a></li>
<li><a href="#">Examples</a></li>
</ul>
</div>
</div>
<div class="footer__bottom">
<p>© 2024 - Made with modular SCSS</p>
</div>
</div>
</footer>
</div>
// ========================================= // SIMULATED MODULAR SCSS ARCHITECTURE // ========================================= // In a real project, these blocks would be in separate files: // - abstracts/_variables.scss // - abstracts/_mixins.scss // - base/_reset.scss // - base/_typography.scss // - layout/_container.scss // - layout/_grid.scss // - components/_buttons.scss // - components/_cards.scss // - components/_forms.scss // - etc. // ========================================== // 📁 abstracts/_variables.scss // ========================================= // Color palette $color-primary: #3b82f6; $color-primary-light: #93c5fd; $color-primary-dark: #1e40af; $color-secondary: #64748b; $color-secondary-light: #94a3b8; $color-secondary-dark: #334155; $color-success: #10b981; $color-warning: #f59e0b; $color-danger: #ef4444; $color-info: #06b6d4; // Neutral colors $color-white: #ffffff; $color-gray-50: #f8fafc; $color-gray-100: #f1f5f9; $color-gray-200: #e2e8f0; $color-gray-300: #cbd5e1; $color-gray-400: #94a3b8; $color-gray-500: #64748b; $color-gray-600: #475569; $color-gray-700: #334155; $color-gray-800: #1e293b; $color-gray-900: #0f172a; // Typography $font-family-primary: 'Inter', 'SF Pro Display', -apple-system, sans-serif; $font-family-mono: 'Fira Code', 'Monaco', minivan; $font-size-xs: 0.75rem; $font-size-sm: 0.875rem; $font-size-base: 1rem; $font-size-lg: 1.125rem; $font-size-xl: 1.25rem; $font-size-2xl: 1.5rem; $font-size-3xl: 1.875rem; $font-size-4xl: 2.25rem; $font-weight-light: 300; $font-weight-normal: 400; $font-weight-medium: 500; $font-weight-semibold: 600; $font-weight-bold:700; // Spacings (8px system) $space-1: 0.25rem; // 4px $space-2: 0.5rem; // 8px $space-3: 0.75rem; // 12px $space-4: 1rem; // 16px $space-5: 1.25rem; // 20px $space-6: 1.5rem; // 24px $space-8: 2rem; // 32px $space-10: 2.5rem; // 40px $space-12:3rem; // 48px $space-16: 4rem; // 64px // Border radii $radius-sm: 0.375rem; $radius-base: 0.5rem; $radius-lg: 0.75rem; $radius-xl: 1rem; $radius-full: 9999px; // Shadows $shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); $shadow-base: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06); $shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05); $shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04); // Breakpoints $breakpoint-sm: 640px; $breakpoint-md:768px; $breakpoint-lg: 1024px; $breakpoint-xl: 1280px; // Transitions $transition-base: all 0.2s ease-in-out; $transition-fast: all 0.1s ease-in-out; $transition-slow: all 0.3s ease-in-out; // ========================================= // 📁 abstracts/_mixins.scss // ========================================= // Container responsive @mixin container { width: 100%; max-width: 1280px; margin-left: auto; margin-right: auto; padding-left: $space-4; padding-right: $space-4; @media (min-width: $breakpoint-sm) { padding-left: $space-6; padding-right: $space-6; } } // Mixin button @mixin button($variant: 'primary') { display: inline-flex; align-items: center; justify-content: center; padding: $space-3 $space-6; border: 2px solid transparent; border-radius: $radius-lg; font-weight: $font-weight-medium; font-size: $font-size-base; text-decoration: none; cursor: pointer; transition: $transition-base; &:focus { outline: 2px solid rgba($color-primary, 0.5); outline-offset: 2px; } @if $variant == 'primary' { background-color: $color-primary; color: $color-white; &:hover { background-color: $color-primary-dark; transform: translateY(-1px); box-shadow: $shadow-lg; } } @if $variant == 'secondary' { background-color: $color-secondary; color: $color-white; &:hover { background-color: $color-secondary-dark; transform: translateY(-1px); box-shadow: $shadow-lg; } } @if $variant == 'outline' { background-color: transparent; border-color: $color-primary; color: $color-primary; &:hover { background-color: $color-primary; color: $color-white; } } } // Mixin card @mixin card { background-color: $color-white; border-radius: $radius-xl; box-shadow: $shadow-base; overflow:hidden; transition: $transition-base; &:hover { box-shadow: $shadow-xl; transform: translateY(-2px); } } // Mixin grid @mixin grid($columns: 1, $gap: $space-6) { display: grid; grid-template-columns: repeat($columns, 1fr); gap: $gap; @media (max-width: $breakpoint-md) { grid-template-columns: 1fr; gap: $space-4; } } // ========================================= // 📁 base/_reset.scss // ========================================= * { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 16px; scroll-behavior: smooth; } body { font-family: $font-family-primary; font-weight: $font-weight-normal; line-height: 1.6; color: $color-gray-800; background-color: $color-gray-50; } // ========================== // 📁 layout/_container.scss // ========================================= .container { @include container; } // ========================== // 📁 layout/_grid.scss // ======================================== .grid { &--3-col { @include grid(3); } &--2-col { @include grid(2); } } // ========================================= // 📁 components/_buttons.scss // ======================================== .btn { @include button(); &--primary { @include button('primary'); } &--secondary { @include button('secondary'); } &--outline { @include button('outline'); } &--small { padding: $space-2 $space-4; font-size: $font-size-sm; } } // ========================================= // 📁 components/_cards.scss // ======================================== .card { @include card; &__header { padding: $space-6 $space-6 $space-4 $space-6; display:flex; align-items: center; gap: $space-3; } &__icon { font-size: $font-size-2xl; } &__title { font-size: $font-size-xl; font-weight: $font-weight-semibold; color: $color-gray-800; } &__content { padding: 0 $space-6 $space-6 $space-6; p { color: $color-gray-600; margin-bottom: $space-4; } } &__buttons { display: flex; gap: $space-2; flex-wrap:wrap; } } // ========================================= // 📁 components/_forms.scss // ======================================== .form-group { display: flex; flex-direction: column; gap: $space-2; } .input { width: 100%; padding: $space-3; border: 2px solid $color-gray-200; border-radius: $radius-lg; font-size: $font-size-base; transition: $transition-base; &:focus { outline: none; border-color: $color-primary; box-shadow: 0 0 0 3px rgba($color-primary, 0.1); } &::placeholder { color: $color-gray-400; } &--success { border-color: $color-success; background-color: rgba($color-success, 0.05); } } // ========================================= // 📁 components/_alerts.scss // ======================================== .alert { padding: $space-3 $space-4; border-radius: $radius-base; margin-bottom: $space-2; font-weight: $font-weight-medium; &--success { background-color: rgba($color-success, 0.1); border: 1px solid rgba($color-success, 0.3); color: darken($color-success, 20%); } &--warning { background-color: rgba($color-warning, 0.1); border: 1px solid rgba($color-warning, 0.3); color: dark($color-warning, 20%); } } // ========================================= // 📁 layout/_header.scss // ======================================== .header { background-color: $color-white; box-shadow: $shadow-sm; border-bottom: 1px solid $color-gray-200; .container { display: flex; align-items: center; justify-content: space-between; padding-top: $space-4; padding-bottom: $space-4; } &__brand { .logo { font-size: $font-size-2xl; font-weight: $font-weight-bold; color: $color-primary; } } } // ========================================= // 📁 components/_navbar.scss // ========================================= .navbar { &__list { display: flex; list-style: none; gap: $space-2; @media (max-width: $breakpoint-md) { flex-direction: column; gap: 0; } } &__item { // Item styles } &__link { display: block; padding: $space-2 $space-4; color: $color-gray-600; text-decoration: none; border-radius: $radius-base; transition: $transition-base; font-weight: $font-weight-medium; &:hover { color: $color-primary; background-color: rgba($color-primary, 0.1); } &--active { color: $color-primary; background-color: rgba($color-primary, 0.1); } } } // ========================================== // 📁 layout/_hero.scss // ======================================== .hero { background: linear-gradient(135deg, $color-primary 0%, $color-primary-dark 100%); color: $color-white; padding: $space-16 0; text-align: center; &__title { font-size: $font-size-4xl; font-weight: $font-weight-bold; margin-bottom: $space-4; @media (max-width: $breakpoint-md) { font-size: $font-size-3xl; } } &__subtitle { font-size: $font-size-xl; margin-bottom: $space-8; opacity: 0.9; max-width: 600px; margin-left: auto; margin-right: auto; @media (max-width: $breakpoint-md) { font-size: $font-size-lg; } } &__actions { display: flex; gap: $space-4; justify-content: center; flex-wrap:wrap; } } // ========================================= // 📁 layout/_sections.scss // ======================================== .components { padding: $space-16 0; } .section { &__title { text-align: center; font-size: $font-size-3xl; font-weight: $font-weight-bold; color: $color-gray-800; margin-bottom: $space-12; } } // ========================================= // 📁 layout/_footer.scss // ======================================== .footer { background-color: $color-gray-800; color: $color-gray-300; padding: $space-12 0 $space-6 0; &__content { @include grid(2, $space-8); margin-bottom: $space-8; } &__section { h4 { color: $color-white; font-weight: $font-weight-semibold; margin-bottom: $space-4; } ul { list-style: none; li { margin-bottom: $space-2; a { color: $color-gray-400; text-decoration: none; transition: $transition-base; &:hover { color: $color-white; } } } } } &__bottom { text-align: center; padding-top: $space-6; border-top: 1px solid $color-gray-700; color: $color-gray-400; } } // ========================================= // 📁 main.scss (main file) // ========================================== // In a real project, this file would only contain: // @use 'abstracts/variables'; // @use 'abstracts/mixins'; // @use 'base/reset'; // @use 'base/typography'; // @use 'layout/container'; // @use 'layout/grid'; // @use 'components/buttons'; // @use 'components/cards'; // etc...
Monaco Editor v0.45
Summary
Key points to remember
- SCSS is a CSS preprocessor It adds powerful features like variables and mixins, requiring compilation to CSS
- Variables with $ They begin with $ and allow for the centralization of values for better maintenance.
- Nesting and selector & Organize the CSS according to the HTML structure, using & to reference the parent element
- Mixins (@mixin/@include) Create reusable code blocks with parameters to avoid duplication
- Modular architecture Organize your SCSS files into modules with @use for a maintainable and scalable structure.
Sources
To deepen your knowledge:
Validate your knowledge
Test your understanding with this 10-question quiz:

