RWD Rolling Your Own

A small, hand-written set of breakpoints and a CSS Grid layout can give you more control and far less bloat than reaching for a full framework.

When a Framework Is Overkill

Frameworks earn their weight on large, component-heavy products built by teams that need consistency across many contributors. A lot of real projects aren't that: a five-page marketing site, a design that doesn't fit neatly into 12 equal columns, or a performance budget where every unused kilobyte of framework CSS actually matters. In those cases, a framework's grid and utility classes can end up fighting the design instead of supporting it.

  • You're shipping a small number of page templates, not a large evolving app.
  • The design uses an irregular spacing scale or column count that doesn't map cleanly onto a 12-column grid.
  • Performance is a hard constraint and every unused KB of framework CSS is a cost you can't justify.
  • You want full control over class names and markup structure instead of adopting someone else's naming convention.
  • The team already has solid CSS fundamentals, so the framework's main benefit -- not having to know CSS well -- doesn't apply.

A Minimal Responsive Toolkit

You don't need much to replace most of what a framework's grid does: a container class that centers content and caps its width, a small number of consistent breakpoints, and CSS Grid's repeat() function to lay out columns without needing a separate utility class for every possible column count.

A Small Hand-Rolled Grid

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.container {
  width: 100%;
  max-width: 1140px;
  margin-inline: auto;
  padding-inline: 1rem;
}

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
}

@media (min-width: 768px) {
  .grid {
    grid-template-columns: repeat(8, 1fr);
  }
}

@media (min-width: 1200px) {
  .grid {
    grid-template-columns: repeat(12, 1fr);
  }
}
</style>
</head>
<body>

</body>
</html>

Individual items then size themselves with grid-column: span N instead of a wall of pre-made col-1 through col-12 classes -- you only ever write the spans your actual design needs, and nothing else ships to the browser.

Sizing an Item With grid-column

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.card--wide {
  grid-column: span 8;
}

.card--narrow {
  grid-column: span 4;
}
</style>
</head>
<body>

</body>
</html>

Keeping a Hand-Rolled System Maintainable

  • Keep the number of breakpoints small -- two or three is usually enough; a dozen ad-hoc values scattered through a stylesheet is how hand-rolled CSS turns into a mess.
  • Document your breakpoints once, in a comment at the top of the stylesheet, so every @media rule in the file uses the same agreed-upon numbers.
  • Avoid magic numbers: prefer values tied to your type scale or spacing scale over one-off pixel counts picked to fix a single element.
Note: Newer CSS does let you store breakpoint values in custom properties and reference them inside @media rules, but support for that is still inconsistent across browsers as of this writing. Most hand-rolled systems still repeat literal pixel values in each media query and rely on a comment block for documentation instead.
Note: Don't build a whole miniature design system up front. Start with plain CSS, and only extract a reusable utility class once you notice yourself writing the same rule for the third time.

Exercise: RWD Frameworks

What is a primary benefit of using a CSS framework like Bootstrap for responsive design?