Выровнять по левому краю последнюю строку flexbox, используя пробел между полями и полями

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

Мне также нужно, чтобы они были оправданы с помощью space-between и последней строки, выровненной слева.

Я пытаюсь сделать это с помощью flexbox следующим образом:

.outside {
  border: 1px solid black;
}
.container {
  margin: -5px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.container:after {
  content: '';
  flex: auto;
}
.box {
  background: red;
  width: 50px;
  height: 50px;
  margin: 5px;
}
<div class="outside">
  <div class="container">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

Ответ 1

Последнее выравнивание строк является общей проблемой с flexbox.

Один из способов рассмотрения - использовать невидимые элементы гибкости после последнего видимого элемента. Короче говоря, я просто называю их "trailing phantom items".

.outside {
  border: 1px solid black;
}
.container {
  margin: -5px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.container:after {
  content: '';
  flex: auto;
}
.box {
  background: red;
  width: 50px;
  height: 50px;
  margin: 5px;
}

.hidden {
  visibility: hidden;
  margin: 0 5px;
  height: 0;
}
<div class="outside">
  <div class="container">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
    <div class="box hidden"></div>
  </div>
</div>

Ответ 2

Майкл прав, что проблема в том, что вы не можете сделать space-between, а затем выбрать последнюю строку, которая будет flex-start. Часть, которая торчит для меня, является указанной шириной. Это важно?

Если нет, обычным способом сделать это будет использование медиа-запросов для управления количеством отображаемых элементов в строке. Вы можете настроить множество шагов медиа-запросов, чтобы убедиться, что элементы не слишком растягиваются, но таким образом пространство между точками совпадает с вашими обычными решетками сетки, и это заставляет проблему "последних строк" ​​уйти. Думаете, что это сработает?

Пример: http://codepen.io/anon/pen/JbpPKa

Ответ 3

Переполнение стека не позволит мне комментировать ответ Michael_B, но я хотел бы проиллюстрировать, как вычисление количества добавляемых элементов phantom может быть выполнено с помощью JavaScript для всех, кто пытается решить эту проблему.

  /**
   * @param {Integer} numElements The number of elements you're displaying.
   * @param {Number} element Width Width, in pixels, of each element.
   * @param {Number} margin Width, in pixels. Your minimum target margin between items. 2x the margin on each individual item.
   * @param {Number} containerWidth Width, in pixels, of the containing element.
   */
  const getNumPhantomElements = ({numElements, elementWidth, margin, containerWidth}) => {
    const elementsPerRow = Math.floor(containerWidth / (elementWidth + margin));
    const elementsInLastRow = numElements % elementsPerRow;
    const numPhantomElements = elementsPerRow - elementsInLastRow;

    return numPhantomElements;
  };

В этом случае:

const containerWidth = document.querySelector('.container').offsetWidth;
const numPhantomElements = getNumPhantomElements({
  numElements: 21,
  elementWidth: 50,
  margin: 10, // 2x 5px margin on each box
  containerWidth
}); // Append this many elements (output depends on your viewport size)