Skip to main content

Course Progress

Loading...

CSS Layout Techniques

Duration: 60 minutes
Module 1: CSS Layout & Responsive Design

Learning Objectives

  • Master CSS styling techniques
  • Control visual presentation
  • Create attractive designs
  • Understand CSS best practices

Introduction to CSS Layout

Layout is one of the most important aspects of web design. CSS offers several methods for controlling the positioning and arrangement of elements on a webpage, each with its own strengths, limitations, and ideal use cases.

flowchart LR
    A[CSS Layout Methods] --> B[Positioning]
    A --> C[Float-based Layouts]
    A --> D[Flexbox]
    A --> E[CSS Grid]
    
    B --> B1[Static]
    B --> B2[Relative]
    B --> B3[Absolute]
    B --> B4[Fixed]
    B --> B5[Sticky]
    
    C --> C1[Float: left/right]
    C --> C2[Clear: both/left/right]
    
    D --> D1[One-dimensional]
    D --> D2[Content-based]
    D --> D3[Flexible sizing]
    
    E --> E1[Two-dimensional]
    E --> E2[Grid lines/tracks]
    E --> E3[Grid areas]
    
    style A fill:#f9d5e5,stroke:#333,stroke-width:2px
    style B fill:#eeac99,stroke:#333,stroke-width:2px
    style C fill:#e6d7b9,stroke:#333,stroke-width:2px
    style D fill:#b6dcfe,stroke:#333,stroke-width:2px
    style E fill:#d0bfff,stroke:#333,stroke-width:2px

The Evolution of CSS Layout

CSS layout techniques have evolved significantly over time, each new method addressing limitations of previous approaches:

1990s: Table-Based Layouts

Before dedicated CSS layout properties, web developers used HTML tables to create layouts. While effective for the time, table layouts were semantically incorrect, inflexible, and difficult to maintain.

Early 2000s: CSS Positioning and Floats

CSS positioning (static, relative, absolute, fixed) and float properties provided more control over layout without abusing table elements, enabling more semantic HTML.

2010s: Flexbox

The Flexible Box Layout Module (Flexbox) introduced a more intuitive way to design flexible responsive layouts along a single axis, solving many common layout challenges.

2017 onwards: CSS Grid

CSS Grid Layout provides a two-dimensional grid-based layout system, allowing for complex layouts that were previously difficult or impossible with other techniques.

The Building Construction Analogy

Different CSS layout methods can be compared to different construction techniques:

  • CSS Positioning is like placing furniture in a room - you can put things exactly where you want them, regardless of other elements.
  • Float-based layouts are like arranging photos on a wall - elements line up side by side, but require careful management to prevent disarray.
  • Flexbox is like a row of adjustable shelves - items can grow, shrink, and align along a single axis to use space efficiently.
  • CSS Grid is like a blueprint for a building - it creates a complete two-dimensional framework where everything has its place in relation to everything else.

CSS Positioning

Positioning allows you to precisely control where elements appear on a page, even taking them outside of the normal document flow.

Container (position: relative) Normal Flow (position: static) Relative (top: 20px, left: 20px) Absolute (top: 100px, left: 250px) Fixed (bottom: 20px, right: 20px) Sticky (top: 0) CSS Positioning Methods

Position Property Values

position: static (Default)

Elements are positioned according to the normal document flow. The top, right, bottom, left, and z-index properties have no effect.

.static-element {
    position: static;
    /* top, right, bottom, left properties have no effect */
}

Best for: Most elements that follow the normal document flow, which is the default behavior.

position: relative

The element is positioned relative to its normal position. Setting top, right, bottom, or left properties will adjust the element from its normal position while still reserving its original space in the document flow.

.relative-element {
    position: relative;
    top: 20px;      /* Move down 20px from normal position */
    left: 20px;     /* Move right (from left) 20px from normal position */
}

Best for:

  • Making minor position adjustments
  • Creating a positioning context for absolute positioned children
  • Z-index stacking without changing the flow

position: absolute

The element is removed from the normal document flow. It is positioned relative to its nearest positioned ancestor (an element with position other than static), or the initial containing block (usually the viewport) if no positioned ancestor exists.

/* Parent container (creates positioning context) */
.parent {
    position: relative;
}

/* Absolutely positioned child */
.absolute-element {
    position: absolute;
    top: 0;          /* Distance from top of the positioned parent */
    right: 0;        /* Distance from right of the positioned parent */
    /* Element is removed from normal flow - other elements act as if it doesn't exist */
}

Best for:

  • UI elements that need to be precisely positioned
  • Overlays and tooltips
  • Elements that should appear at a specific position regardless of surrounding content

position: fixed

Similar to absolute positioning, but the element is positioned relative to the viewport. It stays in the same position even when the page is scrolled.

.fixed-element {
    position: fixed;
    top: 0;          /* Distance from top of viewport */
    left: 0;         /* Distance from left of viewport */
    width: 100%;
    /* Will stay at top of viewport even when scrolling */
}

Best for:

  • Navigation bars that stay at the top or bottom while scrolling
  • Floating action buttons
  • Cookie consent banners
  • Chat widgets

position: sticky

A hybrid between relative and fixed positioning. The element is treated as relative until it crosses a specified threshold (such as scrolling to a certain point), then it becomes fixed.

.sticky-element {
    position: sticky;
    top: 0;          /* Sticks to top when scrolled to this position */
    /* Acts like relative positioning until the scroll threshold is reached */
}

Best for:

  • Section headers in long lists
  • Navigation elements that should stick after scrolling past a certain point
  • Table headers that remain visible

Position Offset Properties

