Customizing with Sass
CSS variables change Bootstrap's finished file, while Sass lets you build that file again with your own values. Sass is a language on top of CSS with variables like $primary, from which Bootstrap generates all its classes. Change $primary and buttons, links, bg-primary, text-primary and field focus borders change at once. This approach needs a bundler, so we work in the Vite project from the second lesson.
Installing Sass
npm install -D sassVite compiles .scss files by itself once the sass package is installed. Create a src/scss/ folder with a styles.scss file in it.
Overriding variables
Your values go before Bootstrap is imported: its variables are declared with the !default flag and do not overwrite values that are already set.
// src/scss/styles.scss
$primary: #6f42c1;
$border-radius: .75rem;
$font-family-sans-serif: Georgia, serif;
@import "bootstrap/scss/bootstrap";Then in src/main.js replace the Bootstrap stylesheet line with an import of this file:
// src/main.js
import './scss/styles.scss';
import 'bootstrap';Run npm run dev: all btn-primary buttons, links and text-bg-primary badges are purple, the rounding is larger and the font is different — in every component at once.
Useful variables
| Variable | What it changes |
|---|---|
$primary, $success, $danger … | Theme colors |
$font-family-sans-serif | Main font |
$font-size-base | Base text size |
$border-radius | Rounding |
$spacer | Spacing scale step, 1rem by default |
$enable-shadows, $enable-gradients | Turn on component shadows and gradients |
Only the parts you need
Full Bootstrap is about 230 KB of uncompressed CSS. If you only need the grid, buttons and utilities, import the parts separately. The order matters: functions first, then your variables, then the required files, then the components you need:
// src/scss/styles.scss
@import "bootstrap/scss/functions";
$primary: #6f42c1;
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
$spacers: map-merge($spacers, (6: 4.5rem));
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/helpers";
@import "bootstrap/scss/utilities/api";The map-merge line adds a sixth step to the spacing scale, so classes like mt-6 and p-6 appear. The last file, utilities/api, generates the utilities themselves, so it always comes last.
Build warnings
Recent Sass versions print many warnings to the terminal about the deprecated @import in Bootstrap 5.3 sources. They do not break the build. You can hide them in vite.config.js at the project root:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['import', 'mixed-decls', 'color-functions', 'global-builtin'],
},
},
},
});After restarting npm run dev the terminal is clean.
Common mistake
Writing your variables after @import "bootstrap/scss/bootstrap". By then Bootstrap has already generated all classes with the old values, and $primary: #6f42c1; has no effect. Overrides always come before Bootstrap's variables are imported.