0

I'm working on dynamic dashboard widgets using drag and drop, and I've experienced a problem where the height of the largest element creates spaces between lines.

enter image description here

I have added a sample code. Please have a look at it and add your suggestions.

JS Fiddle Link - https://jsfiddle.net/atj393/6azv0L4j/

<section class="test-section">
  <div class="test-div" style="display: inline-block;height: 50px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 100px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 150px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 200px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 250px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 300px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 350px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 400px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 450px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;height: 500px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
</section>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Alexis
  • 816
  • 2
  • 11
  • 28
  • for who is trying to reopen the question, take the time to read *all* the duplicate. The below CSS grid solution is also there among all the other possible solutions – Temani Afif Jul 09 '20 at 14:39

2 Answers2

2

use CSS Grid where each grid item spans one more row then the previous grid item

.test-section {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-gap: 4px;
  grid-auto-rows: 50px;
}

.test-div {
  border: 2px solid #000000;
}

.test-div:nth-of-type(2) {
  grid-row: span 2;
}

.test-div:nth-of-type(3) {
  grid-row: span 3;
}

.test-div:nth-of-type(4) {
  grid-row: span 4;
}

.test-div:nth-of-type(5) {
  grid-row: span 5;
}

.test-div:nth-of-type(6) {
  grid-row: span 6;
}

.test-div:nth-of-type(7) {
  grid-row: span 7;
}

.test-div:nth-of-type(8) {
  grid-row: span 8;
}

.test-div:nth-of-type(9) {
  grid-row: span 9;
}

.test-div:nth-of-type(10) {
  grid-row: span 10;
}
<section class="test-section">
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
</section>

Instead of manually setting the grid-row property on each grid item, you can use javascript

const gridContainer = document.querySelector('.test-section');
let counter = 1;

[...gridContainer.children].forEach(gridItem => {
  gridItem.style.gridRow = 'span ' + counter;
  counter++;
});
.test-section {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-gap: 4px;
  grid-auto-rows: 50px;
}

.test-div {
  border: 2px solid #000000;
}
<section class="test-section">
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
</section>

This solution will work even if the height of the grid items increase or decrease in some random order. For example, if grid items are in following height order:

[50, 100, 75, 25, 50, 100, 75, 25]

With javascript, you can get the minimum height among the grid items and then make each grid item span number of rows equal to the following formula

height of grid item / min height

const gridContainer = document.querySelector('.test-section');
const heights = [50, 100, 75, 25, 50, 100, 75, 25];
const minHeight = Math.min(...heights);

[...gridContainer.children].forEach((gridItem, idx) => {
  gridItem.style.gridRow = 'span ' + (heights[idx] / minHeight);
});
.test-section {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  grid-gap: 4px;
  grid-auto-rows: 50px;
}

.test-div {
  border: 2px solid #000000;
}
<section class="test-section">
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
  <div class="test-div"></div>
</section>
Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • 1
    Just as complement to this answer, you can achieve the same result with a vertical (column) flex box. – E. Zacarias Jul 09 '20 at 14:27
  • @Yousaf, I think this will solve the problem. Let me try this with my code. But, will it work if the height of the div not only increasing but different like, 50, 100, 75, 25,... like that? Thank you. – Alexis Jul 09 '20 at 14:30
  • 1
    @AlexisToby yes, it will work. See the last code snippet in updated answer – Yousaf Jul 09 '20 at 14:53
  • @Yousaf but the alignment collapses as the width varies. https://jsfiddle.net/atj393/96kjprg8/ – Alexis Jul 09 '20 at 15:05
  • 1
    @AlexisToby `div` elements with different widths and heights won't fit together like you want. Unless you want `div` elements to overlap, there will be gaps in between them. – Yousaf Jul 09 '20 at 15:56
  • Yes @Yousaf you are right, I have tried different scenarios, either of the dimension we need to fix for achieving this. Thank you. – Alexis Jul 10 '20 at 08:38
1

You can use flexbox:

.test-section {
  display: flex;
  flex-wrap: wrap;
  flex: 1 1 auto;
}
<section class="test-section">
  <div class="test-div" style="display: inline-block;min-height: 50px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 100px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 150px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 200px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 250px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 300px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 350px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 400px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 450px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
  <div class="test-div" style="display: inline-block;min-height: 500px;border: 2px solid #000000;margin: 4px;">AAAAAAAAAAAAAAAAAAA</div>
</section>
SLePort
  • 15,211
  • 3
  • 34
  • 44
  • thanks for your reply. Yes, I have tried this, but then the height will be equally distributed for all the elements. – Alexis Jul 09 '20 at 14:19
  • 1
    It was not clear how you wanted to fill the gap. Just be careful of the [support of css grids](https://caniuse.com/#feat=css-grid) in browsers. – SLePort Jul 09 '20 at 14:48