These properties work in conjunction with the position property to specify the exact positioning of elements:

  • top: Distance from the top edge of the positioned ancestor or viewport
  • right: Distance from the right edge of the positioned ancestor or viewport
  • bottom: Distance from the bottom edge of the positioned ancestor or viewport
  • left: Distance from the left edge of the positioned ancestor or viewport

The z-index Property

When elements overlap, z-index controls their stacking order. Elements with higher z-index values appear on top of elements with lower values.

/* Elements with higher z-index appear on top */
.back-element {
    position: absolute;
    z-index: 1;       /* Lower value */
}

.front-element {
    position: absolute;
    z-index: 2;       /* Higher value, appears in front */
}

Note: z-index only works on positioned elements (position property set to relative, absolute, fixed, or sticky).

Practical Positioning Examples

Sticky Header

/* Header that sticks to the top when scrolling */
.sticky-header {
    position: sticky;
    top: 0;
    background-color: white;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    z-index: 100;
}

Modal Overlay

/* Full-screen overlay */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 1000;
}

/* Centered modal */
.modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: white;
    padding: 20px;
    border-radius: 5px;
    z-index: 1001;
}

Dropdown Menu

/* Dropdown container */
.dropdown {
    position: relative;
    display: inline-block;
}

/* Dropdown content */
.dropdown-content {
    position: absolute;
    top: 100%;        /* Position below the container */
    left: 0;
    min-width: 200px;
    background-color: white;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    display: none;    /* Hidden by default */
    z-index: 100;
}

/* Show dropdown on hover */
.dropdown:hover .dropdown-content {
    display: block;
}

CSS Tooltip

/* Tooltip container */
.tooltip {
    position: relative;
    display: inline-block;
}

/* Tooltip content */
.tooltip::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: 125%;
    left: 50%;
    transform: translateX(-50%);
    padding: 5px 10px;
    background-color: black;
    color: white;
    border-radius: 3px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s;
}

/* Show tooltip on hover */
.tooltip:hover::after {
    opacity: 1;
    visibility: visible;
}

Positioning Caveats and Best Practices

  • Use sparingly: Overuse of absolute or fixed positioning can create maintenance challenges and unexpected behaviors
  • Consider responsive design: Position values might need to be adjusted for different screen sizes
  • Remember z-index stacking contexts: z-index values work within their own stacking contexts, which can lead to unexpected behavior
  • Avoid positioning for layout: Modern techniques like Flexbox and Grid are usually better for overall page layout

Float-Based Layouts

Before Flexbox and Grid, float-based layouts were the primary method for creating multi-column designs. The float property allows elements to be positioned to the left or right of their container, with other content flowing around them.

Container float: left float: right Content flows around floated elements Float-Based Layout

Basic Float Properties

float

The float property specifies whether an element should float to the left, right, or not at all.

/* Float values */
.float-left {
    float: left;     /* Element floats to the left */
}

.float-right {
    float: right;    /* Element floats to the right */
}

.no-float {
    float: none;     /* Default, element does not float */
}

clear

The clear property specifies which sides of an element cannot be adjacent to floating elements.

/* Clear values */
.clear-left {
    clear: left;     /* No floating elements allowed on the left side */
}

.clear-right {
    clear: right;    /* No floating elements allowed on the right side */
}

.clear-both {
    clear: both;     /* No floating elements allowed on either side */
}

.no-clear {
    clear: none;     /* Default, allows floating elements on both sides */
}

The Clearfix Hack

When all elements within a container are floated, the container's height collapses to zero. The "clearfix" hack solves this problem by forcing the container to recognize and encompass the floated elements.

The Classic Clearfix

/* Clearfix (older method) */
.clearfix:after {
    content: "";
    display: table;
    clear: both;
}

Modern Clearfix

/* Modern clearfix */
.clearfix::after {
    content: "";
    display: block;
    clear: both;
}

Alternative: Overflow Method

/* Using overflow (alternative method, but can cause issues) */
.container {
    overflow: auto;  /* Creates a block formatting context */
}

Creating Layouts with Float

Basic Two-Column Layout

/* Container needs clearfix */
.container {
    width: 100%;
}

.container::after {
    content: "";
    display: block;
    clear: both;
}

/* Two-column layout */
.sidebar {
    float: left;
    width: 25%;
}

.main-content {
    float: right;
    width: 75%;
}

Three-Column Layout

/* Container with clearfix */
.container::after {
    content: "";
    display: block;
    clear: both;
}

/* Three-column layout */
.column {
    float: left;
    width: 33.33%;
    padding: 0 15px;
    box-sizing: border-box;
}

Basic Grid System with Floats

/* Simple float-based grid system */
.row::after {
    content: "";
    display: block;
    clear: both;
}

/* Columns with various widths */
.col-1 { float: left; width: 8.33%; }
.col-2 { float: left; width: 16.66%; }
.col-3 { float: left; width: 25%; }
.col-4 { float: left; width: 33.33%; }
.col-5 { float: left; width: 41.66%; }
.col-6 { float: left; width: 50%; }
.col-7 { float: left; width: 58.33%; }
.col-8 { float: left; width: 66.66%; }
.col-9 { float: left; width: 75%; }
.col-10 { float: left; width: 83.33%; }
.col-11 { float: left; width: 91.66%; }
.col-12 { float: left; width: 100%; }

Modern Uses for Float

While Flexbox and Grid have largely replaced float for layout purposes, float still has legitimate use cases:

Text Wrapping Around Images

/* Original purpose of float - text wrapping around images */
.article-image {
    float: left;
    margin: 0 20px 10px 0;
}

Pull Quotes

/* Pull quote floating in content */
.pull-quote {
    float: right;
    width: 200px;
    margin: 0 0 20px 20px;
    padding: 15px;
    border-left: 4px solid #ddd;
    font-size: 1.2em;
}

