弹性盒/网格布局中的最后一个边距/填充折叠 [英] Last margin / padding collapsing in flexbox / grid layout
问题描述
我有一个项目列表,我试图将这些项目排列成带有 flexbox 的可滚动水平布局.
容器中的每一项都有左右边距,但最后一项的右边距正在折叠.
有没有办法阻止这种情况发生,或者有什么好的解决方法?
ul {列表样式类型:无;填充:0;边距:0;显示:弹性;高度:300px;溢出:自动;宽度:600px;背景:橙色;}乌利{背景:蓝色;颜色:#fff;填充:90px;边距:0 30px;空白:nowrap;弹性基础:自动;}
<ul><li>项目 1</li><li>项目 2</li><li>项目 3</li><li>项目 4</li>
潜在问题 #1
最后一个边距没有被折叠.它被忽略了.
overflow
属性仅适用于内容.它不适用于填充或边距.
这是规范中的内容:
<块引用>来源:W3C
overflow
属性仅限于内容框区域.如果内容溢出其容器,则应用 overflow
.但是 overflow
不会进入 padding 或 margin 区域(当然,除非后面有更多内容).
潜在问题#2
潜在问题 #1 的问题在于它似乎在 flex 或网格格式上下文之外崩溃.例如,在标准块布局中,最后一个边距似乎不会折叠.所以也许 overflow
被允许覆盖边距/填充,不管它在规范中怎么说.
div {高度:150px;溢出:自动;宽度:600px;背景:橙色;空白:nowrap;}跨度 {背景:蓝色;颜色:#fff;填充:50px;边距:0 30px;显示:内联块;}
<span>项目 1</span><span>项目 2</span><span>项目 3</span><span>项目 4</span>
因此,问题可能与过度约束"的元素有关.
<块引用>以下约束必须在另一个的使用值中成立属性:
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
之外的计算值,则这些值被称为过度约束"并且是使用的值之一必须与其计算值不同.如果方向
包含块的属性具有值 ltr
,指定的margin-right
的值被忽略并计算为使等式成立.如果direction
的值为rtl
,这发生在 margin-left
上
(强调)
因此,根据 CSS 视觉格式模型,元素可能是过度约束",结果,右边距被丢弃.
<小时>潜在的解决方法
在最后一个元素上使用右边框代替边距或填充:
li:last-child {右边框:30px 纯橙色;}
ul {列表样式类型:无;填充:0;边距:0;显示:弹性;高度:100px;/* 为演示调整 */溢出:自动;宽度:600px;背景:橙色;}乌利{背景:蓝色;颜色:#fff;填充:90px;边距:0 30px;空白:nowrap;弹性基础:自动;}李:最后一个孩子{右边框:30px 纯橙色;}
<li>项目 1</li><li>项目 2</li><li>项目 3</li><li>项目 4</li>
另一种解决方案使用伪元素代替边距或填充.
flex 容器上的伪元素被渲染为 flex 项目.容器中的第一项是::before
,最后一项是::after
.
ul::after {内容: "";弹性:0 0 30px;}
ul {列表样式类型:无;填充:0;边距:0;显示:弹性;高度:100px;/* 为演示调整 */溢出:自动;宽度:600px;背景:橙色;}乌利{边距:0 30px;背景:蓝色;颜色:#fff;填充:90px;空白:nowrap;弹性基础:自动;}ul::after {内容: "";弹性:0 0 30px;}ul::before {内容: "";弹性:0 0 30px;}
<li>项目 1</li><li>项目 2</li><li>项目 3</li><li>项目 4</li>
I have a list of items that I'm trying to arrange into a scrollable horizontal layout with flexbox.
Each item in the container has a margin left and right, but the right margin of the last item is being collapsed.
Is there a way to stop this happening, or a good workaround?
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>
Potential Problem #1
The last margin is not being collapsed. It's being ignored.
The overflow
property applies only to content. It doesn't apply to padding or margins.
Here's what it says in the spec:
11.1.1 Overflow: the
overflow
propertyThis property specifies whether content of a block container element is clipped when it overflows the element's box.
Now let's take a look at the CSS Box Model:
source: W3C
The overflow
property is limited to the content box area. If the content overflows its container, then overflow
applies. But overflow
doesn't enter into the padding or margin areas (unless, of course, there is more content that follows).
Potential Problem #2
The problem with Potential Problem #1 is that it appears to fall apart outside of a flex or grid formatting context. For example, in a standard block layout, the last margin doesn't appear to collapse. So maybe overflow
is permitted to cover margins / paddings, regardless of what it says in the spec.
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>
Hence, maybe the problem is instead related to elements that are "over-constrained".
10.3.3 Block-level, non-replaced elements in normal flow
The following constraints must hold among the used values of the other properties:
margin-left
+border-left-width
+padding-left
+width
+padding-right
+border-right-width
+margin-right
= width of containing blockIf
width
is notauto
andborder-left-width
+padding-left
+width
+padding-right
+border-right-width
(plus any ofmargin-left
ormargin-right
that are notauto
) is larger than the width of the containing block, then anyauto
values formargin-left
ormargin-right
are, for the following rules, treated as zero.If all of the above have a computed value other than
auto
, the values are said to be "over-constrained" and one of the used values will have to be different from its computed value. If thedirection
property of the containing block has the valueltr
, the specified value ofmargin-right
is ignored and the value is calculated so as to make the equality true. If the value ofdirection
isrtl
, this happens tomargin-left
instead(emphasis added)
So, according to the CSS Visual Formatting Model, elements may be "over-constrained" and, as a result, a right margin gets tossed out.
Potential Workarounds
Instead of margin or padding, use a right border on the last element:
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>
Another solution uses a pseudo-elements instead of margins or padding.
Pseudo-elements on a flex container are rendered as flex items. The first item in the container is ::before
and last item is ::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>
这篇关于弹性盒/网格布局中的最后一个边距/填充折叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!