In this article, I'll demonstrate various techniques for customizing Bootstrap themes, whether for projects using only CSS or those utilizing Sass.
Table of Contents
My project uses just HTML and CSS 🔗
And I used a <link>
to include bootstrap.min.css
in my HTML
I'm using Bootstrap 5 🔗
Bootstrap 5 uses CSS variables to style its components. The base variables are in :root
, and the specific component ones are declared within them. For instance, .btn-primary
:
.btn-primary {
--bs-btn-color: #fff;
--bs-btn-bg: #0d6efd;
--bs-btn-border-color: #0d6efd;
--bs-btn-hover-color: #fff;
--bs-btn-hover-bg: #0b5ed7;
--bs-btn-hover-border-color: #0a58ca;
--bs-btn-focus-shadow-rgb: 49, 132, 253;
--bs-btn-active-color: #fff;
--bs-btn-active-bg: #0a58ca;
--bs-btn-active-border-color: #0a53be;
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
--bs-btn-disabled-color: #fff;
--bs-btn-disabled-bg: #0d6efd;
--bs-btn-disabled-border-color: #0d6efd;
}
You can create your own CSS variables representing the new colors of this theme. Despite being many variables, they follow a repetition pattern.
To do this, simply create a new style sheet just below the Bootstrap one. The CSS gives preference to the one loaded last:
<!-- Bootstrap stylesheet -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<!-- Your stylesheet -->
<link rel="stylesheet" href="style.css" />
Then, adjust their values as desired, preferably using your default variables. This way, you can replicate them across other elements using the same theme.
.btn-primary {
--bs-btn-color: var(--primary-text-base);
--bs-btn-bg: var(--primary-bg-base);
--bs-btn-border-color: var(--primary-border-base);
--bs-btn-hover-color: var(--primary-text-base);
/* ... etc ... */
}
I'm using Bootstrap 4 🔗
With pure CSS, you can utilize specificity to override class content. Bootstrap classes function as utility classes, without co-dependency, having a specificity of 0.0.1.0
, allowing them to be overridden by another class declared later in the code.
💡 If specificity is still a mystery to you, I recommend this article on specificity and cascade by Amelia Wanttenberger.
Bootstrap classes have a base class containing properties common to their variants and another containing properties specific to their variants.
Example
.alert {
position: relative;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.alert-primary {
color: #004085;
background-color: #cce5ff;
border-color: #b8daff;
}
Knowing this, you can create a class with a namespace, e.g., .custom-alert-primary
, with styles overriding the .alert
theme.
Example:
<div class="alert custom-alert-primary" role="alert">
A simple primary alert—check it out!
</div>
◾Using modern CSS 🔗
We can utilize cascade layers to separate Bootstrap and CSS into different layers, giving more priority to the layer with authored code.
Below is an example by Stephanie Eckles using Bootstrap from Smashing Magazine:
@layer bootstrap, base, application;
@import url(bootstrap.css) layer(bootstrap);
@layer base {
body {...}
.alert {...}
.btn-primary {...}
}
The priority using @layer
is defined from left to right, from least to most priority, ensuring that your styles' specificity remains higher than Bootstrap's.
CSS Layers have a global compatibility of 93%, according to Caniuse data.
Chrome | Edge | Firefox | Safari |
---|---|---|---|
99 | 99 | 97 | 15.4 |
My project uses Sass 🔗
And I used @import "bootstrap"
to set up Bootstrap
I'm using Bootstrap 4 or 5 🔗
The Customize → Variable Defaults chapter of Bootstrap 5 documentation shows that it's possible to redeclare configuration variables from the variables.scss
file directly in your import file (usually index.scss
). The procedure is similar for Bootstrap 4, but ensure you check your version's documentation for declared variables and their usage.
// Requerido
@import "../node_modules/bootstrap/scss/functions";
/* Sobrescreve os valores padrão das variáveis padrão */
$body-bg: #000;
$body-color: #111;
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/variables-dark";
/* Remove do objeto $theme-colors do arquivo
variables.scss as chaves de 'info', 'light' e '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";
// Componentes opcionais
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
// etc
For customization, variables declared in the Bootstrap source code are marked with the !default
flag. This means that if you declare a Bootstrap variable before variables.scss
, it won't be overwritten, keeping your alteration as the default value.
The
!default
flag allows a variable to be created only if it doesn't exist yet. For more details, refer to the Sass documentation on default values.
Could it be better 🔗
Wow, but is it more work than Tailwind!?
Yes, definitely, but they serve different purposes. Bootstrap is used by 21% of sites surveyed by W3Techs, with over 6 million weekly downloads, according to npm's website. Since its inception in 2011, Bootstrap has been fundamental in setting standards and concepts that changed the way we do front-end today.
Being found in pure HTML/CSS sites, WordPress pages in PHP, or SPAs built with modern frameworks, Bootstrap's framework development focus was on retro-compatibility and robustness.
Incorporating a compilation step as Tailwind does with PostCSS wouldn't be feasible, as it would make the project dependent on a build tool like Webpack, Rollup, or even Vite in every project, which isn't always necessary.
Another point is that despite using JavaScript, if its functionalities aren't needed, it's extremely opt-in, allowing Bootstrap to be used independently of technologies, even in pure HTML/CSS projects.
Top comments (0)