Bootstrap 5 Framework

Customizing Bootstrap with CSS

15 min Lesson 39 of 40

Understanding Bootstrap CSS Architecture

Bootstrap 5 is built with a clear, modular CSS architecture that makes customization straightforward. Understanding this structure is key to effective customization.

<!-- Bootstrap CSS layers --> 1. CSS Custom Properties (Variables) 2. Reboot (normalize.css + opinionated defaults) 3. Type (typography) 4. Grid 5. Components 6. Utilities 7. Helpers
Note: Bootstrap 5 uses CSS custom properties extensively, making runtime customization much easier than previous versions.

CSS Custom Properties in Bootstrap 5

Bootstrap 5 leverages CSS variables for many of its core values, allowing real-time customization without recompiling Sass.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bootstrap CSS Variables</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> /* View Bootstrap's CSS variables */ :root { /* These are already defined by Bootstrap */ --bs-blue: #0d6efd; --bs-indigo: #6610f2; --bs-purple: #6f42c1; --bs-pink: #d63384; --bs-red: #dc3545; --bs-orange: #fd7e14; --bs-yellow: #ffc107; --bs-green: #198754; --bs-teal: #20c997; --bs-cyan: #0dcaf0; } </style> </head> <body> <div class="container py-5"> <h1>Bootstrap Color System</h1> <div class="row g-3"> <div class="col-md-4"> <div class="p-3 bg-primary text-white rounded">Primary</div> </div> <div class="col-md-4"> <div class="p-3 bg-success text-white rounded">Success</div> </div> <div class="col-md-4"> <div class="p-3 bg-danger text-white rounded">Danger</div> </div> </div> </div> </body> </html>

Overriding Bootstrap Variables with :root

You can override Bootstrap's CSS variables in your own stylesheet to customize the theme globally.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Custom Bootstrap Theme</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> /* Override Bootstrap variables AFTER Bootstrap CSS */ :root { --bs-primary: #6a4c93; --bs-primary-rgb: 106, 76, 147; --bs-secondary: #f72585; --bs-success: #4cc9f0; --bs-danger: #f77f00; --bs-warning: #fcbf49; --bs-info: #4361ee; /* Typography */ --bs-body-font-family: "Segoe UI", Tahoma, sans-serif; --bs-body-font-size: 1.1rem; --bs-body-line-height: 1.7; /* Spacing */ --bs-gutter-x: 2rem; /* Border radius */ --bs-border-radius: 0.5rem; --bs-border-radius-lg: 1rem; } /* Custom body styling */ body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; } </style> </head> <body> <div class="container py-5"> <div class="card shadow-lg"> <div class="card-body p-5"> <h1 class="text-primary mb-4">Custom Bootstrap Theme</h1> <p class="lead">This page uses custom CSS variables to override Bootstrap's default theme.</p> <div class="row g-4 my-4"> <div class="col-md-6"> <button class="btn btn-primary w-100">Primary Button</button> </div> <div class="col-md-6"> <button class="btn btn-secondary w-100">Secondary Button</button> </div> <div class="col-md-6"> <button class="btn btn-success w-100">Success Button</button> </div> <div class="col-md-6"> <button class="btn btn-danger w-100">Danger Button</button> </div> </div> <div class="alert alert-info" role="alert"> All colors are customized using CSS variables! </div> </div> </div> </div> </body> </html>

Adding Custom Utility Classes

Extend Bootstrap's utility system with your own custom classes following Bootstrap's naming conventions.

<style> /* Custom spacing utilities */ .mt-6 { margin-top: 4rem !important; } .mb-6 { margin-bottom: 4rem !important; } .py-6 { padding-top: 4rem !important; padding-bottom: 4rem !important; } /* Custom text utilities */ .text-gradient { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .text-shadow { text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); } /* Custom background utilities */ .bg-gradient-primary { background: linear-gradient(135deg, var(--bs-primary) 0%, var(--bs-secondary) 100%); } .bg-gradient-success { background: linear-gradient(135deg, var(--bs-success) 0%, var(--bs-info) 100%); } /* Custom border utilities */ .border-thick { border-width: 3px !important; } .border-dashed { border-style: dashed !important; } /* Custom shadow utilities */ .shadow-colored { box-shadow: 0 0.5rem 1rem rgba(var(--bs-primary-rgb), 0.3) !important; } /* Hover effects */ .hover-lift { transition: transform 0.3s ease, box-shadow 0.3s ease; } .hover-lift:hover { transform: translateY(-5px); box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); } </style> <div class="container py-5"> <h1 class="text-gradient text-shadow mb-6">Custom Utilities Demo</h1> <div class="row g-4"> <div class="col-md-4"> <div class="card hover-lift shadow-colored"> <div class="card-body bg-gradient-primary text-white"> <h5>Gradient Card</h5> <p>With custom utilities</p> </div> </div> </div> <div class="col-md-4"> <div class="card hover-lift border-thick border-primary"> <div class="card-body"> <h5>Thick Border</h5> <p>Custom border width</p> </div> </div> </div> <div class="col-md-4"> <div class="card hover-lift border-dashed border-secondary"> <div class="card-body"> <h5>Dashed Border</h5> <p>Custom border style</p> </div> </div> </div> </div> </div>

