The Grid System

This section documents Bootstrap 5.x as implemented by the official Bootstrap project. No specific patch version is pinned. Unlike the other reference sections on this site, no single reference book underpins it: the content was generated with the assistance of AI from general knowledge of Bootstrap, and should be verified against the current official documentation at getbootstrap.com/docs before relying on it in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Bootstrap’s grid is a 12-column, flexbox-based layout system built from three layers that always nest in the same order: a container, one or more rows, and one or more columns inside each row. Every responsive layout in Bootstrap — from a simple two-column page to a complex dashboard — is composed from just those three layers plus a small vocabulary of breakpoint suffixes.

Containers

A container is the outermost wrapping element. It centers content horizontally and applies responsive padding (and, indirectly, the margin that separates it from the viewport edge — see The Box Model for what padding/margin mean structurally). Three variants exist:

<div class="container">      <!-- fixed max-width per breakpoint, with gutters -->
<div class="container-fluid"><!-- always 100% of the viewport width -->
<div class="container-md">   <!-- fluid below md, fixed-width at md and up -->

.container sets a max-width that changes at each breakpoint (roughly matching that breakpoint’s minimum width, minus gutters), so the content column stays a comfortable reading width on large screens instead of stretching edge-to-edge. .container-fluid never caps its width — it is always 100%, which suits app-like layouts (dashboards, full-bleed hero sections) more than long-form content. The .container-{breakpoint} variants (sm, md, lg, xl, xxl) are fluid up to that breakpoint and fixed-width from it upward — a middle ground useful when a layout should be edge-to-edge on mobile but capped on desktop.

Rows and columns

A row is a flex container (display: flex; flex-wrap: wrap;) that introduces a negative margin to offset the gutter padding columns add, so columns and containers align correctly at the edges. Columns are the flex items inside it:

<div class="container">
  <div class="row">
    <div class="col">Column A</div>
    <div class="col">Column B</div>
    <div class="col">Column C</div>
  </div>
</div>

Bare .col (no number) divides the available width equally among however many sibling columns share the row — three .col elements each take a third, four take a quarter, and so on, recalculated automatically.

The 12-column logic

Bootstrap’s grid conceptually divides each row into 12 equal-width units. A numbered column class, .col-{n}, spans n of those 12 units — .col-4 is one third of the row, .col-6 is half, .col-12 is the full width:

<div class="row">
  <div class="col-4">col-4</div>
  <div class="col-4">col-4</div>
  <div class="col-4">col-4</div>
</div>

<div class="row">
  <div class="col-6">col-6</div>
  <div class="col-6">col-6</div>
</div>

<div class="row">
  <div class="col-3">col-3</div>
  <div class="col-9">col-9</div>
</div>

Column widths do not have to sum to exactly 12: if a row’s columns add up to more than 12, the excess columns wrap onto a new line as a unit (they do not split); if they add up to less, the row simply leaves unused space on the right (in a left-to-right document).

flowchart TB subgraph xs["xs (<576px) -- stacked, one column per row"] direction LR xs1["col-12"] end subgraph md["md (≥768px) -- 3 + 9"] direction LR md1["col-md-3"] md2["col-md-9"] end subgraph lg["lg (≥992px) -- 3 + 6 + 3"] direction LR lg1["col-lg-3"] lg2["col-lg-6"] lg3["col-lg-3"] end xs --> md --> lg classDef unit fill:#3f51b5,stroke:#1a237e,color:#fff class xs1,md1,md2,lg1,lg2,lg3 unit

The same markup can carry different column classes for different breakpoints simultaneously (see below), which is how a single set of <div> elements goes from stacked-on-mobile to a three-column desktop layout without any JavaScript or duplicated HTML.

Breakpoints

Every column class can be suffixed with a breakpoint infix that makes it apply from that viewport width upward (mobile-first: an unsuffixed class applies at all widths unless overridden by a wider breakpoint):

Breakpoint Infix Applies from

Extra small

(none)

