13

I have a bunch of inline-block elements over several lines which I'd like to center horizontally. The inline-block elements all have the same fixed size, but I'd like the centering to be able to handle page resizing and adding or removing elements.

I've stripped down the html/css and removed the attempt at centering for clarity. It's at http://jsfiddle.net/fe25H/1/

If you resize the results window so that the third inline-block element drops down, the container fills the width and we get this:

-----------------BODY------------------
|                                     |
||-------------CONTAINER-------------||
||-INLINEBLOCK---INLINEBLOCK--       ||
|||____________||____________|       ||
||-INLINEBLOCK--                     ||
|||____________|                     ||
||___________________________________||
|_____________________________________|

rather than this:

-----------------BODY------------------
|                                     |
|   |----------CONTAINER---------|    |
|   |-INLINEBLOCK---INLINEBLOCK--|    |
|   ||____________||____________||    |
|   |-INLINEBLOCK--              |    |
|   ||____________|              |    |
|   |____________________________|    |
|_____________________________________|

edit based on ptriek's answer regarding a JavaScript solution:

Ptriek's code was a useful starting point; it works for the specific case, but not the general one. I've mostly rewritten it to be more flexible (see http://jsfiddle.net/fe25H/5/).

James
  • 133
  • 5
  • 1
    interesting question, pretty curious if there's a non-javascript solution for this... – ptriek Dec 30 '11 at 23:27
  • 1
    As soon as an element wraps to the next line, the container will assume a width of 100%. This isn't possible without Javascript. – Wex Dec 30 '11 at 23:39
  • What if you used a pseudo-element to fill the extra space? I'm currently trying that, but with little luck. – Costa Michailidis Sep 16 '15 at 16:00

3 Answers3

3

After thinking a bit about it, I agree with Wex' comment above.

So I fiddled a JavaScript solution (jQuery) - I'm not an expert on this, so the code might be improved - but I guess it does exactly what you need:

var resizeContainer = function () {
    var w_window = $(window).width();
    var w_block = $('.inlineblock').width();
    if (w_window < w_block * 3 && w_window >= w_block * 2) {
        $('.container').width(w_block * 2);
    } else if (w_window < w_block * 2) {
        $('.container').width(w_block);
    }  else {
        $('.container').width(w_block * 3);
    } 
};


$(document).ready(resizeContainer);
$(window).resize(resizeContainer);
body {
    text-align:center;
}
.container {
    display: inline-block;
    background-color: #aaa;
    text-align:left;
}
.inlineblock {
    display: inline-block;
    width: 200px;
    height: 200px;
    background-color: #eee;
}
<div class='container'>
    <div class='inlineblock'></div>
    <div class='inlineblock'></div>
    <div class='inlineblock'></div>
</div>

http://jsfiddle.net/ptriek/fe25H/4/

TylerH
  • 20,799
  • 66
  • 75
  • 101
ptriek
  • 9,040
  • 5
  • 31
  • 29
1

The issue stated is, as far as my CSS knowledge will take me, not perfectly solvable with purely CSS.

Mike M. Lin's answer is a very ingenious method, I love the creativity, but there are some errors with it that I can expand on.

NOTE: If anyone finds out the general solution, please let us know, since no-body has done it. Etsy, Amazon, Redbubble, can't see this being achieved anywhere...


1)

You do not need "2 minus the length of the array of div items", this could get computationally expensive for large n of items. Rather, as an approximate rule, you need enough placeholder "blocks" to create a new line in the container. In fact, the number of placeholders is (in pseudocode):

let n = number of block items to display
let n_max = number of block items that fit into one row
let n_ph = number of "placeholder" block items

/*if number of items exceeds max number for a row (starts a new line), then 
 you'll need to start another line with n_max - 1 placeholders*/
if n >= n_max then
    n_ph = n_max - 1
end if

//you don't need any placeholders if number of items fills all rows completely
if n % n_max == 0 then
    n_ph = 0
end if

Notice that I have omitted the case when n < n_max. That is difficult, and you will have to play around with your n_ph values for when n < n_max. If you need n_ph to work for different window sizes, I would consider adding a window width observer and adding or taking away a placeholder for your "responsive" width bands. It is a pain, but you will likely either not have n < n_max ever, or, your n_max is small and it's not a pain to "manually taylor" n_ph for the responsive bands.

2)

You don't need the container to be inline-block. It works with or without it I have found.

Sam Hughes
  • 153
  • 7
0

You can add invisible placeholders to the end of your inline blocks. That will left-align the last row.

http://jsfiddle.net/aakt65x4/

However, if you don't fill up the first row, the entire thing will appear left-aligned.

HTML:

<!--
  Centers a group of boxes that wrap to the width of its container.
  Also left-aligns them inside the container.
  Issue: Does not center group if there aren't enough boxes to fill
  the first row.
  -->
<div class="container">
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>
    <div class="block"></div>

    <!--
      How many placeholders do you need?
      At least the number of blocks minus two.
      -->
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
</div>

CSS:

body {
    text-align: center;     /* center a max-width container */
    font-size: 0;           /* remove spaces between blocks */
}
.container {                /* you don't need this */
    background-color: #eee; /* so you can see what's happening */
    max-width: 960px;       /* to demonstrate the centering of a max-width container */
    display: inline-block;  /* center the max-width container */
    text-align: center;     /* center the group of blocks */
}
.block {
    display: inline-block;  /* left-align within the group */
    background-color: red;  /* so you can see what's happening */
    height: 100px;
    width: 100px;
    margin: 10px;
}
.placeholder {
    display: inline-block;  /* add to the line of blocks */
    width: 120px;           /* width + margin of a block */
}
Mike M. Lin
  • 9,992
  • 12
  • 53
  • 62