0

Here's the effect I want: I have a set of tiles that I want to arrange in a grid on the screen, as many across as will fit given the screen size. Then, I want the whole block centered, i.e. whatever space is left over after fitting as many tiles as possible, I want split half left and half right. Or, if there aren't enough tiles to fill the width, I want the remaining space divided.

For example, let's represent each tile as "XXXX". We have some space between them, which I'll represent with an "-". Let's say we have five tiles. So, on a very wide screen, we might see this:

---XXXX-XXXX-XXXX-XXXX-XXXX---

On a narrower screen:

--XXXX-XXXX-XXXX-XXXX---
--XXXX------------------

Narrower still:

-XXXX-XXXX-XXXX-
-XXXX-XXXX------

Etc.

The tiles are div's with various stuff inside. For purposes here, we can treat them as an atomic unit.

I can get the tiles to wrap easily enough by making them float's or inline-blocks. I thought I could then just wrap them in a larger div, then center that div within an outer div. But no.

If I make them float's, it centers fine as long as they all fit on one row. But once it takes two rows, they all go flush left. It looks like CSS's layout engine calculates the width of the row as if there was no wrapping, uses that to calculate centering, makes left and right margin 0, and THEN wraps within the inner block.

The closest I've come is to make them inline-blocks and put text-align: center on an outer block. But then, the last row is centered under the first row, instead of being flush-left under the first row.

See http://jsfiddle.net/vaLLsudh/ for that last, almost solution.

Pang
  • 9,564
  • 146
  • 81
  • 122
Jay
  • 26,876
  • 10
  • 61
  • 112
  • 1
    There's no way of giving a block a flexible width as you described it. You can give a `
    ` a `max-width` and center it, that's all.
    – Aloso May 04 '16 at 19:39
  • 1
    If I'm getting your Q correctly... I think you should have to use JS. – Roko C. Buljan May 04 '16 at 19:40
  • You could use `@media` sections for different screen sizes. – Aloso May 04 '16 at 19:41
  • 2
    @Aloso yes. Thousands of `@media` for every px... – Roko C. Buljan May 04 '16 at 19:42
  • 1
    Possible duplicate of [CSS when inline-block elements line-break, parent wrapper does not fit new width](http://stackoverflow.com/q/34995740/1529630). If the wrapper prefers to be as wide as 5 tiles but there is less available space, its width will be the full available space, not the maximum width of contents among lines. – Oriol May 04 '16 at 19:42
  • Please... I'm a bit lost in your graphs and 30 lines of text... in short, you actually want that the wrapping "*row*" is not centered but aligned left with the upper *"row"*? – Roko C. Buljan May 04 '16 at 19:48
  • @Aloso Well, I can wrap the floats in a div that has a style of "display: inline-block". Then the wrapper takes on the width of the total width of the floats. I can then put that div inside an outer div with text-align: center. That works great as long as the floats all fit on one line. But once they take two lines, it doesn't work anymore. – Jay May 04 '16 at 19:52
  • @aloso Okay, I suppose I could have a separate media query for every possible number of tiles that could fit on the screen. In this case the tiles are a fixed width, so that would be possible. Seems pretty ugly though. Maybe I'll do that if there's absolutely nothing better. – Jay May 04 '16 at 19:54
  • @RokoC.Buljan I want multiple rows all flush left with respect to each other, but then all the rows, i.e. the whole grid, centered on the screen. (And when I say "I want", I mean "The client wants".) Or think of it this way: The first row centered on the screen. All rows below it aligned left with the first row. – Jay May 04 '16 at 19:56
  • @Jay I get it. That's exactly what I was saying (asking). – Roko C. Buljan May 04 '16 at 19:57
  • Can you not use flexbox/flex-wrap? – Chris W. May 04 '16 at 20:13
  • @GCyrillus That flows correctly, but it is not centered within the outer div. – Jay May 04 '16 at 20:26
  • @ChrisW. Possibly, but I understand that's not supported in IE prior to 11. I was hoping for a solution with a little more downward-compatibility. Our client still reports errors to us when the sites we build for them don't work in IE7. Literally, that's not a joke. I'll push back on IE7, but I can't really push back on IE10. – Jay May 04 '16 at 20:35
  • The simplest and probably only way to achieve this in pure CSS is by using Flexbox. You can use a polyfill like https://github.com/10up/flexibility to support IE < 11. – Chris May 04 '16 at 20:43
  • Yea you're right about that, flex won't play nice with anything legacy like that. You're going to need javascript amigo. – Chris W. May 04 '16 at 20:44

2 Answers2

2

I've only done this with three blocks because I'm working on kind of a small screen but, Is this what you mean?

http://jsfiddle.net/vaLLsudh/3/

I've used some rough values but you could do the maths properly. This also assumes you are always going to be working with blocks of fixed widths.

You would have to write (max number of horizontal blocks - 1) media queries, but that might not be all that painful depending on what sort of limits you are thinking of imposing.

If you are pre-compiling your CSS with LESS or SASS also, you could probably output them as a loop for a single point of maintenance.

.outer {
    text-align: center;
}

.inner {
    display: inline-block;
    width: 700px;
    text-align: left;
}

.tile {
    display: inline-block;
    text-align: left;
    width: 200px;
    height: 100px;
    border: 10px solid black;
    margin: 0 10px 10px 0;
}

@media(max-width:800px) {

    .inner {
        width: 500px;
    }
}

@media(max-width:600px) {

    .inner {
        width: 220px;
    }
}
Community
  • 1
  • 1
  • I ended up doing this with JavaScript. I'll declare you the winner because this solution works, and I always prefer solutions that work over those that don't. It's a little ugly because in my case, the tiles are actually 240 pixels wide, assuming we allow for screens 2000 pixels wide we would need 8 media queries. That seems a bit much but not impossible. – Jay May 05 '16 at 03:13
1

ChristopherThomas's answer has merit. But I ended up doing it with JavaScript:

In a function that gets called during load (not showing the whole load process because there's a bunch of stuff not relevant here, or in any rational universe for that matter):

tileMargins();
$(window).resize(tileMargins);

And then:

function tileMargins() {
  var w1 = $(".outer").width();
  var wtile = $(".inner .tile").outerWidth(true);
  var x = Math.floor(w1 / wtile);
  var margin;
  if (x < 1) {
    margin = 0;
  }
  else {
    var maxx = $(".inner").children().length;
    if (x > maxx) x = maxx;
    margin = (w1 - wtile * x) / 2;
  }
  $(".inner").css("margin-left", margin + "px");

}

That seems like an awful lot of code just to center a block. If someone can show me a simpler way, I'm interested.

Jay
  • 26,876
  • 10
  • 61
  • 112