Left aligned last row in centered grid of elements

Ivan Durst picture Ivan Durst · Oct 22, 2013 · Viewed 19.1k times · Source

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

Fix centering last line of elements in fluid container grid to be left aligned while container stays centered

Center multiple inline blocks with CSS and align the last row to the left

Answer

web-tiki picture web-tiki · May 22, 2014

Solution with display inline-block

This adaptive grid is much simpler : less markup and less CSS so it will be easier to implement in a production site and adapt to your exact needs.

=>> DEMO <<= (resize the result window to see the effect)

html, body {
    margin:0;
    padding:0;
}
#container{
    font-size:0;
    margin:0 auto;
    width:1000px;
}
.block {
    font-size:20px;
    width: 150px;
    height: 150px;
    margin:25px;
    background: gold;
    display:inline-block;
}

@media screen and (max-width: 430px) {
    #container{
        width:200px;
    }
}

@media screen and (min-width: 431px) and (max-width: 630px) {
   #container{
        width:400px;
    }
}
@media screen and (min-width: 631px) and (max-width: 830px) {
   #container{
        width:600px;
    }
}
@media screen and (min-width: 831px) and (max-width: 1030px) {
   #container{
        width:800px;
    }
}
<div id="container">
    <div class="block">1</div>
    <div class="block">2</div>
    <div class="block">3</div>
    <div class="block">4</div>
    <div class="block">5</div>
    <div class="block">6</div>
    <div class="block">7</div>
    <div class="block">8</div>
    <div class="block">9</div>
    <div class="block">10</div>
    <div class="block">11</div>
    <div class="block">12</div>
    <div class="block">13</div>
</div>

It involves :

  1. 4 media queries for 200px wide blocks and a container expandable to 1000px. Depending on the width of your grid elements and the total width of your container you may have to make less or more

  2. removing white-spaces between inline-block elements (in the following demo I used the font-size technique but you can use other ones (see How to remove the space between inline-block elements? for other techniques)

  3. fixed margins between blocks

The number of blocks in one line adapts to the size of the container. The text-align property stay to default value left so the last items are aligned to the left.


Floats with adaptive margins between both blocks and container

=>> DEMO <<= (you need to resize the result window under 750px to see it in action)

html, body {
    margin:0;
    padding:0;
    min-width:150px;
}
.wrap {
    float:left;
    position:relative;
}
.foto {
    width: 150px;
    height: 150px;
    background: gold;
    position:absolute;
}

#warning{display:none;}
@media screen and (min-width: 631px) {
    .wrap {
        width:20%;
        padding-bottom:25%;
    }
    .wrap:nth-child(4n+2), .wrap:nth-child(4n+3){
        
    }
    .wrap .foto {
        top:-75px;
        margin-top:100%;
        right:-30px;
    }
    .wrap:nth-child(4n+2){
        margin:0 5% 0 7.5%;
    }
    .wrap:nth-child(4n+3){
     margin-right:7.5%;
    }
    .wrap:nth-child(4n+2) .foto{
        left:50%;
        margin-left:-75px;
    }
    .wrap:nth-child(4n+3) .foto{
        right:50%;
        margin-right:-75px;
    }
    .wrap:nth-child(4n) .foto{
        left:-30px;
    }   
    #container{
        margin-top:-45px;
    }
}

@media screen and (min-width: 481px) and (max-width: 631px) {
    .wrap {
        width:25%;
        padding-bottom:33.3%;
    }
    .wrap:nth-child(3n+2){
        margin:0 12.5%;        
    }
    .wrap .foto {
        top:-75px;
        margin-top:100%;
        right:-37px;
    }
     .wrap:nth-child(3n+2) .foto{
        left:50%;
        margin-left:-75px;
    }
     .wrap:nth-child(3n) .foto{
        left:-37px;
    }
    #container{
        margin-top:-37px;
    }
}


@media screen and (min-width: 331px) and (max-width: 480px) {
    .wrap {
        width:33.3%;
        padding-bottom:50%;
        clear:left;
    }
    .wrap:nth-child(even) {
        float:right;
        clear:right;
    }
    .wrap .foto {
        top:-75px;
        margin-top:100%;
        right:-50px;
    }
    .wrap:nth-child(even) .foto {
        left:-50px;
    }
    .wrap:nth-child(4n+3) .foto, .wrap:nth-child(4n+4) .foto {
        bottom:-75px;
        margin-bottom:100%;
    }
    #container{
        margin-top:-25px;
    }
}


@media screen and (max-width: 330px) {
    .wrap {
        width:50%;
        padding-bottom:100%;
        clear:left;
    }
    .wrap:nth-child(odd) .foto {
        right:-75px;
        bottom:0;
        bottom:-75px;
        margin-bottom:100%;
    }
    .wrap:nth-child(even) .foto {
        top:0px;
        right:-75px;
        top:-75px;
        margin-top:100%;
    }
}

@media screen and (min-width: 751px) {
    #warning{
        color:#fff;
        display:block;
        position:fixed;
        width:100%;
        height:50%;
        top:25%;
        left:0;
        background:#000;
        text-align:center;
        font-size:30px;
}
<div id="container">
    <div class="wrap"><div class="foto">1</div></div>
    <div class="wrap"><div class="foto">2</div></div>
    <div class="wrap"><div class="foto">3</div></div>
    <div class="wrap"><div class="foto">4</div></div>
    <div class="wrap"><div class="foto">5</div></div>
    <div class="wrap"><div class="foto">6</div></div>
    <div class="wrap"><div class="foto">7</div></div>
    <div class="wrap"><div class="foto">8</div></div>
    <div class="wrap"><div class="foto">9</div></div>
    <div class="wrap"><div class="foto">10</div></div>
    <div class="wrap"><div class="foto">11</div></div>
    <div class="wrap"><div class="foto">12</div></div>
    <div class="wrap"><div class="foto">13</div></div>
    <div class="wrap"><div class="foto">14</div></div>
    <div class="wrap"><div class="foto">15</div></div>
</div>

<!-- FOLLOWING JUST FOR THE DEMO -->
<div id="warning">I haven't written the code for windows bigger than 751px.<br/>
    You must resize this window under 751px.</div>

This technique involves :

  1. floats
  2. position:absolute;
  3. :nt-child() css selector
  4. media queries

It centers the blocks in their container and gives the same margin on the top/left/tight/bottom of all the blocks + sides of the container. As this solution uses floats, the last row is aligned to the left.

The number of blocks in one line adapts to the width of the window.