Как центрировать гибкий контейнер, но выровнять по левому краю элементы

Я хочу, чтобы элементы flex были центрированы, но когда у нас есть вторая строка, чтобы иметь 5 (из изображения ниже) в 1 и не центрироваться в родительском.

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

Вот пример того, что у меня есть:

ul {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;
}
li {
  list-style-type: none;
  border: 1px solid gray;
  margin: 15px;
  padding: 5px;
  width: 200px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

Ответ 1

Flexbox Задача и ограничение

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

Используя код, отправленный в вопросе, мы можем создать новый контейнер flex, который обертывает текущий контейнер flex (ul), который позволит нам центрировать ul с помощью justify-content: center.

Затем элементы гибкости ul можно выровнять по левому краю с помощью justify-content: flex-start.

#container {
    display: flex;
    justify-content: center;
}

ul {
    display: flex;
    justify-content: flex-start;
}

Это создает центрированную группу выровненных по левому краю элементов.

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

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

Это происходит потому, что в гибком макете (и, вообще говоря, в CSS) контейнер:

  • не знает, когда обтекает элемент;
  • не знает, что ранее занятое пространство теперь пусто, а
  • не пересчитывает свою ширину для сжатия более узкого макета.

Максимальная длина пробела справа - это длина элемента гибкости, который должен был находиться в контейнере.

В следующей демонстрационной версии, изменив размер окна по горизонтали, вы увидите, что пробелы приходят и уходят.

DEMO


Более практичный подход

Желаемый макет может быть достигнут без flexbox с помощью inline-block и медиа-запросов.

HTML

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul {
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see https://stackoverflow.com/a/32801275/3597276 */
}

li {
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;
}

@media screen and (max-width: 430px) { ul { width: 200px; } }
@media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
@media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px;  } }
@media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
@media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }

Приведенный выше код отображает контейнер с горизонтальной ориентацией с выровненными по левому краю дочерними элементами:

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

DEMO


Другие параметры

Ответ 2

Как предположил @michael, это ограничение для текущего flexbox. Но если вы все еще хотите использовать flex и justify-content: center; , затем мы можем обойти это, добавив фиктивный элемент li и назначив margin-left.

    const handleResize = () => {
        const item_box = document.getElementById('parentId')
        const list_length  = item_box.clientWidth
        const product_card_length = 200 // length of your child element
        const item_in_a_row = Math.round(list_length/product_card_length)
        const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
        const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin 
        const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
        dummy_product.style.marginLeft = '${left_to_set}px'
    }
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

Проверить эту скрипку (изменить размер и посмотреть) или видео для справки