Bulma's columns grid: how flex sizing and breakpoint modifiers actually resolve
Bulma's .columns is a flex container and .column shares the row equally. How breakpoint modifiers, gutters, and is-multiline actually resolve — and what to check in devtools.
29 Jun 2026, 20:52 UTC

What Bulma's .columns actually does
Bulma's grid is not a grid engine. .columns is a flex container and .column is a flex item that shares the row equally with its siblings. There is no JavaScript, no measurement pass, and no inline styles: every layout decision comes from a class you write in the markup and a rule Bulma already shipped.
That single fact explains most of the behavior people find surprising. Equal splitting is the default, not something you opt into. Widths are opt-in overrides. And because the container only becomes a flex container from the tablet breakpoint upward in the class API described here, stacked-on-mobile is the default rather than a fallback you have to build.
A worked configuration: three cards, three breakpoints
Say you want a card row that is one card per line on phones, two per line on tablets, and three per line on desktop and wider. The container and one card look like this:
<div class="columns is-multiline">
<div class="column is-full-mobile is-half-tablet is-one-third-desktop">
<div class="box">Card one</div>
</div>
<div class="column is-full-mobile is-half-tablet is-one-third-desktop">
<div class="box">Card two</div>
</div>
<div class="column is-full-mobile is-half-tablet is-one-third-desktop">
<div class="box">Card three</div>
</div>
</div>
Open the file in a browser with the Bulma stylesheet linked, then resize the window slowly. Three things to watch:
- Below the tablet breakpoint the cards stack.
.columnsis not a flex container there, so the width modifiers have nothing to act on. - At tablet width and above,
is-half-tabletgives each card 50%. Two fit per line; the third wraps becauseis-multilinelets the flex line break. - At desktop width,
is-one-third-desktoptakes over and three fit per line.
The suffix is a media query, not a "this size only" switch. -tablet applies from the tablet breakpoint upward and -desktop from the desktop breakpoint upward, so the later rule wins once both are active. That is why the order you type the classes in the attribute does not matter, but the order Bulma writes them in the stylesheet does.
is-full-mobile here is belt-and-braces: columns already stack below the tablet breakpoint, so it documents intent more than it changes rendering. It is harmless to keep and easier to read than an implicit default.
Confirming the mechanism in devtools
Select the .columns element in the inspector and look at Computed styles. You should see display: flex at desktop width and display: block at phone width. Select a .column and look at its computed flex shorthand and width: the width should read 50% at tablet and roughly 33.33% at desktop. If the computed width is still auto, the modifier class is misspelled or the breakpoint has not been crossed.
Widths, offsets, and the two numbering systems
Bulma offers two ways to express the same width: named fractions (is-half, is-one-quarter, is-two-thirds) and a twelve-column scale (is-1 through is-12). is-6 and is-half both produce a half-width column. Pick one convention per codebase; mixing them makes layout intent hard to grep for.
Two modifiers behave differently from the rest and are worth knowing before you need them:
is-narrowmakes a column take only the width its content needs instead of an equal share. Useful for an icon strip beside a flexible content column.is-offset-*pushes a column to the right by the given fraction, which is how you center a single fixed-width column inside a row.
Alignment lives on the container, not the child. is-vcentered on .columns vertically centers the columns against each other; is-centered horizontally centers columns that do not fill the row. Putting either on a .column does nothing.
Limits and the mistakes that show up most
Gutters are padding plus negative margins
Bulma creates the gap between columns by giving each .column horizontal padding and pulling the .columns container outward with matching negative margins. Two practical consequences:
- A background or border set directly on
.columnwill not reach the visual edge of the row, because the padding sits inside the element. Put the visual box on a child element instead. - A
.columnselement that is a direct child of something with no horizontal padding — a barebody, a full-bleed section — can push the page wider than the viewport and produce a horizontal scrollbar. Wrapping it in a padded container, or usingis-gapless, avoids that.
is-multiline without widths
This is the most common source of "the layout looks fine at 1400px and broken at 900px." With is-multiline and no width modifiers, every column in a wrapped row stretches to fill the full row, so a row of three becomes a row of two plus a row of one that is twice as wide as its siblings. If you allow wrapping, give the columns an explicit width at each breakpoint, as in the example above.
No JavaScript layer
Bulma ships CSS only. Dropdowns, modals, the navbar burger, and tabs are styled states that you toggle by adding and removing is-active from your own script. If you are weighing Bulma against a framework with bundled behavior, budget for that code.
Bundle size when you only want the grid
Bulma is a component framework, not a utility framework, so linking the full stylesheet ships rules for buttons, forms, tables, and everything else. If the grid is all you need, import only the grid partial from the Sass source rather than the full build. Import syntax and file paths changed between the 0.9.x and 1.x lines, so check the documentation for the exact version you install — this is the part of this article most likely to be version-sensitive.
How to check your result
- Resize the viewport slowly through 768→769px and 1023→1024px. The layout should change once at each boundary, not flicker.
- In devtools, confirm
display: flexon.columnsabove the tablet breakpoint and percentage widths on each.column. - Scroll horizontally at the narrowest width. A horizontal scrollbar usually means a
.columnselement is sitting in an unpadded parent. - Disable JavaScript and reload. The grid should be identical, because none of it depends on script.
Version note: the class names and breakpoint behavior described here reflect the stable Bulma column API across the 0.9.x and 1.x lines. Exact media query boundaries, Sass import paths, and any deprecated aliases should be verified against the changelog for the version you actually load.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.