Grid with flex fallback

by batcave

HTML

<div class="main">
  <div class="main__actions">
    <button class="button js-button" data-amount="2" data-class="cards--two">two</button>
    <!--<button class="button js-button" data-amount="3" data-class="cards--three">three</button>-->
    <button class="button js-button" data-amount="4" data-class="cards--four">four</button>
    <div class="main__currently-showing">Currently showing: <span class="main__number">4</span></div>
  </div>
  <div class="cards cards--four">
    <div class="product-card">1</div>
    <div class="product-card">2</div>
    <div class="product-card">3</div>
    <div class="product-card">4</div>
    <div class="product-card">5</div>
    <div class="product-card">6</div>
    <div class="product-card">7</div>
    <div class="product-card">8</div>
    <div class="product-card">9</div>
    <div class="product-card">10</div>
    <div class="card--filler"></div>
    <div class="card--filler"></div>
    <div class="card--filler"></div>
  </div>
</div>

SCSS

/* general */

* {
  box-sizing: border-box;
}

body {
  padding: 1rem;
}

.main {
  max-width: 81.25rem;
  margin: 1rem auto;
}

.main__actions {
  display: flex;
  align-items: center;
  margin-bottom: 2rem;
}

.main__currently-showing {
  padding: 0 2rem;
}

.button {
  display: inline-block;
  padding: .5rem;
  min-width: 10rem;
  border: none;
  background-color: #dddddd;
  border-radius: 4px;
  margin-right: 1rem;
}

/* cards */

$card-width: 19.375rem;

.cards {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -0.5rem;
  
  @supports (grid-gap: 1rem) {
    display: grid;
    grid-gap: 1.25rem;
    margin: 0;
  }
}

.cards--two {
  grid-template-columns: 1fr;

  @media (min-width: 767px) {
    grid-template-columns: repeat(2, minmax(calc(364px - 1.25rem), 1fr));
  }
}

.cards--four {
  grid-template-columns: repeat(auto-fill, minmax($card-width, 1fr));
}

.cards > * {
  flex-grow: 1;
  flex-shrink: 1;
  margin: calc(1.25rem / 2);
  
  @supports (grid-gap: 1rem) {
    margin: 0;
  }
}

.cards--two > * {
  flex-basis: 100%;
  
  @media (min-width: 767px) {
    flex-basis: calc(50% - 1.25rem);
  }
}

.cards--four > * {
  flex-basis: calc($card-width - 1.25rem);
}

.card--filler {
  height: 0;
  flex: 1 1 19.375rem;
  flex-grow: 1;
  flex-shrink: 1;
  margin: 0 0.5rem;
  
  @supports (grid-gap: 1rem) {
    display: none;
  }
}

/* product card */

.product-card {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  background-color: #ededed;
  padding: 1rem;
  height: 10rem;
}

JavaScript

const buttons = document.querySelectorAll('.js-button')

buttons.forEach(button => {
  button.addEventListener('click', function(e) {
    const number = document.querySelector('.main__number')
    const classesToRemove = ['cards--two', 'cards--four']
    const classToAdd = this.getAttribute('data-class')
    const cards = document.querySelector('.cards')

    number.innerHTML = this.getAttribute('data-amount')

    classesToRemove.forEach(item => {
      cards.classList.remove(item)
    })

    cards.classList.add(classToAdd)
  })
})