I have a bunch of same-size blocks set to display:inline-block
inside a div that has text-align:center
set to align the blocks.
| _____ _____ _____ _____ |
| | | | | | | | | |
| | 1 | | 2 | | 3 | | 4 | |
| |_____| |_____| |_____| |_____| |
| _____ _____ _____ _____ |
| | | | | | | | | |
| | 5 | | 6 | | 7 | | 8 | |
| |_____| |_____| |_____| |_____| |
| |
The blocks fill the div horizontally, and as the browser window shrinks, some blocks break to new lines, creating more rows and less columns. I want everything to still remain centered, with the last row aligned flush to the left, like this :
| _____ _____ _____ |
| | | | | | | |
| | 1 | | 2 | | 3 | |
| |_____| |_____| |_____| |
| _____ _____ _____ |
| | | | | | | |
| | 4 | | 5 | | 6 | |
| |_____| |_____| |_____| |
| _____ _____ |
| | | | | |
| | 7 | | 8 | |
| |_____| |_____| |
| |
What currently happens is this:
| _____ _____ _____ |
| | | | | | | |
| | 1 | | 2 | | 3 | |
| |_____| |_____| |_____| |
| _____ _____ _____ |
| | | | | | | |
| | 4 | | 5 | | 6 | |
| |_____| |_____| |_____| |
| _____ _____ |
| | | | | |
| | 7 | | 8 | |
| |_____| |_____| |
| |
I cannot add extra filler divs like one suggestion, because there could be any number of blocks, and the amount of rows and columns will vary depending on browser width. I also cannot style block #7 directly, for the same reason. The blocks must always remain centered no matter how many columns.
Here is a pen to better demonstrate:
http://codepen.io/anon/pen/IDsxn
Is this possible? I feel like it sure should be. I would prefer not to use flexbox as it is only ie10+, and I'd like ie9+. I would really like a pure CSS solution, but if you tell me JS is the only way, I'd love to see that in action.
For reference - similar questions, though none were thoroughly explained:
How to align left last row/line in multiple line flexbox
CSS - Left align the last row of images in a centered div
Center multiple inline blocks with CSS and align the last row to the left
For what it's worth: It's now 2017 and the grid layout module does this out of the box
* {
margin:0;
padding:0;
}
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-gap: 10px;
justify-content: center;
align-content: flex-start;
margin: 0 auto;
text-align: center;
margin-top: 10px;
}
.block {
background-color: #ddd;
border: 1px solid #999;
height: 100px;
width: 100px;
}
<div class="container">
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
<div class="block">Foo</div>
</div>
If the browser support suits you - then use grid. If not, then read on....
As mentioned in @Web-tiki's answer, the best you can do with CSS is with a series of media queries.
That being said, if you are using a preprocessor such as LESS - this isn't such a difficult or error-prone task. (although, yes, the CSS will still be long and ugly)
Here's how to take advantage of LESS to set up the media queries:
First set up some less variables according to the design which you need:
@item-width:100px;
@item-height:100px;
@marginV: 4px;
@marginH: 2px;
@min-cols:2;
@max-cols:9; //set an upper limit of how may columns you want to write the media queries for
Then:
Set up an iteration mixin like this: (You can paste this code into http://less2css.org)
.loopingClass (@index-width) when (@index-width <= @item-width * @max-cols) {
@media (min-width:@index-width) {
.container{
width: @index-width;
}
}
.loopingClass(@index-width + @item-width + 2*@marginH);
}
.loopingClass (@item-width * @min-cols + @min-cols*@marginH*2);
The above mixin will spit out a series of media queries in the form:
@media (min-width: 208px) {
.container {
width: 208px;
}
}
@media (min-width: 312px) {
.container {
width: 312px;
}
}
@media (min-width: 416px) {
.container {
width: 416px;
}
}
@media (min-width: 520px) {
.container {
width: 520px;
}
}
@media (min-width: 624px) {
.container {
width: 624px;
}
}
@media (min-width: 728px) {
.container {
width: 728px;
}
}
@media (min-width: 832px) {
.container {
width: 832px;
}
}
With remaining CSS (LESS):
.container {
margin: 0 auto;
text-align: center;
overflow: auto;
min-width: @min-cols * @item-width;
max-width: @max-cols * @item-width;
display: block;
list-style:none;
}
.block {
background-color: #ddd;
border:1px solid #999;
box-sizing:border-box;
float: left;
height: @item-height;
width: @item-width;
margin:@marginV @marginH;
}
... you get the desired result.
All I need to do is change the variables that I used in the LESS mixin according to my needs - I get the exact layout that I'm after.