6

Is there a way to fill a given container with an arbitrary number of square, identically-sized children (as few as five and as many as 50) so that the children:

  1. fill the container leaving as little vertical and horizontal space as possible; and
  2. do not overflow the container?

For example, imagine a box of 17 circular avatars that have each been scaled up until any further size increase will cause them to wrap and flow beyond the bottom of the container.

I know that I can use JS to calculate the optimal scale of the children to fill the container, but I feel like either flex or grid has this functionality built in.

This is about as close as I have gotten:

.container {
    border: 1px solid tomato;
    display: flex;
    flex-wrap: wrap;
    gap: 1vw;
    height: 100vh;
    justify-content: center;
    width: 100vw;
}

.container > div {
    background-color: coral;
    flex: 0 0 12%;
    margin: .5em;
}

.container .div::before {
    content: '';
    display: block;
    padding-top: 100%;
}
    <div class="container">
        <!-- 32 children -->
        <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
        <div></div><div></div>
    </div>

Apologies if this is a duplicate. I've done my honest best to seek the answer before asking.


[EDIT: adding detail]

Here's the desired result showing a box with a FIXED size and items sized until the container is completely filled. If the box were a different size than this or there were a different number of items inside, the items would scale until they each fit inside without overflowing. The alignment of the two orphans at the end is unimportant, but they must be the same size as the rest of the items.

Desired result

Andrew
  • 14,204
  • 15
  • 60
  • 104
  • 1
    Neither of these have such functionality. Javascript is the best option here. – Paulie_D Oct 16 '20 at 19:22
  • 1
    Css cannot calculate the size of the children without a specific number being known or the dimensions of the parent being calculated. This is why Javascript is required. – Paulie_D Oct 16 '20 at 19:26
  • 1
    can you give illustrate how the fill should occur? it seems that you are looking for flex-grow that already do this perfectly (in addition to the default stretch alignment) – Temani Afif Oct 16 '20 at 19:29
  • @TemaniAfif : I updated the question with an image showing the desired result. – Andrew Oct 17 '20 at 03:16

3 Answers3

0

This is (sort of) possible to achieve with flex. You can make sure the gaps between each column are even with the space-evenly property on justify-content. However, to get the rows to have the same gap between them as the columns is not possible without javascript. Instead, you'll have to manually define a row gap via row-gap.

.flex-container {
  width: 300px;
  
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  row-gap: 8px; /* Issue on this line */
  
  background-color: blue;
}

.flex-item {
  padding: 30px;
  background-color: red;
}
<div class="flex-container wrap">
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
  <div class="flex-item">1</div>
</div>

As a side note, this is definitely not possible to do in grid due to the fact that you cannot have implicit size definitions in template-columns. I.e. the following will not work:

grid-template-columns: repeat(auto-fit, minmax(max-content, 1fr))
Dylan Kerler
  • 2,007
  • 1
  • 8
  • 23
  • How about `repeat(auto-fit, fit-content(100%))`? – connexo Oct 18 '20 at 15:05
  • in your case the height of the container is based on the element size which is the opposite of what asked here. The element need to have their size dynamic based on the container size – Temani Afif Oct 18 '20 at 16:21
0

It seems the only way to do this is with Javascript.

I at first thought of using CSS tables to do this, but you need to determine how much lines exist manually, so that wasn't an option. But if you do want to do it that way, this JSFiddle will be of help.

Also, defining the values manually (eg. 4em) like in @ThomasRyan's answer will not be of help because you need to mind different container sizes (If you want to make the container width 10px instead of 100vw).

Here we simply generate the child count, then get the width and height by dividing the container width/height by the child count, adding 10px to mind margin.

var container = document.querySelector('.container');
var childCount = random(5, 50);

var childHeight = container.clientHeight / childCount + 10;
var childWidth = container.clientWidth / childCount + 10;

for (var i = 0; i < childCount; i++) {
  container.innerHTML += '<div style="height:' + childHeight + 'px;width:' + childWidth + 'px"></div>';
}

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}
body {
  margin: 0;
}

.container {
  display: flex;
  flex-wrap: wrap;
  height: 100vh;
  width: 100vw;
  justify-content: center;
  align-items: center;
}

.container > div {
  background-color: coral;
  margin: 10px;
}
<div class="container"></div>
benhatsor
  • 1,863
  • 6
  • 20
-1

Is this what you want

.container {
    border: 1px solid tomato;
    display: flex;
    flex-wrap: wrap;
    gap: 1vw;
    height: 100vh;
    justify-content: center;
    width: 100vw;
}

.container > div {
    background-color: coral;
    flex: 0 0 4em;
    
    margin: .5em;
}

.container .div::before {
    content: '';
    display: block;
    padding-top: 100%;
}
    <div class="container">
        <!-- 32 children -->
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
Nbody
  • 1,168
  • 7
  • 33
  • What if he wants to make the container width `10px` instead of `100vw`, for example? Will he have to calculate the values manually? – benhatsor Oct 18 '20 at 14:50