Containers & the Grid System
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:
| Class | Behaviour |
|---|---|
container | Full width on phones, then a fixed maximum width that steps up at each breakpoint, centred |
container-fluid | Always 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:
| Breakpoint | Class infix | Applies from | Typical device |
|---|---|---|---|
| Extra small | none | 0px | Phones in portrait |
| Small | sm | 576px | Phones in landscape |
| Medium | md | 768px | Tablets |
| Large | lg | 992px | Laptops |
| Extra large | xl | 1200px | Desktops |
| Extra extra large | xxl | 1400px | Large 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.
<!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.
<!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:
<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:
<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-6to work on phones. It only applies from 768px up. Addcol-12(or nothing, since columns are full width by default) for small screens. - Styling the column itself. Adding borders or backgrounds directly on a
colmakes 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
containerfor a centred, limited width andcontainer-fluidfor full width. - The grid has 12 columns; rows hold columns, and columns hold content.
- Breakpoints are
sm576px,md768px,lg992px,xl1200px andxxl1400px; classes apply from their breakpoint upwards. - Combine classes such as
col-12 col-sm-6 col-lg-3to change the layout at each size. colshares space equally,col-autofits its content, androw-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
<!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?
The grid is based on 12 columns, which divide neatly into halves, thirds, quarters and sixths.
2. What does col-md-4 mean?
Bootstrap is mobile-first: an infix class applies from its breakpoint and above.
3. Which container is always 100% of the screen width?
container-fluid never sets a maximum width; container steps up through fixed widths.
4. Three col elements without numbers sit in one row. How wide is each?
Plain col columns divide the row equally; col-auto is the one that fits its content.
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
