下面是实现这种布局的五个选项:
CSS定位
Flexbox与隐形DOM元素
Flexbox与隐形伪元素
flex: 1
CSS网格布局
方法#1:CSS定位属性
应用位置:相对于伸缩容器。
应用位置:D项的绝对位置。
现在这个项目完全位于伸缩容器中。
更具体地说,项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元素)
结合了汽车边际和一个新的,无形的灵活项目的布局可以实现。
新的伸缩项目与项目D相同,并被放置在相反的一端(左边缘)。
更具体地说,因为伸缩对齐是基于自由空间的分配,新项目是保持中间三个盒子水平居中的必要平衡。新项目必须与现有的D项目宽度相同,否则中间的方框不会精确居中。
新项目从视图中删除,可见性:hidden。
简而言之:
创建D元素的副本。
把它放在列表的开头。
使用灵活的自动边距来保持A, B和C居中,两个D元素从两端创造相等的平衡。
应用可见性:隐藏到重复的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:弹性自动边距和不可见的弹性项目(伪元素)
这个方法类似于第2条,除了它在语义上更简洁,而且必须知道D的宽度。
创建一个与D宽度相同的伪元素。
将它放在容器的开头,使用::before。
使用灵活的自动边距来保持A, B和C的完美居中,pseudo和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开始,而不是担心左右项目的宽度相等,以保持平衡,只要给每个项目一个弹性:这将迫使他们都消耗可用的空间,从而居中中间的项目。
然后,您可以将display: flex添加到单个项目,以便对其内容进行对齐。
目前在Chrome, Firefox, Edge和可能的其他浏览器中,简写规则flex: 1分解为:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
在容器上使用最小高度时,基于flex的百分比单位(%)会导致此方法失效。这是因为,作为一般规则,子节点的百分比高度需要在父节点上显式设置height属性。
这是一条可以追溯到1998年(CSS Level 2)的老CSS规则,在许多浏览器中或多或少仍然有效。详情请见这里和这里。
下面是用户2651804在评论中发布的问题说明:
# flex-container {
显示:flex;
flex-direction:列;
背景:蓝绿色;
宽度:150 px;
最小高度:80 vh;
justify-content:之间的空间;
}
# flex-container > div {
背景:橙色;
保证金:5 px;
}
# flex-container > div:第一个孩子{
flex: 1;
}
# flex-container::{后
内容:“”;
flex: 1;
}
< div id = " flex-container " >
<div>非常长的烦人的文本,将添加到其父元素的高度之上
< div > < / 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网格布局
这可能是最干净和最有效的方法。不需要绝对定位,虚假元素或其他hack。
只需创建一个包含多列的网格。然后把你的项目放在中间和结尾的列中。基本上,只要把第一列空了。
ul {
显示:网格;
Grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5 px;
justify-items:中心;
}
Li:n -child(1) {grid-column-start: 2;}
Li:n -child(4) {margin-left:自动;}
/*仅用于演示*/
Ul{填充:0;保证金:0;list-style:没有;}
Li {padding: 5px;背景:# aaa级;}
P {text-align: center;}
< ul >
<李> < /李>
<李> B < /李>
<李> C < /李>
<李> D < /李>
< / ul >
<p><span>| true center |</span></p>