Week 5: Modern CSS Layouts

Flexbox, Grid, and Responsive Design

INFO 153A/253A - Front-End Web Architecture

UC Berkeley School of Information

September 22, 2025

Today's Learning Objectives

  • Master Flexbox for one-dimensional layouts
  • Command CSS Grid for two-dimensional layouts
  • Choose the right tool: Flexbox vs Grid
  • Implement modern responsive design patterns
  • Build complex layouts without media queries
  • Understand the box model in modern contexts
Key Insight: Modern CSS layouts eliminate the need for hacks, floats, and complicated positioning. Everything you need is built into the platform.

Part 1: Prep Work Recap

Review of concepts from your videos and reading

↓ Navigate down for details

Flexbox Basics from Prep

/* The fundamental flexbox setup */
.container {
    display: flex;  /* Creates flex container */
}

/* All direct children become flex items automatically */
  • This property transforms the container into a flex container, fundamentally changing how its children behave
  • Notice how we only need one property to activate the entire flexbox layout system
  • The key insight here is that flexbox is opt-in - you choose which containers become flex containers
  • This pattern is useful when you need to arrange items in a single dimension (row or column)
  • Common mistake to avoid: Forgetting that only direct children become flex items, not all descendants

Flexbox Direction and Axes

/* Controlling flex direction */
.row-container {
    display: flex;
    flex-direction: row;  /* Default - left to right */
}

.column-container {
    display: flex;
    flex-direction: column;  /* Top to bottom */
}
  • This property controls whether items flow horizontally (row) or vertically (column)
  • The main axis follows the flex-direction - horizontal for row, vertical for column
  • The cross axis is perpendicular to the main axis - this distinction is crucial for alignment
  • Why it matters: All other flexbox properties depend on understanding which axis they affect
  • This differs from normal flow because items can be arranged in any direction, not just document flow

Grid Basics from Prep

/* Creating a basic grid */
.grid-container {
    display: grid;
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
}
  • This creates a 3x3 grid with specific column widths and row heights
  • The fr unit represents a fraction of available space - incredibly powerful for responsive design
  • Notice how we explicitly define both dimensions, unlike flexbox's single dimension
  • The key difference is Grid gives you control over both rows AND columns simultaneously
  • This pattern works perfectly for page layouts, dashboards, and any two-dimensional arrangement
  • Common confusion: Grid items don't automatically fill cells - they need to be placed

Responsive Design from Prep

/* Mobile-first media queries */
.container {
    /* Base mobile styles */
    padding: 1rem;
}

@media (min-width: 768px) {
    .container {
        /* Tablet and larger */
        padding: 2rem;
    }
}
  • Mobile-first means starting with the smallest screen and enhancing upward
  • This approach ensures your site works on all devices, not just desktop
  • The breakpoint (768px) represents typical tablet width, but should be based on your content
  • Why mobile-first wins: Simpler base styles, progressive enhancement, better performance
  • This differs from desktop-first where you'd use max-width queries and override downward

Part 2: Flexbox Deep Dive

Mastering one-dimensional layouts

↓ Navigate down for comprehensive coverage

The Flexbox Mental Model

Think of Flexbox as a Highway System

Car 1
Car 2
Car 3
  • The highway (container) determines the rules and direction of travel
  • Cars (items) follow the highway's rules but can have individual behaviors
  • Traffic can flow in one direction at a time (row or column)
  • Cars can change lanes (align-self) while following the overall flow
  • This mental model helps because it makes the parent-child relationship intuitive
  • Key realization: The container does most of the work, items just respond

Flexbox Alignment Properties

/* Complete alignment control */
.flex-container {
    display: flex;

    /* Main axis alignment */
    justify-content: space-between;

    /* Cross axis alignment */
    align-items: center;

    /* Multi-line alignment */
    align-content: stretch;
}
  • justify-content controls distribution along the main axis (horizontal in row, vertical in column)
  • align-items controls alignment along the cross axis (vertical in row, horizontal in column)
  • align-content only works when items wrap to multiple lines with flex-wrap
  • The power here is complete control over spacing and alignment with just three properties
  • Common pattern: justify-content: space-between for navigation with logo left, menu right
  • Pro tip: These three properties handle 90% of layout needs

