Sass Variables
Variables are one of the most powerful features in Sass. They allow you to store values that you want to reuse throughout your stylesheet. This makes updating colors, fonts, and other design elements much easier and more consistent.
Variable Syntax
// Defining variables
$primary-color: #3498db;
$secondary-color: #2ecc71;
$base-font: 'Roboto', sans-serif;
$base-font-size: 16px;
$spacing-unit: 8px;
// Using variables
body {
font-family: $base-font;
font-size: $base-font-size;
color: $primary-color;
margin: $spacing-unit * 2;
}
.button {
background-color: $secondary-color;
padding: $spacing-unit $spacing-unit * 2;
}
Analogy: Variables are like Recipe Ingredients
Think of Sass variables like the ingredients list at the beginning of a recipe. Instead of repeating "2 tablespoons of olive oil" throughout the recipe steps, the recipe just refers to "the olive oil." If you want to substitute another oil, you only need to change it in one place—the ingredients list—not everywhere it's used in the recipe.
Types of Variables
-
Colors:
$primary: #3498db; $secondary: rgb(46, 204, 113); $tertiary: hsl(340, 82%, 52%); -
Numbers:
$base-size: 16px; $line-height: 1.5; $border-radius: 4px; -
Strings:
$font-stack: 'Helvetica', Arial, sans-serif; $image-path: '/assets/images/'; -
Booleans:
$enable-shadows: true; $is-dark-theme: false; -
Lists:
$button-sizes: 'small', 'medium', 'large'; $border-widths: 1px, 2px, 3px; $box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); -
Maps (key-value pairs):
$breakpoints: ( 'small': 576px, 'medium': 768px, 'large': 992px, 'xlarge': 1200px ); -
null (represents absence of a value):
$border: null;
Variable Scope
Variables in Sass have scope, similar to programming languages. There are two types:
- Global Variables: Defined outside any selector and accessible throughout the stylesheet.
- Local Variables: Defined inside a selector and only accessible within that selector and its nested selectors.
$global-color: blue; // Global variable
.container {
$local-padding: 20px; // Local variable
padding: $local-padding;
color: $global-color;
.child {
border: 1px solid $global-color;
margin: $local-padding / 2; // Local variables are accessible in nested selectors
}
}
.another-element {
// This would cause an error as $local-padding is not accessible here
// margin: $local-padding;
// But global variables work fine
color: $global-color;
}
!default Flag
The !default flag allows you to set a default value for a variable that can be overridden:
// _variables.scss
$primary-color: blue !default;
// main.scss
$primary-color: red; // This will override the default
@import 'variables';
body {
color: $primary-color; // Will be red, not blue
}
This is particularly useful for creating customizable libraries or frameworks.
Real-World Example: Design Tokens
Major companies use design tokens (implemented as variables) for consistent branding across platforms:
// Airbnb-inspired design tokens
$rausch: #FF5A5F; // Primary brand color
$babu: #00A699; // Secondary brand color
$arches: #FC642D; // Tertiary brand color
$hof: #484848; // Text color
$foggy: #767676; // Subdued text color
// Spacing scale (8pt grid)
$space-xs: 4px;
$space-sm: 8px;
$space-md: 16px;
$space-lg: 24px;
$space-xl: 32px;
$space-xxl: 64px;
// Font sizes
$text-xs: 12px;
$text-sm: 14px;
$text-md: 16px;
$text-lg: 18px;
$text-xl: 22px;
$text-xxl: 28px;
// Border radius
$radius-sm: 4px;
$radius-md: 8px;
$radius-lg: 12px;
$radius-pill: 999px;
Nesting
Nesting is a feature that allows you to nest CSS selectors inside one another, mirroring the structure of your HTML. This makes your style rules more organized and reduces repetition.
Basic Nesting
CSS
nav {
background: #333;
}
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav ul li {
display: inline-block;
}
nav ul li a {
color: white;
text-decoration: none;
padding: 10px 15px;
display: block;
}
nav ul li a:hover {
background: #555;
}
SCSS with Nesting
nav {
background: #333;
ul {
margin: 0;
padding: 0;
list-style: none;
li {
display: inline-block;
a {
color: white;
text-decoration: none;
padding: 10px 15px;
display: block;
&:hover {
background: #555;
}
}
}
}
}
The & Parent Selector
The ampersand symbol (&) in Sass refers to the parent selector. It's particularly
useful for pseudo-classes, pseudo-elements, and modifier classes.
.button {
padding: 10px 15px;
background: blue;
color: white;
// Pseudo-classes
&:hover {
background: darkblue;
}
// Pseudo-elements
&::before {
content: "→";
margin-right: 5px;
}
// Modifier classes
&.button--large {
padding: 15px 25px;
font-size: 1.2em;
}
// Different states
&.is-active {
background: green;
}
// Parent selectors
.dark-theme & {
background: navy;
color: #eee;
}
}
Warning: Nesting Depth
While nesting makes code more organized, excessive nesting can lead to:
- Overly specific selectors (specificity issues)
- Bloated CSS output
- Styles that are too tightly coupled to HTML structure
Best practice: Limit nesting to 3-4 levels deep.
BEM with Sass
The BEM (Block Element Modifier) methodology pairs particularly well with Sass nesting and the & selector:
.card {
border-radius: 4px;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
// Elements
&__header {
padding: 16px;
border-bottom: 1px solid #eee;
}
&__title {
margin: 0;
font-size: 18px;
}
&__body {
padding: 16px;
}
&__footer {
padding: 16px;
border-top: 1px solid #eee;
}
// Modifiers
&--featured {
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transform: scale(1.05);
}
&--dark {
background: #333;
color: white;
.card__header, .card__footer {
border-color: #555;
}
}
}
This compiles to clean, organized CSS that follows BEM conventions:
.card {
border-radius: 4px;
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.card__header {
padding: 16px;
border-bottom: 1px solid #eee;
}
.card__title {
margin: 0;
font-size: 18px;
}
.card__body {
padding: 16px;
}
.card__footer {
padding: 16px;
border-top: 1px solid #eee;
}
.card--featured {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transform: scale(1.05);
}
.card--dark {
background: #333;
color: white;
}
.card--dark .card__header, .card--dark .card__footer {
border-color: #555;
}
Partials & Imports
Partials are separate files containing Sass code segments. They help you organize
your styles into smaller, more manageable pieces. Combined with the @import
directive, they enable a modular approach to CSS.
Creating Partials
Partials are named with a leading underscore to indicate they shouldn't be compiled directly into CSS:
_variables.scss
_base.scss
_typography.scss
_components.scss
_layout.scss
_utilities.scss
Importing Partials
The @import directive allows you to include the content of one Sass file into another:
// main.scss
@import 'variables';
@import 'base';
@import 'typography';
@import 'layout';
@import 'components';
@import 'utilities';
Note: In Sass, when importing a partial, you can omit both the leading underscore and the file extension.
The 7-1 Pattern
A popular organization method for Sass projects is the 7-1 pattern: 7 folders, 1 file.
- abstracts/: Variables, functions, mixins, and placeholders
- base/: Reset, typography, standard element styles
- components/: Buttons, cards, forms, and other reusable UI components
- layout/: Header, footer, grid system, and general layout components
- pages/: Page-specific styles
- themes/: Different visual themes
- vendors/: Third-party libraries and frameworks
All of these folders contain partial files, which are imported into a single main.scss file:
// main.scss
// Abstracts
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
// Vendors
@import 'vendors/bootstrap';
@import 'vendors/jquery-ui';
// Base
@import 'base/reset';
@import 'base/typography';
// Layout
@import 'layout/header';
@import 'layout/footer';
@import 'layout/grid';
// Components
@import 'components/buttons';
@import 'components/cards';
@import 'components/forms';
// Pages
@import 'pages/home';
@import 'pages/about';
// Themes
@import 'themes/default';
@import 'themes/dark';
Real-World Example: Bootstrap SCSS Structure
Bootstrap, one of the most popular CSS frameworks, uses a similar approach with its SCSS source:
bootstrap/
├── scss/
│ ├── _variables.scss
│ ├── _functions.scss
│ ├── _mixins.scss
│ ├── _root.scss
│ ├── _reboot.scss
│ ├── _type.scss
│ ├── _grid.scss
│ ├── _forms.scss
│ ├── _buttons.scss
│ ├── _transitions.scss
│ ├── _dropdown.scss
│ ├── _nav.scss
│ ├── _navbar.scss
│ └── ...more component files
└── bootstrap.scss (imports all partials)
@use and @forward (Modern Sass)
In modern Sass (from Dart Sass 1.23.0), @use and @forward are
preferred over @import to address namespace issues and improve modularity.
@use
The @use rule loads a Sass file as a module, creating a namespace
for its variables, functions, and mixins:
// _colors.scss
$primary: blue;
$secondary: green;
// main.scss
@use 'colors';
.button {
background-color: colors.$primary; // Access via namespace
color: white;
}
You can also customize the namespace:
@use 'colors' as c;
.button {
background-color: c.$primary;
color: white;
}
Or make all members available without a namespace:
@use 'colors' as *; // Use with caution to avoid name conflicts
.button {
background-color: $primary; // No namespace needed
color: white;
}
@forward
The @forward rule loads a Sass file and makes its variables,
functions, and mixins available to files that @use the forwarding file:
// _variables.scss
$primary: blue;
$secondary: green;
// _colors.scss
@forward 'variables';
$tertiary: red;
// main.scss
@use 'colors';
.button {
background-color: colors.$primary; // From variables.scss
border-color: colors.$tertiary; // From colors.scss
}
This is particularly useful for creating library entry points:
// abstracts/_index.scss
@forward 'variables';
@forward 'functions';
@forward 'mixins';
// main.scss
@use 'abstracts';
body {
color: abstracts.$text-color;
font-family: abstracts.$font-stack;
}
Practice Activities
- Color System: Create a color system with primary, secondary, and accent colors, including light and dark variants for each. Use a naming convention that makes sense.
-
Nesting Challenge: Take the following elements and implement them using proper
Sass nesting:
- A dropdown menu component
- A tabbed interface
- A form with various input types
- Project Organization: Set up a project with the 7-1 pattern and create the basic files needed for a simple website. Focus on the file structure rather than the content.
- BEM Implementation: Create a card component using BEM methodology and Sass nesting. Include variations like featured, dark mode, and different sizes.
Additional Resources
- Sass Variables Documentation
- Sass Nesting Documentation
- @use and @forward Documentation
- How to Structure a Sass Project
- BEM 101
- U.S. Web Design System - A real-world design system using Sass
Key Takeaways
- Variables store reusable values and make maintaining styles easier
- Nesting creates more readable and organized CSS by mimicking HTML structure
- The parent selector (&) is powerful for creating variations and working with BEM
- Partials and imports allow modular organization of your Sass code
- The 7-1 pattern provides a scalable architecture for large projects
- Modern Sass uses @use and @forward for better modularization