I have a number of tiles, all the same, static width and height inside some container. The width of the container is dynamic. The number of tiles is dynamic. I need the tiles to "wrap" such that as many as possible fit on each row but a new row is created when the number of tiles fills up the width of the container. A full row of tiles should be centered. A row of tiles that is not full should be left aligned with a full row (or positioned as if it was full and centered). See the diagram below.
In this diagram, the green represents the container, the black represents the tiles.
I can get close by making the tiles inline-block
and using text-align: center
on the container. However, that comes out like the following instead:
Here's a code sample. I am able to make necessary changes to the HTML.
.container {
border: 5px solid #0f0;
width: 250px;
text-align: center;
}
.tile {
margin: 3px;
display: inline-block;
border: 5px solid #000;
width: 50px;
height: 40px;
}
<div class="container">
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
There is a way to do it with the CSS Grid Layout. One has to put the following properties to the parent element, which is the .container
element in this scenario:
display: grid;
grid-template-columns: repeat(auto-fill, 60px);
grid-gap: 10px;
justify-content: center;
I've tried a lot to make this work, but in the end I was only successful with the CSS Grid Layout which I used for the first time here. I bet there are more readers that aren't very familiar with the above properties so I will add one or two lines of explanation for each.
display: grid;
There's not much to say about this, apart from the limitations in browser support.
grid-template-columns: repeat(auto-fill, 60px);
The grid-template-columns CSS property defines the line names and track sizing functions of the grid columns.
This property is a bit more complicated as there are many different options for its value. Here we use the repeat() function which requires the number of columns as first argument and the width of each column cell as second argument. Fortunately, it's possible to define a variable column number by using auto-fill
. The width of 60px
is the width of the .tile
(50px for the width and 10px for the border).
grid-gap: 10px;
The grid-gap CSS property is a shorthand property for grid-row-gap and grid-column-gap specifying the gutters between grid rows and columns.
To define different gap widths for columns and rows you can use grid-gap: 5px 10px;
where the first value is for the row-gap. I randomly selected 10px
for this example.
justify-content: center;
Finally let's tell the browser to center the content of our container (the grid) if there is space around. This property is not related to the CSS Grid Layout. It is usually used in flexbox scenarios but works like a charm here as well.
I added the described four properties to the .container
and removed the margin as well as the width from the .tile
. Solution tested in Firefox 52 and Chrome 57.
.container {
border: 5px solid #0f0;
width: 250px;
display: grid;
grid-template-columns: repeat(auto-fill, 60px);
grid-gap: 10px;
justify-content: center;
}
.tile {
display: inline-block;
border: 5px solid #000;
height: 40px;
}
<div class="container">
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
In the FF developer console (F12) there is a built-in grid highlighter that allows easy debugging of the defined grid:
You could use flexbox, but if the last row doesn't have enough elements you'll have a similar issue as with inline-block.
You can use :before and :after to fill out the last row, but if more than 2 elements are missing from the last row it won't help entirely.
div {
display: flex;
align-items: stretch;
justify-content: center;
flex-wrap: wrap;
}
div > * {
margin: 1rem;
}
div::before,
div::after {
background: red; /* For demo only */
display: block;
content: "";
width: 200px;
height: 200px;
margin: 1rem;
order: 99999999;
}
<div>
<img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200"><img src="http://placehold.it/200x200">
</div>
Edit: Looking at my own example I realise this doesn't solve your problem. I'll delete this post unless it helps you somehow anyway.
Edit2: You may actually have to resolve to adding some empty divs using JS to fill out the void. That should work though I'd definitely consider it an ugly hack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With