Preventing double borders in CSS Grid
Asked Answered
V

10

95

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>
Vilipend answered 19/12, 2017 at 8:38 Comment(0)
D
84

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>
Dosser answered 19/12, 2017 at 8:54 Comment(7)
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.Diagraph
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.Leena
This is the real asnwer! It even works with wrapping contentAgenesis
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.Coinsure
@Coinsure https://mcmap.net/q/37303/-setting-element-width-based-on-height-via-css / https://mcmap.net/q/224990/-css-grid-square-layout-duplicateDosser
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: #55073759.Coinsure
It doesnt work if you have to move first item to match week day for example if you use calendarZygophyllaceous
M
97

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>
Mondrian answered 19/12, 2017 at 12:35 Comment(6)
@pttsky you can change the opacity of the whole div.Westlund
It does not work, there are different border widths.Topside
If cells have different border sizes/colors this does not work.Ralline
A complement to this idea is to use an "outline" property on each tile.Babbage
I am noticing slight variations in the gap, maybe it's not always respected to a good accuracy.Twenty
This is so funny, it was the only way to get non-embossed borders on tables back in 2000Dickens
D
84

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>
Dosser answered 19/12, 2017 at 8:54 Comment(7)
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.Diagraph
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.Leena
This is the real asnwer! It even works with wrapping contentAgenesis
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.Coinsure
@Coinsure https://mcmap.net/q/37303/-setting-element-width-based-on-height-via-css / https://mcmap.net/q/224990/-css-grid-square-layout-duplicateDosser
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: #55073759.Coinsure
It doesnt work if you have to move first item to match week day for example if you use calendarZygophyllaceous
J
38

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>
Jacobinism answered 19/7, 2018 at 14:23 Comment(1)
You just need to add a .grid { grid-gap: 1px; } to fix the superposition of elements.Joejoeann
N
28

.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.

Neonate answered 19/12, 2017 at 8:44 Comment(1)
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 ..Vilipend
A
15

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.

Actinometer answered 8/10, 2019 at 11:10 Comment(0)
C
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>
Crocidolite answered 23/1, 2019 at 12:45 Comment(1)
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;Lactalbumin
P
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

Phenomenology answered 14/6, 2022 at 10:43 Comment(0)
N
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.

Northamptonshire answered 13/7, 2023 at 9:14 Comment(0)
B
-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>
Buddha answered 4/2, 2019 at 18:22 Comment(0)
W
-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>
Wald answered 12/5, 2021 at 15:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.