Search code examples
csscss-gridgrid-layout

Add space before and after first and last grid items


My question is identical to this question, but the given solution does not work.

Here is a codepen of what I'm working with.

I've tried two different approaches, both of which are almost correct but not quite:

1. Applying ::before and ::after psuedo classes to first and last grid items

Unfortunately when I add margin-left and margin-right properties to the first and last grid item respectively, it adds the space to the grid items as if it were padding space and not margin space, otherwise this works fine.

2. Applying ::before and ::after psuedo classes to grid container

It will not allow me to manipulate the width of ::before. For some reason the width property of ::before does not take effect. Notably, it seems as if the value of its width is the same width value as any given grid item.

I noticed another peculiarity, which is ultimately irrelevant, with this approach too. If I apply a width to ::after, grid-gap also gets applied as if it is inserting an invisible grid item.

:root {
  --gap: 25px;
}

body {
  width: 100vw;
  overflow-x: hidden;
  margin: 0
}

#c {
  width: 100%;
  height: 50px;
  overflow-x: auto;
  display: grid;
  grid-gap: 20px;
  grid-auto-flow: column;
  grid-auto-columns: calc(calc(100% - calc(var(--gap) * 2)) / 1.5);
  border: solid red 1px;
}

/* second approach */
#c::before {
  content: '';
  width: var(--gap);
}

#c::after {
  content: '';
  width: 1px; /* works out to about 25px or var(--gap) */
}

.i {
  width: 100%;
  height: 25px;
}

/* first approach */
/*
.i:first-child::before {
  content: '';
  margin-left: var(--gap);
}

.i:last-child::after {
  content: '';
  margin-right: var(--gap);
}
*/

.i:nth-child(odd) {
  background: skyblue;
}

.i:nth-child(even) {
  background: pink;
}
<div id='c'>
  <div class='i'>1</div>
  <div class='i'>2</div>
  <div class='i'>3</div>
  <div class='i'>4</div>
  <div class='i'>5</div>
  <div class='i'>6</div>
  <div class='i'>7</div>
  <div class='i'>8</div>
  <div class='i'>9</div>
  <div class='i'>10</div>
  <div class='i'>11</div>
  <div class='i'>12</div>
  <div class='i'>13</div>
  <div class='i'>14</div>
  <div class='i'>15</div>
  <div class='i'>16</div>
  <div class='i'>17</div>
  <div class='i'>18</div>
  <div class='i'>19</div>
  <div class='i'>20</div>
  <div class='i'>21</div>
  <div class='i'>22</div>
  <div class='i'>23</div>
  <div class='i'>24</div>
</div>

Does anybody have any idea why this stuff is happening?

How can I change the width of ::before?


Solution

  • One idea to change the width of before is to define a column template like below that will force the width of the first element only then the other will follow the grid-auto-columns. Basically we define an explicit grid with 1 column then the browser will add more column as needed to create the implicit grid:

    :root {
      --gap: 25px;
    }
    
    body {
      width: 100vw;
      overflow-x: hidden;
      margin: 0
    }
    
    #c {
      width: 100%;
      height: 50px;
      overflow-x: auto;
      display: grid;
      grid-gap: 20px;
      grid-template-columns:1px;
      grid-auto-flow: column;
      grid-auto-columns: calc(calc(100% - calc(var(--gap) * 2)) / 1.5);
      border: solid red 1px;
    }
    
    /* second approach */
    #c::before {
      content: '';
    }
    
    #c::after {
      content: '';
      width: 1px; /* works out to about 25px or var(--gap) */
    }
    
    .i {
      /*width: 100%; not needed*/
      height: 25px;
      /*display: inline-block; not needed*/
    }
    
    .i:nth-child(odd) {
      background: skyblue;
    }
    
    .i:nth-child(even) {
      background: pink;
    }
    <div id='c'>
      <div class='i'>1</div>
      <div class='i'>2</div>
      <div class='i'>3</div>
      <div class='i'>4</div>
      <div class='i'>5</div>
      <div class='i'>6</div>
      <div class='i'>7</div>
      <div class='i'>8</div>
      <div class='i'>9</div>
      <div class='i'>10</div>
      <div class='i'>11</div>
      <div class='i'>12</div>
      <div class='i'>13</div>
      <div class='i'>14</div>
      <div class='i'>15</div>
      <div class='i'>16</div>
      <div class='i'>17</div>
      <div class='i'>18</div>
      <div class='i'>19</div>
      <div class='i'>20</div>
      <div class='i'>21</div>
      <div class='i'>22</div>
      <div class='i'>23</div>
      <div class='i'>24</div>
    </div>