Currently Available: Need a skilled Software Developer for your next project?
Categories
Bootstrap

Customizing Bootstrap 5 with Sass Variables

This guide shows you how to customize Bootstrap 5 using Sass variables. You'll learn how to modify colors, typography, spacing, and components by adjusting Bootstrap's source variables instead of writing CSS overrides. We'll cover setup, key variables, practical examples, and best practices for maintaining your customizations.

Setting Up Sass with Bootstrap 5 (Step-by-Step)

Before customizing Bootstrap’s variables, you need a Sass build setup. Here’s how to get started:

  1. Install Node.js and a Package Manager: Ensure you have Node.js and npm (Node’s package manager) installed. These tools will let you fetch Bootstrap and Sass.

  2. Create a Project and Install Bootstrap: Initialize a project folder for your website or app. Inside it, use npm to install Bootstrap’s source:

    npm install bootstrap@5

    This will download Bootstrap 5’s source files (including the Sass .scss files) into node_modules/bootstrap/.

  3. Install Sass Compiler: Sass can be compiled using various tools. An easy option is the official Sass CLI. You can install it globally via npm:

    npm install -g sass

    Alternatively, you can use build tools like Gulp, Webpack, or Parcel to compile Sass – Bootstrap’s docs provide guides for these but the CLI is straightforward for beginners.

  4. Set Up Folder Structure: Create a directory for your own Sass files (e.g., scss/ in your project). Do not edit Bootstrap’s files directly – keep them in node_modules/bootstrap/ (or a separate folder) and manage your custom code separately For example:

    your-project/
    ├── scss/
    │   └── custom.scss   (your main Sass file)
    ├── css/
    │   └── custom.css    (compiled output)
    └── node_modules/
       └── bootstrap/    (Bootstrap source files)
  5. Create a Custom Sass File: In the scss/ folder, create custom.scss. This file will import Bootstrap’s Sass and override default variables. There are two ways to import Bootstrap: Option A: Import all of Bootstrap at once, or Option B: Import parts of Bootstrap in sequence.

    • Option A (simplest): In custom.scss, first override any variables you want, then import the full Bootstrap bundle:

      // custom.scss (Option A)
      $primary: #6f42c1;  // example override (change primary color)
      $enable-rounded: false;  // example override (disable rounded corners)
      @import "../node_modules/bootstrap/scss/bootstrap";

      This approach is simple — you list your custom variables (before the import) and then bring in all of Bootstrap. Bootstrap’s default variables are defined with the !default flag, so your values for $primary or others will take precedence when the import runs Note: One limitation is that functions and maps from Bootstrap aren’t available above this import, so if you need to use Bootstrap’s Sass functions (like color.mix() or maps) in your custom values, use Option B.

    • Option B (granular control): Import Bootstrap’s source in pieces, which allows more advanced customization (like modifying maps or using functions). The recommended import order from Bootstrap is: functions → variable overrides → Bootstrap’s variables → any maps overrides → rest of Bootstrap’s files For example:

      // custom.scss (Option B)
      @import "../node_modules/bootstrap/scss/functions";         // 1. Import Sass functions first
      // 2. Override default variables:
      $primary: #6f42c1;
      $font-family-base: "Open Sans", sans-serif;
      // 3. Import Bootstrap default variables and dark mode variables:
      @import "../node_modules/bootstrap/scss/variables";
      @import "../node_modules/bootstrap/scss/variables-dark";
      // 4. (Optional) Override Sass maps (e.g., theme-colors) here
      // $theme-colors: ( "primary": #6f42c1, ... );
      // 5. Import the rest of Bootstrap’s core:
      @import "../node_modules/bootstrap/scss/maps";
      @import "../node_modules/bootstrap/scss/mixins";
      @import "../node_modules/bootstrap/scss/root";
      // 6. Import any Bootstrap components you need:
      @import "../node_modules/bootstrap/scss/utilities";
      @import "../node_modules/bootstrap/scss/reboot";
      @import "../node_modules/bootstrap/scss/type";
      // ... (import other components as needed) ...
      @import "../node_modules/bootstrap/scss/utilities/api";
      // 7. Add any custom CSS/Sass (if needed) below

      This approach lets you include only the parts of Bootstrap you use (for a smaller bundle) and position your overrides exactly where needed. For example, you can modify the $theme-colors map by inserting overrides after the default variables but before the maps are processed It’s slightly more setup, but offers maximum flexibility.

  6. Compile Sass to CSS: With custom.scss configured, run the Sass compiler to produce your custom Bootstrap CSS. For a one-time compile:

    sass scss/custom.scss css/custom.css

    Or during development, watch for changes and auto-compile:

    sass --watch scss/custom.scss css/custom.css

    This will output a custom.css file. If you installed Sass via npm, you can also add a script in your package.json to run this. Using the CLI is just one option – you could also integrate Sass compilation into build pipelines (Webpack, Gulp, etc.) as needed

  7. Include the Compiled CSS in Your HTML: Link the generated css/custom.css in your HTML file instead of the default Bootstrap CSS. This file now contains Bootstrap’s styles, but with all your customizations baked in. For example:

    <link rel="stylesheet" href="css/custom.css">

    Ensure this link is placed in the HTML <head> before any of your page’s content.

