Module 24 : Bootstrap Cards – Structure & Layout.
Bootstrap Card
the anatomy of a Bootstrap Card and each part maps to HTML/CSS.
Build single cards and multi-card layouts (responsive grids).
Use card components: header, body, footer, image, list-group, overlays, and utilities.
Create interactive cards (links, buttons, modals, collapse).
Implement advanced behaviors: card groups, equal-height cards, card decks replacement, responsive card columns, card flipping.
Optimize cards for accessibility and performance.
2) Card anatomy
A Card is a flexible content container. Think of it as a small panel with optional parts. Core parts:
card — outer wrapper.
card-body — main content container for text, headings, and actions.
card-title, card-text — semantic elements inside card-body.
card-header — optional top bar (title, meta).
card-footer — optional bottom bar (meta, actions).
card-img-top, card-img-bottom — images that span full width.
list-group inside cards for structured lists.
utilities (spacing, flex, text colors) to control layout.
Simple card:
<div class="card" style="width: 18rem;"> <img src="..." class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">Card title</h5> <p class="card-text">A quick example text to build on the card title.</p> <a href="#" class="btn btn-primary">Go somewhere</a> </div> </div>
Explanation line-by-line
<div class="card"> — sets card's base styling (border, background, border-radius, box-shadow depending on utilities).
style="width: 18rem;" — fixed width. In practice use grid or utilities instead of inline styling.
<img class="card-img-top"> — a full-width image placed at top; automatic responsive behavior.
<div class="card-body"> — padding and vertical rhythm for content.
.card-title and .card-text — typographic helpers; not mandatory but semantically helpful.
.btn inside card-body — actions attached to that card.
3) Layout patterns & responsive placement
A. Single column / centered card
Use utilities (e.g., mx-auto, w-50, or grid classes) to center cards.
B. Multi-card grid
Use Bootstrap grid to create responsive card layouts. Example 3-column on md+ and single column on small:
<div class="container"> <div class="row g-4"> <div class="col-12 col-md-6 col-lg-4"> <div class="card h-100"> <img src="..." class="card-img-top" alt="..."> <div class="card-body d-flex flex-column"> <h5 class="card-title">Title</h5> <p class="card-text flex-grow-1">Description...</p> <a href="#" class="btn btn-primary mt-3 align-self-start">Action</a> </div> </div> </div> <!-- repeat columns --> </div> </div>
Key points
row g-4: creates gutters (spacing) between columns.
col-12 col-md-6 col-lg-4: responsive column sizes.
card h-100: makes each card full height of its column so cards align.
d-flex flex-column + flex-grow-1 on body/text ensures buttons stick to bottom and descriptions expand to fill space — equal height effect.
C. Card groups vs card decks (Bootstrap 5)
card-group: groups cards with shared borders and equal height, but less responsive.
card-deck is removed in Bootstrap 5 — prefer grid + utilities.
For masonry-like columns use CSS column-count or Masonry JS; Bootstrap’s row gives a row-based grid (not masonry).
4) Common card variations & components
Header / Footer
<div class="card"> <div class="card-header">Featured</div> <div class="card-body">...</div> <div class="card-footer text-muted">Footer</div> </div>
Headers are typically used for metadata; footers for small print or action links.
List group inside card
<ul class="list-group list-group-flush"> <li class="list-group-item">An item</li> <li class="list-group-item">Another item</li> </ul>
list-group-flush removes the card-body padding between list and card edge.
Image overlay (useful for hero cards)
<div class="card bg-dark text-white"> <img src="..." class="card-img" alt="..."> <div class="card-img-overlay d-flex align-items-end"> <h5 class="card-title">Overlay title</h5> </div> </div>
card-img-overlay positions content over the image. Combine with text-* utilities for contrast.
Linkable card (make whole card clickable)
Use an <a> wrapper or JavaScript. Semantic approach: put <a class="stretched-link"> inside card to extend link to whole card:
<div class="card"> <img src="..." class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">Title</h5> <p class="card-text">...</p> <a href="/product/1" class="stretched-link"></a> </div> </div>
Note: stretched-link requires the link to be positioned within a relatively positioned container — .card qualifies.
5) Accessibility
Add alt text for images.
Use semantic tags for titles (<h3>, <h4>) as appropriate.
Ensure interactive elements (buttons, links) are keyboard accessible (tab order).
For card-img-overlay or images with text, ensure sufficient text contrast (WCAG AA).
Avoid using only color to convey information; use text or icons + aria attributes.
6) interactive & dynamic cards
Collapse inside a card (Bootstrap collapse)
<div class="card"> <div class="card-header"> <button class="btn btn-link" data-bs-toggle="collapse" data-bs-target="#details1"> Toggle details </button> </div> <div id="details1" class="collapse"> <div class="card-body">Hidden details...</div> </div> </div>
Modal triggered from card
Place a button in card-body with data-bs-toggle="modal" and data-bs-target="#myModal". Use dynamic data attributes if you populate modal content via JS.
Card flip (CSS)
A CSS transform/3D trick: two faces (front/back). Use preserve-3d, transform-style, and toggling a class on hover or click.
7) practical
Build a responsive product gallery with cards, each card includes image, title, price, short description, a "Details" button that opens a modal with extended info, and cards are equal-height.
Files: index.html, styles.css, scripts.js. Use Bootstrap 5 (CSS + JS bundle) and minimal custom CSS.
Boilerplate (include Bootstrap)
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Product Gallery</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <!-- gallery goes here --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <script src="scripts.js"></script> </body> </html>
Replace CDN version as appropriate for your project. relies on Bootstrap JS for modals.
Card grid HTML
<div class="container py-5"> <div class="row g-4" id="productRow"> <!-- Cards inserted here (6 example cards) --> <!-- Example single card --> <div class="col-12 col-md-6 col-lg-4"> <div class="card h-100"> <img src="img/product1.jpg" class="card-img-top" alt="Product 1"> <div class="card-body d-flex flex-column"> <h5 class="card-title">Product 1</h5> <p class="card-text flex-grow-1">Short description of product 1.</p> <div class="d-flex justify-content-between align-items-center"> <span class="fw-bold">$19.99</span> <button class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-product-id="1">Details</button> </div> </div> </div> </div> </div> </div>
Modal HTML (single reusable modal)
<div class="modal fade" id="productModal" tabindex="-1" aria-hidden="true"> <div class="modal-dialog modal-lg modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="modalTitle">Product</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <img id="modalImg" src="" class="img-fluid mb-3" alt=""> <p id="modalDesc"></p> <p><strong>Price: </strong> <span id="modalPrice"></span></p> </div> <div class="modal-footer"> <button class="btn btn-primary">Buy now</button> <button class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div>
JavaScript to populate modal (simplified)
// scripts.js const products = { 1: {title: 'Product 1', price: '$19.99', img: 'img/product1.jpg', desc: 'Long description...'}, 2: {title: 'Product 2', price: '$29.99', img: 'img/product2.jpg', desc: 'Long description...'}, // ... }; document.addEventListener('click', (e) => { const btn = e.target.closest('[data-product-id]'); if (!btn) return; const id = btn.getAttribute('data-product-id'); const p = products[id]; if (!p) return; document.getElementById('modalTitle').textContent = p.title; document.getElementById('modalImg').src = p.img; document.getElementById('modalImg').alt = p.title; document.getElementById('modalDesc').textContent = p.desc; document.getElementById('modalPrice').textContent = p.price; // show modal programmatically (optional) const modal = new bootstrap.Modal(document.getElementById('productModal')); modal.show(); });
Exercises
Convert the product grid to load products dynamically (render cards from products object).
Goal: practice DOM rendering and separating data from view.
Add a "like" icon toggle (use <button aria-pressed="false">), persist likes in localStorage.
Goal: state persistence, accessible toggle.
Implement keyboard shortcuts: when modal is open, Escape closes modal, ArrowRight shows the next product.
Goal: accessibility & keyboard behavior.
8) Exercises
Exercise A — Build a profile card
Build a small profile card (avatar, name, role, short bio, follow button). Make it responsive so that on sm it becomes horizontal (avatar left, text right).
Hint: Use Bootstrap grid inside card-body or use d-flex flex-row flex-column with responsive utility classes (e.g., flex-column flex-sm-row).
Solution sketch:
<div class="card" style="max-width: 540px;"> <div class="row g-0 align-items-center"> <div class="col-auto p-3"> <img src="avatar.jpg" class="rounded-circle" width="80" alt="Avatar"> </div> <div class="col p-3"> <div class="card-body p-0"> <h5 class="card-title mb-1">Alice Doe</h5> <p class="text-muted mb-2">Frontend Engineer</p> <p class="card-text small">Short bio...</p> <a href="#" class="btn btn-sm btn-primary">Follow</a> </div> </div> </div> </div>
Exercise B — Equal-height feature cards
Create 4 feature cards in a row with icons, short text, and button — all cards should have equal heights and buttons aligned at bottom.
Hint: d-flex flex-column h-100 on .card, flex-grow-1 on the content area.
Exercise C — Accessible overlay text
Create an image card with overlay text; ensure the text has sufficient contrast and is readable on small devices.
Hint: Use bg-dark bg-opacity-50 on the overlay container, test with devtools mobile sizes, add aria-label where appropriate.
9) Common pitfalls
Using card-deck or older patterns from Bootstrap 4 — update to grid + utilities.
Inline widths for layout — prefer grid columns and responsive utilities.
Images not responsive — use card-img-top and ensure images are sized and optimized for web (compress).
Buttons stick at top — use flex column + mt-auto or flex-grow-1 technique.
Non-semantic headings — choose appropriate heading levels for accessibility.
10) Research
create production-grade systems, research these topics:
Performance & image optimization
Responsive images via srcset/sizes.
Lazy loading: <img loading="lazy">.
CDN + format choices (WebP/AVIF fallback).
Accessibility
ARIA patterns for complex cards (e.g., cards as widgets, accessible modal patterns).
Keyboard focus management when using stretched-link and modals.
Design systems
How cards map into component libraries (Storybook) and design tokens.
Theming: custom properties (CSS variables) to modify card border radius, shadows, spacing.
Advanced layout
CSS Grid vs Bootstrap grid for card layouts (use cases for each).
Masonry layout techniques (CSS columns, Masonry JS).
Equal-height strategies beyond flexbox (grid auto-rows with minmax).
Server-side rendering & hydration
Rendering card lists server-side (Next.js, Rails) vs client-side (React/Vue), tradeoffs.
Progressive enhancement — have semantic HTML first, JS for enhancement.
Testing
Visual regression testing for card UI (Percy, Chromatic).
Unit tests for card behavior (buttons open modal, data attributes handled).
Security
Prevent XSS when injecting card content from untrusted sources — sanitize HTML or use textContent.
11) Materials repo with HTML/JS/CSS skeleton, placeholder images.
12) reference
.card — wrapper
.card-body — content area
.card-title, .card-subtitle, .card-text
.card-header, .card-footer
.card-img-top, .card-img-bottom, .card-img
.card-img-overlay — content on top of image
.list-group + .list-group-flush — lists inside card
.h-100 — make card stretch to fill column
.d-flex .flex-column .flex-grow-1 — keep action button at bottom
.stretched-link — make link cover whole card area
13) Example: Product card with badge and rating
<div class="card h-100"> <div class="position-relative"> <img src="img/prod.jpg" class="card-img-top" alt="Product"> <span class="position-absolute top-0 start-0 m-2 badge bg-success">In stock</span> <span class="position-absolute top-0 end-0 m-2 badge bg-warning text-dark">4.5 ★</span> </div> <div class="card-body d-flex flex-column"> <h6 class="card-title mb-1">Product name</h6> <p class="card-text small text-muted flex-grow-1">Short description goes here and can span lines.</p> <div class="d-flex justify-content-between align-items-center"> <span class="fw-bold">$24.00</span> <a href="/p/1" class="btn btn-sm btn-primary stretched-link">View</a> </div> </div> </div>
14) tips
Treat cards as components: keep markup consistent and data-driven.
Create a component library (Storybook) for your cards — helps reuse and testing.
Profile images and icons: combine SVG icons (inline or sprite) with aria-hidden="true" and a separate screen-reader label.
For dynamic content, keep state off the DOM when possible — use JS frameworks or progressive enhancement techniques.
No comments:
Post a Comment