This article is based on Bootstrap 5.3 alpha 1. This is the first version of bootstrap that supports dark mode. Customization guidelines can be found in https://getbootstrap.com/docs/5.3/customize/sass/
Customization starts when importing bootstrap scss to our scss. Don’t import the whole bootstrap like this
@import "../node_modules/bootstrap/scss/bootstrap";
Instead, import individual bootstrap modules and insert our overrides between these modules like this.
// Custom.scss
// Option B: Include parts of Bootstrap
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "../node_modules/bootstrap/scss/functions";
// 2. Include any default variable overrides here
@import "custom-variables.scss";
// 3. Include the remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/variables-dark";
// 4. Include any default map overrides here (map merge, map remove)
// Create your own map
$custom-colors: (
"custom-color": #900
);
// Merge the theme color maps
$theme-colors: map-merge($theme-colors, $custom-colors);
// remove from the theme color map
$theme-colors: map-remove($theme-colors, "info", "warning");
// 5. Include remainder of required parts
@import "../node_modules/bootstrap/scss/maps";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";
// 6. Optionally include any other parts as needed
@import "../node_modules/bootstrap/scss/utilities";
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
@import "../node_modules/bootstrap/scss/images";
@import "../node_modules/bootstrap/scss/containers";
@import "../node_modules/bootstrap/scss/grid";
// Helpers
// @import "../node_modules/bootstrap/scss/helpers";
// @import "../node_modules/bootstrap/scss/helpers/clearfix";
// @import "../node_modules/bootstrap/scss/helpers/color-bg";
// @import "../node_modules/bootstrap/scss/helpers/colored-links";
@import "../node_modules/bootstrap/scss/helpers/ratio";
// @import "../node_modules/bootstrap/scss/helpers/position";
// @import "../node_modules/bootstrap/scss/helpers/stacks";
// @import "../node_modules/bootstrap/scss/helpers/visually-hidden";
// @import "../node_modules/bootstrap/scss/helpers/stretched-link";
@import "../node_modules/bootstrap/scss/helpers/text-truncation";
// @import "../node_modules/bootstrap/scss/helpers/vr";
// 7. Custom utilities
@import "custom-utilities";
// 8. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "../node_modules/bootstrap/scss/utilities/api";
// 9. Add plugin css includes here
@import "swiper";
// 10. Add additional custom code here
@import "custom-styles";
Lets dive into each sections and start customizing.
1. Bootstrap functions
This is the sass functions provided by bootstrap. Leave it as it is.
2. Custom variables
Here we will override bootstrap variables and variables-dark, Lets see some important variables that must be customized in all projects. Don’t overwrite map variables (variables values defined inside “()”), will do it in section 4
- Theme colors
$primary: primary theme color $secondary: secondary theme color $success: Success color $info: info color $warning: warning color $danger: danger color or error color $light: light color $dark: dark color
- Quickly modify global styling by enabling or disabling optional features. Setting these variables to true or false will enable or disable certain bootstrap features. Setting these variables according to our project needs will save a lot of css in output bundle (Options reference)
$enable-caret: true !default; enable caret in dropdown $enable-rounded: true !default; enable border-radius in bootstrap components $enable-shadows: false !default; enable shadows in buttons, inputs $enable-gradients: false !default; enable gradients in button, carousel, dropdowns $enable-transitions: true !default; enable transitions $enable-reduced-motion: true !default; disable motion based transitions(Indicates that user has notified the system that they prefer an interface that removes or replaces the types of motion-based animation that trigger discomfort for those with vestibular motion disorders.) $enable-smooth-scroll: true !default; enable scroll-behavior: smooth; in html $enable-grid-classes: true !default; enable bootstrap grid system $enable-container-classes: true !default; enable .container, .container-fluid classes $enable-cssgrid: false !default; enable display: grid based grid system $enable-button-pointers: true !default; enable cursor: pointer to buttons $enable-rfs: true !default; enable responsive font size. in rfs font size is calculated with respect to window width. $enable-validation-icons: Â Â true !default; enable validation icons in form elements $enable-negative-margins: Â Â false !default; enable negative margin classes like mn-1 $enable-deprecation-messages: true !default; enable deprecation messages $enable-important-utilities: Â true !default; enable bootstrap utility classes
- The spacer values will generate padding and margin classes(p-1,mb-0,…)
$spacer: 1rem !default; $spacers: ( 0: 0, 1: $spacer * .25, 2: $spacer * .5, 3: $spacer, 4: $spacer * 1.5, 5: $spacer * 3, ) !default;
- Settings for the `<body>` element.
$body-bg: $white !default; $body-color: $gray-900 !default;
- Grid breakpoints
$grid-breakpoints: ( xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px ) !default;
- Max widths for container
$container-max-widths: ( sm: 540px, md: 720px, lg: 960px, xl: 1140px, xxl: 1320px ) !default;
- Global font related
$font-family-base: Font family applied to body $font-size-root: Root font size applied to html, this value will equal to 1 rem $font-size-base: Font size applied to body
First customize these variables and don’t write CSS code to override. There are so many other variables which are component specific variables.
// padding variables for both button and input // This will effect both input and button // If button and input values are different separate variables are also available $input-btn-padding-y: .375rem !default; $input-btn-padding-x: .75rem !default;
You can check these in respective components in bootstrap docs when using these components.
And check the variables-dark.scss if your project have dark mode. More details on dark mode section
Change sass variables for global value, if any value that different from global value bootstrap provide css variables to override it locally. More details on css variables section.
3. Bootstrap variables
We are customizing bootstrap variable in custom variables, so leave this as it is
4. Map overrides
In this section bootstrap map variables can be customized. Map variables can be override from custom-variable but we have to repeat the whole map object this will violate DRY(Don’t Repeat Yourself) rule in development.
- To add new value to a map
$custom-colors: ( "custom-color": #900 ); $theme-colors: map-merge($theme-colors, $custom-colors);
- To remove from map
$theme-colors: map-remove($theme-colors, "info", "warning");
- To edit existing vale
$custom-colors:( "primary":#f00 ); $theme-colors: map-merge($theme-colors, $custom-colors);
Please remove unused theme colors from $theme-colors. This will save a lot of CSS. Also be careful when add a new color $theme-colors because it will add a lot of CSS to final bundle. This is same for $grid-breakpoints. Don’t add rarely used breakpoints to this map.
5. Bootstrap required parts
These are bootstrap mixins, root styles and variables, maps. Don’t edit these
6. Bootstrap optional components
These are bootstrap components scss, only enable components that are used in our project. The best practice is comment all component scss and uncomment required component scss when it use in our project.
In the optional components there is helper.scss which includes helper class scss. Some helper classes useful but some are not depending the project. Please enable only required helpers. In helpers the color-bg helper is a powerful helper which generate background color from theme colors and text color calculated by color contrast. Which means for dark background it generate light text and for light background it generate dark text depending on contrast ratio.
There is a utilities.scss which holds all utility classes variables. We will customize this in the next section.
7. Custom utilities
In this we will customize bootstraps utility classes. Utility classes have commonly used css like “d-flex” which have “display: flex;” css rule. All utility classes may not be used in the project or all utility class values may not used, so customizing utilities will reduce size of output css bundle.
To customize this either copy all variables inside utilities.scss to custom-utitlities.scss and remove unused utilities or values and comment bootstrap utilities, in thas case the custom-utilities.scss must be placed above bootstrap utilities.scss. Or keep the bootstrap utilities file as it is and only customise required utilities with map-merge and map-remove. Let’s see this in detail. (Utilities reference)
- Lets take a look at opacity utility class
$utilities: (
"opacity": (
property: opacity,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);
This will output
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
- The values can be a scss map or scss map variable which is initialized outside of utility map and called inside utility values, or just space separated values. ex:
$opacity-values: (
0: 0,
25: 0.25,
50: 0.5,
75: 0.75,
100: 1,
)
$utilities: (
"opacity": (
property: opacity,
values: $opacity-values,
)
);
$utilities: (
"opacity": (
property: opacity,
values: 0 1,
)
); // output= .opacity-0 {opacity:0}, .opacity-1: {opacity-1}
- If we want to change class name add a class property
$utilities: (
"opacity": (
class: o,
property: opacity,
values: $opacity-values,
)
);
// output
.o-0 { opacity: 0; }
.o-25 { opacity: .25; }
.o-50 { opacity: .5; }
.o-75 { opacity: .75; }
.o-100 { opacity: 1; }
- We can also remove class by setting class: null then the value will taken as class name
$utilities: (
"visibility": (
property: visibility,
class: null,
values: (
visible: visible,
invisible: hidden,
)
)
);
// Output
.visible{visibility: visible}
.invisible{visibility: hidden}
- If we want css variable instead of css rule
$utilities: (
"opacity": (
class: o,
css-var: true,
css-variable-name: opacity-var
property: opacity,
values: $opacity-values,
)
);
// Output
.o-0 { --opacity-var: 0; }
.o-25 { --opacity-var: .25; }
.o-50 { --opacity-var: .5; }
.o-75 { --opacity-var: .75; }
.o-100 { --opacity-var: 1; }
- If we want to use a local variable inside css ruleset, ex:
$utilities-bg-colors:(
primary: --bs-primary-rgb
);
$utilities: (
"background-color": (
property: background-color,
class: bg,
local-vars: (
"bg-opacity": 1
),
values: $utilities-bg-colors,
)
);
.bg-primary {
--bs-bg-opacity: 1;
background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;
}
- If we want to classes for state like hover or focus
$utilities: (
"opacity": (
property: opacity,
class: opacity,
state: hover,
values: $opacity-values
)
);
// Output
.opacity-0-hover:hover { opacity: 0; }
.opacity-25-hover:hover { opacity: .25; }
.opacity-50-hover:hover { opacity: .5; }
.opacity-75-hover:hover { opacity: .75; }
.opacity-100-hover:hover { opacity: 1; }
- For utility class for every media queries add responsive: true
$utilities: (
"opacity": (
property: opacity,
responsive: true,
values: $opacity-values
)
);
// Output
.opacity-0 { opacity: 0; }
...
@media (min-width: 576px) {
.opacity-sm-0 { opacity: 0 !important; }
...
}
@media (min-width: 768px) {
.opacity-md-0 { opacity: 0 !important; }
...
}
...
- For print media query add print: true;
$utilities: (
"opacity": (
property: opacity,
print: true,
values: $opacity-values
)
);
// Output
.opacity-0 { opacity: 0; }
...
@media print {
.opacity-print-0 { opacity: 0 !important; }
...
}
Lets start customizing utilities.
- Add new utility
$utilities: map-merge(
$utilities,
(
"cursor": (
property: cursor,
class: cursor,
values: auto pointer,
)
)
);
- Override existing utility
$utilities: (
"overflow": (
responsive: true,
property: overflow,
values: visible hidden scroll auto,
),
);
- Add new utility value
$utilities: map-merge(
$utilities,
(
"opacity": map-merge(
map-get($utilities, "opacity"),
(
values: map-merge(
map-get(map-get($utilities, "opacity"), "values"),
(20: 0.2),
),
),
),
)
);
- Enable responsive
$utilities: map-merge(
$utilities, (
"opacity": map-merge(
map-get($utilities, "opacity"),
( responsive: true ),
),
)
);
- Rename class name
$utilities: map-merge(
$utilities, (
"opacity": map-merge(
map-get($utilities, "opacity"),
( class: op ),
),
)
);
- Remove utility. Can be done by using map-remove or map-merge
$utilities: map-remove($utilities, "width", "float");
$utilities: map-merge(
$utilities,
(
"width": null,
"opacity": null,
)
);
- Add, remove, modify, custom-utilities.scss will be like this
$utilities: map-merge(
$utilities,
(
// Remove the `width` utility
"width": null,
// Make an existing utility responsive
"border": map-merge(
map-get($utilities, "border"),
( responsive: true ),
),
// Add new utilities
"cursor": (
property: cursor,
class: cursor,
responsive: true,
values: auto pointer grab,
),
// Change or add value of utility
"opacity": map-merge(
map-get($utilities),
values: map-merge(
map-get(map-get($utilities,"opacity"),"values")
(10:0.1)
)
)
...
),
);
8. Utilities API
This file will convert utility variable to utility classes. Leave it as it is.
9. Add plugin css
scss of plugins included in the project can import here.
10. Add additional custom
Custom css that we write can be imported here
CSS variables
Bootstrap provide css variables of almost all scss variables. The global css variables can be found in root.scss, In html this can be found in :root{} (html element). The component specific variables are defined in root component class. For button component .btn{} will have all css variables. First set scss variables that effect globally. After any change in style which are set in sass variables to be changed in css variable. For example we need a outlined button with text color black. By default .btn-outline-primary{--bs-btn-color: $primary} has text color of primary color. To change the text color add a class to the button and override the css variable not the color css rule.
.btn-outline-custom{--bs-btn-color: #{$black}}
The list of sass and css variables are listed in respective component pages. Don’t overwrite bootstrap css, first overwrite scss variable, if style is still different then overwrite css variable. If css and scss variables are not available then you can override bootstrap css rule.
Dark mode
Bootstrap support color mode from version 5.3.0. Bootstrap provide separate variable file for dark mode (variable-dark.scss). Color modes can be toggled globally on the <html> element, or on specific components and elements, by changing value of data-bs-theme attribute. Bootstrap also support system default theme by using @media (prefers-color-scheme: dark) media query. But we need to specify which method has to take by setting $color-mode-type variable in variables.scss. If it set to media-query then the system default theme will be active, if set to data the value of the data-bs-theme will be the default theme. In bootstrap website a javascript is provided to toggle theme and check system theme and set selected theme to local storage. https://getbootstrap.com/docs/5.3/customize/color-modes
For theme specific styles can use color-mode(mode){} mixin. Bootstrap have separate sass variables for color mode, But css variables are same. Bootstrap assign respective sass variables to css variables by using color-mode mixin. So when switch theme the value of css variables changed to corresponding sass variables. If we use these these css variables we don’t have worry about theme. Let’s see these variables in detail.
--#{$prefix}body-color: #{$body-color-dark}; // Body text color - scss variable $body-color-dark(dark) and $body-color(light)
--#{$prefix}body-bg: #{$body-bg-dark}; // Body background color - scss variable $body-bg-dark(dark) and $body-bg(light)
--#{$prefix}emphasis-color: #{$body-emphasis-color-dark}; // Higher contrast text color - scss variable $body-emphasis-color-dark(dark) and $body-emphasis-color(light)
--#{$prefix}secondary-color: #{$body-secondary-color-dark}; // Body lighter text color - scss variable $body-secondary-color-dark(dark) and $body-secondary-color(light)
--#{$prefix}secondary-bg: #{$body-secondary-bg-dark}; // Body lighter background color - scss variable $body-secondary-bg-dark(dark) and $body-secondary-bg(light)
--#{$prefix}tertiary-color: #{$body-tertiary-color-dark}; // Body even lighter text color - scss variable $body-tertiary-color-dark(dark) and $body-tertiary-color(light)
--#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark}; // Body even lighter background color - scss variable $body-tertiary-bg-dark(dark) and $body-tertiary-bg(light)
--#{$prefix}primary-text: #{$primary-text-dark}; // Primary high contrast text color - scss variable $primary-text-dark(dark) and $primary-text(light)
--#{$prefix}secondary-text: #{$secondary-text-dark}; // secondary high contrast text color - scss variable $secondary-text-dark(dark) and $secondary-text(light)
...
--#{$prefix}primary-bg-subtle: #{$primary-bg-subtle-dark}; // Primary high contrast background color - scss variable $primary-bg-subtle-dark(dark) and $primary-bg-subtle(light)
...
--#{$prefix}primary-border-subtle: #{$primary-border-subtle-dark}; // Primary high contrast border color - scss variable $primary-border-subtle-dark(dark) and $primary-border-subtle(light)
...
--#{$prefix}heading-color: #{$headings-color-dark}; // heading color - scss variable $headings-color-dark(dark) and $headings-color(light)
--#{$prefix}link-color: #{$link-color-dark}; // link text color - scss variable $link-color-dark(dark) and $link-color(light)
--#{$prefix}link-hover-color: #{$link-hover-color-dark}; // link hover color - scss variable $link-hover-color-dark(dark) and $link-hover-color(light)
--#{$prefix}code-color: #{$code-color-dark}; // <code> color - scss variable $code-color-dark(dark) and $code-color(light)
--#{$prefix}border-color: #{$border-color-dark}; // border color - scss variable $border-color-dark(dark) and $border-color(light)
--#{$prefix}border-color-translucent: #{$border-color-translucent-dark}; // semi-transparent border color - scss variable $border-color-translucent-dark(dark) and $border-color-translucent(light)
Code optimization
Follow these rules during development to reduce code and reduce effort
- Set sass variables properly. The global variables are included in this article, component specific variables can be found in respective component page. Customize components with these variables.
- If sass variables are not available or sass variable already customized and style is still different then customize with css variable. Before customizing css variable add a class to the component and change variable based on that class.
- Remove unused theme colors form theme color map and media queries from breakpoints map.
- Try not to add new theme color and media query in their maps.
- Remove unused utilities and utility values from utility map.
- Maximum utilization of bootstrap components, utility classes and helper classes and reduce custom styles.
- Use responsive font sizes(rfs) and avoid media queries to change font size. Use rfs by using mixins
@include font-size(4rem);for font size and@include rfs(4rem, margin-bottom);for other properties. - Remove unused components, utilities and helper classes.
Top comments