以下是实现此布局的五个选项:
- CSS定位
- 带有不可见DOM元素的Flexbox
- 带有不可见伪元素的Flexbox
- Flexbox与
flex: 1
- CSS网格布局
方法1:CSS定位属性
应用于position: relative
flex容器。
应用于position: absolute
项目D。
现在,此项目已完全放置在flex容器中。
更具体地说,项目D从文档流中删除,但停留在最接近的祖先的范围内。
使用CSS偏移属性top
并将right
此元素移到适当位置。
li:last-child {
position: absolute;
top: 0;
right: 0;
background: #ddd;
}
ul {
position: relative;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p {
text-align: center;
margin-top: 0;
}
span {
background-color: aqua;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
此方法的一个警告是,某些浏览器可能无法从正常流程中完全删除绝对定位的flex项目。这会以非标准的意外方式更改对齐方式。更多详细信息:绝对定位的弹性项目不会从IE11的常规流中移除
方法2:Flex自动边距和不可见的Flex项(DOM元素)
结合使用页auto
边距和新的,不可见的柔性项目,可以实现布局。
新的弹性项目与项目D相同,并位于另一端(左边缘)。
更具体地说,因为弯曲对齐基于自由空间的分布,所以新项目是保持三个中间框水平居中的必要平衡。新项目的宽度必须与现有D项目的宽度相同,否则中间框将无法精确居中。
使用将该新项目从视图中删除visibility: hidden
。
简而言之:
- 创建该
D
元素的副本。
- 将其放在列表的开头。
- 使用Flex
auto
利润率保持A
,B
并C
居中,既有D
元素创建从两端完全平衡。
- 申请
visibility: hidden
副本D
li:first-child {
margin-right: auto;
visibility: hidden;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>D</li><!-- new; invisible spacer item -->
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
方法3:Flex自动页边距和不可见的Flex项(伪元素)
此方法与#2相似,但在语义上更清晰,并且D
必须知道的宽度。
- 创建一个宽度与相同的伪元素
D
。
- 将其放置在容器的开头
::before
。
- 使用Flex
auto
利润率保持A
,B
而C
完全居中,用伪和D
元素来创建从两端完全平衡。
ul::before {
content:"D";
margin: 1px auto 1px 1px;
visibility: hidden;
padding: 5px;
background: #ddd;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
方法4:添加flex: 1
到左侧和右侧项目
从上面的方法2或方法3开始,不必担心左右项目的宽度相等以保持相等的平衡,只需给每个项分配即可flex: 1
。这将迫使它们都占用可用空间,从而使中间项居中。
然后,您可以添加display: flex
到各个项目以使其内容对齐。
关于在以下情况下使用此方法的min-height
注意事项:目前,在Chrome,Firefox,Edge和其他可能的浏览器中,速记规则flex: 1
细分如下:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
当在容器上使用该百分比单位(%)时,flex-basis
此方法将中断min-height
。这是因为,通常来说,子级上的百分比高度要求height
在父级上进行显式的属性设置。
这是一条可以追溯到1998年的旧CSS规则(CSS Level 2),在某种程度上还是在许多浏览器中仍然有效。有关完整的详细信息,请参见此处和此处。
这是user2651804在评论中发布的问题的说明:
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container>div {
background: orange;
margin: 5px;
}
#flex-container>div:first-child {
flex: 1;
}
#flex-container::after {
content: "";
flex: 1;
}
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
解决方案是不使用百分比单位。尝试px
或根本不尝试(这实际上是规范的建议,尽管事实上至少有一些主要的浏览器出于某种原因附加了百分比单位)。
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container > div {
background: orange;
margin: 5px;
}
/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */
#flex-container > div:first-child {
flex: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex: 1;
flex-basis: 0;
}
/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY
#flex-container > div:first-child {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
*/
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
方法5:CSS网格布局
这可能是最干净,最有效的方法。无需绝对定位,伪造元素或其他黑客手段。
只需创建一个具有多列的网格。然后将项目放在中间和结尾列中。基本上,只需将第一列留空。
ul {
display: grid;
grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5px;
justify-items: center;
}
li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }
/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p { text-align: center; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>| true center |</span></p>