Flex 居中应该这么写

假设现有个很简单的需求,让 item 在 container 容器内居中:

html 复制代码
<div class="container">
  <div class="item">居中</div>
</div>

当前 CSS 样式为:

css 复制代码
.container {
  width: 500px;
  height: 300px;
  background-color: yellow;
}
.item {
  padding: 10px;
  background-color: lightgreen;
}

当前的效果如下:

而想要的效果区域在黄色容器内上下和左右都居中。很简单,只要给 container 容器设置为 flex 布局,并且在主轴和交叉轴上都居中即可,代码如下:

css 复制代码
.container {
  display: flex;
  align-items: center;
  justify-content: center;
}

很快就能实现下面的效果了:

然而,这样居中是有问题的,请不要这么写代码,笔者推荐的方式是:

css 复制代码
.container {
  display: flex;
}

.item {
  margin: auto;
}

即不要给容器设置 justify-contentalign-items 属性,而是给子元素设置 margin: auto,可以实现同样的效果:

原因分析

为什么要这么设置呢?问题出现在当 Item 的内容不再是简单的「居中」两个字,而是很长一段文本,导致撑满了整个 flex 布局的容器的时候,请看:

html 复制代码
<div class="container">
  <div class="item">当乌鸦飞过山头,云彩在空中飘荡,太阳逐渐升起,洒下金色的光芒,照亮了整个大地,万物苏醒,迎接新的一天的到来。在这美丽的早晨里,鲜花绽放,鸟儿欢唱,微风轻拂着脸庞,带来一丝凉意,让人感到宁静而舒适。
    小时候,总幻想着长大后的自己会过上理想中的生活,拥有自己的家庭、事业和幸福。而如今,当我回望过去,发现生活没有想象中的那么简单,充满了各种考验和挑战。但我并不畏惧,因为我相信坚持和努力能够克服一切困难,让梦想成为现实。
    在这个充满机会和竞争的世界里,每个人都在追寻着自己的梦想。有人选择脚踏实地,默默付出,一步一个脚印地追求成功;有人选择勇往直前,大胆冒险,不惧失败地追求突破。而我,我希望能够找到自己的定位,做自己喜欢的事情,用心去追求,用行动去证明自己的价值。
    人生就像一本书,每个人都是其中的主角,我们要用自己的双手去书写精彩的篇章。无论遇到什么困难和挫折,我相信只要坚持不懈,勇往直前,就一定能够战胜困难,实现自己的梦想。
    所以,让我们一起迎接生活的挑战,抓住机遇,勇往直前,相信自己的能力,努力奋斗,让每一天都过得有意义,活出自己想要的精彩人生!
  </div>
</div>

此时,文本太长,超出容器范围了:

可以看到,开头的文本被截断了,并没有显示出来!这就是因为给 flex 设置 align-items: center 导致的。即使设置容器的 overflow 属性,让里面的文本能够滚动。顶部溢出的文本依然显示不出来。

而此时如果你使用的是 margin: auto 的居中方案,则不会出现此问题,开头的文本能够正常显示:

类似案例

上面是问题是因为 flex 容器内的元素在交叉轴方向上溢出了,顶部区域不可见。类似的,当左右布局,在主轴方向超出溢出的时候,也会导致开始左侧区域内容不可见,例如:

下面的代码可以复现上面的案例,其中 DOM 结构如下:

html 复制代码
<div class="flex-container">
  <div class="item" style="background-color: yellow;">
    <h2>box #1</h2>
    <p>this box disappears and can't be accessed via scroll</p>
  </div>
  <div class="item" style="background-color: antiquewhite;">
    <h2>box #2</h2>
    <p>this box is fully accessible at all times
    </p>
  </div>
  <div class="item" style="background-color: lightgreen;">
    <h2>box #2</h2>
    <p>this box is fully accessible at all times
  </div>
</div>

CSS 代码如下:

css 复制代码
.flex-container {
  display: flex;
  justify-content: center;
}

.item {
  flex: 1;
}

.item p {
  white-space: nowrap;
}

这里的关键是因为 justify-content: center 导致的,去掉即可。

底层设计

造成上述问题的原因是 flex 布局本身的缺陷导致的:

Flexbox's alignment properties do "true" centering, unlike other centering methods in CSS. This means that the flex items will stay centered, even if they overflow the flex container.
This can sometimes be problematic, however, if they overflow past the top edge of the page, or the left edge [...], as you can't scroll to that area, even if there is content there!

为了彻底解决这个问题,CSS 标准增加了 safeunsafe 两个关键字:

用户可以在设置 flex 元素居中的时候指定是 safe 模式:

css 复制代码
justify-content: safe center;
align-self: safe center;

可是这个新属性的兼容性并不是很好,大家在项目中谨慎使用:

相关推荐
dot.Net安全矩阵几秒前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
Hellc00711 分钟前
MacOS升级ruby版本
前端·macos·ruby
前端西瓜哥20 分钟前
贝塞尔曲线算法:求贝塞尔曲线和直线的交点
前端·算法
又写了一天BUG21 分钟前
npm install安装缓慢及npm更换源
前端·npm·node.js
cc蒲公英35 分钟前
Vue2+vue-office/excel 实现在线加载Excel文件预览
前端·vue.js·excel
Java开发追求者35 分钟前
在CSS中换行word-break: break-word和 word-break: break-all区别
前端·css·word
好名字082139 分钟前
monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)
前端·javascript
pink大呲花1 小时前
css鼠标常用样式
前端·css·计算机外设
Flying_Fish_roe1 小时前
浏览器的内存回收机制&监控内存泄漏
java·前端·ecmascript·es6
小小竹子1 小时前
前端vue-实现富文本组件
前端·vue.js·富文本