Limitations of Float-Based Layouts

  • Complexity: Requires clearfix solutions and careful width management
  • Vertical alignment: Difficult to vertically align elements
  • Equal height columns: Hard to achieve without additional techniques
  • Source order dependency: Layout is tied to the HTML source order
  • Responsive design: Requires media queries and often complex adjustments
  • Nested float layouts: Can become unwieldy and difficult to maintain

Historical Note: While float-based layouts are considered somewhat outdated for creating entire page layouts, understanding them remains important for legacy code maintenance and specific use cases like wrapping text around images.

Flexbox (Flexible Box Layout)

The Flexible Box Layout Module, or Flexbox, is a one-dimensional layout model designed for arranging items in rows or columns. It excels at distributing space and aligning items when the size of items is unknown or dynamic.

Flex Container (display: flex) Main Axis (justify-content) Cross Axis (align-items) Flex Item 1 Flex Item 2 Flex Item 3 Flexbox Layout Model

Key Flexbox Concepts

The Flex Container and Flex Items

A flex container is created by setting the display property of an element to flex or inline-flex. All direct children of this container become flex items.

/* Create a flex container */
.container {
    display: flex;           /* Block-level flex container */
    /* or */
    display: inline-flex;    /* Inline-level flex container */
}

Main Axis and Cross Axis

Flexbox operates on two axes:

  • Main Axis: The primary axis along which flex items are placed (horizontally by default)
  • Cross Axis: The perpendicular axis to the main axis
/* Controlling the direction of the main axis */
.container {
    display: flex;
    flex-direction: row;            /* Default: left to right */
    /* Other options: */
    flex-direction: row-reverse;    /* Right to left */
    flex-direction: column;         /* Top to bottom */
    flex-direction: column-reverse; /* Bottom to top */
}

Flex Container Properties

flex-wrap

Determines whether flex items are forced into a single line or can be wrapped onto multiple lines.

.container {
    display: flex;
    flex-wrap: nowrap;         /* Default: single line */
    /* Other options: */
    flex-wrap: wrap;           /* Multiple lines if needed */
    flex-wrap: wrap-reverse;   /* Multiple lines in reverse order */
}

flex-flow

Shorthand property for flex-direction and flex-wrap.

.container {
    display: flex;
    flex-flow: row nowrap;     /* Default */
    /* Other examples: */
    flex-flow: column wrap;
    flex-flow: row-reverse wrap-reverse;
}

justify-content

Defines how space is distributed between and around flex items along the main axis.

.container {
    display: flex;
    justify-content: flex-start;    /* Default: items packed at start */
    /* Other options: */
    justify-content: flex-end;      /* Items packed at end */
    justify-content: center;        /* Items centered */
    justify-content: space-between; /* Items evenly distributed; first at start, last at end */
    justify-content: space-around;  /* Items evenly distributed with equal space around them */
    justify-content: space-evenly;  /* Items evenly distributed with equal space between them */
}

align-items

Defines how flex items are aligned along the cross axis.

.container {
    display: flex;
    align-items: stretch;      /* Default: items stretch to fill container */
    /* Other options: */
    align-items: flex-start;   /* Items aligned at start of cross axis */
    align-items: flex-end;     /* Items aligned at end of cross axis */
    align-items: center;       /* Items centered on cross axis */
    align-items: baseline;     /* Items aligned by their baselines */
}

align-content

Aligns flex container's lines within the flex container when there is extra space on the cross axis (only applies when there are multiple rows or columns).

.container {
    display: flex;
    flex-wrap: wrap;
    align-content: stretch;     /* Default: lines stretch to fill container */
    /* Other options: */
    align-content: flex-start;  /* Lines packed at start */
    align-content: flex-end;    /* Lines packed at end */
    align-content: center;      /* Lines centered */
    align-content: space-between; /* Lines evenly distributed; first at start, last at end */
    align-content: space-around;  /* Lines evenly distributed with equal space around them */
}

gap, row-gap, column-gap

Controls the space between flex items.

.container {
    display: flex;
    gap: 20px;              /* Equal gap in both directions */
    /* Or specify dimensions separately: */
    row-gap: 20px;          /* Gap between rows */
    column-gap: 10px;       /* Gap between columns */
}

Flex Item Properties

order

Controls the order in which flex items appear within their container, regardless of source order.

/* Default order is 0 for all items */
.first-item {
    order: -1;  /* Appears before other items */
}

.middle-item {
    order: 0;   /* Default */
}

.last-item {
    order: 1;   /* Appears after other items */
}

flex-grow

Determines how much a flex item can grow relative to other items when there is extra space.

/* Default is 0 (don't grow) */
.no-grow {
    flex-grow: 0;  /* Won't grow */
}

.grow {
    flex-grow: 1;  /* Will grow */
}

.grow-more {
    flex-grow: 2;  /* Will grow twice as much as .grow */
}

flex-shrink

Determines how much a flex item will shrink relative to other items when there isn't enough space.

/* Default is 1 (shrink equally) */
.shrink {
    flex-shrink: 1;  /* Will shrink normally */
}

.shrink-more {
    flex-shrink: 2;  /* Will shrink twice as much as others */
}

.no-shrink {
    flex-shrink: 0;  /* Won't shrink */
}

flex-basis

Defines the default size of a flex item before remaining space is distributed.

/* Default is auto (use item's width/height) */
.item {
    flex-basis: auto;  /* Default */
}

.item-pixel {
    flex-basis: 200px;  /* Initial size of 200px */
}

.item-percent {
    flex-basis: 25%;    /* Initial size of 25% of container */
}

flex

Shorthand property for flex-grow, flex-shrink, and flex-basis.

/* Default is 0 1 auto */
.item {
    flex: 0 1 auto;  /* flex-grow: 0, flex-shrink: 1, flex-basis: auto */
}

