Последнее смещение полей / отступов в макете flexbox / grid

У меня есть список элементов, которые я пытаюсь расположить в прокручиваемом горизонтальном макете с помощью flexbox.

Каждый элемент в контейнере имеет поле слева и справа, но правое поле последнего элемента свернуто.

Есть ли способ остановить это или хороший обходной путь?

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: flex;
  height: 300px;
  overflow: auto;
  width: 600px;
  background: orange;
}
ul li {
  background: blue;
  color: #fff;
  padding: 90px;
  margin: 0 30px;
  white-space: nowrap;
  flex-basis: auto;
}
<div class="container">
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
  </ul>
</div>

5 ответов

Потенциальная проблема № 1

Последнее поле не разрушается. Это игнорируется.

overflow свойство распространяется только на контент. Это не относится к отступам или полям.

Вот что сказано в спецификации:

11.1.1. Переполнение: overflow имущество

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

Теперь давайте посмотрим на CSS Box Model:

Источник: W3C

overflow свойство ограничено областью содержимого поля. Если содержимое переполняет его контейнер, то overflow применяется. Но overflow не входит в области отступов или полей (если, конечно, нет больше контента, который следует).


Потенциальная проблема № 2

Проблема с потенциальной проблемой № 1 заключается в том, что она разваливается вне контекста гибкого или сеточного форматирования. Например, в стандартном макете блока последнее поле не выглядит свернутым. Так что, может быть overflow разрешено покрывать поля / отступы, независимо от того, что говорится в спецификации.

div {
  height: 150px;
  overflow: auto;
  width: 600px;
  background: orange;
  white-space: nowrap;
}
span {
  background: blue;
  color: #fff;
  padding: 50px;
  margin: 0 30px;
  display: inline-block;
}
<div class="container">
    <span>Item 1</span>
    <span>Item 2</span>
    <span>Item 3</span>
    <span>Item 4</span>
</div>

Следовательно, возможно, проблема вместо этого связана с элементами, которые "чрезмерно ограничены".

10.3.3 Блочные, незаменяемые элементы в нормальном потоке

Следующие ограничения должны соблюдаться среди используемых значений других свойств:

margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right = ширина вмещающего блока

Если width не является auto а также border-left-width + padding-left + width + padding-right + border-right-width (плюс любой из margin-left или же margin-right это не auto) больше ширины содержащего блока, то любой auto значения для margin-left или же margin-right для следующих правил рассматриваются как ноль.

Если все вышеперечисленное имеет вычисленное значение, отличное от auto значения называются "чрезмерно ограниченными", и одно из используемых значений должно отличаться от его вычисленного значения. Если direction свойство содержащего блока имеет значение ltr указанное значение margin-right игнорируется, и значение вычисляется так, чтобы сделать равенство истинным. Если значение direction является rtl это случается с margin-left вместо

(выделение добавлено)

Таким образом, в соответствии с моделью визуального форматирования CSS, элементы могут быть "чрезмерно ограничены", и, в результате, выбрасывается правое поле.


Потенциальные обходные пути

Вместо отступа или отступа используйте правую границу последнего элемента:

li:last-child {
  border-right: 30px solid orange;
}

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: flex;
  height: 100px; /* adjusted for demo */
  overflow: auto;
  width: 600px;
  background: orange;
}
ul li {
  background: blue;
  color: #fff;
  padding: 90px;
  margin: 0 30px;
  white-space: nowrap;
  flex-basis: auto;
}
li:last-child {
  border-right: 30px solid orange;
}
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
</ul>

Другое решение использует псевдоэлементы вместо полей или отступов.

Псевдоэлементы в флекс-контейнере отображаются как флекс-элементы. Первый элемент в контейнере ::before и последний пункт ::after,

ul::after {
  content: "";
  flex: 0 0 30px;
}

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: flex;
  height: 100px; /* adjusted for demo */
  overflow: auto;
  width: 600px;
  background: orange;
}
ul li {
  margin: 0 30px;
  background: blue;
  color: #fff;
  padding: 90px;
  white-space: nowrap;
  flex-basis: auto;
}
ul::after {
  content: "";
  flex: 0 0 30px;
}

ul::before {
  content: "";
  flex: 0 0 30px;
}
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
</ul>

Ваша проблема не сама по себе. Это полоса прокрутки, измеряющая только видимое содержимое элемента.

Один из способов решить эту проблему - создать видимый элемент, который занимает поле

Это решение обрабатывает это, используя псевдо на последнем дочернем

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: flex;
  height: 300px;
  overflow: auto;
  width: 600px;
  background: orange;
}
ul li {
  background: blue;
  color: #fff;
  padding: 90px;
  margin: 0 30px;
  white-space: nowrap;
  flex-basis: auto;
  position: relative;
}
li:last-child:after {
  content: "";
  width: 30px;
  height: 1px;
  position: absolute;
  left: 100%;
  top: 0px;
}
<div class"container">
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
  </ul>
</div>

Вы можете установить width а также overflow на div контейнер и набор display: inline-flex скорее, чем flex на ul, так что размер гибкого бокса будет рассчитываться на основе элементов внутри, и все отступы и поля будут применяться без каких-либо проблем.

.container {
  width: 600px;
  overflow: auto;
}

.container ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: inline-flex;
  background: orange;
}

.container li {
  padding: 60px;
  margin: 0 30px;
  white-space: nowrap;
  background: blue;
  color: #fff;
}
<div class="container">
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
  </ul>
</div>

По состоянию на октябрь 2023 года, похоже, эту проблему можно решить без псевдоэлементов, используя комбинациюgapиpaddingна родительском элементе вместоmargin.

Смотрите решение. Я удаляю white-space, flex-basis а также margin, чтобы предоставить вам чистое решение flexbox.

Это реле на flex-flow: row (По горизонтали), justify-content: space-around (ваше поле) и не более!! width изменено на 1200px так как отступ 90px, установите общую ширину блоков больше чем 600px (определено в вашем фрагменте).

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-flow: row ;
  justify-content: space-around;
  height: 300px;
  overflow: auto;
  width: 1200px;
  background: orange;
}
ul li {
  background: blue;
  color: #fff;
  padding: 90px;
}
<div class"container">
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
  </ul>
</div>

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