85

Given the current CSS grid example, how can I collapse the borders in order to avoid the double borders ?

This is such a simple thing to achieve using an Html table. How do I do it using display: grid ?

.wrapper {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
  border: 1px solid black;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
klugjo
  • 19,422
  • 8
  • 57
  • 75

10 Answers10

88

Instead of using an actual border around grid items, use the background color on the container (for "border" color) and the grid-gap property (for "border" width).

.wrapper {
  display: inline-grid;
  grid-template-columns: 50px 50px 50px 50px;
  border: 1px solid black;
  grid-gap: 1px;
  background-color: black;
}

.wrapper > div {
  background-color: white;
  padding: 15px;
  text-align: center;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
78

You may do like this :

.wrapper {
  display: inline-grid;
  grid-template-columns: 50px 50px 50px 50px;
  border-bottom: 1px solid black;
  border-left: 1px solid black;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
  border-top: 1px solid black;
  border-right: 1px solid black;
}

body {
 background:pink;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>

Another idea is to rely on gradient to fill gaps like below:

.wrapper {
  display: inline-grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-gap:1px;
  background:
    linear-gradient(#000,#000) center/100% 1px no-repeat,
    repeating-linear-gradient(to right,transparent 0 50px,#000 0 51px);
  border:1px solid;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
}

body {
 background:pink;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>

You can also adjust the initial solution to make it more flexible and it will work with any number of items inside a row.

Run the below code on full page and resize the window:

.wrapper {
  display: grid;
  max-width:800px;
  grid-template-columns: repeat(auto-fill,minmax(100px,1fr));
  border-top: 1px solid black;
  border-left: 1px solid black;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
  border-bottom: 1px solid black;
  border-right: 1px solid black;
}

body {
 background:pink;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
  <div>10</div>
  <div>11</div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • This answer works better with non solid lines and semi-transparant borders. However, cell items are 49px here which can be a bit of nuisance. That's easily fixable. – René Dec 19 '17 at 09:26
  • 3
    It makes more sense if the container has border top, that way if there is only 6 items in the grid the grid won't have a random line. – GeorgeButter Aug 15 '19 at 05:10
  • 1
    This is the real asnwer! It even works with wrapping content – Hairi Dec 15 '21 at 09:30
  • This solution works well, with one drawback: the elements themselves change width upon resizing. That makes it not so suitable for building a mobile responsive paginator, where I want all the elements to be perfectly square, at all times. – Jay Feb 11 '23 at 14:54
  • @Jay https://stackoverflow.com/a/68073761/8620333 / https://stackoverflow.com/a/54927248/8620333 – Temani Afif Feb 11 '23 at 14:58
  • Thanks for the suggestions. But there's a pre-defined number of columns, and I'd like to keep those dynamic. It seems that it can't be done with pure css: https://stackoverflow.com/questions/55073259/style-only-first-item-in-each-flexbox-row. – Jay Feb 11 '23 at 15:05
31

I found a solution by using the outline property.

.grid {
 width: 100%;
 height: 700px;
 display: grid;
 grid-template-columns: repeat(4, 25fr);
 grid-template-rows: repeat(4, 25fr);
 margin-bottom: 30px;
 grid-gap: 1px;
}

.grid-item {
 background-color: silver;
 outline: 1px solid gray; /* The outline creates the border */
 text-align: center;
 position: relative;
 z-index: 1; /* original z-index */
}

/* If you want to change the color on the hover state */
.grid-item:hover {
 outline: 1px solid red;
 z-index: 2; /* You must apply a z-index bigger than the original z-index or else some parts of the outline will be behind other grid elements */
}
<div class="grid">
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
</div>
EoghanM
  • 25,161
  • 23
  • 90
  • 123
24

.wrapper {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
  border: 1px solid black;
  margin:0 -1px -1px 0;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>
margin:0 -1px -1px 0; 

This should do the trick.

Krzysztof Mazur
  • 568
  • 2
  • 13
  • 2
    Kind of hacky but at least it does the trick. Can't believe there isn't an easier way to do this. I might as well build my grid with flexbox .. – klugjo Dec 19 '17 at 08:51
14

There is an easy way to do this:

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

.grid__item {
  border: 1px solid gray;
  box-sizing: content-box;
  width: 100%;
  height: 100%;
}
<div class="grid">
  <div class="grid__item">1</div>
  <div class="grid__item">2</div>
  <div class="grid__item">3</div>
  <div class="grid__item">4</div>
  <div class="grid__item">5</div>
  <div class="grid__item">6</div>
  <div class="grid__item">7</div>
  <div class="grid__item">8</div>
  <div class="grid__item">9</div>
  <div class="grid__item">10</div>
  <div class="grid__item">11</div>
  <div class="grid__item">12</div>
</div>

P.s. The main trick here is in box-sizing: content-box. You don't need it if you do not globally override it with another value. But many people uses border-box, in that case, this override solves the problem with the gap.

Niklan
  • 401
  • 4
  • 9
4

Something I've used with success is simply adding a box shadow to the grid items, along with a column and row gap. This then allows the columns size to always be exactly as determined in grid-template-columns. Then simply changing the column and row gap and box shadow size allows for a thicker border.

.wrapper {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-column-gap: 1px;
  grid-row-gap: 1px;
}
.wrapper > div {
  padding: 15px;
  text-align: center;
  box-shadow: 0 0 0 1px;
}
<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>
dan richardson
  • 3,871
  • 4
  • 31
  • 38
  • works great if you only want top & bottom border and left & right no border. grid: `row-gap: 1px` items: `box-shadow: 0 1px black, 0 -1px black;` – mfgmicha Jul 05 '21 at 11:39
0

For anyone who will struggle with an odd number of elements and a specific amount of frames you can use the following approach

<style>
  .wrapper {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    border: 1px solid;
    grid-gap: 1px;
  }

  .element {
    display: flex;
    flex-direction: column;
    background-color: azure;
    min-height: 10rem;
    border: 1px solid;
    margin: -1px;
  }
</style>

<body>
  <div class="wrapper">
    <div class="element"></div>
    <div class="element"></div>
    <div class="element"></div>
    <div class="element"></div>
    <div class="element"></div>
    <div class="element"></div>
  </div>
</body>

https://codepen.io/sergeytkhojevskiy/pen/XWZOJOL

urDMG
  • 428
  • 1
  • 6
  • 14
0

If your grid has the same number of items for rows and columns, with the same size (think of a tic tac toe game), then you can put half the border around the containing div (the one you add the grid style to) and the other half on every internal container, that will make them all have effectively just the normal border width.

TheYuriG
  • 134
  • 1
  • 9
-1

The win-win code would be to set

  • grid items: border-bottom & border-right
  • grid wrapper: border-top & border-left

So it would correct even if top columns not equal to bottom columns

.wrapper {
  display: inline-grid;
  grid-template-columns: 50px 50px 50px 50px;
  border-top: 1px solid black;
  border-left: 1px solid black;
}

.wrapper > div {
  padding: 15px;
  text-align: center;
  border-bottom: 1px solid black;
  border-right: 1px solid black;
}

<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
</div>
okater
  • 7
  • 2
-1

If you will fix the number of item per row this solution will fit you,

this example for 3 each row, but you can edit

.grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr;
  gap: 0;
  grid-template-areas: '. . .';
}

.grid-item {
  order: 0;
  flex: 0 1 auto;
  text-align: center;
  padding: 1rem;
  font-size: 12px;
  background-color: #e8e8e8;
  border-color: #000;
  border-style: solid;
  border-width: 0;

  border-right-width: 1px;
  border-bottom-width: 1px;
}

/*first 3 items*/
  .grid-item:nth-child(-n + 3) {
    border-top-width: 1px;
  }

/*last item on each row*/
  .grid-item:nth-child(3n + 0) {
    border-right-width: 1px;
    background-color: cadetblue;
  }
  
/*first item on each row*/

.grid-item:first-child,
  .grid-item:nth-child(3n + 1) {
    border-left-width: 1px;
    background-color: red;
  }
  
/*middel item on each row (not used)*/
  .grid-item:nth-child(3n - 1) {
   // border-left-width: 1px;
   background-color: yellow;
  }

/*last item (not used)*/
  .grid-item:last-child {
   // border-left-width: 0;
    background-color: green
    }
<div class="grid-container">

<div class="grid-item"> 1 </div>

<div class="grid-item"> 2 </div>

<div class="grid-item"> 3 </div>

<div class="grid-item"> 1 </div>

<div class="grid-item"> 2 </div>

<div class="grid-item"> 3 </div>

<div class="grid-item"> 1 </div>

<div class="grid-item"> 2 </div>


</div>
Mansour Alnasser
  • 4,446
  • 5
  • 40
  • 51