Flexbox Centering - The Holy Grail

/* Perfect centering - horizontally and vertically */
.perfect-center {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

/* Centering with flexibility */
.flexible-center {
    display: flex;
    place-content: center;  /* Shorthand for both! */
}
  • This three-line solution solves what took hacks for decades
  • justify-content: center centers along the main axis (horizontally by default)
  • align-items: center centers along the cross axis (vertically by default)
  • min-height: 100vh ensures the container fills the viewport for true centering
  • The place-content shorthand sets both properties at once - newer but very useful
  • Why this matters: Centering is one of the most common layout requirements
  • Historical context: Before flexbox, this required negative margins or table-cell display

Flex Item Properties - The Details

/* Understanding flex shorthand */
.flex-item {
    /* flex: grow shrink basis */
    flex: 1 1 200px;
}

/* Common patterns decoded */
.equal-width {
    flex: 1;  /* Same as flex: 1 1 0 */
}

.no-shrink {
    flex: 0 0 auto;  /* Never shrink, natural size */
}

.fixed-width {
    flex: 0 0 300px;  /* Always 300px */
}
  • flex-grow (first value) determines how extra space is distributed among items
  • flex-shrink (second value) determines how items compress when space is tight
  • flex-basis (third value) sets the initial size before growing or shrinking
  • The shorthand flex: 1 is incredibly common - it makes items share space equally
  • flex: 0 0 auto means "stay at your natural size, don't grow or shrink"
  • Real-world usage: Sidebars often use flex: 0 0 250px for fixed width
  • Common confusion: flex: 1 is NOT the same as width: 100%

Advanced Flexbox - Order and Wrapping

/* Reordering without changing HTML */
.priority-item {
    order: -1;  /* Negative moves to front */
}

.last-item {
    order: 999;  /* Large number moves to end */
}

/* Wrapping for responsive layouts */
.card-container {
    display: flex;
    flex-wrap: wrap;  /* Allow items to wrap */
    gap: 1.5rem;      /* Modern spacing */
}
  • The order property changes visual order without touching HTML - perfect for responsive design
  • Default order is 0 so negative values come first, positive values come last
  • flex-wrap: wrap allows items to flow to next line when they don't fit
  • The gap property adds spacing between items without margin hacks
  • Use case for order: Moving navigation items for mobile without JavaScript
  • Why wrapping matters: Creates responsive layouts without media queries
  • Pro tip: gap is superior to margins because it only applies between items

Professional Flexbox Patterns

/* Sticky Footer Pattern */
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
main {
    flex: 1;  /* Grows to push footer down */
}

/* Navigation Bar Pattern */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
}
.nav-menu {
    display: flex;
    gap: 2rem;
}
  • The sticky footer pattern keeps the footer at viewport bottom even with little content
  • flex: 1 on main makes it expand to fill available space, pushing footer down
  • The navbar pattern splits content to opposite ends - perfect for logo and menu
  • Nested flex containers are common and powerful - flex within flex
  • Why these patterns work: They leverage flexbox's space distribution intelligence
  • Industry standard: These exact patterns are used in Bootstrap, Material UI, and other frameworks

Part 3: CSS Grid Mastery

Two-dimensional layout control

↓ Navigate down for complete grid knowledge

Grid Mental Model - Think Bigger

Grid is Like City Planning

Building A
Wide Building B
Tall Tower
Building C
Building D
  • Unlike Flexbox's highway, Grid gives you a complete city block to design
  • Buildings (items) can span multiple lots (cells) in any direction
  • You have explicit control over both the structure and item placement
  • The grid is defined first, then items are placed into it
  • This mental model reveals why Grid excels at page layouts and complex designs

Creating Grid Structures

/* Explicit grid with mixed units */
.layout {
    display: grid;
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    gap: 20px;
}

/* Repeating patterns */
.gallery {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1rem;
}
  • grid-template-columns defines the width and number of columns
  • Mixing units is powerful: fixed pixels for sidebars, fr for flexible content
  • The fr unit distributes available space proportionally after fixed sizes
  • auto sizing means "fit the content" - perfect for headers and footers
  • repeat() function eliminates repetition - repeat(4, 1fr) creates four equal columns
  • gap applies spacing between all grid items uniformly
  • Why this matters: You can create any layout structure with just these properties

Grid Line Placement

/* Placing items using grid lines */
.header {
    grid-column: 1 / -1;  /* Span full width */
    grid-row: 1;
}

.sidebar {
    grid-column: 1;
    grid-row: 2 / 4;  /* Span rows 2-3 */
}

.content {
    grid-column: 2 / 4;
    grid-row: 2;
}
  • Grid lines are numbered starting from 1, not 0 (unlike arrays!)
  • Negative numbers count from the end: -1 is the last line
  • grid-column: 1 / -1 is the idiom for "full width" - incredibly useful
  • The syntax is start-line / end-line for both columns and rows
  • Items can overlap by using the same grid cells - intentional layering!
  • Common mistake: Forgetting that lines are between cells, not the cells themselves
  • Pro technique: Use browser DevTools to visualize line numbers

Grid Areas - Semantic Layouts

/* Define areas with ASCII art! */
.app {
    display: grid;
    grid-template-areas:
        "header header header"
        "nav    main   aside"
        "nav    main   aside"
        "footer footer footer";
    grid-template-columns: 200px 1fr 250px;
    grid-template-rows: auto 1fr auto auto;
}

/* Place items in areas */
.header { grid-area: header; }
.nav    { grid-area: nav; }
.main   { grid-area: main; }
.aside  { grid-area: aside; }
.footer { grid-area: footer; }
  • Grid areas provide a visual representation of your layout in CSS
  • The ASCII art approach makes layouts self-documenting
  • Each string represents one row, spaces separate columns
  • Repeating names makes that area span multiple cells
  • This is incredibly readable - anyone can understand the layout
  • Maintenance benefit: Changing layout is just editing the template
  • Use a period (.) to create empty cells in the template
  • This differs from line-based by being semantic rather than numeric

Responsive Grid - No Media Queries!

/* Auto-responsive card grid */
.card-grid {
    display: grid;
    grid-template-columns:
        repeat(auto-fit, minmax(250px, 1fr));
    gap: 1.5rem;
}

/* Even better with modern CSS */
.modern-grid {
    display: grid;
    grid-template-columns:
        repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    gap: 1.5rem;
}
  • auto-fit creates as many columns as will fit in the container
  • minmax(250px, 1fr) means minimum 250px, maximum equal share
  • This automatically reflows from 1 to 2 to 3+ columns as space allows
  • No media queries needed - the grid adapts to available space
  • The min() function prevents overflow on very small screens
  • This single pattern replaces dozens of lines of media query code
  • Why it's powerful: Truly fluid responsive design
  • Use case: Product grids, card layouts, image galleries

Advanced Grid Techniques

/* Dense packing for masonry-like layout */
.masonry {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-flow: dense;
}

/* Overlapping grid items */
.hero-section {
    display: grid;
    grid-template-columns: 1fr;
}
.hero-image,
.hero-text {
    grid-column: 1;
    grid-row: 1;  /* Both in same cell! */
}
.hero-text {
    z-index: 1;  /* Layer on top */
    align-self: center;
    justify-self: center;
}
  • grid-auto-flow: dense fills gaps automatically for compact layouts
  • Dense packing rearranges items to minimize empty space
  • Overlapping is intentional in Grid - perfect for layered designs
  • Same cell placement creates depth and visual interest
  • z-index controls stacking order when items overlap
  • align-self and justify-self position items within their cells
  • Use cases: Hero sections, card overlays, complex magazine layouts

