Выровненный по левому краю последний ряд в центрированной сетке элементов

У меня есть куча блоков одинакового размера display:inline-block внутри div, который имеет text-align:center установить для выравнивания блоков.

|        _____   _____   _____   _____       |
|       |     | |     | |     | |     |      |
|       |  1  | |  2  | |  3  | |  4  |      |
|       |_____| |_____| |_____| |_____|      |
|        _____   _____   _____   _____       |
|       |     | |     | |     | |     |      |
|       |  5  | |  6  | |  7  | |  8  |      |
|       |_____| |_____| |_____| |_____|      |
|                                            |

Блоки заполняют div по горизонтали, и когда окно браузера сжимается, некоторые блоки переходят на новые строки, создавая больше строк и меньше столбцов. Я хочу, чтобы все оставалось по центру, чтобы последний ряд был выровнен по левому краю, например так:

|        _____   _____   _____        |
|       |     | |     | |     |       |
|       |  1  | |  2  | |  3  |       |
|       |_____| |_____| |_____|       |
|        _____   _____   _____        |
|       |     | |     | |     |       |
|       |  4  | |  5  | |  6  |       |
|       |_____| |_____| |_____|       |
|        _____   _____                |
|       |     | |     |               |
|       |  7  | |  8  |               |
|       |_____| |_____|               |
|                                     |

В настоящее время происходит следующее:

|        _____   _____   _____        |
|       |     | |     | |     |       |
|       |  1  | |  2  | |  3  |       |
|       |_____| |_____| |_____|       |
|        _____   _____   _____        |
|       |     | |     | |     |       |
|       |  4  | |  5  | |  6  |       |
|       |_____| |_____| |_____|       |
|            _____   _____            |
|           |     | |     |           |
|           |  7  | |  8  |           |
|           |_____| |_____|           |
|                                     |

Я не могу добавить дополнительные заполнители div, как одно предложение, потому что может быть любое количество блоков, а количество строк и столбцов будет варьироваться в зависимости от ширины браузера. Я также не могу стилизовать блок № 7 напрямую по той же причине. Блоки должны всегда оставаться в центре независимо от того, сколько столбцов.

Вот ручка, чтобы лучше продемонстрировать:

http://codepen.io/anon/pen/IDsxn

Это возможно? Я чувствую, что так и должно быть. Я бы предпочел не использовать flexbox, так как это всего лишь 10+, и я бы хотел ie9+. Мне бы очень хотелось чисто CSS-решение, но если вы скажете мне, что JS - единственный способ, я бы хотел увидеть это в действии.

Для справки - похожие вопросы, хотя ни один из них не был подробно объяснен:

Как выровнять левый последний ряд / строку в многострочном flexbox

CSS - выравнивание по левому краю последнего ряда изображений по центру

Исправьте центрирование последней линии элементов в сетке контейнера для жидкости, чтобы она была выровнена по левому краю, пока контейнер остается в центре

Центрируйте несколько встроенных блоков с помощью CSS и выровняйте последний ряд по левому краю

8 ответов

Решение

Вот очень простое решение JavaScript (и некоторые небольшие изменения в вашем CSS) для вас:

http://jsfiddle.net/ha68t/

Это работает нормально для меня.

CSS:

.container {
  margin: 0 auto;
  max-width:960px;
  background-color: gold;
}

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

JavaScript:

$(document).ready(function(){
    setContainerWidth();
});

$(window).resize(function(){
   setContainerWidth();
});

function setContainerWidth()
{
    $('.container').css('width', 'auto'); //reset
    var windowWidth = $(document).width();
    var blockWidth = $('.block').outerWidth(true);
    var maxBoxPerRow = Math.floor(windowWidth / blockWidth);
    $('.container').width(maxBoxPerRow * blockWidth);
}

JQuery требуется:)

Решение с отображением inline-блока

Эта адаптивная сетка намного проще: меньше разметки и меньше CSS, так что ее будет легче внедрить в производственный сайт и адаптировать к вашим конкретным потребностям.

= >> DEMO << = (измените размер окна результатов, чтобы увидеть эффект)

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>

Это включает в себя:

  1. 4 медиа-запроса для блоков шириной 200 пикселей и контейнер, расширяемый до 1000 пикселей. В зависимости от ширины элементов сетки и общей ширины контейнера, вам может потребоваться сделать меньше или больше

  2. удаление пробелов между элементами inline-block (в следующей демонстрации я использовал технику font-size, но вы можете использовать другие (см. Как удалить пробел между элементами inline-block? для других методов)

  3. фиксированные поля между блоками

Количество блоков в одной строке адаптируется к размеру контейнера. text-align свойство остается до значения по умолчанию left поэтому последние элементы выровнены по левому краю.


Поплавки с адаптивными полями между блоками и контейнером

= >> DEMO << = (вам нужно изменить размер окна результатов до 750px, чтобы увидеть его в действии)

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>

Эта техника включает в себя:

  1. поплавки
  2. position:absolute;
  3. :nt-child() css селектор
  4. медиа-запросы

Он центрирует блоки в их контейнере и дает одинаковое поле сверху / слева / плотнее / снизу всех блоков + сторон контейнера. Поскольку в этом решении используются числа с плавающей точкой, последний ряд выравнивается по левому краю.

Количество блоков в одной строке адаптируется к ширине окна.

Для чего это стоит: сейчас 2017, и модуль разметки сетки делает это из коробки

* {
    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>

(Codepen demo).

Если поддержка браузера вам подходит - тогда используйте сетку. Если нет, то читайте дальше....


Как упоминалось в ответе @Web-tiki, лучшее, что вы можете сделать с помощью CSS, - это выполнить серию медиа-запросов.

При этом, если вы используете препроцессор, такой как LESS - это не такая сложная или подверженная ошибкам задача. (хотя, да, CSS все равно будет длинным и безобразным)

ОБНОВЛЕНО CODEPEN ( измените размер окна, чтобы увидеть результаты)

Вот как воспользоваться LESS для настройки медиа-запросов:

Сначала установите несколько переменных в соответствии с нужным вам дизайном:

@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

Затем:

Настройте итерационный миксин так: (Вы можете вставить этот код в 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);

Приведенный выше миксин выложит серию медиа-запросов в виде:

@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;
  }
}

