49

我有一个项目列表,我试图用 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>

4

4 回答 4

83

潜在问题 #1

最后一个边距没有被折叠。它被忽略了。

overflow属性仅适用于content。它不适用于填充或边距。

这是规范中所说的:

11.1.1 溢出:overflow 属性

此属性指定块容器元素的内容在溢出元素的框时是否被剪裁。

现在让我们看一下CSS 盒子模型

在此处输入图像描述

来源:W3C

overflow属性仅限于内容框区域。如果内容溢出其容器,则overflow应用。但overflow不会进入填充或边距区域(当然,除非后面还有更多内容)。


潜在问题 #2

潜在问题 #1 的问题在于它似乎在 flex 或 grid 格式化上下文之外分崩离析。例如,在标准块布局中,最后一个边距似乎不会折叠。所以也许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= 包含块的宽度

如果widthis notauto并且border-left-width+ padding-left+ width+ padding-right+ border-right-width(加上任何 margin-leftor margin-rightthat are not auto)大于包含块的宽度,则对于以下规则, or的任何auto值 都被视为零。margin-leftmargin-right

如果以上所有的计算值都不auto是 ,则这些值被称为“过度约束”,并且使用的值之一必须与其计算值不同。如果direction 包含块的属性ltr值为 ,margin-right则忽略 的指定值并计算该值以使等式成立。如果 的值为 ,则direction发生rtl这种情况margin-left

(重点补充)

因此,根据CSS Visual Formatting Model,元素可能被“过度约束”,结果,右边距被扔掉了。


潜在的解决方法

在最后一个元素上使用右边,而不是边距或填充:

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>

于 2016-08-17T12:45:22.963 回答
9

您的问题不在于利润本身。它是仅标注元素可见内容的滚动条。

解决它的一种方法是创建一个占据边距的可见元素

此解决方案在最后一个孩子上使用伪处理此问题

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>

于 2016-08-17T10:29:44.150 回答
4

您可以在容器上设置widthand ,而不是在 上设置,这样弹性盒子的大小将根据里面的项目来计算,并且所有的填充和边距都将应用而没有任何问题。overflowdivdisplay: inline-flexflexul

.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>

于 2018-03-04T15:00:38.333 回答
-2

查看解决方案。我删除white-space,flex-basismargin, 为您提供一个纯粹的 flexbox 解决方案。

flex-flow: row它在(水平),justify-content: space-around(您的保证金)上中继,仅此而已!由于90px 的填充将框的总宽度设置为超过 600px(在您的代码段中定义),因此将width其更改为。1200px

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>

于 2016-08-17T10:02:51.290 回答