Part 4: Choosing Between Flexbox and Grid

Making the right architectural decision

↓ Navigate down for decision frameworks

The Dimension Rule

Simple Decision Framework

  • One dimension? → Use Flexbox
  • Two dimensions? → Use Grid
  • Unknown items? → Use Flexbox
  • Defined structure? → Use Grid
  • Flexbox excels when items should flow in a single direction
  • Grid excels when you need control over rows AND columns
  • Dynamic content often works better with Flexbox's flexibility
  • Page layouts almost always benefit from Grid's structure
  • The key insight: It's not about which is "better" - it's about the right tool

Use Case Comparison

Component Best Choice Why?
Navigation Bar Flexbox ✅ Single row of items
Page Layout Grid ✅ Multiple regions
Card Gallery Grid ✅ Two-dimensional alignment
Button Group Flexbox ✅ Linear arrangement
Form Layout Both! 🎯 Grid for structure, Flex for rows
  • Notice the pattern: Linear = Flexbox, Structural = Grid
  • Forms often use both because they have both needs
  • This isn't absolute - you can make either work for most layouts
  • Performance is identical - choose based on maintainability

The Power Couple Pattern

/* Grid for page structure */
.app {
    display: grid;
    grid-template-columns: 250px 1fr 300px;
    grid-template-areas:
        "header header header"
        "nav    main   aside"
        "footer footer footer";
}

/* Flexbox for component internals */
.card {
    display: flex;
    flex-direction: column;
}
.card-footer {
    display: flex;
    justify-content: space-between;
    margin-top: auto;
}
  • Grid defines the macro layout (page structure)
  • Flexbox handles micro layouts (component details)
  • This separation makes code more maintainable
  • Each tool does what it does best
  • Real-world fact: Most modern sites use this pattern
  • Why it works: Clear separation of concerns

When to Break the Rules

/* Sometimes Flexbox works for "2D" */
.card-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}
.card {
    flex: 0 1 calc(33.333% - 0.67rem);
}

/* Sometimes Grid works for "1D" */
.nav {
    display: grid;
    grid-template-columns: auto 1fr auto;
    /* Logo | Spacer | Menu */
}
  • Flexbox with wrap can create grid-like layouts
  • This works when items should be equal height naturally
  • Grid for navigation gives precise control over spacing
  • The lesson: Rules are guidelines, not laws
  • Choose based on what makes the code clearest
  • Team consistency matters more than perfect choice

Part 5: Media Queries Fundamentals

Responsive design foundation from Chapter 8

↓ Navigate down for essential concepts

Introduction to Media Queries

/* The @media rule applies styles conditionally */
@media screen and (min-width: 768px) {
    .container {
        width: 750px;
        margin: 0 auto;
    }
}

/* Breakpoints define when layouts change */
.card {
    width: 100%;  /* Mobile default */
}

@media (min-width: 768px) {
    .card {
        width: 50%;  /* Tablet and up */
    }
}
  • Media queries enable responsive design with one codebase
  • The @media rule checks device characteristics
  • Breakpoints are thresholds where layouts adapt
  • min-width means: "this width and larger"
  • One HTML file serves all devices elegantly

Common Breakpoints

/* Industry-standard breakpoints */

/* Smartphones (base styles, no query needed) */
.container { padding: 1rem; }

/* Small devices (576px+) - landscape phones */
@media (min-width: 576px) {
    .container { max-width: 540px; }
}

/* Tablets (768px+) - iPad portrait */
@media (min-width: 768px) {
    .container { max-width: 720px; }
}

/* Desktop (992px+) - laptops and beyond */
@media (min-width: 992px) {
    .container { max-width: 960px; }
}

/* Widescreen (1200px+) - large monitors */
@media (min-width: 1200px) {
    .container { max-width: 1140px; }
}
  • 576px: Landscape smartphones
  • 768px: Tablets (iPad portrait)
  • 992px: Desktop computers
  • 1200px: Wide screens
  • These are guidelines, not rules - let content decide