С оставшимся 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;
}

... вы получите желаемый результат.

... и это очень легко настроить макет:

Все, что мне нужно сделать, это изменить переменные, которые я использовал в миксине LESS, в соответствии с моими потребностями - я получаю точный макет, который мне нужен.

Попробуйте это с помощью простого CSS:

CSS:

.row {text-align: center; font-size: 0;}.block {text-align: center; display: inline-block; ширина:150px; высота:15px; поле:5px; border:1px solid #dddddd; размер шрифта: 13px;}

HTML:

<div class="row">
  <div class="block"></div> 
</div>

.row{text-align:center;font-size:0;}
    .block{text-align:center;display:inline-block;width:150px;height:150px;margin:5px; border:1px solid #dddddd;font-size:13px;line-height:150px;}
<div class="row">
      <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>

С flexbox, некоторыми псевдоэлементами, дополнительным div, и после большого разочарования я смог достичь этого без медиазапросов (поскольку мне нужно было поместить свою сетку во многие элементы разных размеров, медиазапросы не будут работать для меня),

Одно предостережение: водостоки между предметами текучие.

Демо: http://codepen.io/anon/pen/OXvxEW

CSS:

.wrapper {
    display: flex;
    flex-wrap: wrap;
    border: 2px solid #ffc0cb;
    max-width: 1100px;
    margin: 0.5rem auto;
    justify-content: center;
}

.wrapper:after {
    content: ' ';
    flex: 1;
    height: 100%;
    border: 1px solid #00f;
    margin: 0.5rem;
}

.child {
    flex: 1;
    border: 2px solid #ffa500;
    min-width: 300px;
    margin: 0.5rem;
    text-align: center;
}

.child-contents {
    width: 300px;
    border: 2px solid #008000;
    height: 100px;
    margin: 0 auto;
}

HTML:

<div class='wrapper'>
    <div class='child'>
        <div class='child-contents'></div>
    </div>
    <div class='child'>
        <div class='child-contents'></div>
    </div>
    <div class='child'>
        <div class='child-contents'></div>
    </div>

    ...etc., more .child's...

</div>

Конечный результат - что-то вроде этого, где зеленые прямоугольники - это div. Розовые / оранжевые границы приведены только для справки, чтобы вы могли видеть, что происходит. Если вы удалите розовые / оранжевые границы, вы должны получить сетку, которую вы ищете (хотя, опять же, обратите внимание, что желоб является жидким).

введите описание изображения здесь

На сегодняшний день единственное чистое решение для этого с

Модуль CSS Grid Layout ( Codepen demo)

В основном соответствующий код сводится к следующему:

ul {
  display: grid; /* (1) */
  grid-template-columns: repeat(auto-fill, 120px); /* (2) */
  grid-gap: 1rem; /* (3) */
  justify-content: center; /* (4) */
  align-content: flex-start; /* (5) */
}

1) Сделать элемент контейнера контейнером сетки

2) Установите сетку с "автоматическим" количеством столбцов шириной 120px. (Значение автозаполнения используется для адаптивных макетов).

3) Установите промежутки / желоба для строк и столбцов сетки.

4) и 5) - похоже на flexbox.

body {
  margin: 0;
}
ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, 120px);
  grid-gap: 1rem;
  justify-content: center;
  align-content: flex-start;
  
  /* boring properties: */
  list-style: none;
  width: 90vw;
  height: 90vh;
  margin: 2vh auto;
  border: 5px solid green;
  padding: 0;
  overflow: auto;
}
li {
  background: tomato;
  height: 120px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>

Codepen demo ( измените размер, чтобы увидеть эффект)


Поддержка браузера - Caniuse

В настоящее время поддерживается Chrome (Blink) и Firefox, с частичной поддержкой IE и Edge (см. Это сообщение Рэйчел Эндрю)


Дальнейшее чтение по сеткам CSS:

Используйте 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: #ddd;
  border:1px solid #999;
  display: inline-block;
  height: 100px;
  margin: 4px 2px;
  width: 100px;
}

Готово.

Не существует "нормального" решения вашей проблемы, а есть только упомянутые "обходные пути".

Ситуация такова, что ваш контейнер блоков заполнит доступное пространство до максимально доступного / установленного значения, а затем переместит все внутренние блоки на следующую строку, что приведет к переполнению контейнера. Также с другими конфигурациями, такими как плавающий, это будет то же самое поведение. Так работает рендеринг - каждый раз жадный в пространстве, чтобы вычислить поведение внутренних элементов.

Возможно, будущие Flexbox сделают это возможным - но я не читал полные спецификации. Просто предположение...

Другие вопросы по тегам