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;

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

相关推荐
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫4 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦4 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子5 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享6 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
清灵xmf7 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨7 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL8 小时前
npm入门教程1:npm简介
前端·npm·node.js
小白白一枚1118 小时前
css实现div被图片撑开
前端·css