Containers & the Grid System

Bootstrap · Lesson 3 of 28 7 min read Updated

Almost every Bootstrap page is laid out with the grid system: a set of containers, rows and columns that rearrange themselves for phones, tablets and laptops. Once you understand it, you can build product listings, dashboards and full page layouts with nothing but class names.

In this lesson you will learn the three containers, the six breakpoints, and how to size columns for each screen size.

Containers

A container is the outer box that holds your content. It adds padding on the left and right and, for most types, limits how wide the content can grow. There are three kinds:

ClassBehaviour
containerFull width on phones, then a fixed maximum width that steps up at each breakpoint, centred
container-fluidAlways 100% of the screen width
container-md (and -sm, -lg, -xl, -xxl)100% wide until that breakpoint, then behaves like container

Use container for most pages, so lines of text do not stretch across a huge monitor. Use container-fluid for things that should touch both edges, such as a dashboard or a full-width banner. You can use several containers on one page, for example a fluid header followed by a normal container for the content.

Breakpoints

A breakpoint is a screen width at which the layout is allowed to change. Bootstrap has six:

BreakpointClass infixApplies fromTypical device
Extra smallnone0pxPhones in portrait
Smallsm576pxPhones in landscape
Mediummd768pxTablets
Largelg992pxLaptops
Extra largexl1200pxDesktops
Extra extra largexxl1400pxLarge monitors

The infix goes in the middle of a class name, as in col-md-6. Bootstrap is mobile-first: a class with an infix applies from that width upwards. So col-md-6 means "half width on medium screens and everything larger", and below 768px it does nothing. Classes without an infix apply at every size.

For container, the maximum widths are 540px, 720px, 960px, 1140px and 1320px at the sm, md, lg, xl and xxl breakpoints.

Rows and columns

Inside a container you place a row, and inside the row you place columns. The grid has 12 columns, so the numbers in your classes should add up to 12 per line.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Basic grid</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
  <style>
    .row > div > div { padding: 12px; background: #e9e3f5; border: 1px solid #c9b8e8; border-radius: 6px; }
  </style>
</head>
<body>
  <div class="container py-3">
    <h1 class="h4">Rohtak Sports Store</h1>
    <div class="row mb-3">
      <div class="col-8"><div>Main content (8 of 12)</div></div>
      <div class="col-4"><div>Sidebar (4 of 12)</div></div>
    </div>
    <div class="row">
      <div class="col"><div>Bats</div></div>
      <div class="col"><div>Balls</div></div>
      <div class="col"><div>Pads</div></div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

The first row splits into 8 and 4 columns: two thirds and one third. The second row uses plain col three times. A col without a number is an auto-layout column: all such columns share the width equally, so you get three equal thirds without doing any maths.

Under the hood a row is a Flexbox container (see CSS Flexbox) and each column is a flex item with padding on both sides. That padding is the gutter, the gap between columns.

Responsive columns

The real power is combining classes for different breakpoints. Each class sets the width from its breakpoint upwards, until a larger breakpoint overrides it.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Responsive products</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-3">
    <div class="row g-3">
      <div class="col-12 col-sm-6 col-lg-3"><div class="p-3 border rounded">Cricket bat<br><strong>₹1,299</strong></div></div>
      <div class="col-12 col-sm-6 col-lg-3"><div class="p-3 border rounded">Tennis balls<br><strong>₹240</strong></div></div>
      <div class="col-12 col-sm-6 col-lg-3"><div class="p-3 border rounded">Batting gloves<br><strong>₹899</strong></div></div>
      <div class="col-12 col-sm-6 col-lg-3"><div class="p-3 border rounded">Kit bag<br><strong>₹1,050</strong></div></div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Read the classes from smallest screen to largest:

  • col-12: on phones, each product takes the full width, so they stack in one column.
  • col-sm-6: from 576px, each takes half, giving two per row.
  • col-lg-3: from 992px, each takes a quarter, giving four per row.

Drag the result panel narrower and wider to watch the layout change. When the column numbers in a row add up to more than 12, the extra columns simply wrap onto a new line, which is exactly what happens here on small screens.

Sizing from the row: row-cols

Writing the same classes on every column gets repetitive. With row-cols-* you set the number of columns once, on the row:

HTML
<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-4 g-3">
  <div class="col">Cricket bat</div>
  <div class="col">Tennis balls</div>
  <div class="col">Batting gloves</div>
  <div class="col">Kit bag</div>
</div>

This gives exactly the same layout as the previous example: one per row on phones, two from sm, four from lg. It is the cleanest way to build a grid of cards.

Auto-width and mixed columns

col-auto makes a column only as wide as its content, and plain col columns share whatever space is left. This is handy for a label and a value, or a logo next to a search box:

HTML
<div class="row align-items-center">
  <div class="col-auto"><img src="https://course.ethicscomputer.in/assets/samples/logo.svg" alt="Store logo" width="120"></div>
  <div class="col"><input class="form-control" type="search" placeholder="Search products"></div>
</div>

You can also mix one fixed column with auto columns: col-6 plus two col gives half, then two quarters.

Common mistakes

  • Putting columns directly in a container. Columns must be direct children of a row; otherwise the gutters and widths break.
  • Putting content directly in a row. Only columns should be direct children of a row. Put your text and cards inside a column.
  • Expecting col-md-6 to work on phones. It only applies from 768px up. Add col-12 (or nothing, since columns are full width by default) for small screens.
  • Styling the column itself. Adding borders or backgrounds directly on a col makes the boxes touch, because the gutter is padding inside the column. Put an inner <div> in the column and style that, as the examples do.

Key points

  • Use container for a centred, limited width and container-fluid for full width.
  • The grid has 12 columns; rows hold columns, and columns hold content.
  • Breakpoints are sm 576px, md 768px, lg 992px, xl 1200px and xxl 1400px; classes apply from their breakpoint upwards.
  • Combine classes such as col-12 col-sm-6 col-lg-3 to change the layout at each size.
  • col shares space equally, col-auto fits its content, and row-cols-* sets the column count on the row.

Exercise

Ananya wants a page for her Jaipur handicrafts shop with six products. On phones show one product per row, on tablets (md) three per row, and on large screens (xl) six per row. Use row-cols-* on the row, give each product a bordered, padded box with its name and price, and add a gap between boxes with g-3.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Jaipur Handicrafts</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-3">
    <div class="row row-cols-1 row-cols-md-3 row-cols-xl-6 g-3">
      <div class="col"><div class="p-3 border rounded">Blue pottery vase<br>₹850</div></div>
      <div class="col"><div class="p-3 border rounded">Block-print quilt<br>₹2,200</div></div>
      <div class="col"><div class="p-3 border rounded">Mojari shoes<br>₹1,150</div></div>
      <div class="col"><div class="p-3 border rounded">Puppet pair<br>₹600</div></div>
      <div class="col"><div class="p-3 border rounded">Brass lamp<br>₹1,400</div></div>
      <div class="col"><div class="p-3 border rounded">Bandhani dupatta<br>₹950</div></div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

row-cols-1 sets one column per row on phones, row-cols-md-3 three from 768px, and row-cols-xl-6 six from 1200px. Each col holds an inner box, so the borders do not touch.

Quick Quiz

1. How many columns does the Bootstrap grid have per row?

2. What does col-md-4 mean?

3. Which container is always 100% of the screen width?

4. Three col elements without numbers sit in one row. How wide is each?

Learn Bootstrap with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call