Module 20 : Using CSS Grid with Bootstrap.
1. Bootstrap grid vs CSS Grid — complementary tools
Bootstrap grid (row + column classes) is a 12-column, mobile-first system built with Flexbox. It's great for quick, consistent, and semantic column layouts and for using out-of-the-box responsive breakpoints (.col-md-6 etc.).
CSS Grid is a two-dimensional layout system (rows + columns) — ideal for complex layouts where you control both axes (e.g., dashboard grids, masonry-like galleries, precise placement).
Rule of thumb: use Bootstrap for content flow and components (navs, cards, forms) and Grid for page-level layout when you need control of rows and columns simultaneously.
2. Breakpoints — coordinating Bootstrap and Grid
Bootstrap breakpoints are standardized (sm, md, lg, xl, xxl). Use them in CSS media queries to keep consistent responsive behavior:
@media (min-width: 768px) { /* md */ ... }
Grid also supports responsive definitions with media queries or repeat(auto-fit, minmax(...)) to make components adapt.
3. Grid sizing units & features to master
fr — fraction of free space. Use for proportional sizing.
minmax(min, max) — prevents elements from shrinking too small or growing unreasonably.
auto-fit / auto-fill with minmax() — create responsive tile layouts without explicit breakpoints.
grid-template-areas — readable layout mapping.
subgrid (where supported) — lets children inherit parent grid tracks (still limited browser support).
examples
All examples use Bootstrap 5 markup (you can use the CDN or installed package).
Example 1 — Two-column responsive layout (Grid inside Bootstrap container)
HTML:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <div class="container my-4"> <div class="page-grid"> <aside class="sidebar p-3">Sidebar content</aside> <main class="content p-3"> <h1>Page Title</h1> <p>Article / main content...</p> </main> </div> </div>
CSS:
.page-grid { display: grid; grid-template-columns: 1fr; /* mobile: single column */ gap: 1rem; } /* at Bootstrap md breakpoint (>=768px) make 250px sidebar + fluid content */ @media (min-width: 768px) { .page-grid { grid-template-columns: 250px 1fr; align-items: start; } } .sidebar { background: #f8f9fa; /* bootstrap light */ border-radius: 0.5rem; }
Why this works: We keep Bootstrap’s .container for consistent horizontal padding and use Grid to define the column relationship. On small screens it stacks (single column). On md+ we create a fixed-width sidebar and fluid main content.
Example 2 — Responsive cards gallery with auto-fit and minmax
HTML:
<div class="container my-4"> <div class="card-grid"> <!-- repeat card items --> <div class="card"> ... </div> <div class="card"> ... </div> <!-- ... --> </div> </div>
CSS:
.card-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } .card { padding: 1rem; border: 1px solid #ddd; border-radius: .5rem; }
Explanation: auto-fit + minmax(220px, 1fr) means as many 220px minimum cards will fit into the row; remaining width is distributed (1fr). No need for explicit breakpoints; the layout is fluid.
Example 3 — Admin dashboard
HTML skeleton:
<div class="container-fluid px-3"> <div class="dashboard-grid"> <header class="dashboard-header">Header</header> <nav class="dashboard-nav">Nav</nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main"></nav> <section class="dashboard-main">Main</section> <aside class="dashboard-stats">Stats</aside> <footer class="dashboard-footer">Footer</footer> </div> </div>
CSS:
.dashboard-grid{ display:grid; grid-template-columns: 240px 1fr 320px; grid-template-rows: 60px 1fr 40px; grid-template-areas: "header header header" "nav main stats" "footer footer footer"; gap: 1rem; } /* Assign areas */ .dashboard-header { grid-area: header; } .dashboard-nav { grid-area: nav; } .dashboard-main { grid-area: main; } .dashboard-stats { grid-area: stats; } .dashboard-footer { grid-area: footer; } /* Responsive: collapse into single column on small screens */ @media (max-width: 767.98px) { .dashboard-grid{ grid-template-columns: 1fr; grid-template-rows: auto; grid-template-areas: "header" "nav" "main" "stats" "footer"; } }
Explanation: grid-template-areas gives readable mapping of the layout. On small screens the layout stacks vertically using a media query aligned with Bootstrap breakpoints.
methods
Keep semantics: use main, aside, header, footer to preserve accessibility.
Use Bootstrap containers & utilities for spacing and consistent breakpoints — container, container-fluid, .p-3, .mx-auto.
Avoid mixing Bootstrap .row/.col inside elements you also place into a grid cell unless you need nested column behavior. It's fine to nest—Bootstrap columns inside a Grid area provide internal column layout.
Prefer minmax and fr to fixed pixel widths for responsive flexibility; use pixel widths for sidebars or items that must remain constant.
Test keyboard navigation & focus order — Grid can change visual order; do not reorder DOM with grid-area if it changes logical focus order unless you explicitly manage tabindex.
Pay attention to reflow — large grid-auto-rows or complex calculations can cause repaints; keep DOM minimal and avoid heavy CSS transitions on layout properties.
Exercises
Exercise 1 — Convert Bootstrap columns to CSS Grid
Given a Bootstrap .row with three .col-md-4, rebuild it using CSS Grid so that it becomes 1 column on mobile, 3 equal columns at md+, with 16px gap.
Solution:
<div class="container"> <div class="three-grid"> <div>Item 1</div> <div>Item 2</div> <div>Item 3</div> </div> </div>
.three-grid { display:grid; gap:16px; grid-template-columns:1fr; } @media (min-width:768px) { .three-grid { grid-template-columns: repeat(3, 1fr); } }
Explanation: Simple responsive switch using a media query aligned to Bootstrap md.
Exercise 2 — Masonry-like layout
Create a masonry-like layout using CSS Grid columns.
Note: True masonry uses JS or grid-auto-flow: dense hack. A simple CSS approach:
.masonry { column-count: 3; column-gap: 1rem; } .masonry .item { display: inline-block; width: 100%; margin-bottom: 1rem; }
Explanation: This uses CSS columns (not Grid) for masonry effect. Alternatively, use Masonry JS or CSS Grid + grid-auto-rows with varying row spans (more advanced).
Create a responsive admin dashboard with:
Top header with app name + user avatar
Left navigation (collapsible on small screens)
Main area with cards and a grid of widgets
Right column with stats (hidden on small screens)
Footer
Setup
Create an index.html, include Bootstrap CSS and optionally Bootstrap JS (for collapse behavior).
Add a styles.css.
Use a container-fluid to allow a full-width dashboard.
Steps
Step 1 — Base HTML
<body> <div class="container-fluid px-3"> <div class="dashboard-grid"> <header class="dashboard-header">...</header> <nav class="dashboard-nav">...</nav> <main class="dashboard-main">...</main> <aside class="dashboard-stats">...</aside> <footer class="dashboard-footer">...</footer> </div> </div> </body>
Step 2 — Grid layout (desktop)
In styles.css:
.dashboard-grid{ display:grid; grid-template-columns: 220px 1fr 320px; grid-template-rows: 64px 1fr 48px; grid-template-areas: "header header header" "nav main stats" "footer footer footer"; gap:1rem; min-height: 100vh; }
Add area as in earlier examples.
Step 3 — Make nav collapsible (Bootstrap)
Inside .dashboard-nav, use a Bootstrap collapse to hide nav on small screens — keep nav DOM order so keyboard focus remains logical.
Step 4 — Widgets using nested Grids
Inside .dashboard-main:
<div class="main-widgets"> <div class="widget">...</div> <div class="widget">...</div> <div class="widget">...</div> <div class="widget">...</div> </div>
CSS:
.main-widgets { display:grid; gap:1rem; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } .widget { padding:1rem; border-radius:.5rem; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.05); }
Step 5 — Responsive collapse
At max-width: 767.98px:
@media (max-width:767.98px){ .dashboard-grid { grid-template-columns: 1fr; grid-template-areas: "header" "nav" "main" "stats" "footer"; } .dashboard-stats { display:none; } /* or keep and stack */ }
Step 6 — Accessibility checks
Ensure nav has aria-label.
Ensure focus states are visible (use :focus-visible styles).
Make sure header elements are semantic and H1 only appears once.
Checklist
Responsive layout matches mock (header/nav/main/stats/footer).
Nav collapses on small screens (Bootstrap collapse).
Widgets reflow using auto-fit.
Keyboard navigation through nav and controls works.
No content overflows the container at any breakpoint.
Layout correctness: 40%
Responsiveness: 25%
Accessibility & semantics: 15%
Code structure/readability: 10%
Extra polish (animations, theme): 10%
Advanced topics
CSS Subgrid — allows alignment. Good for complex nested grids; check browser support and progressive enhancement.
Grid vs Flexbox performance — show comparable rendering speeds; the choice should be semantic and based on layout complexity. Research recent browser engine optimizations (Blink, Gecko).
Responsive patterns without media queries — repeat(auto-fit, minmax()) can reduce breakpoint complexity.
Accessibility — logical DOM order vs visual order; impact of order and grid placement on screen readers and keyboard navigation.
Generative layouts — use CSS functions (clamp(), min(), max()) to create fluid typography and spacing in conjunction with grid sizing.
Progressive enhancement & fallbacks — use feature queries @supports (display: grid) to provide fallbacks for older browsers.
Testing & CI — automate visual regression tests (Percy, Playwright snapshots) to catch layout regressions.
Recommended a coding specialist:
Measure time-to-first-paint (TTFP) and layout shifts (CLS) for pages that use heavy Grid layouts vs pure Bootstrap.
Conduct usability testing for keyboard-only users when visual order differs from DOM order.
tips
Overflowing Grid Items: Use min-width: 0 on flex/grid children to allow them to shrink: .grid-item { min-width: 0; }
Unexpected placement: Check grid-auto-flow and grid-auto-rows; explicitly set grid-column/grid-row for precise placement.
Focus order mismatch: If you position items visually out of DOM order, ensure keyboard flow remains logical (avoid using CSS to visually reorder interactive items unless you manage focus).
Using Bootstrap .row inside grid items: remember .row has negative margins; wrap .row in a .container or add .g-0 if mixing inside grid areas.
specialist notes
struggle with minmax, auto-fit, and how Grid interacts with intrinsic sizing.
Demo flow: Start with simple Grid examples and progressively combine with Bootstrap components (cards, navbars).
Provide starter repo + failing test cases (responsive test images) for automated grading.
Pair programming: to swap DOM order to see how focus and screen readers behave.
Support materials: Provide for grid-* properties and Bootstrap breakpoint table.
Self-contained markup + styles (Dashboard simplified)
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Grid + Bootstrap Dashboard</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> :root { --gap: 1rem; } body { background:#f1f3f5; } .dashboard-grid{ display:grid; grid-template-columns: 220px 1fr 320px; grid-template-rows: 64px 1fr 48px; grid-template-areas: "header header header" "nav main stats" "footer footer footer"; gap: var(--gap); min-height:100vh; padding:1rem; } .dashboard-header { grid-area: header; background:#fff; display:flex; align-items:center; gap:1rem; padding:0 1rem; border-radius:.5rem; } .dashboard-nav { grid-area: nav; background:#fff; padding:1rem; border-radius:.5rem; } .dashboard-main { grid-area: main; padding:1rem; } .dashboard-stats { grid-area: stats; background:#fff; padding:1rem; border-radius:.5rem; } .dashboard-footer { grid-area: footer; background:#fff; padding: .5rem 1rem; border-radius:.5rem; display:flex; align-items:center; } .main-widgets { display:grid; gap:1rem; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } .widget { background:#fff; padding:1rem; border-radius:.5rem; box-shadow:0 1px 2px rgba(0,0,0,.04); } @media (max-width:767.98px){ .dashboard-grid{ grid-template-columns: 1fr; grid-template-areas: "header" "nav" "main" "stats" "footer"; } .dashboard-stats { display:none; } } </style> </head> <body> <div class="container-fluid px-0"> <div class="dashboard-grid"> <header class="dashboard-header"> <h2 class="h5 mb-0">Acme Admin</h2> <div class="ms-auto d-flex align-items-center gap-2"> <button class="btn btn-sm btn-outline-secondary">New</button> <img src="https://via.placeholder.com/40" alt="avatar" class="rounded-circle"> </div> </header> <nav class="dashboard-nav" aria-label="Primary"> <ul class="nav flex-column"> <li class="nav-item"><a class="nav-link active" href="#">Dashboard</a></li> <li class="nav-item"><a class="nav-link" href="#">Reports</a></li> <li class="nav-item"><a class="nav-link" href="#">Settings</a></li> </ul> </nav> <main class="dashboard-main"> <div class="main-widgets"> <div class="widget">Widget 1</div> <div class="widget">Widget 2</div> <div class="widget">Widget 3</div> <div class="widget">Widget 4</div> </div> </main> <aside class="dashboard-stats"> <h6>Stats</h6> <p>Quick numbers and charts...</p> </aside> <footer class="dashboard-footer"> <small class="text-muted">© 2025 Your Company</small> </footer> </div> </div> </body> </html>
exercises
Replace the right-hand stats column with a sticky element that remains visible while the main content scrolls — implement position: sticky inside a grid cell.
Implement a card layout where cards have different heights but maintain a uniform baseline using grid-auto-rows + row-span technique (calculate grid-row: span N;).
Build a responsive form that rearranges fields from 2-column desktop grid to single-column mobile, while preserving logical focus order.
No comments:
Post a Comment