Following these steps, you have a Sass workflow for Bootstrap. Now any changes to Sass variables in custom.scss will be reflected in the output CSS after recompiling. This setup isolates your theme changes from the core library (making upgrades easier) and leverages Sass’s power to customize Bootstrap at the source.

Key Bootstrap 5 Sass Variables Overview

Bootstrap 5 provides an extensive list of Sass variables that control nearly every aspect of its design. Here are some of the key categories of variables and what they affect:

  • Color Variables: Bootstrap’s color scheme is defined by a palette of variables. Primary, secondary, success, danger, warning, info, light, and dark are the main theme colors. By default, these are tied to a base palette – for example, $primary uses a shade of blue (#0d6efd by default) $danger is a red (#dc3545), etc. All theme colors are also gathered in the $theme-colors Sass map, which maps color names to their variable values (e.g. "primary": $primary, and so on) There are also generic color variables like $blue, $indigo, $red, $gray-100...$gray-900 for the full palette Changing these can globally update button colors, alerts, links, and any component that uses theme colors.

  • Typography Variables: These variables control fonts and text styling across Bootstrap. Important ones include $font-family-base (the default typeface stack for body text), $font-size-base (base font size, typically 1rem which equals 16px by default), and $line-height-base (line height for body text) By adjusting $font-family-base, you change the font for almost all components at once. There are also variables for headings and specialized text, such as $headings-font-weight, $headings-color, and $link-color (which sets anchor tag colors globally . For example, setting $font-family-base: "Roboto", sans-serif; would give your whole Bootstrap site a Roboto font.

  • Spacing Variables: Bootstrap’s spacing (margin/padding) utilities and component spacing use a scale defined by Sass variables. The core is $spacer (default 1rem) which is the base unit. From this, a Sass map $spacers generates incremental spacing classes (e.g., 0.25rem, 0.5rem up to larger values for .m-1, .m-2, etc.). By increasing $spacer or altering the $spacers map, you can make all spacing in components and utilities larger or smaller in a consistent way. For instance, you might set $spacer: 1.5rem; to globally increase spacing gaps.

  • Layout and Grid Variables: The responsive grid system is driven by variables too. $grid-breakpoints is a Sass map that defines the pixel width breakpoints for each tier (xs, sm, md, etc.), and $container-max-widths sets the max-width for container at each breakpoint By default, $grid-breakpoints includes xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px (these values may vary slightly in v5.3+). $grid-columns (default 12) determines how many columns the grid has and $grid-gutter-width (default 1.5rem) controls the space between columns If you need a different grid setup (say, a 16-column grid or different breakpoints), these variables let you tweak that (we’ll see examples later).

  • Component Variables: Each Bootstrap component (buttons, navbars, cards, etc.) often has its own Sass variables for fine-tuning. For example, buttons have $btn-padding-y, $btn-padding-x, $btn-border-radius, $btn-font-weight, and more to adjust their shape and feel. The default button border radius is controlled by $btn-border-radius (which itself defaults to the global $border-radius variable). If you set $border-radius: 0; and recompile, most components (buttons, cards, etc.) will have sharp corners instead of rounded Similarly, the navbar uses $navbar-padding-y for vertical padding, $navbar-color and $navbar-bg for text and background colors, etc. Nearly every component’s dimensions and colors are derived from variables, allowing systematic updates.

  • Global Options Variables: Bootstrap 5 also includes “options” variables (mostly booleans) that enable or disable certain features globally. For example, $enable-rounded can turn all rounded corners on or off in one go $enable-shadows toggles decorative box-shadows on components and $enable-gradients controls whether components use gradients in their backgrounds By default these are true or false as Bootstrap ships (often true for rounded, false for gradients in v5), but you can flip them in your custom Sass to change multiple components at once. For instance, setting $enable-gradients: true; and recompiling will give buttons and other elements a gradient per the theme colors.

These are just a few of the core variables; Bootstrap’s _variables.scss file contains hundreds of variables covering everything from transitions and z-indexes to form control heights. The key takeaway is: if there’s a design aspect of Bootstrap you want to change, there’s likely a Sass variable for it. Adjusting that variable will consistently update the UI framework-wide, rather than needing to override many individual CSS rules.

Customizing Bootstrap’s Look with Sass Variables (Practical Examples)

In this section, we’ll walk through practical examples of using Sass variables to customize colors, typography, spacing, and components in Bootstrap 5. Each example assumes you have a custom.scss set up (as described above) and will demonstrate what to change and the effect it produces.

1. Customizing Theme Colors

One of the most common theming tasks is changing Bootstrap’s color scheme. With Sass, this is straightforward:

  • Override Standard Theme Colors: To change the primary or secondary color (or any of the theme colors), override their variables before importing Bootstrap. For example:

    // In custom.scss, before @import "bootstrap";
    $primary: #6610f2;    // a deep purple (overriding default blue)
    $secondary: #ffc107; // a bright yellow (overriding default gray)

    This will make all components that use $primary (like .btn-primary buttons, alert-primary backgrounds, text-primary, etc.) turn purple instead of Bootstrap blue. Secondary will change to yellow (affecting badges, secondary buttons, etc.). Under the hood, Bootstrap sets its $theme-colors map using these variables, so by overriding (and then importing), you’ve effectively rethemeed the entire UI

  • Add New Theme Colors: What if you want an additional theme color (for a custom button style or alert)? Bootstrap’s $theme-colors is a Sass map, and you can merge new entries into it. For example, to add a “brand” color:

    $brand: #5cdb95; // define a new color variable  
    $theme-colors: map-merge($theme-colors, (
    "brand": $brand
    ));

    Place this after the default variables are loaded. This uses Sass’s map-merge function to add a "brand" key to the $theme-colors map After recompiling, you’ll have classes like .text-brand, .bg-brand, and utilities or components can use theme-color("brand") if needed.

  • Remove or Replace Theme Colors: Conversely, to slim down the default palette, you can remove some colors. For instance, maybe your design doesn’t use Info, Light, or Dark variants. You can drop them:

    @import "../node_modules/bootstrap/scss/functions";
    @import "../node_modules/bootstrap/scss/variables";
    @import "../node_modules/bootstrap/scss/variables-dark";
    $theme-colors: map-remove($theme-colors, "info", "light", "dark");
    @import "../node_modules/bootstrap/scss/maps";
    @import "../node_modules/bootstrap/scss/mixins";
    @import "../node_modules/bootstrap/scss/root";

    In this snippet (which follows the partial import pattern), we import the base variables, then use Sass’s map-remove to drop the keys for info, light, and dark from $theme-colors before the maps and rest of Bootstrap are imported. The result is that no CSS will be generated for those theme colors (saving some output). Note: Removing core keys like this should be done carefully – some components expect certain theme colors to exist. Bootstrap’s docs note that removing primary, danger, etc., could cause compilation issues unless you also adjust the code that uses them It’s often safer to replace values rather than remove keys, unless you know a color isn’t used.

By customizing theme colors via variables and maps, you achieve a new color scheme without writing a single line of manual CSS. Everything remains in the Bootstrap structure, which means utility classes, components, and any element referencing those colors just work with the new values.

2. Customizing Typography (Fonts and Text)

Typography defines the personality of your site. Sass variables let you easily apply your brand’s fonts and adjust text sizing:

  • Change the Base Font Family: Bootstrap’s default font-family is a “native font stack” (system fonts) but you might want a custom web font. Simply set $font-family-base:

    $font-family-base: "Helvetica Neue", Helvetica, Arial, sans-serif;

    You can supply a fallback stack as shown. After compilation, all body text and most components will use this font stack. There are also $font-family-sans-serif and $font-family-monospace variables (Bootstrap sets these to common defaults), which $font-family-base references by default. Changing the base will affect nearly everything, while you could also target specific contexts (like setting $headings-font-family if you want headings in a different font). By default, Bootstrap’s headings use the base font-family, but you could override $headings-font-family and $headings-font-weight for a distinct heading style.

  • Adjust Base Font Size and Line Height: The variable $font-size-base controls the default text size in Bootstrap. It’s 1rem by default (which equals 16px in most browsers). If you wanted slightly larger base text, you might do:

    $font-size-base: 1.125rem; // ~18px base font
    $line-height-base: 1.6;   // adjust line height for readability

    Because so much of Bootstrap’s typography (and component sizing, thanks to RFS - Responsive Font Sizes is built off the base font size, a small change here will scale up many elements. For example, <p> text, list items, and default button text will all render larger. Make sure to adjust $line-height-base proportionally to maintain legibility.

  • Global Link Styles: The link color and hover behavior can be themed via $link-color and related variables. For instance:

    $link-color: $teal;               // use Bootstrap’s teal for links
    $link-hover-color: darken($teal, 15%);  // darken teal on hover
    $link-decoration: underline;

    Here we used Sass’s darken() function to define the hover state (note: Bootstrap also provides its own shade-color() function that might yield better contrast . After compiling, all <a> tags in your project will reflect these styles unless overridden by a more specific component style. This is an example of using Sass functions to compute a variable value – since we placed it before the main import, we have to ensure Sass functions are imported (that’s why Option B includes @import "functions" at the top . If using Option A, stick to static values or ensure your Sass environment has those functions available.

Using Sass variables for typography ensures that your typographic changes propagate uniformly. There’s no need to comb through the CSS – by setting a few variables, you restyle all components’ text in one go.

3. Customizing Spacing and Sizing

Bootstrap uses a spacing scale for margins/paddings and component padding. Sass variables let you tweak these for a more compact or more spacious design:

  • Global Spacing Scale: The simplest tweak is to change $spacer, the default spacer unit. For a more compact design, you might set $spacer: 0.5rem; (8px) or for more breathing room, $spacer: 2rem; (32px). This single change will alter the generated utility classes (e.g., .mt-1 will now be 0.5rem instead of 1rem, etc.) It will also affect components that use the spacing scale. If you need fine control, you can directly adjust the $spacers map, which looks something like:

    $spacers: (
    0: 0,
    1: $spacer * .25,  // 0.25rem by default
    2: $spacer * .5,   // 0.5rem
    3: $spacer,        // 1rem
    4: $spacer * 1.5,  // 1.5rem
    5: $spacer * 3     // 3rem
    );

    You could override specific entries or add new ones (e.g., define a 6: $spacer * 5 for a very large utility). If you decide your design needs more granular spacing options, you can expand this map and Bootstrap will generate corresponding utility classes for you.

  • Component Padding/Margins: Many components have their own padding variables. For example, modals use $modal-inner-padding for the padding inside the modal, cards use $card-spacer-y and $card-spacer-x for their padding, etc. If you find a certain component too cramped or too spaced out, look for a Sass variable for it. For instance, to increase the padding inside cards:

    $card-spacer-y: 2rem;
    $card-spacer-x: 2rem;

    This would make card bodies have 2rem (32px) padding vertically and horizontally, instead of the default (which is 1rem each by default). After recompiling, all .card components reflect the new padding.

  • Border Radius and Border Thickness: While not exactly spacing, adjusting sizing of common elements also falls under customization. Two notable ones: $border-radius (and related variables like $border-radius-lg for larger components, $btn-border-radius specifically for buttons, etc.) and $border-width. Setting $border-radius: 0.3rem; (or any value) will change the rounded corners on cards, buttons, inputs, etc., if $enable-rounded is true Similarly, you could globally make borders thicker or thinner via $border-width. These simple changes dramatically alter the aesthetic (for example, a zero border radius gives a very flat, “Microsoft Fluent” style, whereas larger radii give a more pill-shaped modern look).

By harnessing spacing and sizing variables, you avoid writing lots of utility classes in HTML or repetitive CSS. You decide on the scale in Sass, and let Bootstrap’s utility generator and component styles apply it everywhere. This keeps your design system consistent.

4. Component-Specific Customization Examples

Let’s consider a couple of specific components to illustrate how Sass variables can tailor them:

  • Buttons: Perhaps you want your primary buttons to be a bit bigger and bolder. You can tweak:

    $btn-padding-y: .75rem;
    $btn-padding-x: 1.5rem;
    $btn-font-weight: 600;

    These increase the vertical padding (making the button taller), horizontal padding (wider), and font weight (darker text). Because we haven’t explicitly changed $btn-border-radius here, it will still use whatever $border-radius is (or $border-radius-lg if the button size is large, etc.). If you want pill buttons, you could set $btn-border-radius: 50rem; (an absurdly high value to make it fully rounded). After compiling, every <button class="btn"> in your project uses the new sizes without additional HTML classes.

  • Navbar: Suppose you want a custom colored navbar that isn’t just using .bg-light or .bg-dark. You can override the default navbar color variables:

    $navbar-padding-y: 2rem;
    $navbar-light-color: #ffffff;
    $navbar-light-bg: #343a40;

    This example does two things: increases the vertical padding of .navbar (making it taller) and redefines the “light” navbar variant to have white text on a dark gray background (instead of the default light variant which is dark text on a light background). Now, using <nav class="navbar navbar-light"> in your HTML will produce a navbar with your custom colors (since we changed what “light” means in terms of color). Alternatively, you could have added a new $navbar-dark-bg or define your own .navbar-brand-color via Sass, but using the existing hooks can be simpler.

  • Forms: Form controls have variables for their heights, padding, and borders. If you find the default form fields too large, you might set $input-btn-padding-y: .25rem; (affects vertical padding for inputs and buttons) or $input-height: auto; (to let them resize based on content). For checkboxes and radios, variables like $form-check-input-width and $form-check-input-bg let you adjust their appearance. For example, to make custom checkboxes blue by default:

    $form-check-input-active-bg: $primary; 
    $form-check-input-active-border-color: $primary;

    This will use your primary color for the check indicator when active (applied to custom switches, etc., that use those variables).

Overall, the pattern is: find the Sass variable for the component aspect you want to change, override it in your custom Sass, and rebuild. The Bootstrap documentation and the _variables.scss file are great references to discover these variable names With practice, you’ll know many of them by heart, but even experienced developers keep the docs handy to identify the right variable to tweak.

Advanced Customization Techniques

Beyond basic theming, Sass opens up more advanced ways to customize Bootstrap 5. This includes fundamentally altering the grid system, creating custom utility classes with mixins, and using functions for dynamic styles. Here are some advanced techniques:

Modifying the Grid System

Bootstrap’s grid is flexible, but you might have project requirements that differ from the default 12-column grid or standard breakpoints. Using Sass, you can change the grid at its source:

  • Changing Number of Columns: The number of columns in the grid can be adjusted by overriding $grid-columns. By default this is 12 If you set $grid-columns: 16; and recompile, Bootstrap will generate a 16-column grid. That means classes like .col-1 through .col-16 (instead of up to 12) will be available, and each column will be 1/16th of a row (with appropriate percentages) when using the grid classes Keep in mind if you change this, you must use the new column counts in your layout (a .col-8 in a 16-col grid is 50% width). This is a powerful tweak if you need a different grid division.

  • Customizing Grid Gutters: $grid-gutter-width defines the padding between columns in a grid (default 1.5rem, i.e., ~24px total gutter) To make a tighter grid with less spacing, you could set $grid-gutter-width: 1rem; (16px gutters) or even smaller. This affects the padding in .container and .row setup that create the gutters. It will also influence the generation of .gx-* and .gy-* utility classes for controlling gutters.

  • Responsive Breakpoint Tweaks: The $grid-breakpoints map is where you define the viewport widths for each breakpoint tier (like when col-sm-* starts applying, etc.). For example, by default it’s something like:

    $grid-breakpoints: (
    xs: 0,
    sm: 576px,
    md: 768px,
    lg: 992px,
    xl: 1200px,
    xxl: 1400px
    );

    You can override this map to change these values or even the number of tiers. Suppose your design only needs four breakpoints instead of six. You could do:

    $grid-breakpoints: (
    xs: 0,
    sm: 480px,
    md: 768px,
    lg: 1024px
    );
    $container-max-widths: (
    sm: 420px,
    md: 720px,
    lg: 960px
    );

    In this example, we dropped XL and XXL, and adjusted breakpoints to custom values (480px for small, etc.), and provided matching container widths After recompiling, classes like .col-xl-* and .col-xxl-* would no longer exist, and your container will max at 960px on large screens. All the grid CSS (including media queries for the new breakpoints, as well as utilities like responsive visibility classes) will realign to these new settings This shows how Sass variables enable a deeply custom grid without rewriting the grid CSS yourself – you declare your changes, and Bootstrap’s Sass generates the appropriate new CSS.

Using Mixins and Functions for Custom Styles

Sass mixins and functions are advanced tools that Bootstrap provides for those who want to extend the framework or create their own components with Bootstrap’s style logic.

  • Sass Functions in Bootstrap: Bootstrap includes custom functions, especially for colors. For example, shade-color($color, $weight) and tint-color($color, $weight) will mix a color with black or white respectively, based on a weight (percentage) These are used internally instead of the native Sass darken()/lighten() for more consistent results. You can use them in your own code. Suppose you want a slightly tinted background using your primary color for a custom component:

    .highlight-box {
    background-color: tint-color($primary, 15%);  // 15% white mix into primary
    border: 1px solid shade-color($primary, 20%); // 20% black mix into primary
    }

    This will give a lighter background and a slightly darker border using the primary color as a base, ensuring it stays within the theme palette.

  • Utility Mixins: Many Bootstrap utility classes (for margin, padding, flex, etc.) have corresponding mixins. If you prefer to avoid lots of classes in your HTML, you can use these mixins in your Sass to apply styles. For example, @include padding-y(2); in a selector would apply padding-top and padding-bottom equal to $spacer * 2 (i.e., the same as .py-2 utility). Similarly, @include text-hide; or @include clearfix; apply what their utility classes would. This way, you can create semantic classes in your Sass that still leverage Bootstrap’s ready-made styles.

  • Responsive Mixins: The grid breakpoints come with mixins like @include media-breakpoint-up(sm) { ... } which is an easier way to write @media (min-width: 576px) { ... } (taking your custom breakpoints into account) There are also media-breakpoint-down and media-breakpoint-between mixins. For example:

    .hero-text {
    font-size: 1.5rem;
    @include media-breakpoint-up(md) {
      font-size: 2.5rem;
    }
    }

    This will make .hero-text larger on medium and up screens, using the breakpoint from your (possibly customized) $grid-breakpoints. By using the mixin, if you ever adjust the breakpoint values, this media query adjusts automatically on the next compile.

  • Component Mixins: Bootstrap’s Sass often defines mixins to generate parts of components. For instance, the .container class styles are encapsulated in a make-container() mixin There’s a make-col() mixin for grid column styles, etc. You can use these to build new components that behave like Bootstrap’s. A quick example: say you want a special container variant that has extra padding and a max-width of 1000px. You could do:

    .container-narrow {
    @include make-container();        // apply base container styles
    max-width: 1000px !important;    // override the typical max-width
    }

    By including make-container(), you get the same horizontal padding and auto centering as a normal .container then you customize what you need (here, forcing a specific max width). This mixin reuse prevents you from accidentally deviating in other aspects like gutter spacing, etc. Another example: @include button-variant($color, $bg, $border) is a mixin to quickly generate a new button style if you pass it colors – you could use it to define a new .btn-mybrand if needed, keeping consistency with how .btn-primary is defined internally.

Using mixins and functions requires a bit more Sass knowledge, but it’s a powerful way to extend Bootstrap beyond its default offerings while staying within the design system. It’s like writing your own Bootstrap-styled components or utilities, without writing all the CSS from scratch.

Component-Specific File Overrides (Partial Sass Imports)

For very large projects, you might not want to compile all of Bootstrap if you only use a subset of components. With Sass, you can import only what you need. For example, you could omit the Carousel, Modal, or Tooltip CSS if you don’t use those. The Option B import strategy we showed earlier demonstrates how you can include or exclude parts. This can be considered an advanced technique to optimize output. Just be cautious: some components depend on others (e.g., Navbar needs Navs, forms might need Reboot, etc.), so consult Bootstrap’s documentation or the comments in bootstrap.scss to know the required import order

In summary, advanced customization with Sass means you’re not limited to theming existing components – you can reshape the framework’s grid and create new styles leveraging the same building blocks Bootstrap uses. The result is a highly custom UI but built on Bootstrap’s robust foundations.

Sass vs CSS Overrides vs Utility Classes: Pros and Cons

Bootstrap can be customized in multiple ways. It’s worth comparing the Sass approach to two other common methods: overriding compiled CSS, and using utility classes or custom CSS. Each approach has its advantages and trade-offs:

  • Sass Variables (Recompile Bootstrap): Pros: This method (the focus of our guide) allows comprehensive, centralized control over the theme. You change a variable once (e.g., $primary) and it consistently updates the entire framework’s output. The resulting CSS is clean – you’re not loading default Bootstrap and then overriding it, you’re generating exactly the CSS you need with your design choices. This often means smaller file sizes and no duplication of styles. It’s great for maintainability, since your “config” (the variables) is separate from the code. Cons: The Sass approach requires a build step – you must have a Sass compiler in your workflow, which adds complexity if you’re not already using one. It also ties you to Bootstrap’s Sass source, meaning you need to stay aware of changes if you upgrade Bootstrap (your custom variables may need adjustments if Bootstrap introduces new ones or changes defaults in a new version). In short, it’s more setup initially and requires knowledge of Sass, but pays off in scalability.

  • CSS Overrides (after Bootstrap): This approach means including the standard Bootstrap CSS (via CDN or bootstrap.min.css) and then adding your own additional CSS file to override styles. Pros: It’s very straightforward – no build tools needed, you just write normal CSS. This can be fine for small tweaks or quick prototypes. Cons: Overrides can become messy. You often need to use equal or higher specificity selectors to override Bootstrap’s styles, which can lead to long selectors or excessive !important usage. There’s also a performance cost: the browser loads Bootstrap’s CSS and your overrides, potentially applying and then undoing styles. This can result in larger CSS overall. Maintaining overrides can get difficult as the project grows (you might override the same variable in multiple places). In essence, CSS overrides work for minor customizations but can lead to fragile, hard-to-maintain code for larger changes.

  • Utility Classes and Custom CSS in HTML: Bootstrap 5 offers tons of utility classes (like .text-center, .bg-primary, .pt-3, etc.) which let you adjust styles directly in your HTML. You can also write your own small CSS snippets for one-off needs. Pros: Utility classes are quick and don’t require any compiling or even leaving your HTML file. You can often achieve a different look by simply mixing and matching classes (for example, to change a component’s color, you might add a .bg-success class). This is great for prototyping or when you only need to tweak a few elements. Cons: Relying heavily on utilities can make your HTML cluttered with class names, which some developers find less semantic and harder to read. Also, utilities can’t cover every scenario – if you want a slightly different padding not in the default scale, or a completely custom component style, you’ll end up writing CSS anyway. Using lots of custom CSS (outside of Sass) can suffer the same issues as overrides: scattered rules that are not centrally managed. In summary, utilities are convenient for incremental changes, but for large-scale theming they may fall short or result in unwieldy markup.

When to use which? If you need a cohesive theme across your project, using Sass to customize Bootstrap is typically the best route (you get consistency and save time in the long run). For quick tweaks or legacy projects where introducing a build step isn’t feasible, CSS overrides or utilities might suffice. In practice, you can also mix approaches: for example, use Sass for the broad strokes (colors, fonts, etc.), and still use a few utility classes in your HTML for layout or spacing adjustments. The key is to avoid fighting against yourself – if you find you’re writing many CSS rules to undo Bootstrap defaults, that’s a sign you should switch to the Sass variable method instead

Best Practices for Managing a Bootstrap 5 Sass Project

Working with Bootstrap’s Sass customization offers great power, but it’s important to keep your project organized and maintainable. Here are some best practices to consider:

  • Keep Bootstrap Source and Custom Code Separate: As emphasized earlier, avoid editing Bootstrap’s own files. Always use a separate custom.scss (and perhaps multiple Sass partials for your code) that import Bootstrap This way, updating Bootstrap (to a newer version) is much easier – you can drop in the new bootstrap/ source and recompile, without trying to remember what you changed. Your custom file acts as a clear record of all your design modifications.

  • Leverage the !default System (Override, Don’t Modify): All of Bootstrap’s variables in _variables.scss are marked with !default, meaning they only take effect if not already set. Use this to your advantage: override variables in your custom file instead of changing Bootstrap’s defaults directly. For example, instead of finding $primary in _variables.scss and changing it there, just set $primary in your file. This ensures your value overrides the default when compiled It’s less error-prone and keeps the library code intact.

  • Follow the Import Order Requirements: If you use the granular import approach, pay attention to the required order (functions → variables → rest of Bootstrap) A common mistake is trying to override variables after importing Bootstrap – that won’t work because by then the CSS is already generated with default values. Always override before the relevant Sass is compiled. The rule of thumb from Bootstrap is: “Variable overrides must come after our functions are imported, but before the rest of the imports” If something didn’t seem to take effect, check the order of your @import statements.

  • Use Source Maps and Dev Tools: When developing, compile Sass with source maps enabled (sass --source-map or equivalent in build tools). This way, in the browser DevTools, you can see which Sass file/line a given CSS rule came from. It helps to quickly identify if a style is coming from Bootstrap’s default or your custom overrides. This can guide you on which variable to override or if you need to write a new rule.

  • Reference Documentation and Source Files: The Bootstrap docs (Customize section) and the GitHub source are your friends. If you’re not sure which variable controls a particular style, search the _variables.scss file or check documentation pages for clues. For example, the Utilities docs often list the Sass variables used to generate them. Also, the Stack Overflow and Bootstrap community is active – often someone has asked about a particular customization, and answers might point you to the right variable or mixin.

  • Partial Files for Your Custom Code: If your project is large, consider splitting your Sass into multiple files (partials) that get imported into custom.scss. For instance, you might have _variables-custom.scss (where you override Bootstrap vars), and separate files for additional custom styles or theme-specific styles (like _override-buttons.scss if you write extra CSS for buttons). This isn’t strictly necessary, but can keep things organized. Just ensure the main custom.scss imports them in the correct order (custom variable overrides should still come before Bootstrap’s import, etc.).

  • Test and Iterate Gradually: When making many customizations, do them in steps and recompile to see the effects. If you change too many variables at once and something looks off, it’s harder to pinpoint why. For example, you might first change the color scheme variables and check the UI. Then adjust typography, verify it, then spacing, and so on. This iterative approach ensures each set of changes works as expected, and if something breaks (like a component doesn’t look right after removing a theme color), you can address it before moving on.

  • Maintain Consistency: Try to use the Sass approach for all global design changes. Avoid the temptation to sprinkle random CSS overrides in a separate stylesheet for things you could solve with a variable. Mixing methods can lead to confusion later (e.g., overriding a color in Sass but then another dev overriding it again in CSS because they missed the variable). Treat your Sass variables as the single source of truth for Bootstrap’s design tokens whenever possible.

  • Keep Performance in Mind: Removing unused components and utilities via Sass imports can reduce your CSS file size. If you know for sure that your project will never use certain components (say, the Carousel or Toasts), you can choose not to import those SCSS files. Similarly, Bootstrap’s default utilities cover a wide range – if you want to slim down, you can customize the utilities API in Bootstrap (this is an advanced topic) or simply not use what you don’t need. However, premature optimization might not be necessary; modern gzip compression makes even the full Bootstrap CSS quite manageable for most projects. Still, being mindful of what you include is good practice (Bootstrap’s docs have an “Optimize” section discussing this .

  • Documentation for Your Team: If you’re working in a team, document the major Sass variable changes you’ve made. This could be a simple comment block at the top of your custom.scss listing, for example: “// Custom theme: Primary = Purple (#6f42c1), Secondary = Yellow (#ffc107), Font = Roboto, etc.”. It helps onboard others to your customized bootstrap. Also mention the build process (e.g., “Run npm run sass to compile”). Clear documentation ensures everyone uses the theme correctly and knows how to update it.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Subscribe to my newsletter

Get new posts when I publish them.

I respect your privacy. Unsubscribe at any time.

Leave a Reply

Your email address will not be published. Required fields are marked *