How to set internal border lines on a CSS Grid layout

Greg Robleto

Most examples I see of CSSGrid layouts are blocks or cards stacked in different variations. I went looking for a solid example of just thin internal grid lines separating a sequence of elements, and couldn’t find what I wanted to see, so I built it. Just for fun, I populated this sample set with different Jedi and their lightsaber colors. The CodePen can be found here: CSS Grid Lines with Jedi Lightsabers

CSS Grid with Border Lines

The first key piece is setting up a grid container when the view-state is larger than mobile. This is done using the following code on a service-grid wrapper:

@media (min-width: 768px) {
.service-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr) ) ;
grid-gap: 0px;
}
}

The min size of 300px is arbitrary but works with the outer container that has a max-width of 1170px. The grid-gap is set to 0px because we want clean lines for the interior dividers balanced between grid cells, so there should be no extra gap space.

Also each item in the CSS Grid has the following code:

.service-item {
padding: 3rem;
text-align: center;
border-top: 1px solid #dfdfdf;
}
@media (min-width: 768px) {
.service-item {
border-top: 1px solid #dfdfdf;
border-left: 1px solid #dfdfdf;
}
}

That provides in the a default border on the top in all cases and adds a border on the left starting post-mobile for tablet and desktop rendering.

Omitting the Outer Borders for Tablet

The above result has an imbalance of the left-most grid items having a left border but the right-most items not having a right border. Similarly, the top row has a top border, but there is no bottom border. What we want is only internal borders, no external, so those left-border on the left and top-borders on the top have to go.

To do this, we need to do some manipulation of the grid using the :nth-child pseudo-class. Starting with these classes for the two-column post-mobile / tablet view

@media (min-width: 768px) {
.service-item {
border-top: 1px solid #dfdfdf;
border-left: 1px solid #dfdfdf;
&:nth-child(-n+2) {
border-top: none;
}
&:nth-child(odd) {
border-left: none;
}
}
}

These nth-child lines of code remove the top-border across the first two cells. At this width, the maximum number of rows is two, so the external top border is now removed. To remove the external left border, we can use the nth-child(odd) capability to pull the border off the first, third, fifth columns which all happen to be the left-side columns. This completes the look we’re going for in tablet view.

Omitting the Outer Borders for Desktop

For the three-column desktop view, we need to correct for the tablet styles we just added and then add the necessary nth-child parameters for three column format. The resulting code is:

@media (min-width: 992px) {
.service-item {
border-top: 1px solid #dfdfdf;
border-left: 1px solid #dfdfdf;
&:nth-child(-n+2) {
border-top: 1px solid #dfdfdf;
}
&:nth-child(odd) {
border-left: 1px solid #dfdfdf;
}
&:nth-child(-n+3) {
border-top: none;
}
&:first-child,
&:nth-child(3n+1) {
border-left: none;
}
}
}

We start by resetting the border-top and left everywhere. Then we specifically return the borders removed in tablet view above. This may be excessive, but I wanted this re-set so we weren’t inheriting any border removing from the previous media query. At this point we can being focusing on what’s needed to remove the external borders on 3-column desktop view.

First, we remove the top borders for the first three cells using the nth-child(-n+3) equation. Then we removed every third cells left border (starting with the 4th) using the nth-child(3n+1). Finally, we circle back and pull the left border off that first cell by calling first-child. This completes the look we’re going for in desktop view.

Setting the lightsabers with SCSS

This exercise was primarily to determine the needed code for the internal-bordered grid, but while setting up a series of items to pattern, I went into the SCSS partial and set up the following variables, mixin and code.

$red: #ff093c;
$blue: #21bbeb;
$purple: #af4ba4;
$green: #1dc887;
@mixin lightsaber($color) {
background-color: lighten( $color, 20% );
border: solid 3px $color;
border-radius: 5px;
}

This sets the four colors variables for lightsabers. The mixin sets that color variable as the outer-border for the lightsaber element and adjusts the actual element background color to 20% lighter.

Finally, the lightsabers are not there own element in the HTML code. These are created completely with CSS using a pseudo :after effect on the name in the h3 tag, as seen here:

h3 {
&:after {
margin: 12px auto 0;
width: 125px;
height: 5px;
background-color: #333;
display: block;
content: “”;
}
}
h3.red:after { @include lightsaber($red)}
h3.green:after { @include lightsaber($green)}
h3.purple:after { @include lightsaber($purple)}
h3.blue:after { @include lightsaber($blue)}

That’s about it

The net result, beyond having now a handy reference for remembering lightsaber colors, is this provides a working prototype for seeing how to set in internal-borders using only HTML and CSS Grid. Again, if you want to view the full pen on CodePen, you can find it here: CSS Grid Lines with Jedi Lightsabers

Greg Robleto

Written by

Product Design and Development Lead at The Motley Fool writing mostly about design and front-end development. Thx for reading.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade