zemirco
zemirco

Reputation: 16395

CSS grid - Creating a responsive generic dashboard containing cards of various widths

I'm trying to create a very generic dashboard. I have the Bootstrap breakpoints:

I have 3 different types of cards:

On the left and on the right side we have 20px padding.

The 4 column wide card can only be 4 columns wide when we actually have 4 columns. If we force the 4 column width on small screens it breaks the layout. On small screens we only have 1 column. On a tablet we might have only 2 columns. In those scenarios the 4 column card should be as large as possible but never larger than 4 columns.

The underlying question is: How can I specify the width for my cards and at the same time keep the responsive behavior? The challenge is not to specify fixed columns, e.g. grid-column: 1 / 3. I'm getting the cards from the backend as a flat array. Each card then tells me if it wants to be 1, 2, or 4 columns wide. The cards do not have a certain order and the order might also change.

I also have a demo at StackBlitz - https://stackblitz.com/edit/js-ryxler?file=style.css

My questions are:

  1. Is this the best way to solve my problem?
  2. Is there an option to do this without media queries?

body,
html {
  margin: 0;
}


/* 

  We're using the bootstrap breakpoints:
    - 576px
    - 768px
    - 992px
    - 1200px
    - 1400px

  We have 3 different types of cards:
    - 1 column wide
    - 2 columns wide
    - 4 columns wide

  On the left and on the right side we have 20px padding.

  The 2 column layout appears at 768px => 2*354px + 3*20px = 768px

  The 3 column layout appears at 992px => 3*304px + 4*20px = 992px

  The 4 column layout appears at 1200px => 4*275px + 5*20px = 1200px

  ! Problem:

  The 4 column wide card can only be 4 columns wide when we actually have 4 columns.
  If we force the 4 column width on small screens it breaks the layout.
  On small screens we only have 1 column.
  On a tablet we might have only 2 columns.
  In those scenarios the 4 column card should be as large as possible but never larger than 4 columns.

*/

.wrapper {
  padding: 20px;
  display: grid;
  grid-auto-flow: dense;
  grid-template-columns: repeat(auto-fill, minmax(354px, 1fr));
  grid-auto-rows: 250px;
  gap: 20px;
}

.blue {
  background-color: lightblue;
}

.coral {
  background-color: lightcoral;
  grid-row: span 2;
}

.salmon {
  background-color: lightsalmon;
}

.grid-column-2 {
  grid-column: span 1;
}

.grid-column-4 {
  grid-column: span 1;
}


/* 2 columns */

@media (min-width: 768px) {
  .grid-column-2 {
    grid-column: span 2;
  }
  .grid-column-4 {
    grid-column: span 2;
  }
}


/* 3 columns */

@media (min-width: 992px) {
  .wrapper {
    grid-template-columns: repeat(auto-fill, minmax(304px, 1fr));
  }
  .grid-column-4 {
    grid-column: span 3;
  }
}


/* 4 columns */

@media (min-width: 1200px) {
  .wrapper {
    grid-template-columns: repeat(auto-fill, minmax(275px, 1fr));
  }
  .grid-column-4 {
    grid-column: span 4;
  }
}
<div class="wrapper">
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
</div>

Thank you!

Upvotes: 1

Views: 269

Answers (1)

Charles Lavalard
Charles Lavalard

Reputation: 2321

You can't specify exact width on exact breakpoint without media query but you can remove some CSS property

For exemple

// This will make it take all the columns available
.grid-column-4 {
  grid-column: 1 / -1;
}

body,
html {
  margin: 0;
}

.wrapper {
  padding: 20px;
  display: grid;
  grid-auto-flow: dense;
  grid-template-columns: repeat(auto-fill, minmax(354px, 1fr));
  grid-auto-rows: 250px;
  grid-gap: 20px;
}

.blue {
  background-color: lightblue;
}

.coral {
  background-color: lightcoral;
}

.salmon {
  background-color: lightsalmon;
}

.grid-column-4 {
  grid-column: 1/-1;
  // I saw that you were initialising this value on every breakpoint
  // this will make it take all the columns available
}


/* 2 columns */

@media (min-width: 768px) {
  .grid-column-2 {
    grid-column: span 2;
  }
}


/* 3 columns */

@media (min-width: 992px) {
  .wrapper {
    grid-template-columns: repeat(auto-fill, minmax(304px, 1fr));
  }
}


/* 4 columns */

@media (min-width: 1200px) {
  .wrapper {
    grid-template-columns: repeat(auto-fill, minmax(275px, 1fr));
  }
  .grid-column-4 {
    grid-column: span 4;
  }
}
<div class="wrapper">
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
</div>


You could also use CSS variables to make it more modular

:root {
  --size: 354px;
}

body,
html {
  margin: 0;
}

.wrapper {
  padding: 20px;
  display: grid;
  grid-auto-flow: dense;
  grid-template-columns: repeat(auto-fill, minmax(var(--size), 1fr));
  grid-auto-rows: 250px;
  grid-gap: 20px;
}

.blue {
  background-color: lightblue;
}

.coral {
  background-color: lightcoral;
}

.salmon {
  background-color: lightsalmon;
}

.grid-column-4 {
  grid-column: 1/-1;
  // I saw that you were initialising this value on every breakpoint
  // this will make it take all the columns available
}


/* 2 columns */

@media (min-width: 768px) {
  .grid-column-2 {
    grid-column: span 2;
  }
}


/* 3 columns */

@media (min-width: 992px) {
   :root {
    --size: 304px;
  }
}


/* 4 columns */

@media (min-width: 1200px) {
   :root {
    --size: 275px;
  }
  .grid-column-4 {
    grid-column: span 4;
  }
}
<div class="wrapper">
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="salmon grid-column-2"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="coral grid-column-4"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="blue"></div>
  <div class="salmon grid-column-2"></div>
</div>

Upvotes: 1

Related Questions