/* Commonly used values */
.item-grow-shrink {
    flex: 1;        /* Same as flex: 1 1 0% */
}

.item-fixed {
    flex: 0 0 200px;  /* Fixed width, no grow, no shrink */
}

.item-grow-only {
    flex: 1 0 auto;   /* Grow, don't shrink, start at auto size */
}

align-self

Allows a flex item to override the container's align-items property for itself.

/* Default is auto (use container's align-items value) */
.container {
    display: flex;
    align-items: center;  /* Center all items by default */
}

.item-top {
    align-self: flex-start;  /* This item aligns to the top */
}

.item-bottom {
    align-self: flex-end;    /* This item aligns to the bottom */
}

Practical Flexbox Examples

Navigation Bar

/* Responsive navigation bar */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
}

.logo {
    /* Logo styles */
}

.nav-menu {
    display: flex;
    gap: 1rem;
}

/* Mobile menu */
@media (max-width: 768px) {
    .nav-menu {
        flex-direction: column;
    }
}

Card Layout

/* Card container */
.card-container {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

/* Individual cards */
.card {
    flex: 1 0 300px;  /* Grow, don't shrink, min 300px width */
    display: flex;
    flex-direction: column;
}

.card-body {
    flex: 1;  /* Take up remaining space */
}

.card-footer {
    margin-top: auto;  /* Push to bottom */
}

Holy Grail Layout

/* Classic "holy grail" layout with header, footer, and three columns */
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;  /* Full viewport height */
}

header, footer {
    flex: 0 0 auto;  /* Fixed height, don't grow or shrink */
}

.content-wrapper {
    display: flex;
    flex: 1;  /* Take remaining space */
}

.sidebar-left, .sidebar-right {
    flex: 0 0 200px;  /* Fixed width sidebars */
}

main {
    flex: 1;  /* Take remaining space */
}

/* Responsive adjustments */
@media (max-width: 768px) {
    .content-wrapper {
        flex-direction: column;
    }
    
    .sidebar-left, .sidebar-right {
        flex: 0 0 auto;  /* Auto height */
    }
}

Centering Content

/* Perfect centering (both horizontally and vertically) */
.center-container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;  /* Full viewport height */
}

Advantages of Flexbox

  • Simplicity: More intuitive than float-based layouts
  • Flexibility: Items can grow and shrink
  • Direction independence: Works in any direction (row, column)
  • Alignment: Powerful alignment capabilities
  • Order control: Visual order can differ from source order
  • Space distribution: Intelligent allocation of space

Limitations of Flexbox

  • One-dimensional: Only handles layout in a single direction (row OR column) at a time
  • Complex grid layouts: Less suitable for two-dimensional grid systems
  • Nested flexbox complexity: Can become unwieldy with complex nesting

Best Used For: One-dimensional layouts, navigation menus, centering content, distributing space between items, and flexible content that needs to adapt to available space.

CSS Grid Layout

CSS Grid Layout is a two-dimensional layout system designed for complex layouts that work in rows AND columns simultaneously. It provides unprecedented control over how elements are placed on a page.

Grid Container (display: grid) Item 1 Item 2 Item 3 Item 4 Item 5 Item 6 Item 7 Item 8 1 2 3 4 5 6 7 1 2 3 4 5 6 7 CSS Grid Layout

Key Grid Concepts

Grid Container and Grid Items

A grid container is created by setting the display property of an element to grid or inline-grid. All direct children of this container become grid items.

/* Create a grid container */
.container {
    display: grid;           /* Block-level grid container */
    /* or */
    display: inline-grid;    /* Inline-level grid container */
}

Grid Lines, Tracks, Cells, and Areas

  • Grid Lines: The horizontal and vertical dividing lines that form the grid structure
  • Grid Tracks: The spaces between grid lines (rows and columns)
  • Grid Cells: The smallest unit of space on the grid, defined by the intersection of rows and columns
  • Grid Areas: Any rectangular area bounded by four grid lines

Grid Container Properties

grid-template-columns and grid-template-rows

Define the size of columns and rows in the grid.

/* Fixed sizes */
.container {
    display: grid;
    grid-template-columns: 200px 200px 200px;  /* Three columns of 200px each */
    grid-template-rows: 100px 200px;           /* Two rows: 100px and 200px */
}

/* Flexible sizes with fr unit */
.container {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;  /* Three columns in 1:2:1 ratio */
    grid-template-rows: auto 1fr;        /* First row auto-sized, second takes remaining space */
}

/* Using repeat() function */
.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);  /* Same as: 1fr 1fr 1fr */
    grid-template-rows: repeat(2, 100px);   /* Same as: 100px 100px */
}

/* Mixed units */
.container {
    display: grid;
    grid-template-columns: 200px 1fr 2fr;  /* Fixed first column, flexible others */
}

grid-template-areas

Defines named grid areas, creating a visual representation of the layout.

.container {
    display: grid;
    grid-template-columns: 1fr 3fr 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "header header header"
        "sidebar-left main sidebar-right"
        "footer footer footer";
}

grid-template

Shorthand for grid-template-rows, grid-template-columns, and grid-template-areas.

.container {
    display: grid;
    grid-template:
        "header header header" auto
        "sidebar-left main sidebar-right" 1fr
        "footer footer footer" auto
        / 1fr 3fr 1fr;
    /* This is equivalent to the previous example */
}

grid-column-gap, grid-row-gap, and grid-gap

Define the space between grid rows and columns. These properties have been renamed to column-gap, row-gap, and gap, but the old names still work.

.container {
    display: grid;
    column-gap: 20px;    /* Space between columns */
    row-gap: 10px;       /* Space between rows */
    /* Or use the shorthand: */
    gap: 10px 20px;      /* row-gap column-gap */
}

