ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CSS3 Flex Box 布局从原理到实战:告别浮动,彻底解决垂直居中与等分布局

CSS3 Flex Box 布局从原理到实战:告别浮动,彻底解决垂直居中与等分布局 这段时间一直在重构之前的一个老管理后台翻到早期页面的时候我差点没认出来那是我自己写的代码满屏的 float: left、无休止的 clearfix、为了垂直居中套了三层父元素、按钮等宽分布靠手算百分比……说实话看到这些我一点都不怀念。我真正意识到 CSS3 弹性盒子Flex Box改变了整个布局思路是那次我用不到十行 Flex 相关代码替换掉原来一百多行浮动和 hack 的时候。这篇文章不是属性手册的搬运而是我想把从原理到实战、再到各种诡异坑位的一整套经验完整讲透。不管你是刚开始接触 Flex Box 的新手还是已经用了很久但偶尔会被 flex-shrink 和 min-width 折磨的开发者这篇文章都值得看完。1. 为什么满大街都在谈 Flex Box传统布局模式的三宗罪很多教程上来就列属性说 Flex Box 很好用但很少有人认真讲清楚它到底解决了什么痛点让那么多前端开发者用过一次就回不去了。我先把当年那些布局方式的苦水倒一倒你就能理解 Flex Box 为什么能成为现代布局的地基。1.1 用浮动排版的隐痛浮动float最早的设计目的是图文绕排就是让文字环绕在图片周围像报纸排版那样。结果早期没有更好的方案大家硬是拿它来搭整个页面骨架于是诞生了一堆根本不合理的代码习惯。浮动元素会脱离正常文档流父容器如果不做处理子元素全部浮起来之后高度直接塌成 0。为了撑起父容器我们要么在后面加一个清除浮动的空元素要么给父元素加上 overflow: hidden要么用经典的 ::after 伪元素写 clearfix。每个项目都要复制这段代码.clearfix::after { content: ; display: block; clear: both; }这还只是开始。浮动元素的宽度计算很敏感两栏布局里左边固定 200px右边想填满剩余空间通常要配合 calc(100% - 200px)再小心翼翼地处理 padding 和 border稍不留神就溢出换行。想要浮动元素垂直居中对不起做不到。想要两栏等高浮动更是直接绕道走。这些痛点叠加在一起让搭布局这件事变成了和浏览器斗智斗勇。1.2 垂直居中难到发指的年代在 Flex Box 普及之前前端社区流传着一个段子垂直居中是 CSS 里最大的难题。这不是夸张是真的难。我当时最常用的方案有三套表格 cell 法、绝对定位法、line-height 法。表格 cell 法是模拟 table 的 vertical-align但需要额外包一层而且对 HTML 结构有侵入性绝对定位法需要知道元素的宽高才能用 top: 50% 再 margin 负值回拉一旦内容变成动态的、高度未知这招就废了line-height 只对单行文本有效多行文本直接走样。/* 绝对定位法要求已知宽高 */ .modal { position: absolute; top: 50%; left: 50%; width: 400px; height: 200px; margin-top: -100px; margin-left: -200px; }这套写法的问题在于只要内容变多、弹窗高度变成自适应就得回去改 margin-top。更难受的是同一个页面里可能有十几种不同尺寸的内容块需要居中用传统方案你得给每个尺寸单独写一套偏移样式。而在 Flex Box 里居中就是一个属性组合的事后面我会专门讲。1.3 等高分栏与等宽排列的荒谬做法传统布局里还有两个需求让人头疼等高分栏和等宽排列。等高分栏就是三栏内容高度不一致但背景色和底边框要始终保持一样高。早期解决方案非常反直觉用 margin-bottom: -9999px padding-bottom: 9999px 这种负 margin 伪等高技巧靠超大数值的间距把背景色撑出去再用容器 overflow: hidden 截断。这方法看着聪明实际上非常脆弱一旦容器需要显示滚轮背景色就可能被截出问题。等宽排列更难。比如四个按钮要均分一整行宽度以前的写法是先算百分比25%、25%、25%、25%然后还得处理四个按钮之间的间距。如果间距是 20px那每个按钮实际宽度要改成 calc(25% - 15px)最后一个还不能加右边距否则整行会溢出。这还没完如果按钮数量是动态的比如后台管理界面里权限按钮有时 3 个有时 5 个你得重新算一遍。Flex Box 出现之后这类问题一句话就解决了。1.4 Flex Box 改善的其实是布局思维说了这么多痛点我想表达一个核心观点Flex Box 带来的不是某个属性的修补而是一整套布局思维的转变。在传统块级布局里我们面对的是文档流元素从上到下排列宽度、高度、浮动、定位全靠自己声明浏览器就是个照章办事的搬运工。而在 Flex Box 里我们面对的是主轴和交叉轴两条轴你告诉容器项目往哪个方向排、剩余空间怎么分配、超出之后换不换行、项目在两条轴上分别怎么对齐剩下的计算全部交给浏览器。这就是为什么很多人上手 Flex Box 之后会有一种如释重负的感觉你不再需要精确计算每个盒子的尺寸只需要描述布局意图浏览器会帮你把数学题做完。理解到这一层之后再去看那些属性就不是死记硬背而是一套有逻辑的体系了。2. 先把两条轴线掰扯清楚主轴与交叉轴的底层逻辑Flex Box 整个体系的根基就是两条轴主轴main axis和交叉轴cross axis。官方文档里画了很多图但我觉得很多人没真正理解这两条轴的关系。我试着用最直白的方式讲清楚。2.1 主轴由 flex-direction 一锤定音主轴的排布方向由容器上的 flex-direction 属性决定它一共有四个值row主轴从左到右这是默认值row-reverse主轴从右到左column主轴从上到下column-reverse主轴从下到上主轴决定了项目沿着哪个方向排成一列也决定了主轴起点main start和主轴终点main end在哪里。比如 row-reverse 不仅让项目顺序反转起点也变成了视觉上的右侧第一个项目会从右边开始排。这里有个常见误区很多人以为 column 就是把 row 转 90 度那么简单其实不完全是。column 模式下项目的宽度不会自动变成 100%它的交叉轴方向变成了水平方向所以水平对齐要靠 align-items后面会讲。方向一变你脑子里的坐标系就得跟着变。2.2 交叉轴永远与主轴垂直交叉轴就是与主轴垂直的那条轴。主轴是 row 时交叉轴是垂直方向从上到下主轴是 column 时交叉轴是水平方向从左到右。两个轴一横一竖构成了 Flex 布局的坐标系。理解这条轴的实战意义在于你会发现很多属性是跟着轴走的。例如 justify-content 管的是主轴方向的项目分布align-items 管的是交叉轴方向的对齐。如果你把 flex-direction 从 row 改成 column那么原来的水平居中需求可能要从 justify-content 变成 align-items这正是新手最容易搞混的地方。2.3 用排队和列队理解两组对齐属性抽象概念讲多了容易绕我用一个生活场景来对应。把主轴方向想成一条排队的通道所有的项目就是在通道里排队的人。justify-content 管的是整条队伍在通道里的分布方式队伍靠左站flex-start、靠右站flex-end、站在正中间center、第一个人顶着左边最后一个人顶着右边然后中间均匀散开space-between、每个人前后间距相同space-around、所有间距完全相等space-evenly。交叉轴方向则可以理解成每个人在自己的站位上怎么站align-items 决定他们是头顶对齐flex-start、脚底对齐flex-end、中心对齐center、还是把身高拉满填满整个站立区stretch。在 Flex 里stretch 是 align-items 的默认值这解释了为什么很多子元素在没有显式设置高度时会被拉成和容器一样高——我们站在队伍里默认就是要站满的。2.4 两条轴的本质从盒子思维到轴线思维我见过不少人学 Flex Box 已经能写代码了但遇到复杂需求还是犯懵根本原因是思维还停留在这个盒子应该多宽、多高上。Flex 布局真正要求你的是把问题翻译成项目在主轴和交叉轴上分别怎么放。举例来说以前做两栏布局你会想右边这栏到底该占多宽减去左边宽度之后还剩多少。改成 Flex 思维之后你会想右边这栏占满主轴上的所有剩余空间。前者是精确计算后者是声明意图浏览器的计算引擎帮你搞定一切。这个思维转换一旦完成再回来看 Flex 的属性每一个都不会觉得突兀因为它们本质上是同一套坐标系下对排布、分配、对齐三个问题的回答。3. 容器上的六大开关direction、wrap、justify-content、align-items、align-content、gapFlex 布局中写在容器上的属性决定了整个布局框架。这里我按实际使用频率和对布局效果的影响来逐个拆解。3.1 flex-direction方向定错后面全白搭flex-direction 是布局方向的总开关我在实际项目里遇到过很多次为什么 justify-content: flex-end 没生效的疑问一看代码容器设置了 column主轴已经变成垂直方向了flex-end 自然就作用到垂直方向上了。所以在写容器样式之前先问自己一句这一组项目是要横着排还是竖着排横着排用 row 系列竖着排用 column 系列。reverse 系列一般用于某些特殊 UI比如列表从底部往上弹或者处理阅读顺序与视觉顺序不一致的需求。正常情况下我不会主动推荐 reverse因为它会同时改变主轴起点视觉顺序和 DOM 顺序不一致时容易给后续维护埋坑。3.2 flex-wrap默认不换行空间不够就压缩Flex 容器默认 flex-wrap: nowrap意思是所有项目挤在一条轴线上哪怕容器的宽度不够也不会自动换行而是触发 flex-shrink 让项目收缩。很多时候我们期待的是一行放不下就换行比如商品卡片列表、标签组、图片墙。这种场景必须显式加上 flex-wrap: wrap。加上之后项目才会在主轴放不下的情况下折行形成多行的效果。一个容易混淆的点是flex-wrap 和 flex-shrink 都会在空间不足时做出反应但二者是两套逻辑。flex-shrink 是在不换行的前提下把项目压缩flex-wrap 是允许项目换到新的一行。两者可以同时存在但你要清楚自己想要的是压缩还是折行。像标签云、搜索历史这种内容我不建议让它们 shrink因为紧凑的压缩会让内容难读直接 wrap 反而更自然。3.3 justify-content主轴空间怎么分分给谁justify-content 控制项目在主轴上的分布方式。我列一个对照表把几个值的使用场景一次说清值表现典型场景flex-start项目从主轴起点开始排末尾留白默认的页面内容左对齐flex-end项目从主轴终点开始排开头留白弹窗底部按钮靠右center项目在主轴方向整体居中居中的提示、加载图标space-between首尾贴边中间项目间距相等导航栏左右两侧分散中间自适应space-around每个项目左右间距相等首尾只有一半间距图标分布间距需求不太严格时space-evenly所有项目之间以及首尾间距完全相等需要视觉上完全等距的菜单栏用的时候有个小经验如果两端的间距表现和中间不一致多半是选错了上面某个值。真正常用的其实就 flex-start、flex-end、center、space-between 几个space-around 和 space-evenly 偶尔用在图标、按钮组的均分上。3.4 align-items交叉轴上的起点终点与拉伸align-items 默认值是 stretch这是我在代码审查里见过最多误会的地方。因为默认是 stretch所以只要子项目没设置高度它们就会被拉成容器交叉轴的高度。比如一个容器里有文字又有图片你没有给文字标签设置 height它会被拉高导致行高表现异常。其他四个常用值flex-start项目贴交叉轴起点也就是行首flex-end项目贴交叉轴终点center项目在交叉轴方向居中baseline项目按第一行文字的基线对齐常用于多行文字和图标混排baseline 是一个被低估的值。有些排版场景下多个带不同字号或不同 padding 的元素如果用 flex-start 或者 center文字的底线会参差不齐而 baseline 会让它们像印刷体一样对齐在同一条基线上观感会精致很多。3.5 align-content多行项目才有的对齐方式align-content 是很多人完全不用的属性因为它只在 flex-wrap: wrap 并且实际产生了多行时才生效。它作用的对象是多行整体而不是单个项目。可以把它理解成交叉轴方向上的 justify-content当有多行项目时这些行在交叉轴方向上怎么分布由 align-content 控制。注意区分 align-items 和 align-contentalign-items 控制的是每一行内部项目的对齐方式而 align-content 控制的是行与行之间在交叉轴方向上的分布。当只有一行项目时align-content 不生效你必须用 align-items。当有多行项目且容器高度超过内容总高度时align-content: center 可以让整个多行内容整体垂直居中这是很多新手想实现而不得其法的需求。3.6 gap给项目间距别再逐项加 margin在 Flex 布局里设置项目间距以前的标准做法是给项目写 margin然后处理第一个和最后一个多余边距。用 :first-child 和 :last-child 去清零或者给容器加负 margin这些都是权宜之计。现在主流浏览器都支持了 gap、row-gap、column-gap直接写在容器上就行.container { display: flex; flex-wrap: wrap; gap: 16px 24px; }上面这行代码表示行间距 16px列间距 24px。gap 的好处是不会额外占用项目自身的空间而且不会在容器边界产生多余的边距。从 2021 年以后gap 在 Flex 布局里的兼容性已经足够好了我在新项目里会直接使用不再维护一堆 margin 清零的兼容代码。4. 项目身上的微操按钮flex-basis、flex-grow、flex-shrink 与 flex 速记容器属性定义了框架项目属性则负责回答单个项目在这个框架里怎么伸缩。这部分是 Flex Box 里最容易被忽略、却是最能发挥威力的地方。理解了 flex 的实现逻辑你就再也不会被为什么这个元素被压扁了这种问题困扰。4.1 flex-basis项目的基本尺寸基准flex-basis 定义的是项目在主轴方向上的基准尺寸。在 row 模式下它决定的是项目的基础宽度在 column 模式下它决定的是项目的基础高度。它有三个典型取值auto基准尺寸取项目自身的 width 或 height如果没有设置则取内容尺寸固定值比如 200px、30%项目优先按这个值作为基准0基准尺寸为 0完全忽略项目自身的 width这里有一个重要特性当 flex-basis 设置了具体数值非 auto时它的优先级高于 width 属性。也就是说如果你同时写了 width: 300px 和 flex-basis: 200px在 Flex 布局中实际起作用的基准是 200px。遇到为什么 width 不生效的问题时先怀疑一下是不是 flex-basis 在作怪。4.2 flex-grow剩余空间的分配逻辑flex-grow 默认值是 0表示项目不放大。当所有项目的 flex-grow 之和小于 1 时会有部分剩余空间留在容器里当总和大于等于 1 时剩余空间会被全部瓜分。它的计算公式是这样的每个项目分配到的额外空间 剩余空间 ×该项目 flex-grow 值 ÷ 所有项目 flex-grow 值之和。举个例子容器宽度 600px三个项目 flex-basis 都是 100px那么剩余空间是 300px。如果三个项目的 flex-grow 分别是 1、2、1那么它们分别分到 300 × (1/4) 75px、300 × (2/4) 150px、75px最终宽度是 175px、250px、175px。很多人误以为 flex-grow 是宽度比其实只有当所有项目 flex-basis 都为 0 时flex-grow 的比值才恰好等于最终尺寸的比值。所以如果你想实现三个项目按 1:2:1 的比例分配容器宽度正确的写法是给所有项目设置 flex-basis: 0再配 flex-grow: 1、2、1。如果不把 basis 清零最终结果会受到内容宽度影响。4.3 flex-shrink空间不足时谁先缩flex-shrink 默认值是 1表示空间不足时项目允许收缩。它的计算逻辑比 grow 更反直觉因为它的权重需要乘以 flex-basis。flex-shrink 的计算公式是每个项目需要缩减的量 溢出空间 ×该项目 flex-basis × flex-shrink 值÷所有项目 flex-basis × flex-shrink 值的加权和。我举一个具体例子容器宽度 300px三个项目 flex-basis 都是 200px总和 600px溢出 300px。三个项目 flex-shrink 为默认的 1 时加权值分别为 200、200、200总和 600。每个项目缩减 300 × (200/600) 100px最终宽度都是 100px。如果把第二项的 flex-shrink 改为 2那么加权值变成 200、400、200总和 800。缩减量分别为 300 × (200/800) 75px、300 × (400/800) 150px、75px最终宽度为 125px、50px、125px。可以看到 flex-shrink 值大不代表缩减量线性变多而是缩减量按加权比例分配。这就是为什么当你设置 flex-shrink: 0 时该项目完全不会被压缩其他项目则会承担全部溢出缩减。4.4 速记 flex: 1、flex: auto、flex: none 的真实含义实际开发中很少会分开写 grow、shrink、basis而是用 flex 速记。我整理了最常用的几个速记值对照关系如下速记写法展开后的值效果flex: initial0 1 auto不放大空间不足可缩小基准取自身尺寸默认行为flex: auto1 1 auto既可以放大也可以缩小基准取自身尺寸flex: 11 1 0%基准为 0项目平均分配容器空间flex: none0 0 auto不放大不缩小严格按内容或自身尺寸我在项目里的习惯是单侧栏固定、另一侧自适应时自适应一侧直接写 flex: 1等宽分布的子项全部写 flex: 1需要完全按内容排布、不参与伸缩的标签写 flex: none。需要注意 flex: 1 的 basis 是 0%这是一个很关键的行为。它意味着项目忽略自身内容宽度完全基于容器空间来平均分配。如果你的项目里有长文本直接 flex: 1 可能会导致内容被强行压缩换行这时需要考虑 min-width 的处理我留到踩坑部分详细讲。4.5 order 与 align-self布局边缘的微操order 属性可以改变项目在视觉上的排列顺序默认值都是 0数值小的排在前面。比如商品列表里要突出某个主推商品可以给它 order: -1让它排到最前面而不需要改 DOM 结构。不过要提醒一点order 改变的是视觉顺序不是 DOM 顺序对键盘导航和屏幕阅读器用户来说实际的焦点顺序仍然是按 DOM 来的这会导致读屏顺序和看到的不一致。如果是为了交互体验调整顺序我会优先考虑修改 DOM 结构如果只是纯视觉层面的装饰性排序order 可以用。align-self 则允许单个项目覆盖容器上的 align-items 设置。比如容器整体 align-items: center但最后一个按钮希望贴着底部一个 align-self: flex-end 就搞定了不需要为了它再套一层容器。5. 实战对照Flex Box 终结的四种经典布局方案理论讲得再多不如直接看代码落地。我从真实项目里挑出四类最常见的布局需求把 Flex Box 写法和传统写法做一个对比你会更直观地感受到这套体系的价值。5.1 垂直水平居中的一劳永逸写法垂直居中这个老大难问题在 Flex Box 里的解法非常干净.wrapper { display: flex; justify-content: center; align-items: center; }不管里面是一个 100px 的小图标还是一段高度不定的动态内容这两行都能让它既水平居中又垂直居中。而且不需要知道子元素的高度也不需要给它设置任何偏移量。遮罩层、加载动画、空状态提示我都用这套写法从没翻过车。还有一种隐藏玩法容器设置 display: flex子元素设置 margin: auto也能实现居中。这个写法在某些嵌套场景下有用因为 margin: auto 在 Flex 布局里会吸收项目在对应方向上的所有剩余空间。比如一个侧边栏布局主内容区要水平居中其他区域要保持原有排布直接在目标元素上写 margin: auto 就行不必对容器动刀。5.2 两栏自适应布局侧栏固定主内容撑满后台管理系统最常见的布局左侧固定宽度菜单右侧内容区填满剩余宽度。用 Flex Box 写起来非常直接.layout { display: flex; min-height: 100vh; } .sidebar { flex: 0 0 220px; } .main { flex: 1; min-width: 0; }侧栏 flex: 0 0 220px 表示固定宽度 220px既不放大也不缩小主内容 flex: 1 填满剩余空间。没有浮动没有清除浮动没有 calc 计算也不存在侧栏和主内容高度不齐的问题因为 align-items 默认 stretch 会让两者天然等高。这里我给主内容加了一个 min-width: 0很多人可能不理解。它的作用是防止主内容里的长文本或表格把 Flex 项目撑破。如果不加当内容宽度超过可用空间时flex: 1 的项目会因为隐式最小尺寸min-width: auto而无法收缩到预期宽度最终导致布局溢出。5.3 三栏等高布局Flex 下的等高是天然的传统的三栏等高布局要靠负 margin 伪造或者靠背景平铺而在 Flex 容器里等高是一个默认行为不需要任何额外处理.columns { display: flex; align-items: stretch; } .column { flex: 1; }三个栏目无论内容多长它们的高度都会自动撑满容器而容器的高度又由最高的一栏决定。这样每栏的背景色或边框底部都会齐平视觉上干净利落。这个特性在卡片列表、数据概览、仪表盘分区里尤其好用。5.4 导航栏与按钮组均分、换行、顺序调整导航栏是一个 Flex Box 高频场景。典型的顶部导航有两种需求一是左右分布品牌在左边菜单在右边二是多个菜单项均分整行。左右分布可以这样写.nav { display: flex; align-items: center; } .nav .menu { display: flex; gap: 24px; margin-left: auto; }menu 组用 margin-left: auto 吸走左侧剩余空间实现自动推到右侧不需要单独包裹浮动层。均分按钮组更简单给所有按钮 flex: 1 即可平均分配宽度在移动端希望按钮换行时给容器加 flex-wrap: wrap按钮再加 min-width 控制换行断点。比如按钮在 480px 以下每行两个可以写 flex: 1 0 45%折行后自动均匀排成两列。Flex Box 把这种响应式变化变成了属性调整不再需要反复计算百分比。5.5 移动端卡片流wrap 加 space-between 的黄金组合移动端首页最常见的卡片列表用 Flex Box 实现起来非常顺手.card-list { display: flex; flex-wrap: wrap; gap: 16px; } .card { flex: 1 1 280px; max-width: 360px; }每一张卡片基础宽度 280px空间充足时可以长到 360px空间不足时自动换行。gap 负责统一间距不需要再为 margin 和负 margin 操心。这种写法相比传统 float 加百分比的方式最大的优势是内容驱动换行卡片数量变化、容器宽度变化布局都会自动适配不需要写一堆断点。6. 我在项目中踩过的 Flex Box 的坑附兼容性速查Flex Box 用起来爽但坑也不少。很多坑不是属性本身的问题而是属性之间的相互作用超出了直觉。我把这些年踩过的、以及帮别人排查过的典型问题整理在这里这些经验是文档里不会写清楚的。6.1 flex-basis 与 width 同时设置到底听谁的前面提到过flex-basis 的优先级高于 width在取值非 auto 时。这个规则看起来简单但实际代码里经常会引发奇怪的问题。有一个真实场景某张卡片设置了 width: calc(33.33% - 20px) 作为三列布局的宽度被同事改成 flex 布局之后忘了删掉原来的 width只加了 flex: 1期望是自适应分配。结果卡片宽度还是按 33.33% 走因为 flex: 1 的 basis 是 0%按理说应该忽略 width但这里因为卡片本身有内容宽度min-width: auto 又把项目撑回到了内容宽度附近最终表现出看起来 width 生效了的假象。排查时我一度很困惑。这类问题的最好处理方式就是代码里只保留一套尺寸定义。要使用 Flex 分配空间就清理掉多余的 width要依赖 width 控制尺寸就写 flex: none。两者同时存在要么是维护者没意识到优先级要么是故意为之但没写注释无论哪种都是隐患。6.2 min-width: auto 这个隐式默认值是怎么坑我的Flex 项目默认的 min-width 是 auto也就是说它不允许被压缩到小于内容的最小宽度。这个设计对一般内容很友好但对长文本、长链接、长英文单词来说就是灾难。举个例子一个 flex: 1 的详情区域里放了一长串 URL或者一个超长的英文单词由于 min-width: auto这个项目无论如何都不会被压缩到比这个单词的宽度还窄于是整个布局被撑破后面几列被挤到旁边。解法是给这个项目加上 min-width: 0或者在项目内部设置 overflow: hidden 或 overflow-wrap: break-word。这里有个规律凡是flex 项目内部出现了文本溢出、布局被撑破的问题十有八九是 min-width: auto 在作怪。我给团队写规范的时候会把 min-width: 0 列为 Flex 自适应性布局项目的默认选项除非你明确知道内容一定很窄。6.3 高度 stretch 引发的那次布局事故align-items 默认是 stretch这在很多场景下是好事但有一次我在做一个表单页时被它坑过表单项的右侧有一个提示图标我原本只想让图标和输入框顶对齐结果因为容器默认 stretch图标被拉到了一个和输入框等高的高度视觉上出现了一大片空白区域点击区域也变得异常大。排查过程很顺利因为我知道默认值就会这么干马上给图标设置了 align-self: flex-start 就解决了。我想说的是当你发现某个元素莫名其妙变高了时第一反应应该检查它所在的 Flex 容器有没有显式设置 align-items。stretch 这个东西默认生效但它并不总是你想要的。6.4 margin: auto 在 Flex 布局里的隐藏用法margin: auto 在 Flex 布局中是一个隐藏神器。它不仅能实现居中还能实现分组布局中的自动推挤。比如顶部导航左边是 logo、中间是搜索框、右边是用户信息如果我不想给中间元素单独设置宽度或 flex-grow最简单的方式是给中间的搜索框加上 margin-left: auto 和 margin-right: auto它会自动把两侧剩余空间平分让搜索框稳稳待在中间。右边同理给用户信息写 margin-left: auto 就能把它推到最右边。这个技巧的底层原理是Flex 布局中auto 方向的 margin 会吸收该方向上的所有剩余空间。多个 auto margin 会平分剩余空间所以左右 auto 导致居中单侧 auto 导致整体靠边。理解了这一点你再也不需要为推挤单独包容器了。6.5 兼容性速查与降级策略虽然现在已经是现代浏览器的时代但依然有企业客户跑在老旧系统上兼容性仍然值得说明。环境Flex Box 支持情况Chrome 29、Firefox 28、Safari 9支持标准语法iOS Safari 8 及以下部分支持需要 -webkit- 前缀IE10支持 -ms- 前缀的旧语法IE11支持大部分标准语法但在 flex-basis 和 min-height 组合上存在 bug我的降级策略分两步。第一步构建工具里加 Autoprefixer自动补全 -webkit- 和 -ms- 前缀。第二步对关键布局页面写一个回退方案用 float 加宽度百分比做基础布局然后用 supports 检测浏览器是否完整支持 Flex 的某个关键属性支持则覆盖成 Flex 布局.layout { display: block; } .layout .sidebar { float: left; width: 220px; } supports (display: flex) { .layout { display: flex; } .layout .sidebar { float: none; width: auto; } }这个方法能保证老浏览器看到的是一个还能用的布局现代浏览器则享受到 Flex 的完整特性。对于绝大多数项目来说做到这个程度已经足够了。6.6 最后说点实在话Flex Box 学了这么多年我的核心体会其实就一句话先画轴再写属性最后再去跟浏览器要结果。每次搭一个 Flex 布局我都会先问自己两个问题。主轴方向是什么项目换不换行想清楚这两点哪个属性管哪条轴就全清楚了。其次写项目尺寸时坚持用 flex 速记哪怕只写一个 flex: 1 或者 flex: none都比只写 flex-grow 缺失另外两个属性更可控。第三遇到任何这个元素为什么被撑破/压扁/不换行的诡异问题检查顺序永远是 min-width、flex-shrink、flex-basis 这三个绝大多数坑都藏在这里面。Flex Box 足够好用但它也不是万能的。真正复杂的不规则二维布局要交给 CSS Grid一维的、线性的、需要灵活分配空间的场景Flex Box 是最趁手的工具。把这两件事分清楚你的 CSS 布局水平会再上一个台阶。
返回列表