sasslinear-gradients

How to generate a bootstrap grid column overlay with SCSS?


I'm using bootstrap's 12-column grid layout and I'd like to make a "development helper" that overlays the grid columns & gutters so we can visualize the grid to help the non-developers on my team understand how the grid works in a real application.

I'm using SCSS to generate a linear-gradient with alternating stripes, and it's mostly working but something in the calculations is just slightly off.

Here is the relevant portion of my SCSS code

@function grid-stripes($column-color, $gutter-color: transparent) {
  $stripes: null;
  $col-width: percentage(divide(1, $grid-columns));

  @for $i from 1 through $grid-columns {
    //Columns
    $col-pos: calc((#{$col-width} * #{$i}) - #{$grid-gutter-width});
    $stripes:
      $stripes,
      $column-color $col-pos,
      $column-color $col-pos;

    //Gutters
    @if $i != $grid-columns {
      //Don't add a final gutter
      $gutter-pos: calc((#{$col-width} * #{$i}) - #{$grid-gutter-width});
      $stripes:
        $stripes,
        $gutter-color $gutter-pos,
        $gutter-color $gutter-pos;
    }
  }

  @return linear-gradient(to right, $stripes);
}

.row {
  position: relative;

  &::before {
    display: block;
    content: '';
    position: absolute;
    left: $grid-gutter-width / 2;
    right: $grid-gutter-width / 2;
    height: 100%;
    z-index: 1;
    opacity: 0.25;
    pointer-events: none; //allow clicks to pass through
    background: grid-stripes(red);
    background-size: cover;
  }
}

If I have this layout that uses the grid, I would want the overlay to show one red column on top of each grid column. On something that takes up 6 columns, I should see the 6 red columns

Instead, my overlay just isn't quite correct in terms of spacing the columns out with the gutters in between the columns, and it seems to fade between the transparent and red colors, where I just want a hard line to divide these


Here is a working demo of it so you can see the output generated by SCSS: https://codepen.io/FiniteLooper/pen/ZEgYrbP?editors=0100


Solution

  • Requirements

    I need to to always show 12 columns regardless of what it contains, this way you always see the grid in terms of what layout options are available to you

    Solution

    Pseudo element ::before

    To have your column visible, having a pseudo element is a good idea, this way you can stack it on top of your grid.

    A single column

    Using background-image: linear-gradient() with hard stops, you can highlight both the gutter (made with padding) and the content of the column.

              background: linear-gradient(to right, 
                black 0%, 
                black 0.5px, 
                rgba(255, 0, 0, 0.2) 0.5px, 
                rgba(255, 0, 0, 0.2) 0.75rem, 
                rgba(255, 255, 0, 0.2) 0.75rem, 
                rgba(255, 255, 0, 0.2) calc(100% - 0.75rem), 
                rgba(255, 0, 0, 0.2) calc(100% - 0.75rem), 
                rgba(255, 0, 0, 0.2) calc(100% - 0.5px), 
                black calc(100% - 0.5px)
              );
    

    Now you have the background-image for 1 column.

    All columns

    All you need to do now, is to repeat this gradient:

    background-size: calc(100% / 12);
    

    As you have twelve columns, you need to configure the gradient to take 1/12 of the total width. Then it will repeat.

    Code

    .visible-grid {
      .row {
        position: relative;
    
        &::before {
          display: block;
          content: '';
          position: absolute;
          height: 100%;
          z-index: 1;
          opacity: 0.25;
          pointer-events: none;
          left: 0;
          right: 0;
          background: linear-gradient(to right, 
            black 0%, 
            black 0.5px, 
            rgba(255, 0, 0, 0.2) 1px, 
            rgba(255, 0, 0, 0.2) 0.75rem, 
            rgba(255, 255, 0, 0.2) 0.75rem, 
            rgba(255, 255, 0, 0.2) calc(100% - 0.75rem), 
            rgba(255, 0, 0, 0.2) calc(100% - 0.75rem), 
            rgba(255, 0, 0, 0.2) calc(100% - 0.5px), 
            black calc(100% - 0.5px)
          );
          background-size: calc(100% / 12);
        }
      }
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet" />
    <main class="container mt-2 visible-grid">
      <button type="button" class="btn btn-primary" onclick="document.querySelector('main').classList.toggle('visible-grid')">Toggle Grid</button>
      <h3>Plain Columns</h3>
      <div class="row mt-2">
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 1</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 2</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 3</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 4</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 5</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 6</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 7</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 8</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 9</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 10</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 11</div>
        </div>
        <div class="col-1">
          <div style="height: 200px" class="bg-secondary text-white">col 12</div>
        </div>
      </div>
    
      <hr>
    
      <h2>Example Content</h2>
      <div class="row mt-2">
        <div class="col-6">
          <div class="card shadow">
            <div class="card-body">
              <h5 class="card-title">6 Columns</h5>
              <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
            </div>
          </div>
        </div>
        <div class="col-3">
          <div class="card shadow">
            <div class="card-body">
              <h5 class="card-title">3 Columns</h5>
              <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
            </div>
          </div>
        </div>
        <div class="col-3">
          <div class="card shadow">
            <div class="card-body">
              <h5 class="card-title">3 Columns</h5>
              <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
            </div>
          </div>
        </div>
    
      </div>
    </main>