justify-items and align-items

Control how grid items are aligned within their grid cells along the row and column axes.

.container {
    display: grid;
    justify-items: stretch;  /* Default: items fill cell width */
    /* Other options: start, end, center */
    
    align-items: stretch;    /* Default: items fill cell height */
    /* Other options: start, end, center */
}

justify-content and align-content

Control how the grid itself is aligned within the container when the grid is smaller than the container.

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);  /* Fixed-width columns */
    width: 500px;  /* Container wider than grid */
    
    justify-content: start;    /* Default: grid starts at left */
    /* Other options: end, center, space-between, space-around, space-evenly */
    
    align-content: start;      /* Default: grid starts at top */
    /* Other options: end, center, space-between, space-around, space-evenly */
}

grid-auto-columns and grid-auto-rows

Define the size of automatically generated rows and columns for implicitly placed grid items.

.container {
    display: grid;
    grid-template-columns: 1fr 1fr;  /* 2 explicit columns */
    grid-auto-rows: 100px;           /* Automatically created rows are 100px */
}

grid-auto-flow

Controls how auto-placed items are inserted into the grid.

.container {
    display: grid;
    grid-auto-flow: row;       /* Default: place items by rows */
    /* Other options: */
    grid-auto-flow: column;    /* Place items by columns */
    grid-auto-flow: row dense; /* Attempt to fill holes in the grid */
}

grid

Shorthand property for all grid properties.

.container {
    display: grid;
    grid: auto-flow dense 100px / 1fr 1fr 1fr;
    /* Equivalent to:
       grid-auto-flow: row dense;
       grid-auto-rows: 100px;
       grid-template-columns: 1fr 1fr 1fr; */
}

Grid Item Properties

grid-column-start, grid-column-end, grid-row-start, grid-row-end

Define which grid lines an item starts and ends at.

.item {
    grid-column-start: 1;
    grid-column-end: 3;     /* Item spans from column line 1 to 3 */
    grid-row-start: 2;
    grid-row-end: 4;        /* Item spans from row line 2 to 4 */
}

grid-column and grid-row

Shorthand properties for the start and end properties.

.item {
    grid-column: 1 / 3;     /* From column line 1 to 3 */
    grid-row: 2 / 4;        /* From row line 2 to 4 */
    
    /* Alternative with span notation: */
    grid-column: 1 / span 2; /* Start at column line 1, span 2 columns */
    grid-row: 2 / span 2;    /* Start at row line 2, span 2 rows */
}

grid-area

Shorthand for grid-row-start, grid-column-start, grid-row-end, grid-column-end, or refers to a named area from grid-template-areas.

/* Using grid lines */
.item {
    grid-area: 2 / 1 / 4 / 3; /* row-start / column-start / row-end / column-end */
}

/* Using named areas */
.container {
    display: grid;
    grid-template-areas:
        "header header header"
        "sidebar main main"
        "footer footer footer";
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

justify-self and align-self

Control how an individual grid item is aligned within its cell.

.item {
    justify-self: center;    /* Center horizontally within cell */
    /* Other options: start, end, stretch (default) */
    
    align-self: center;      /* Center vertically within cell */
    /* Other options: start, end, stretch (default) */
}

Special Grid Features

minmax() Function

Defines a size range between a minimum and maximum value.

.container {
    display: grid;
    grid-template-columns: minmax(100px, 1fr) 2fr;
    /* First column is at least 100px, but can grow to use available space */
}

auto-fill and auto-fit

Creates a flexible number of columns or rows based on container size.

/* Auto-fill: creates as many columns as will fit */
.auto-fill {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}

/* Auto-fit: similar, but collapses empty tracks */
.auto-fit {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

Named Grid Lines

Gives names to grid lines for easier referencing.

.container {
    display: grid;
    grid-template-columns: 
        [sidebar-start] 1fr 
        [sidebar-end content-start] 3fr 
        [content-end];
    grid-template-rows: 
        [header-start] auto 
        [header-end content-start] 1fr 
        [content-end footer-start] auto 
        [footer-end];
}

.header {
    grid-column: sidebar-start / content-end;
    grid-row: header-start / header-end;
}

Practical Grid Examples

Basic Grid Layout

/* Simple 3-column grid */
.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}

/* Responsive grid: 3 columns on desktop, 2 on tablet, 1 on mobile */
.responsive-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
}

Classic Page Layout

/* Classic website layout with header, footer, main content, and sidebars */
.page {
    display: grid;
    grid-template-areas:
        "header header header"
        "nav main aside"
        "footer footer footer";
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    min-height: 100vh;
}

.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* Responsive adjustment */
@media (max-width: 768px) {
    .page {
        grid-template-areas:
            "header header header"
            "nav nav nav"
            "main main main"
            "aside aside aside"
            "footer footer footer";
        grid-template-columns: 1fr;
    }
}

Image Gallery

/* Responsive image gallery with varying image sizes */
.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-auto-rows: 200px;
    gap: 10px;
}

/* Feature images spanning multiple cells */
.gallery-item {
    overflow: hidden;
}

.gallery-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.feature-item {
    grid-column: span 2;
    grid-row: span 2;
}

Dashboard Layout

/* Dashboard with widgets of different sizes */
.dashboard {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(100px, auto);
    gap: 15px;
}

.widget-small {
    grid-column: span 1;
    grid-row: span 1;
}

.widget-medium {
    grid-column: span 2;
    grid-row: span 1;
}

.widget-large {
    grid-column: span 2;
    grid-row: span 2;
}

.widget-full {
    grid-column: 1 / -1;  /* Spans all columns */
}

Card Layouts with Grid Areas

/* Card with defined areas */
.card {
    display: grid;
    grid-template-areas:
        "image image"
        "title title"
        "description description"
        "meta actions";
    grid-template-columns: 1fr auto;
    gap: 10px;
}

