以下是实现此布局的五种选项:
-
CSS 定位
-
带有不可见 DOM 元素的 Flexbox
-
带有不可见伪元素的 Flexbox
-
弹性框
flex: 1
-
CSS 网格布局
方法 1:CSS 定位属性
应用于 position: relative
弹性容器。
适用 position: absolute
于项目 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>
一个缺点 是,某些浏览器可能无法完全将绝对定位的弹性项目从正常流中移除。这会以非标准、意想不到的方式改变对齐方式。更多详细信息: IE11 中绝对定位的弹性项目不会从正常流中移除
方法 2:弹性自动边距和不可见弹性项目(DOM 元素)
自动边距 auto
margins 可以实现布局。
新的弹性项目与项目 D 相同,且位于另一端(左边缘)。
更具体地说,由于弹性对齐基于可用空间的分布,因此新项目是保持三个中间框水平居中的必要平衡。新项目的宽度必须与现有的 D 项目相同,否则中间框将无法精确居中。
新项目将从视图中移除, visibility: hidden
.
简而言之:
-
创建该元素的副本
D
。
-
将其放置在列表的开头。
-
使用弹性
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 项目(伪元素)
必须知道 D
的宽度
-
创建一个与宽度相同的伪元素
D
.
-
将其放置在容器的开头
::before
.
-
使用弹性
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 一起使用的 about using this method with min-height
: 目前在 Chrome、Firefox、Edge 以及可能的其他浏览器中,简写规则 flex: 1
分解如下:
-
flex-grow: 1
-
flex-shrink: 1
-
flex-basis: 0%
单位 (%) on flex-basis
导致此方法中断 min-height
。这是因为,一般来说,子元素的百分比高度需要 height
在父元素上进行显式属性设置。
这是一条可追溯到 1998 年( CSS Level 2 )的旧 CSS 规则,它仍然在很多浏览器中或多或少地有效。有关完整详细信息,请参见 此处 和 此处 .
在评论中提出的问题的说明 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>