Home > front end >  How to make smaller items setting rows themselves?
How to make smaller items setting rows themselves?

Time:03-08

I'm trying to create CSS classes that will allow me to store widgets' grid layout configuration in DB and to be dynamic.

My goal is to have reusable classes to auto position widgets according to order in HTML and size defined by a class. The problem is the small widget needs to have a defined row value in order to be placed correctly.

My goal is to achieve the following layout:

Expected layout

I created the following HTML and CSS:

<div >
  <div >1</div>
  <div >2</div>
  <div >3</div>
  <div >4</div>
  <div >5</div>
  <div >6</div>
  <div >7</div>
</div>
.widgets-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: auto;
  column-gap: 17px;
  row-gap: 15px;

  max-width: 100%;
  padding: 15px;

  .widgets-grid__widget {
    border-radius: 3px;
    box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.15);
    height: 200px;
    background-color: #ffffff;
    grid-column: span 4;
    grid-row: span 2;
  }

  .widgets-grid__widget:nth-child(odd) {
    grid-column: 1 / 3; // left column
  }

  .widgets-grid__widget:nth-child(even) {
    grid-column: 3 / 5; // right column
  }

  .widgets-grid__widget.widget--small {
    grid-column: 2 / 3;
    height: auto;

    // my hack
    &:nth-child(odd) {
      grid-row: 1; // manual positon :(
    }
    &:nth-child(even) {
      grid-row: 2; // manual positon :(
    }
  }

  .widgets-grid__widget.widget--medium {
    grid-column: 1 / 2;
  }
}

So if no additional class provided widget will have standard size 2x2. There are 2 other sizes: .widget--medium (1 col and 2 rows) and .widget--small (1 row and 1 col).

I created a hack to achieve my goal, but it won't work if I will have small widgets in 2'nd and 3'rd rows...

// my hack
&:nth-child(odd) {
  grid-row: 1; // manual position :(
}
&:nth-child(even) {
  grid-row: 2; // manual position :(
}

I tried also grid-row: auto but then widget 4 is broken.

Broken widget 4

Please advise!

Try on StackBlitz: https://stackblitz.com/edit/web-platform-5o8cxz

CodePudding user response:

One solution is to use grid-areas to define exactly where you want elements to go in the grid, and assign the appropriate grid-area to each class. See grid-areas docs here

Something like this:

.parent {
  height: 500px;
  width: 800px;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3,  1fr);
  grid-template-areas: "one two four" "one two five" "three two six";
}

.parent > * {
  background-color: gray;
  height: 100%;
  width: 100%;
}

.c1 {
  grid-area: one;
}

.c2 {
  grid-area: two;
}

.c3 {
  grid-area: three;
 }

.c4 {
  grid-area: four;
  
 }

.c5 {
  grid-area: five;
 }

.c6 {
  grid-area: six;
 }
<div >
   <div class='c1'></div>
   <div class='c2'></div>
   <div class='c3'></div>
   <div class='c4'></div>
   <div class='c5'></div>
   <div class='c6'></div>
</div>

CodePudding user response:

For your specific case, grid is trying to keep all the elements in document order, thus it is creating new rows in order to accommodate the extra space needed.

That is the default behavior of grid, but you can override this by setting the parent grid-container to have the following property:

grid-auto-flow: dense

This will allow grid items to be displayed in the first available open grid, and will allow them to be out of document order if your layout needs it.

Grid flow docs

A really great youtube content creator Kevin Powell can teach you all of the really handy, lesser known properties of flex and grid. Highly recommended to anyone trying to get better at webpage layouts:

Masonry Layout

  • Related