.card-image { grid-area: image; }
.card-title { grid-area: title; }
.card-description { grid-area: description; }
.card-meta { grid-area: meta; }
.card-actions { grid-area: actions; }

Advantages of CSS Grid

  • Two-dimensional: Can create complex layouts in rows and columns simultaneously
  • Named areas: Intuitive layout mapping with grid-template-areas
  • Line-based placement: Precise control over item positioning
  • Auto-placement: Automatically places items in the grid
  • Explicit control: Fine-grained control over track sizes
  • Layout first: Design the layout independently of content
  • Responsive by design: Features like auto-fill/auto-fit make responsive layouts easier

Limitations of CSS Grid

  • Browser support: Not supported in older browsers (though support is now very good)
  • Learning curve: More complex than Flexbox for simple layouts
  • Subgrid support: Limited support for the subgrid feature in some browsers

Best Used For: Complex two-dimensional layouts, overall page structure, grid-based designs like dashboards, galleries, and card layouts.

Comparing Layout Methods

Each CSS layout method has its strengths and ideal use cases. Modern web development often uses a combination of techniques.

Feature Positioning Float-Based Flexbox CSS Grid
Dimensions n/a One-dimensional (horizontal) One-dimensional (row OR column) Two-dimensional (rows AND columns)
Control over layout Precise positioning Limited control Flexible distribution along an axis Complete layout control in both dimensions
Content order Independent of source Tied to source order Can reorder with the order property Complete freedom with grid-area
Spacing control Manual (top, left, etc.) Limited (margins) Good (justify-content, gap) Excellent (gap, template areas)
Responsive design Needs complete rewriting Requires media queries Good (flex-basis, flex-grow) Excellent (minmax, auto-fit/fill)
Best for UI components, overlays, tooltips Text wrapping, legacy support Navigation, cards, one-dimensional layouts Page layouts, complex grid-based designs

When to Use Each Method

Use CSS Positioning When:

  • You need precise control over an element's position
  • You're creating UI components like tooltips, popups, or modals
  • You need to position elements outside the normal flow
  • You're creating sticky elements like headers or navigation

Use Float-Based Layouts When:

  • You need to wrap text around images
  • You're supporting very old browsers
  • You're maintaining legacy code
  • You need simple horizontal layouts with text flow

Use Flexbox When:

  • You're working with one-dimensional layouts (row or column)
  • You want flexible sizing of elements
  • You need simple alignment or space distribution
  • You're creating navigation menus, toolbars, or card layouts
  • You want to vertically center content
  • Your layout needs to adapt to different screen sizes in a simple way

Use CSS Grid When:

  • You need two-dimensional control (rows and columns)
  • You're creating the overall page layout
  • You have a complex grid-based design
  • You want to place items precisely in a layout regardless of source order
  • You're creating image galleries, dashboards, or complex card layouts
  • You need both rows and columns to align

Combining Layout Methods

Modern web development often combines different layout techniques for the best results. Here are some common combinations:

Grid for Page Structure, Flexbox for Components

/* Page layout with Grid */
.page {
    display: grid;
    grid-template-areas:
        "header header header"
        "nav main aside"
        "footer footer footer";
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    min-height: 100vh;
}

.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* Navbar component with Flexbox */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.nav-menu {
    display: flex;
    gap: 1rem;
}

/* Card component with Flexbox */
.card {
    display: flex;
    flex-direction: column;
}

.card-body {
    flex: 1; /* Takes up available space */
}

.card-footer {
    margin-top: auto; /* Pushes to bottom */
}

Grid for Layout, Positioning for UI Components

/* Main layout with Grid */
.container {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 20px;
}

.header {
    grid-column: span 12;
}

.sidebar {
    grid-column: span 3;
}

.content {
    grid-column: span 9;
    position: relative; /* Creates positioning context */
}

/* Tooltip using positioning */
.tooltip {
    position: relative;
    display: inline-block;
}

.tooltip-text {
    position: absolute;
    top: -30px;
    left: 50%;
    transform: translateX(-50%);
    background: #333;
    color: white;
    padding: 5px 10px;
    border-radius: 4px;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.3s;
}

.tooltip:hover .tooltip-text {
    visibility: visible;
    opacity: 1;
}

Floats for Text Wrapping, Flexbox for Navigation

/* Article with image float */
.article img {
    float: left;
    margin: 0 20px 10px 0;
}

/* Navigation with Flexbox */
.nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.nav-links {
    display: flex;
    gap: 1.5rem;
}

Best Practices for Combining Layout Methods

  • Follow the natural strengths of each layout method
  • Use Grid for overall page structure and two-dimensional layouts
  • Use Flexbox for one-dimensional components like navigation, toolbars, and card content
  • Use Positioning for UI elements that need to be precisely placed or that overlay other content
  • Use Floats primarily for their original purpose - wrapping text around images
  • Consider nesting layout contexts - Grid containers can contain Flexbox items and vice versa
  • Plan your layout hierarchy from the outside in, from page to component level

Creating Responsive Layouts

Modern websites need to work on devices of all sizes. Each layout method has its own approach to responsive design.

Responsive Positioning

Fixed or absolute positioning often needs completely different values at different breakpoints.

/* Mobile-first approach with positioning */
.sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: -250px; /* Off-canvas by default */
    width: 250px;
    transition: left 0.3s ease;
}

.sidebar.open {
    left: 0; /* Slide in when open */
}

/* Desktop version */
@media (min-width: 992px) {
    .sidebar {
        position: static; /* Back to normal flow */
        width: 25%;
        float: left;
    }
    
    .main-content {
        width: 75%;
        float: left;
    }
}

Responsive Flexbox

