Episode 1 — Fundamentals / 1.11 — CSS Frameworks TailwindCSS and Bootstrap
1.11.g — Customizing Bootstrap
In one sentence: Real-world Bootstrap projects require customization — SASS variable overrides, cherry-picking components, and the utilities API let you match your brand, reduce bundle size, and extend the framework without fighting it.
Navigation: ← 1.11.f — Bootstrap Grid & Components · 1.11.h — TailwindCSS vs Bootstrap →
1. Why customize?
Out-of-the-box Bootstrap is fast to prototype with, but shipping a production site with default styles has problems:
- Generic look — users and designers notice "the Bootstrap look"
- Bundle size — the full CSS is ~230 KB uncompressed; you likely use < 30% of it
- Brand mismatch — your brand colors, fonts, and spacing differ from Bootstrap defaults
- Specificity conflicts — overriding deeply nested selectors with custom CSS leads to brittle code
Bootstrap was designed to be customized via SASS. Working with the system is easier than fighting it.
2. SASS variable overrides
The most powerful customization technique: override variables before the import.
// custom.scss
// 1. Override variables
$primary: #6366f1; // Indigo instead of blue
$secondary: #64748b;
$success: #22c55e;
$danger: #ef4444;
$font-family-base: "Inter", system-ui, sans-serif;
$font-size-base: 1rem;
$border-radius: 0.75rem;
$body-bg: #f8fafc;
$body-color: #1e293b;
// 2. Import Bootstrap (uses your overrides)
@import "bootstrap/scss/bootstrap";
Why before? Bootstrap uses !default on all variables — this means "use this value unless the variable is already defined." By defining yours first, Bootstrap picks up your values.
Common variables to override
| Variable | Default | Controls |
|---|---|---|
$primary | #0d6efd | Primary brand color (buttons, links, active states) |
$body-bg | #fff | Page background |
$body-color | #212529 | Default text color |
$font-family-base | system stack | Base font |
$font-size-base | 1rem | Root font size |
$border-radius | 0.375rem | Default rounding |
$spacer | 1rem | Base spacing unit (generates margin/padding utilities) |
$grid-gutter-width | 1.5rem | Gutter between grid columns |
$enable-rounded | true | Toggle border-radius globally |
$enable-shadows | false | Toggle box shadows on components |
3. Custom color themes
Bootstrap's color map generates variants for every component:
$theme-colors: (
"primary": #6366f1,
"secondary": #64748b,
"success": #22c55e,
"info": #06b6d4,
"warning": #f59e0b,
"danger": #ef4444,
"light": #f1f5f9,
"dark": #0f172a,
);
@import "bootstrap/scss/bootstrap";
This automatically generates .btn-primary, .bg-primary, .text-primary, .alert-primary, .badge-bg-primary, etc. — all using your custom color.
Adding new theme colors
$custom-colors: (
"brand": #8b5cf6,
"accent": #f97316,
);
$theme-colors: map-merge($theme-colors, $custom-colors);
Now btn-brand, bg-accent, text-brand all work automatically.
4. Cherry-picking components
Don't need carousels, toasts, or popovers? Import only what you use:
// custom.scss — selective imports
// Required core
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
// Reset and base
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
// Layout
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
// Components you actually use
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/card";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/modal";
@import "bootstrap/scss/alert";
// Utilities
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api";
Result: A CSS bundle with only the components your project needs — often 50–70% smaller than the full library.
5. Adding custom components alongside Bootstrap
Write custom components that use Bootstrap's variables and mixins for consistency:
// _custom-components.scss
.feature-card {
background: $white;
border-radius: $border-radius-lg;
padding: $spacer * 2;
box-shadow: $box-shadow;
transition: transform 0.2s ease;
&:hover {
transform: translateY(-4px);
box-shadow: $box-shadow-lg;
}
&__title {
font-size: $h5-font-size;
font-weight: $font-weight-bold;
color: $primary;
margin-bottom: $spacer * 0.5;
}
&__text {
color: $body-color;
font-size: $font-size-base;
}
}
By using Bootstrap's variables ($spacer, $primary, $border-radius-lg), your custom components stay in sync with the theme.
6. The utilities API
Bootstrap 5 lets you generate custom utility classes or modify existing ones:
$utilities: map-merge(
$utilities,
(
"cursor": (
property: cursor,
class: cursor,
values: auto pointer grab not-allowed,
),
"opacity": map-merge(
map-get($utilities, "opacity"),
(
values: map-merge(
map-get(map-get($utilities, "opacity"), "values"),
(10: .1, 90: .9),
),
),
),
)
);
This generates .cursor-pointer, .cursor-grab, .opacity-10, .opacity-90 — utility classes that follow Bootstrap's naming conventions.
Utilities API options
| Option | What it does |
|---|---|
property | The CSS property (cursor, background-color, etc.) |
class | The class prefix (.cursor-*) |
values | Map or list of values to generate |
responsive | true → generate responsive variants (cursor-md-pointer) |
state | Generate state variants (e.g., hover) |
7. Using CSS custom properties
Bootstrap 5 exposes many values as CSS custom properties (aka CSS variables):
:root {
--bs-primary: #0d6efd;
--bs-body-bg: #fff;
--bs-body-color: #212529;
--bs-border-radius: 0.375rem;
}
You can override these at runtime without recompiling SASS:
[data-theme="dark"] {
--bs-body-bg: #0f172a;
--bs-body-color: #e2e8f0;
}
Limitation: Not all Bootstrap internals use CSS variables yet — SASS overrides remain the most complete approach.
8. Reducing bundle size — checklist
| Technique | Savings |
|---|---|
| Cherry-pick imports | 50–70% smaller CSS |
| PurgeCSS (via PostCSS) | Removes unused classes from final CSS |
| Skip JS components | Don't include bootstrap.bundle.js if you only need styles |
| Minify + gzip | Standard compression; reduces ~230 KB → ~25 KB gzipped |
| Use CDN | Leverages browser cache from other sites using the same CDN |
9. Key takeaways
- Override SASS variables before importing Bootstrap —
!defaultmakes this work. - Use the
$theme-colorsmap to set your brand colors; Bootstrap generates all variant classes automatically. - Cherry-pick imports to ship only the components you use — dramatically reduces bundle size.
- Custom components should use Bootstrap's variables and mixins for theme consistency.
- The utilities API lets you generate custom utility classes that follow Bootstrap conventions.
- CSS custom properties allow runtime theme changes without recompilation.
Explain-It Challenge
Explain without notes:
- Why Bootstrap variables use
!defaultand why your overrides must come before the import. - How cherry-picking SASS imports reduces the production CSS bundle size.
- One use case for Bootstrap's utilities API — what can you create with it?
Navigation: ← 1.11.f — Bootstrap Grid & Components · 1.11.h — TailwindCSS vs Bootstrap →