Mobile-First vs Desktop-First

/* MOBILE-FIRST (Modern Standard) */
.nav {
    display: block;      /* Simple mobile layout */
}
@media (min-width: 768px) {
    .nav {
        display: flex;   /* Enhanced for tablets+ */
    }
}

/* DESKTOP-FIRST (Legacy) */
.nav {
    display: flex;       /* Complex desktop layout */
}
@media (max-width: 767px) {
    .nav {
        display: block;  /* Simplified for mobile */
    }
}
  • Mobile-first: Start simple, enhance with min-width
  • Desktop-first: Start complex, simplify with max-width
  • Mobile-first wins: Better performance, forces essential design
  • Industry standard: Mobile-first is the modern approach

Combining Media Queries with Flexbox/Grid

/* Stack on mobile, side-by-side on larger screens */
.cards {
    display: flex;
    flex-direction: column;  /* Mobile: stack vertically */
    gap: 1rem;
}

@media (min-width: 768px) {
    .cards {
        flex-direction: row;  /* Tablet+: horizontal layout */
        flex-wrap: wrap;
    }
    .card {
        flex: 0 1 calc(50% - 0.5rem);  /* 2 columns */
    }
}

/* Grid responds to screen size */
.layout {
    display: grid;
    grid-template-columns: 1fr;  /* Mobile: single column */
}

@media (min-width: 768px) {
    .layout {
        grid-template-columns: 250px 1fr;  /* Sidebar + main */
    }
}
  • Pattern: Stack elements on mobile, arrange horizontally on larger screens
  • Media queries adjust layout systems, not individual items
  • This combination creates truly responsive components
  • Modern CSS = Layout tools + Media queries working together

Advanced Features (Overview)

/* Orientation queries */
@media (orientation: landscape) {
    .video { width: 70%; }
}

/* Combining conditions with 'and' */
@media (min-width: 768px) and (orientation: landscape) {
    .gallery { grid-template-columns: repeat(4, 1fr); }
}

/* Modern range syntax */
@media (640px <= width <= 1024px) {
    .content { padding: 2rem; }
}

/* High-resolution displays */
@media (min-resolution: 2dppx) {
    .logo { background-image: url('logo@2x.png'); }
}
  • Orientation: Detect landscape vs portrait
  • Combining: Use 'and' for multiple conditions
  • Ranges: Clean syntax for width ranges
  • Resolution: Serve hi-res assets to retina displays
  • Keep it simple - complexity creates maintenance issues

Part 6: Beyond Media Queries

Modern responsive techniques

↓ Navigate down for cutting-edge patterns

Intrinsic Web Design

/* Fluid typography */
h1 {
    font-size: clamp(1.5rem, 4vw, 3rem);
}

/* Fluid spacing */
.section {
    padding: clamp(1rem, 5vw, 3rem);
}

/* Fluid grid */
.grid {
    display: grid;
    grid-template-columns:
        repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}
  • clamp() provides minimum, preferred, and maximum values
  • The viewport unit (vw) scales with screen width
  • This creates smooth scaling between breakpoints
  • No jumps at media query boundaries
  • The min() function prevents overflow on small screens
  • This approach reduces media queries by 70-80%
  • Why it matters: Truly fluid, not stepped, responsive design

Container Queries - The Game Changer

/* Define container */
.card-container {
    container-type: inline-size;
    container-name: card;
}

/* Style based on container size */
@container card (min-width: 400px) {
    .card {
        display: grid;
        grid-template-columns: 150px 1fr;
    }
}

@container card (min-width: 600px) {
    .card {
        grid-template-columns: 200px 1fr 100px;
    }
}
  • Container queries respond to parent size, not viewport
  • This enables truly modular components
  • Components adapt based on where they're used
  • Same component can look different in sidebar vs main
  • This solves the responsive component problem
  • Browser support is now excellent (2024+)
  • Revolutionary because components become context-aware