Flexbox makes it easy to reorder and resize elements at different breakpoints.

/* Mobile-first approach with Flexbox */
.container {
    display: flex;
    flex-direction: column; /* Stack vertically on mobile */
}

.sidebar {
    order: 1; /* Appears after main content on mobile */
}

.main-content {
    order: 0; /* Appears first on mobile */
}

/* Tablet and up */
@media (min-width: 768px) {
    .container {
        flex-direction: row; /* Side by side on larger screens */
    }
    
    .sidebar {
        flex: 0 0 250px; /* Fixed width */
        order: 0; /* Restore original order */
    }
    
    .main-content {
        flex: 1; /* Take remaining space */
    }
}

Responsive Grid

CSS Grid provides powerful tools for responsive layouts, often requiring fewer media queries.

/* Basic responsive grid without media queries */
.auto-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
}

/* More complex responsive grid */
.dashboard {
    display: grid;
    gap: 20px;
    
    /* Mobile: single column */
    grid-template-columns: 1fr;
    grid-template-areas:
        "header"
        "main"
        "sidebar"
        "footer";
}

/* Tablet */
@media (min-width: 768px) {
    .dashboard {
        grid-template-columns: 3fr 1fr;
        grid-template-areas:
            "header header"
            "main sidebar"
            "footer footer";
    }
}

/* Desktop */
@media (min-width: 1200px) {
    .dashboard {
        grid-template-columns: 1fr 3fr 1fr;
        grid-template-areas:
            "header header header"
            "sidebar-left main sidebar-right"
            "footer footer footer";
    }
}

Using Container Queries

Container queries are a newer feature that allow you to style elements based on their container's size rather than the viewport.

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

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

@container card (max-width: 399px) {
    .card {
        display: flex;
        flex-direction: column;
    }
}

Note: Container queries are a newer feature and may not be supported in all browsers yet.

Responsive Layout Best Practices

  • Mobile-first approach: Start with styles for small screens, then add media queries for larger ones
  • Use relative units: Prefer %, em, rem, vh, vw over fixed pixel values
  • Fluid layouts: Allow content to adapt to different screen sizes
  • Consider content priorities: Adjust layout to prioritize important content on smaller screens
  • Test on real devices: Browser emulation is useful but not perfect
  • Use modern layout features: minmax(), auto-fit, auto-fill make responsive design easier
  • Consider performance: Complex layouts can impact performance on lower-end devices

Complete Layout Examples

Modern Blog Layout

/* Complete blog layout example combining multiple techniques */

/* Overall page structure with Grid */
body {
    display: grid;
    grid-template-areas:
        "header"
        "nav"
        "main"
        "sidebar"
        "footer";
    grid-template-columns: 1fr;
    grid-template-rows: auto auto 1fr auto auto;
    min-height: 100vh;
    margin: 0;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.6;
}

/* Header with sticky positioning and flexbox for content */
header {
    grid-area: header;
    position: sticky;
    top: 0;
    z-index: 100;
    background-color: white;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.header-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    max-width: 1200px;
    margin: 0 auto;
}

/* Navigation with Flexbox */
nav {
    grid-area: nav;
    background-color: #f8f9fa;
}

.nav-container {
    display: flex;
    overflow-x: auto;
    padding: 0.5rem 1rem;
    max-width: 1200px;
    margin: 0 auto;
}

.nav-link {
    flex: 0 0 auto;
    padding: 0.5rem 1rem;
    white-space: nowrap;
    text-decoration: none;
    color: #333;
}

.nav-link:hover {
    color: #0066cc;
}

/* Main content and sidebar with Grid for article layout */
main {
    grid-area: main;
    padding: 1rem;
    max-width: 1200px;
    margin: 0 auto;
}

.article-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 2rem;
}

/* Article card with Flexbox for content */
.article-card {
    display: flex;
    flex-direction: column;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s, box-shadow 0.3s;
}

.article-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
}

.article-image {
    height: 200px;
    background-color: #f1f1f1;
}

.article-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.article-content {
    flex: 1;
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
}

.article-title {
    margin-top: 0;
    margin-bottom: 0.5rem;
    font-size: 1.25rem;
}

.article-excerpt {
    color: #666;
    margin-bottom: 1rem;
}

.article-meta {
    margin-top: auto;
    font-size: 0.875rem;
    color: #999;
}

/* Sidebar */
aside {
    grid-area: sidebar;
    padding: 1rem;
    background-color: #f8f9fa;
}

.sidebar-container {
    max-width: 1200px;
    margin: 0 auto;
}

/* Sidebar widgets with float for image */
.widget {
    margin-bottom: 2rem;
}

.widget-title {
    border-bottom: 2px solid #eee;
    padding-bottom: 0.5rem;
}

.featured-post {
    padding-bottom: 1rem;
    border-bottom: 1px solid #eee;
    margin-bottom: 1rem;
}

.featured-post img {
    float: left;
    width: 80px;
    height: 80px;
    object-fit: cover;
    margin-right: 1rem;
}

.featured-post-title {
    margin: 0 0 0.25rem 0;
    font-size: 1rem;
}

/* Footer */
footer {
    grid-area: footer;
    background-color: #333;
    color: white;
    padding: 2rem 1rem;
}

.footer-container {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem;
    max-width: 1200px;
    margin: 0 auto;
}

.footer-section {
    flex: 1 1 200px;
}

.footer-section h3 {
    border-bottom: 1px solid #555;
    padding-bottom: 0.5rem;
}

/* Responsive adjustments */
@media (min-width: 768px) {
    body {
        grid-template-areas:
            "header header"
            "nav nav"
            "main sidebar"
            "footer footer";
        grid-template-columns: 1fr 300px;
    }
}