Customizing Theme Colors

Create a comprehensive custom color scheme for your Bootstrap project.

<style> /* Define custom color palette */ :root { /* Brand colors */ --brand-purple: #6a4c93; --brand-pink: #f72585; --brand-blue: #4361ee; --brand-cyan: #4cc9f0; --brand-yellow: #fcbf49; /* Override Bootstrap theme colors */ --bs-primary: var(--brand-purple); --bs-primary-rgb: 106, 76, 147; --bs-secondary: var(--brand-pink); --bs-secondary-rgb: 247, 37, 133; --bs-info: var(--brand-blue); --bs-info-rgb: 67, 97, 238; /* Light variants */ --bs-primary-light: rgba(106, 76, 147, 0.1); --bs-secondary-light: rgba(247, 37, 133, 0.1); /* Dark variants */ --bs-primary-dark: #4a3569; --bs-secondary-dark: #d11f6f; } /* Custom background classes */ .bg-primary-light { background-color: var(--bs-primary-light) !important; } .bg-secondary-light { background-color: var(--bs-secondary-light) !important; } /* Custom text classes */ .text-primary-dark { color: var(--bs-primary-dark) !important; } /* Custom button variants */ .btn-gradient { background: linear-gradient(135deg, var(--bs-primary), var(--bs-secondary)); border: none; color: white; transition: transform 0.3s ease, box-shadow 0.3s ease; } .btn-gradient:hover { transform: translateY(-2px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.2); color: white; } .btn-outline-gradient { background: transparent; border: 2px solid var(--bs-primary); color: var(--bs-primary); position: relative; overflow: hidden; z-index: 1; } .btn-outline-gradient::before { content: ""; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(135deg, var(--bs-primary), var(--bs-secondary)); transition: left 0.3s ease; z-index: -1; } .btn-outline-gradient:hover { color: white; border-color: transparent; } .btn-outline-gradient:hover::before { left: 0; } </style> <div class="container py-5"> <h2 class="mb-4">Custom Theme Colors</h2> <!-- Color palette display --> <div class="row g-3 mb-5"> <div class="col-md-2"> <div class="p-4 bg-primary text-white text-center rounded"> <strong>Primary</strong> </div> </div> <div class="col-md-2"> <div class="p-4 bg-secondary text-white text-center rounded"> <strong>Secondary</strong> </div> </div> <div class="col-md-2"> <div class="p-4 bg-info text-white text-center rounded"> <strong>Info</strong> </div> </div> <div class="col-md-2"> <div class="p-4 bg-primary-light text-primary-dark text-center rounded border"> <strong>Light</strong> </div> </div> </div> <!-- Custom buttons --> <div class="d-flex gap-3 flex-wrap"> <button class="btn btn-gradient">Gradient Button</button> <button class="btn btn-outline-gradient">Outline Gradient</button> <button class="btn btn-primary">Primary</button> <button class="btn btn-secondary">Secondary</button> </div> </div>
Tip: Always define both the color and its RGB values when overriding Bootstrap colors to ensure transparency utilities work correctly.

Working with Sass Variables (Overview)

While CSS variables are great for runtime changes, Sass variables offer more powerful compile-time customization.

// custom.scss - Override Bootstrap Sass variables // Color system $purple: #6a4c93; $pink: #f72585; $blue: #4361ee; // Theme colors $primary: $purple; $secondary: $pink; $success: #4cc9f0; $info: $blue; $warning: #fcbf49; $danger: #f77f00; // Typography $font-family-base: "Segoe UI", system-ui, sans-serif; $font-size-base: 1.1rem; $line-height-base: 1.7; $headings-font-weight: 700; // Spacing $spacer: 1rem; $spacers: ( 0: 0, 1: $spacer * 0.25, 2: $spacer * 0.5, 3: $spacer, 4: $spacer * 1.5, 5: $spacer * 3, 6: $spacer * 4 // Custom spacer ); // Border radius $border-radius: 0.5rem; $border-radius-sm: 0.35rem; $border-radius-lg: 1rem; // Buttons $btn-padding-y: 0.75rem; $btn-padding-x: 1.5rem; $btn-border-radius: $border-radius-lg; // Cards $card-border-radius: $border-radius-lg; $card-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1); // Import Bootstrap @import "bootstrap/scss/bootstrap"; // Custom components after Bootstrap .custom-card { border: none; box-shadow: $card-box-shadow; transition: transform 0.3s ease; &:hover { transform: translateY(-5px); } }
Note: To use Sass customization, you need Node.js, npm, and a build process. CSS variables are simpler for most projects.

Creating Custom Components

Build custom components that extend Bootstrap's component system with consistent styling.

<style> /* Custom Card Component */ .card-custom { border: none; border-radius: 1rem; overflow: hidden; transition: all 0.3s ease; box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1); } .card-custom:hover { transform: translateY(-10px); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15); } .card-custom-header { background: linear-gradient(135deg, var(--bs-primary), var(--bs-secondary)); color: white; padding: 2rem; position: relative; } .card-custom-icon { width: 60px; height: 60px; background: rgba(255, 255, 255, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; margin-bottom: 1rem; } /* Custom Badge Component */ .badge-custom { padding: 0.5rem 1rem; border-radius: 2rem; font-weight: 600; text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.5px; } /* Custom Button Group */ .btn-group-custom .btn { border-radius: 0; border-right: 1px solid rgba(255, 255, 255, 0.2); } .btn-group-custom .btn:first-child { border-radius: 0.5rem 0 0 0.5rem; } .btn-group-custom .btn:last-child { border-radius: 0 0.5rem 0.5rem 0; border-right: none; } /* Custom Alert Component */ .alert-custom { border: none; border-left: 4px solid; border-radius: 0.5rem; background: rgba(var(--bs-primary-rgb), 0.1); border-left-color: var(--bs-primary); } .alert-custom-icon { width: 40px; height: 40px; background: var(--bs-primary); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } </style> <div class="container py-5"> <h2 class="mb-4">Custom Components</h2> <div class="row g-4 mb-5"> <div class="col-md-4"> <div class="card-custom"> <div class="card-custom-header"> <div class="card-custom-icon"> 🚀 </div> <h4 class="mb-0">Fast</h4> </div> <div class="card-body"> <p>Lightning-fast performance with optimized code.</p> <span class="badge-custom bg-primary">Premium</span> </div> </div> </div> <div class="col-md-4"> <div class="card-custom"> <div class="card-custom-header"> <div class="card-custom-icon"> 🎨 </div> <h4 class="mb-0">Beautiful</h4> </div> <div class="card-body"> <p>Stunning designs that captivate users.</p> <span class="badge-custom bg-secondary">Popular</span> </div> </div> </div> <div class="col-md-4"> <div class="card-custom"> <div class="card-custom-header"> <div class="card-custom-icon"> 🔒 </div> <h4 class="mb-0">Secure</h4> </div> <div class="card-body"> <p>Enterprise-grade security built-in.</p> <span class="badge-custom bg-success">Featured</span> </div> </div> </div> </div> <!-- Custom Alert --> <div class="alert-custom p-4 d-flex align-items-center gap-3"> <div class="alert-custom-icon"> ℹ </div> <div> <strong>Pro Tip:</strong> Custom components maintain Bootstrap's responsive behavior while adding unique styling. </div> </div> <!-- Custom Button Group --> <div class="btn-group-custom mt-4" role="group"> <button class="btn btn-primary">Option 1</button> <button class="btn btn-primary">Option 2</button> <button class="btn btn-primary">Option 3</button> </div> </div>

Using CSS Cascade Effectively

Leverage CSS specificity and cascade order to override Bootstrap styles cleanly.

<style> /* ❌ BAD: Using !important unnecessarily */ .my-button { background-color: red !important; color: white !important; } /* ✅ GOOD: Using proper specificity */ .btn.btn-custom { background-color: red; color: white; border-color: darkred; } .btn.btn-custom:hover { background-color: darkred; border-color: #8b0000; } /* ✅ GOOD: Scoping overrides to specific sections */ .hero-section .btn-primary { padding: 1rem 2rem; font-size: 1.2rem; border-radius: 2rem; } /* ✅ GOOD: Using CSS custom properties for consistent overrides */ .custom-theme { --bs-primary: #e74c3c; --bs-primary-rgb: 231, 76, 60; } .custom-theme .btn-primary { background-color: var(--bs-primary); } </style> <div class="container py-5"> <h3>Cascade Examples</h3> <!-- Standard Bootstrap button --> <button class="btn btn-primary mb-3">Standard Button</button> <!-- Custom button with proper specificity --> <button class="btn btn-custom mb-3">Custom Button</button> <!-- Scoped customization --> <div class="hero-section my-4"> <button class="btn btn-primary">Hero Button (Larger)</button> </div> <!-- Theme scoped --> <div class="custom-theme my-4"> <button class="btn btn-primary">Themed Button</button> </div> </div>
Warning: Avoid using !important unless absolutely necessary. It makes future customization difficult and breaks the CSS cascade.

Debugging Custom Styles

Techniques for troubleshooting when custom styles don't work as expected.

<!-- Debugging checklist --> 1. Check CSS Load Order: <!-- Bootstrap MUST come first --> <link href="bootstrap.min.css" rel="stylesheet"> <!-- Your custom CSS comes after --> <link href="custom.css" rel="stylesheet"> 2. Inspect Element in Browser DevTools: - Right-click → Inspect - Check which styles are applied - Look for crossed-out styles (overridden) - Check computed values 3. Verify Specificity: <!-- Lower specificity - might not work --> <style> .btn { background: red; } </style> <!-- Higher specificity - better --> <style> .btn.btn-custom { background: red; } </style> 4. Check for Typos: ❌ .btn-primery (typo) ✅ .btn-primary 5. Ensure CSS is Loading: <!-- Open DevTools → Network → Filter: CSS --> <!-- Verify your CSS file loaded (200 status) --> 6. Clear Browser Cache: - Hard refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac) - Or clear cache in DevTools 7. Use Browser DevTools Console: <script> // Check computed style const element = document.querySelector('.btn-primary'); const styles = window.getComputedStyle(element); console.log(styles.backgroundColor); </script>

Performance Considerations

Best practices for maintaining performance while customizing Bootstrap.

Performance Tips:
  • Minimize CSS: Remove unused Bootstrap components
  • Limit !important: Slows down browser style calculation
  • Avoid deep nesting: Keep selectors shallow (max 3 levels)
  • Use CSS variables: Faster than recompiling Sass
  • Combine selectors: Group similar styles together
  • Load critical CSS inline: Include essential styles in <head>
  • Defer non-critical CSS: Load custom fonts asynchronously
<!-- Performance-optimized loading --> <head> <!-- Critical inline CSS --> <style> /* Only essential above-the-fold styles */ :root { --bs-primary: #6a4c93; } body { font-family: system-ui, sans-serif; } .hero { min-height: 100vh; } </style> <!-- Bootstrap CSS --> <link href="bootstrap.min.css" rel="stylesheet"> <!-- Defer non-critical custom CSS --> <link href="custom.css" rel="stylesheet" media="print" onload="this.media='all'"> <!-- Preload fonts --> <link rel="preload" href="fonts/custom-font.woff2" as="font" type="font/woff2" crossorigin> </head>

Exercise: Create Your Custom Theme

Task: Build a complete custom Bootstrap theme with the following requirements:

  1. Define a custom color palette with at least 5 colors
  2. Override Bootstrap's primary, secondary, and success colors
  3. Create 3 custom utility classes
  4. Build a custom card component with hover effects
  5. Create a custom button with gradient background
  6. Add custom spacing utilities (mt-6, mb-6)
  7. Ensure all components are responsive
  8. Test in Chrome DevTools

Bonus: Add dark mode support using CSS variables