JavaScript is required for this site to function.

Creating a ruled CSS Grid using borders and outlines

This article is about how to create a ruled CSS grid. As in, a CSS grid with lines between each item, on all sides. Like a table or a spreadsheet.

It feels like this should be straightforward, but there are still a few different approaches floating around. The approach I will spend the most time on is the one I think works best, and one I have not seen others talk about.

I will also look at CSS gap decorations, a new addition to CSS, and the popular background-color approach.

A border around each item doesn't work

Adding a border to every grid item creates doubled lines wherever neighboring borders meet. The example below makes the problem clear.

my-grid.html
html
<div class="ruled-grid">
  <div class="ruled-grid__item">Item 1</div>
  <div class="ruled-grid__item">Item 2</div>
  <div class="ruled-grid__item">Item 3</div>
  <div class="ruled-grid__item">Item 4</div>
  <div class="ruled-grid__item">Item 5</div>
</div>
my-grid.css
css
.ruled-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
.ruled-grid__item {
  padding: 2rem;
  background: #fff;
  border: 2px solid #000;
}

This ruled grid is not so great...

Where the borders meet, you end up with double border thickness, making the whole thing look wrong.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.

The border + outline method

A straightforward fix is to apply both a border and an outline of the same width and color. A CSS variable can keep their widths in sync. The visible line is the combined width of the border and outline - in this case 4px.

my-grid.css
css
.ruled-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
.ruled-grid__item {
  padding: 2rem;
  background: #fff;
  border: 2px solid #000;
  outline: 2px solid #000;
}

This is a better looking grid

This looks pretty good. We have kind of achieved what we want.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.

How borders and outlines combine

A border is part of an element's box, while an outline is painted outside that box and does not affect its size or the grid layout. Because the grid items sit directly next to each other, each outline overlaps the neighboring item's border. When the border and outline use the same width and color, those overlapping edges appear as one consistent line instead of doubled borders between the items.

But what if we make the border a bit thicker? Let's bump the border and outline up to 12px to highlight one more thing.

my-grid.css
css
.ruled-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
.ruled-grid__item {
  padding: 2rem;
  background: #fff;
  border: 12px solid #000;
  outline: 12px solid #000;
}

Look at the left edge of the grid container and the heading above in the following example. The two should align, but the outlines on the outer grid items extend beyond the container because they do not take up space. This is barely noticeable and usually not an issue unless the lines are quite thick.

Oops...

Now that the lines are thicker, it is more noticeable that they extend beyond the container.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.

But we can fix that by adding the same padding to the grid parent. This is, of course, a good use case for a CSS custom property (variable).

my-grid.css
css
.ruled-grid {
  --grid-line-width: 12px;

  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: var(--grid-line-width);
}
.ruled-grid__item {
  padding: 2rem;
  background: #fff;
  border: var(--grid-line-width) solid #000;
  outline: var(--grid-line-width) solid #000;
}

Fixed with parent padding

Adding the same padding to the grid parent brings the thick border lines back into alignment. One of the strengths of this method is that it does not matter how many elements the grid contains or whether they are evenly distributed.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.
A short video that shows the process described in this post.

We are getting a native solution: CSS Gap decorations

Thanks to Kevin Babbitt, Patrick Brosset, Sam Davis Omekara, Javier Contreras, and probably some other good people, Chrome and Edge 149 offer an exciting new CSS feature called CSS Gap decorations. It allows Grid and Flexbox containers to use the column-rule property to draw vertical lines in their gaps and the row-rule property to draw horizontal lines. Unlike borders or pseudo-elements, these rules are purely visual: they do not add elements, depend on individual grid items, or affect the layout. It is worth noting that the gap and *-rule width are independent of each other.

Gap decorations only draw inside the gaps, so they do not create an outer edge around the grid. To match the ruled appearance of the earlier examples, we still need to add a border to the grid container.

Using the new properties can give you much more control than the border + outline workaround. Rules can use different widths, styles, and colors across gaps, and properties such as rule-break, rule-inset, and rule-visibility-items control intersections, endpoints, and when lines appear. In browsers without support, the layout and its gaps remain intact but the decorations are not shown.

However, this is not a one-to-one replacement for the method described above. The border + outline method can achieve some results that CSS Gap decorations cannot, and vice versa. For example, in a three-column grid with an incomplete final row, the container border still encloses the unused part of that row, while the border + outline method follows only the items that are present. On the other hand, Gap decorations enable effects that were previously impossible or, at best, difficult to implement. The example below demonstrates some of these tradeoffs. This feature deserves its own post (which I might write later!).

gap-decorations.css
css
.gap-decorated-grid {
  --grid-line-width: 2px;

  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 2px;

  column-rule: var(--grid-line-width) solid #000;
  row-rule: var(--grid-line-width) solid #000;
  border: var(--grid-line-width) solid #000;

  /* rule-break: intersection; */
}

.gap-decorated-grid__item {
  background-color: #fff;
}

Native CSS gap decorations

The browser draws these rules inside the grid gaps without adding borders to the individual items. Try playing around with the settings to get to know the possibilities a bit better.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.

A popular approach: the background-color method

There is another straightforward way to create ruled lines without adding borders to the individual items. Give the grid container and its items different background-color values, then add a gap between the items. The container background shows through the gaps and appears to form the lines.

To continue the lines around the outside of the grid, add padding to the container equal to the gap width. A custom property can keep the gap and padding in sync. The background-color method is concise and works without experimental CSS, but it depends on every grid item having an opaque background. It also ties the line color to the container background and the line width to the gap.

That dependency can also be useful. Because the visible lines are really the container background, they can display gradients, images, or even animation. A moving graphic used as the container background will show through the gaps, creating the appearance of animated borders. You can try a simple version of this using the animated-background option in the example below.

background-grid.css
css
.background-grid {
  --grid-line-width: 2px;

  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--grid-line-width);
  padding: var(--grid-line-width);
  background-color: #000;
}

.background-grid__item {
  background-color: #fff;
}

The background-color method

The container's black background remains visible through the gaps and padding, creating lines between the white grid items and a matching border around the outside. Try turning on the animated background in the settings to see how the same technique can create moving borders.

The number 1 is unique because it is neither a prime number nor a composite number.
The number 2 is the smallest prime number and the only even prime.
The number 3 is often associated with balance and completeness, such as beginning, middle, and end.
The number 4 is the first composite number and is equal to .
The number 5 appears frequently in nature, including the five-point symmetry of many flowers and starfish.

Summary and further reading

There is no single best method for every ruled grid. The border + outline technique is dependable and flexible, the background-color method is concise and can create unusual visual effects, and CSS Gap decorations offer powerful native control where supported. As I am writing this, I do not have information on the availability of CSS Gap decorations in Firefox or Safari. The right choice depends on the layout, browser support, and the effect you need.

Further reading