@media (min-width: 1200px) {
    .nav-container {
        justify-content: center;
    }
}

Dashboard Layout

/* Dashboard layout combining Grid, Flexbox, and Positioning */

/* Base styles */
body {
    margin: 0;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    color: #333;
    background-color: #f5f7fa;
}

/* Dashboard layout with Grid */
.dashboard {
    display: grid;
    grid-template-areas:
        "sidebar header"
        "sidebar main";
    grid-template-columns: 250px 1fr;
    grid-template-rows: 60px 1fr;
    min-height: 100vh;
}

/* Fixed sidebar with Flexbox for internal layout */
.sidebar {
    grid-area: sidebar;
    background-color: #2c3e50;
    color: white;
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

.sidebar-logo {
    font-size: 1.5rem;
    font-weight: bold;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.sidebar-nav a {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: #ecf0f1;
    text-decoration: none;
    padding: 0.75rem;
    border-radius: 4px;
    transition: background-color 0.2s;
}

.sidebar-nav a:hover {
    background-color: #34495e;
}

.sidebar-nav a.active {
    background-color: #1abc9c;
}

/* Header with Flexbox */
.header {
    grid-area: header;
    background-color: white;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    padding: 0 1.5rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.search {
    position: relative;
}

.search input {
    padding: 0.5rem 1rem 0.5rem 2.5rem;
    border: 1px solid #ddd;
    border-radius: 4px;
    width: 300px;
}

.search::before {
    content: "🔍";
    position: absolute;
    left: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    color: #999;
}

.user-menu {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.notifications {
    position: relative;
}

.notification-count {
    position: absolute;
    top: -5px;
    right: -5px;
    background-color: #e74c3c;
    color: white;
    font-size: 0.75rem;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
}

/* Main content with Grid for widget layout */
.main {
    grid-area: main;
    padding: 1.5rem;
    overflow-y: auto;
}

.widgets {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin-bottom: 1.5rem;
}

.widget {
    background-color: white;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    overflow: hidden;
}

.widget-header {
    padding: 1rem 1.5rem;
    border-bottom: 1px solid #eee;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.widget-title {
    margin: 0;
    font-size: 1.1rem;
}

.widget-content {
    padding: 1.5rem;
}

/* Data table */
.data-table {
    width: 100%;
    border-collapse: collapse;
}

.data-table th, .data-table td {
    padding: 0.75rem 1rem;
    text-align: left;
    border-bottom: 1px solid #eee;
}

.data-table th {
    background-color: #f9f9f9;
    font-weight: 600;
}

/* Status indicators with positioning */
.status {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 20px;
    font-size: 0.875rem;
}

.status-success {
    background-color: #e3fcef;
    color: #1abc9c;
}

.status-warning {
    background-color: #fef5e5;
    color: #f39c12;
}

.status-danger {
    background-color: #fde8e8;
    color: #e74c3c;
}

/* Responsive adjustments */
@media (max-width: 992px) {
    .dashboard {
        grid-template-areas:
            "header header"
            "sidebar main";
        grid-template-rows: 60px 1fr;
    }
}

@media (max-width: 768px) {
    .dashboard {
        grid-template-areas:
            "header"
            "main";
        grid-template-columns: 1fr;
    }
    
    .sidebar {
        position: fixed;
        left: -250px;
        top: 0;
        bottom: 0;
        z-index: 1000;
        transition: left 0.3s ease;
    }
    
    .sidebar.open {
        left: 0;
    }
}

Wrapping Up

CSS layout techniques have evolved significantly over the years, providing web developers with increasingly powerful and intuitive tools for creating complex and responsive layouts.

Key Takeaways

  • CSS Positioning provides precise control over element placement and is ideal for UI components and special positioning needs
  • Float-based layouts, while somewhat outdated for page layout, still serve their original purpose for text wrapping around images
  • Flexbox excels at one-dimensional layouts, making it perfect for components, navigation, and flexible content distribution
  • CSS Grid offers unprecedented two-dimensional layout control, ideal for overall page structure and complex grid-based designs
  • Modern web development often combines these techniques, using each for its strengths
  • Responsive design is crucial, and each layout method offers its own approach to creating adaptive layouts

Additional Resources

Practice Exercises

Exercise 1: Positioning Practice

Create a simple layout with the following elements:

  1. A header fixed to the top of the page
  2. A sidebar absolutely positioned within a relative container
  3. A tooltip that appears on hover using absolute positioning
  4. A sticky "back to top" button that appears when scrolling down

Exercise 2: Float-based Layout

Create a simple page that demonstrates float-based techniques:

  1. An article with an image floated to the left with text wrapping around it
  2. A pull quote floated to the right within the text
  3. A three-column layout using floats and percentage widths
  4. Proper clearfix to handle container height

Exercise 3: Flexbox Navigation and Cards

Create a page using Flexbox for layout:

  1. A responsive navigation bar with logo on the left and menu items on the right
  2. A container of cards with flexible widths that wrap to new rows as needed
  3. Each card should have an image, title, description, and button, with the button always at the bottom regardless of content length
  4. Create a "holy grail" layout with header, footer, and three columns using Flexbox

Exercise 4: CSS Grid Layout

Create a page using CSS Grid:

  1. An overall page layout with header, footer, main content, and sidebar using grid-template-areas
  2. A responsive image gallery with some feature images spanning multiple grid cells
  3. A form layout with labels and inputs aligned using Grid
  4. Make the layout responsive with appropriate breakpoints

Exercise 5: Combined Techniques

Create a complete webpage that demonstrates all four layout techniques:

  1. Overall page structure with CSS Grid
  2. Navigation and card components with Flexbox
  3. Article with images using Float for text wrapping
  4. Modal/popup and tooltips using Positioning
  5. Make everything responsive and mobile-friendly