Logical Properties for Global Design

/* Old way - physical properties */
.card {
    margin-left: 1rem;
    margin-right: 1rem;
    padding-top: 2rem;
}

/* Modern way - logical properties */
.card {
    margin-inline: 1rem;  /* start and end */
    padding-block-start: 2rem;  /* respects writing mode */
}

/* Automatic RTL support! */
.international {
    border-inline-start: 3px solid blue;
    text-align: start;
}
  • Logical properties adapt to writing direction
  • inline axis is the text direction (horizontal in English)
  • block axis is perpendicular to text (vertical in English)
  • This automatically flips for right-to-left languages
  • No separate RTL stylesheet needed
  • Global web requires international thinking
  • Future-proof your layouts from day one

Modern Responsive Images

/* Responsive images with aspect ratio */
.image-container {
    aspect-ratio: 16 / 9;
    width: 100%;
    overflow: hidden;
}

.image-container img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

/* Art direction with container queries */
@container (max-width: 400px) {
    .hero-image {
        aspect-ratio: 1 / 1;  /* Square on small */
    }
}
  • aspect-ratio maintains proportions without padding hacks
  • This prevents layout shift as images load
  • object-fit: cover crops images intelligently
  • object-position controls crop focal point
  • Container queries enable responsive art direction
  • Different ratios for different contexts
  • Performance benefit: No JavaScript needed

CSS Variables for Responsive Design

/* Define responsive variables */
:root {
    --spacing-unit: clamp(0.5rem, 2vw, 1.5rem);
    --container-width: min(90%, 1200px);
    --grid-cols: 1;
}

@media (min-width: 768px) {
    :root {
        --grid-cols: 2;
    }
}

@media (min-width: 1024px) {
    :root {
        --grid-cols: 3;
    }
}

/* Use variables everywhere */
.container {
    padding: var(--spacing-unit);
    max-width: var(--container-width);
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
}
  • CSS variables centralize responsive values
  • Change once, update everywhere
  • Calculations become more maintainable
  • Media queries just update variables
  • This pattern scales to large projects
  • Teams can share consistent spacing systems
  • Future enhancement: Variables can be animated!

Mobile-First Progressive Enhancement

/* Base mobile styles - works everywhere */
.layout {
    display: block;
    padding: 1rem;
}

/* Enhance for larger screens */
@media (min-width: 768px) {
    .layout {
        display: flex;
        gap: 2rem;
    }
}

/* Add grid for even larger screens */
@media (min-width: 1024px) {
    .layout {
        display: grid;
        grid-template-columns: 250px 1fr 250px;
    }
}

/* Feature detection for newest features */
@supports (container-type: inline-size) {
    .layout {
        container-type: inline-size;
    }
}
  • Start simple, enhance progressively
  • Base styles work on any device
  • Each breakpoint adds capability
  • @supports ensures graceful degradation
  • This approach is resilient and maintainable
  • Mobile-first forces simplicity
  • Result: Faster, more accessible sites

Key Takeaways

  • Flexbox = One-dimensional layouts (rows OR columns)
  • Grid = Two-dimensional layouts (rows AND columns)
  • Use both together - Grid for structure, Flexbox for components
  • Modern responsive design goes beyond media queries
  • Intrinsic sizing creates truly fluid layouts
  • Container queries enable modular responsive components
  • CSS has evolved - no more hacks needed!
Remember: These aren't just academic exercises - they're production techniques used by millions of websites daily.

Resources & Next Steps

Essential Resources

  • CSS-Tricks Complete Guides
  • MDN Layout Documentation
  • Grid Garden & Flexbox Froggy
  • Every Layout patterns
  • Container Queries Primer

Practice Challenges

  • Recreate a favorite website layout
  • Build a responsive dashboard
  • Create a magazine-style layout
  • Design a card system
  • Implement a holy grail layout