Left aligned last row in centered grid of elements

2019-01-02 15:27发布

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

8条回答
呛了眼睛熬了心
2楼-- · 2019-01-02 16:08

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: #ffffd;
  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>

(Codepen demo).

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)

UPDATED CODEPEN (Resize the window to see the results)

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: #ffffd;
  border:1px solid #999;
  box-sizing:border-box;
  float: left;
  height: @item-height;
  width: @item-width;
  margin:@marginV @marginH;
}

... you get the desired result.

...and it's super easy to customize the layout:

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.

查看更多
临风纵饮
3楼-- · 2019-01-02 16:08

Use flexbox:

.container {
  display: -webkit-flex;
   display: flex;
   -webkit-flex-direction: row; 
   flex-direction: row;
   -webkit-justify-content: flex-start;
   justify-content: flex-start;
   flex-wrap:wrap;
}

.block {
  background-color: #ffffd;
  border:1px solid #999;
  display: inline-block;
  height: 100px;
  margin: 4px 2px;
  width: 100px;
}

Done.

查看更多
登录 后发表回答