0px and up (always, unless overridden)

Small

sm

≥576px

Medium

md

≥768px

Large

lg

≥992px

Extra large

xl

≥1200px

Extra extra large

xxl

≥1400px

Combining several breakpoint classes on the same element produces a genuinely responsive layout:

<div class="row">
  <div class="col-12 col-md-6 col-lg-4">
    Full width on phones, half width from md, a third from lg upward
  </div>
  <div class="col-12 col-md-6 col-lg-4">...</div>
  <div class="col-12 col-md-6 col-lg-4">...</div>
</div>

These classes never conflict with each other because each one is generated inside its own @media (min-width: …​) query in Bootstrap’s compiled CSS — .col-md-6 literally only exists inside a @media (min-width: 768px) block. At a 900px viewport, only the md (and unsuffixed) rules apply; the lg/xl/xxl rules simply are not part of any matching media query yet, so there is nothing to override. This is why stacking multiple breakpoint classes on one element is the normal, supported pattern rather than a hack.

Sizing, offsetting, ordering, and nesting

Auto-sizing and equal-width columns

Besides fixed .col-{n} widths, a column can be told to size itself to its content (.col-auto) while its siblings share the rest equally:

<div class="row">
  <div class="col-auto">Fits content</div>
  <div class="col">Takes the remaining space</div>
</div>

Offsetting

.offset-{breakpoint}-{n} pushes a column to the right by n of the 12 units, using margin rather than an empty sibling column — useful for centering or skipping columns without adding markup:

<div class="row">
  <div class="col-md-4">col-md-4</div>
  <div class="col-md-4 offset-md-4">col-md-4, offset 4</div>
</div>

Ordering

.order-{n} (0 through 5, plus .order-first/.order-last) changes the visual order of columns via the flexbox order property, independent of their order in the HTML source:

<div class="row">
  <div class="col order-3">First in HTML, renders last</div>
  <div class="col order-1">Second in HTML, renders first</div>
  <div class="col order-2">Third in HTML, renders second</div>
</div>

Because order is purely visual, screen readers and keyboard tab order still follow the source order — worth keeping in mind for any layout that reorders columns for visual effect, per the accessibility notes on Getting Started.

Nesting

A .row can be nested inside a .col, starting a fresh 12-column context scoped to that column’s own width — the nested row’s columns are fractions of the parent column, not the page:

<div class="row">
  <div class="col-sm-9">
    Level 1: col-sm-9
    <div class="row">
      <div class="col-8 col-sm-6">Level 2: col-8 col-sm-6</div>
      <div class="col-4 col-sm-6">Level 2: col-4 col-sm-6</div>
    </div>
  </div>
</div>

The nesting-containers antipattern

.container/.container-fluid should appear once, at the top of the layout — they set page-level horizontal padding and center the whole layout. Nesting a second .container inside a .row/.col is a common mistake: the inner container adds its own responsive padding and (for the fixed variant) max-width on top of the outer one, which produces doubled gutters and, worse, causes the inner content to stop growing past the inner container’s max-width even though the outer container has more room. Rows and columns nest freely (see above); containers do not.

<!-- Wrong: container nested inside a column -->
<div class="container">
  <div class="row">
    <div class="col">
      <div class="container">...</div>  <!-- doubled gutters, unexpected max-width -->
    </div>
  </div>
</div>

<!-- Right: only rows/columns nest -->
<div class="container">
  <div class="row">
    <div class="col">
      <div class="row">...</div>        <!-- fine, see Nesting above -->
    </div>
  </div>
</div>

The one legitimate exception is deliberately mixing container types at the top level for a page section that needs to break out of the page’s normal width — for example, a full-bleed .container-fluid hero banner followed by a normally-constrained .container for the rest of the page. That is two sibling top-level containers, not one nested inside the other, so it does not hit the doubled-gutter problem above.

For the full grid API — including the CSS Grid-based .row-cols-* and gap utilities — see the official Layout: Grid documentation.