音乐网站的设计,做网站的系统,php网站开发优点,关键词排名关键词快速排名Flexbox 是现代 Web 布局的主流技术之一#xff0c;它提供了一种有效的方式来定位 、排序 和 分布元素#xff0c;即使在视窗或元素大小不明确或动态变化时亦是如此。Flexbox 的优势可以用一句话来表达#xff1a;“在不需要复杂的计算之下#xff0c;元素的大小和顺序可以…Flexbox 是现代 Web 布局的主流技术之一它提供了一种有效的方式来定位 、排序 和 分布元素即使在视窗或元素大小不明确或动态变化时亦是如此。Flexbox 的优势可以用一句话来表达“在不需要复杂的计算之下元素的大小和顺序可以灵活排列 ”即“Flexbox 为您提供了元素大小和顺序的灵活性”。如此一来可以让 Web 的布局变得简单地多。
在这节课程中我将介绍如何使用 Flexbox 来构建 Web 中的一些经典布局实践中常使用的 Web 布局。这些布局在还没有 Flexbox 技术之前就在 Web 中很常见比如等高布局 、分屏 或等分列 、水平垂直居中 、Sticky Footer 、圣杯布局 和 Grid Frameworks简单的网格系统 等只不过我们在使用以往的 Web 布局技术比如浮动float、定位position和内联块display:inline-block等实现会比较困难甚至还需要一定的 CSS 黑魔法Hack 手段但使用 Flexbox 就会显得容易得多。 在开始之前我用一张图来帮助大家回忆一下前面几个有关于 Flexbox 课程的知识 点击查看大图 水平垂直居中 可以说水平垂直居中在 Web 上的运用是随处可见比如一个 Icon 图标在其容器中水平垂直居中一个标题在导航栏中水平垂直居中。 CSS 中可以实现水平垂直居中的技术方案也有很多种至少不会少于十种不同的技术方案。不过这里我们主讲 Flexbox 如何实现水平垂直居中。
首先水平垂直居中常见的效果有两种单行或单列水平垂直居中和多行或多列水平垂直居中。它对应的 HTML 结构可能会像下面这样
!-- 单行或单列水平垂直居中 --
div classcontainer container--singleimg srcavatar.png alt需要在容器中水平垂直居中 /
/div!-- 多行或多列水平垂直居中 --
div classcontainer container--multipleimag srcavatar alt我们要水平垂直居中 /h3大漠|W3cplus.com/h3p掘金小册.现代Web布局/p
/div在 Flexbox 中可以在 Flex 容器上使用
justify-content 的 center 让 Flex 项目水平居中。对于单行而言可以使用 align-items 的 center 让 Flex 项目垂直居中当然使用 align-content 的 center 也可以让 Flex 项目垂直居中但需要显式设置flex-wrap 的值为 wrap 或 wrap-reverse。对于多行而言flex-direction 显式设置了 column则使用 align-items 的 center 让所有 Flex 项目水平居中再配合 justify-content 的 center 实现垂直方向居中
在 CSS 中我们可以像下面这样编码可以轻易实现水平垂直居中
.container {display: flex; /* inline-flex */
}/* 单行(或单列)水平垂直居中 */
.container--single {justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */
}/* 多行或多列水平垂直居中 */
.container--multiple {flex-direction: column;align-items: center; /* 水平居中 */justify-content: center; /* 垂直居中 */
}Demo 地址 https://codepen.io/airen/full/rNvpYJW 单行或多行实现水平垂直居中两者都可以在 Flex 容器上设置 justify-content 和 align-items 属性的值为 center 不同的是在多行的 Flex 容器上要显式设置 flex-direction 属性的值为 column 。
你还可以将 justify-content 和 align-self 配合起来实现水平垂直居中的效果
Flex 容器上设置 justify-content 的值为 center 让 Flex 项目实现水平居中Flex 项目上需要实现垂直居中的 Flex 项目上设置 align-self 的值为 center 。
比如
div classcontainerdiv classitem(^_^)/div
div
.container {display: flex; /* 或 inline-flex */justify-content: center; /* Flex 项目水平居中 */
}.item {align-self: center;
}Demo 地址https://codepen.io/airen/full/abGqoqo 注意从效果上可以看得出来如果在 Flex 项目上未显式设置 align-self:center 时Flex 项目会被拉伸这是因为 Flex 容器的 align-items 默认值为 stretch 。如果你需要避免 Flex 项目在侧轴被拉伸可以重置 align-items 的值为 stretch 之外的值。
这种方法也同样适用于多行或多列水平垂直居中
.container {display: flex;justify-content: center;
}.container * {align-self: center;
}.container--multiple {flex-direction: column;
}Demo 地址 https://codepen.io/airen/full/bGMLbzK 如果实现单个元素Flex 项目在 Flex 容器中水平垂直居中你还可以使用 justify-content 和 align-content 两者的简写属性 place-content 并且将其设置为 center但需要配合 flex-wrap 属性来使用一般设置为 wrap
.container {display: flex;flex-wrap: wrap;place-content: center;/* 等同 */justify-content: center;align-content: center;
}Demo 地址https://codepen.io/airen/full/zYjRYGv 在特定场景或环境之下这种方式也适用于多行水平垂直居中比如 Flex 容器没有足够空间致使 Flex 项目断行 虽然使用一些 Hack 手段可以避免上图这样的现象出现但这样的 Hack 手段会让 Web 布局失去一定的灵活性在实际开发的过程中不建议这样使用。除非你能提前预判
.container .title {flex: 1 0 100%;text-align: center;white-space: nowrap;
}Demo: https://codepen.io/airen/full/poVaoEM 如果你实在需要使用 place-content 来让元素水平垂直居中的话可以考虑和 place-items 结合起来使用即
.container {display: flex;place-content: center;place-items: center;/* place-content 等同于 */justify-content: center;align-content: center;/* place-items 等同于 */align-items: center;justify-items: center;
} 对于多个 Flex 项目时需要在 Flex 容器显式设置 flex-direction: column 。其实它和前面的 justify-content 和 align-items 取值 center 是一样的原理只不过这里使用了其简写属性。
我们前面的课程有介绍过在 Flexbox 布局中你可以在 Flex 项目上设置 margin 的值为 auto 来控制 Flex 项目位置 也就是说如果你只是想控制单个 Flex 项目在 Flex 容器中水平垂直居中的话使用 margin:auto 也是一种不错的选择
.container {display: flex;
}.item {margin: auto;
}Demo 地址 https://codepen.io/airen/full/JjvpjLy 你可以在 Flexbox 布局中使用不同的方式来实现水平垂直居中的效果至于选择哪一种方案可以根据实际情况来选择。如果你实在不知道如何选择还可以借助浏览器调试工具来辅助你快速选择 留个小作业请使用 Flexbox 来实现 Logo 图标在其容器中水平垂直居中 等高布局
Web 设计师为了让页面或组件的 UI 更美观往往会考虑像等高布局这样的效果 如上图所示右侧等高布局看起来总是要比左侧的不等高布局更舒服一些。虽然等高布局在 UI 上会令人感到更舒服但在以往的布局技术中要实现等高布局还是有点麻烦的。
主要原因是我们并不知道元素的高度是多少 即使知道了如果给元素上直接设置一个 height 值很有可能就会造成内容溢出容器甚至是打破 Web 布局。那么使用 Flexbox 包括后面要介绍的 Grid布局技术实现等高布局就会轻易地多甚至可以说是没有任何难度可言。比如我们要实现一个等高布局的卡片组件 上图中的三张卡片排列在一起它们
每一张卡片的视觉高度相等列高相等并且取最大的列每一张卡片有相同的宽度也可以自适应每一张卡片都有缩略图 、标题 、描述文本和一个按钮 并且卡片缩略图大小是相等的而且按钮不管卡片标题和描述文本的长短始终位于卡片底部。
如果不采用 Flexbox 布局技术方案当未给卡片设置一个最小高度时往往实现的效果会像下图这样 如果使用 Flexbox 布局技术实现起来就很简单
div classcardsdiv classcardfigureimg srcthumb.png alt缩略图 //figureh3Card Title/h3pCard Describe/pbuttonButton/button/div!-- 其他 Card --
/div与布局相关的 CSS 代码
.cards {display: flex;flex-wrap: wrap;gap: 1rem;
}.card {display: flex;flex-direction: column;flex: 1 1 300px;
}在这个示例中卡片.card 和其容器 .cards 都是 Flex 容器并且每张卡片的初始化尺寸是 300px 即 flex-basis 的值为 300px而且容器 .cards 无法容纳所有卡片 .card 时它会自动换行并且最后一个卡片宽度变宽了这是因为卡片 .card 设置了flex-grow:1 。 你可能会感到好奇为什么会这样又将如何解决接下来的内容中你会找到答案。我们回到等高布局中来你可能已经发现了只要告诉浏览器卡片容器 .cads 是一个 Flex 容器那么所有卡片 .card 的高度就相等了而且会以最高的那张卡片为主 这是因为Flex 容器 .cards 的 align-items 属性的默认值是 stretch 如果没有调整 align-items 属性的值那么该容器中的所有子元素即 Flex 项目 .card在侧轴方向就会被拉伸并且等于侧轴尺寸。反之就会得到一个不等高的卡片比如你在 .cards 上显式设置了 align-items 的值为 flex-start 你将看到的效果如下
.cards {align-items: flex-start;
}也就是说默认情况之下Flex 容器中的所有 Flex 项目都是相等的 这也是 Flexbox 实现等高布局很容易的主要原因。
虽然说将 .cards 创建为一个 Flex 容器就实现了卡片等高的效果但这个效果还不是设计师所期待的比如第二和第三张卡因卡片标题和描述内容比第一张卡片更少造成按钮偏上卡片底部留下一定的空白空间设计师期望的是所有卡片的按钮都能在底部对齐 要实现上图左侧的效果在 Flexbox 布局中也有多种方式比如我们这个示例每张卡片 .card 本身就是一个 Flex 容器你只需要将剩余空间分配给卡片中的 p 元素描述文本即可就是将其 flex-grow 值设置为 1
.card p {flex-grow: 1;
}Demo 地址 https://codepen.io/airen/full/VwxQLyj 除了上面这种方案之外还可以在 button 元素显式设置 margin-top 的值为 auto
.card button {margin-top: auto;
}Demo 地址 https://codepen.io/airen/full/PoeQPVL 如果你不希望按钮宽度占满整个卡片还可以改变 button 的 algin-self 值比如
/* 按钮居左 */
.card button {align-self: flex-start;
}/* 按钮居右 */
.card button {align-self: flex-end;
}你将得到下面这样的效果 小作业请使用 Flexbox 布局技术实现一个等高布局的 Web 页面 简单化一下 均分列等分列布局 正如上图所示在 Web 中均分列的布局效果很多尤其是在移动端的开发当中底部的菜单栏中的列大多都是均分的。 均分列又称为等分列或等列它的最大特征就是列的宽度是相等的 以往 CSS 实现等分列都是通过百分比来计算比如
列数--column列间距--gap。
一般情况下列宽就是
列宽 容器宽度 - 列数 - 1× 列间距÷ 列数假设是一个三列列间距为0那么每列的宽度将会是
.coumn {/*** 容器宽度 ➜ 100%* 列数 ➜ --columns 3* 列间距 ➜ --gap 0* 列宽 ((100% - (3 - 1) × 0) ÷ 3 33.3333% **/width: 33.33333%;
}或者使用 calc() 函数和 CSS 的自定义属性结合
:root {--container-width: 100%; /* 容器宽度 */--columns: 3; /* 列数 */--gap: 0 ; /* 列间距 */
}.column {width: calc((var(--container-width) - (var(--columns) - 1) * var(--gap)) / var(--columns));
}但不管是哪种方式开发者都需要提前知道等分的列数、列间距等对于构建一个动态的等分列上面方案的缺陷就出来了。开发者需要不断地去做数学计算而且是需要知道参数的情况之下才行 。
如果换成 Flexbox 技术来构建的话开发者就不需要去考虑这些参数了。比如下面这个移动端的底部工具栏的效果 构建它的 HTML 结构并不复杂
footerdiv classitemIcon / Icon name/div!-- 省略其他的菜单项 --
/footer
footer {display: flex;
}.item {flex: 1;min-width: 0; /* 这行代码很重要 */
}/* 菜单项图标和文字的布局 */
.item {display: inline-flex;flex-direction: column;align-items: center;justify-content: center;gap: 5px;
}Demo 地址 https://codepen.io/airen/full/GRdQZYv 使用 flex:1 来均分列即平均分配 Flex 容器可用空间并不是完全可以的它需要配合 min-width:0 一起使用。因为在 Flex 项目上显式设置 flex:1 时已重置了 flex 的初始值flex: 0 1 auto浏览器会把 flex:1 计算成
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%当 flex-basis 为 auto 时 Flex 项目的宽度是 max-content 除非 Flex 容器空间完全不足。也就是说flex:1 时flex-basis 值从 auto 变成了0% 这将覆盖 Flex 项目的内在尺寸min-content Flex 项目的基本尺寸现在是 0 但由于 flex-grow 的存在Flex 项目会扩展以填补空的空间Flex 容器的剩余空间。
而实际上在这种情况下flex-shrink 不再做任何事情因为所有 Flex 项目现在的宽度都是 0 并且正在增长以填补可用空间。只不过 Flex 容器有可能存在没有剩余空间的情况甚至是有不足空间的情况存在。此时flex:1 也就不能均分 Flex 容器的可用空间。 正如上图所示最后一个 Flex 项目的宽度要更大它的 max-content 都比其他 Flex 项目大它有四个汉字宽。
事实上默认情况之下设置了 flex:1 的 Flex 项目在收缩的时候其宽度不会小于其最小内容尺寸min-content。如果要改变这一点需要显式设置 min-width 或 min-inline-size或 min-height 或 min-block-size的值。
CSS 中它们的值为 auto 时会被浏览器计算为 0 。但在 Flexbox 中Flex 项目的 min-width 或 min-height 的值又不会被计算为 0 它的值被计算为 max-content 。
为此要真正达到均分列只在 Flex 项目上显式设置 flex:1 是不够的还需要在 Flex 项目上显式设置 min-width 值为 0 。这也就是说为什么 min-width:0 很重要。
不过在使用 flex:1 的时候需要额外注意的是这个 1 会被视为 flex-grow 的值。如果你要使用 flex 更建议的做法是显式地使用 flex 属性的三个值比如 flex: 1 1 0% 或 flex: 1 1 100% 。 特别提醒这里涉及到了 flex 的相关计算有关于这方面的介绍可以阅读我们前面课程的 0608 讲。 小作业卡片等宽且等高 圣杯布局
圣杯布局Holy Grail Layout是 Web 中典型的布局模式。它看上去像下图这样 就上图而言这就是一个非常普通的三列布局。对圣杯布局有一定了解的同学都应该知道构建圣杯布局时对 HTML 的结构是有一定的要求即 主内容为先 。早期这样做是让用户在 Web 页面加载缓慢时就能先看到主内容。
!-- HTML --
header!-- 页头 --
/header
main!-- 页面主体它包含两个侧边栏和一个主内容列 --article!-- 页面主内容列需要排在 nav 和 aside 前面 --/articlenav!-- 侧边导航栏 --/navaside!-- 侧边内容栏比如广告栏 --/aside
/main
footer!-- 页脚 --
/footer 对于经典的圣杯布局它有
页头 header页脚 footer主内容 article左侧边栏 aside右侧边栏 aside。
它应该具备的能力
在 HTML 文档的源码中主内容 article 要位于两个侧边栏 aside 之前页头 header 和页脚 footer 并没有固定高度即它们的 height 为 auto由其内容或相关盒模型属性值比如 padding 、margin 或 border决定大小在垂直方向中间三列main的高度占据 header 和 footer 之外的浏览器视窗高度并且随着内容增多而变高在水平方向一般情况之下两个侧边栏也是由其内容来决定大小但多数情况之下会给两个侧边栏设置一个固定宽度比如左侧边栏是 220px 右侧边栏是 320px 。中间主内容列 article 占据两侧边栏之外的浏览器视窗宽度并且随着内容增加不会出现水平滚动条。
我们来看一个真实的圣杯布局案例 实现该页面你可能需要的 HTML 结构如下
headerh1W3cplus/h1navullia hrefhome/a/li!-- 其他导航项 --/ul/nav
/header
mainarticleh2现代 Web 布局技术/h2p使用 CSS Flexbox 技术构建圣杯布局Holy Grail Layout/p/articleasideh3左侧列/h3/asideasideh3右侧列/h3/aside
/main
footerullia hrefhomehome/a/li!-- 其他导航项 --/ul
/footer在没有 CSS 加载的情况之下你看到的圣杯布局会是下图这样 注意内容先行的原则 我们可以像下面这样使用 Flexbox 来构建圣杯布局
body {display: flex;flex-direction: column;gap: 1px;min-height: 100vh;
}main {flex: 1 1 0%;min-height: 0;display: flex;gap: 1px;
}aside:nth-of-type(1) {order: -1;min-width: 220px;max-width: 220px;
}aside:nth-of-type(2) {min-width: 320px;max-width: 320px;
}article {flex: 1 1 0%;min-width: 0;
}header {display: flex;flex-wrap: wrap;align-items: center;justify-content: space-between;
}footer {display: flex;justify-content: center;
}可以结合 CSS 的媒体查询在小屏幕下调整布局构建一个具有响应式能力的圣杯布局
media screen and (max-width: 800px) {main {flex-direction: column;}main aside {width: 100%;max-width: none !important;}aside:nth-of-type(1) {order: 1;}
}Demo 地址https://codepen.io/airen/full/YzLeRZx 小作业使用 Flexbox 构建下图这样的 Web 布局
主内容列能随浏览器视窗大小改变侧边栏固定宽度页头和页脚高度由内容决定。 Sticky Footer 布局
首先用下图来解释什么是 Sticky Footer 布局: 页脚Footer的位置会随着页头Header和主内容Content高度而变化但当页头和主内容内容较小其高度总和小于浏览器视窗高度时页脚要始终位于浏览器视窗底部。
对于 Sticky Footer 的布局使用 Flexbox 再容易不过了只需要保持主内容容器它也是一个 Flex 项目能随着它的父容器Flex 容器的剩余空间扩展。简单地说给主内容设置一个 flex-grow 值为 1 即可。具体代码如下
bodyheader/headermain/mainfooter/footer
/body
body {min-height: 100vh;display: flex;flex-direction: column;
}main {flex-grow: 1;
}如果你不希望浏览器视窗高度较小时主内容的高度进行收缩你可以将其 flex-shrink 设置为 0 比如
main {flex: 1 0 auto;/* 等同于 */flex-grow: 1;flex-shrink: 0;flex-basis: auto;
}同样地为了避免页头和页脚因浏览器视窗高度较小时被挤压建议在它们上面设置 flex-shrink 值为 0 。
body {min-height: 100vh;display: flex;flex-direction: column;
}header, footer {flex-shrink: 0;
}main {flex: 1 0 auto;min-height: 0;
}Demo 地址 https://codepen.io/airen/full/XWqZOao 除了上面这种方法之外还可以在 footer 上使用 margin-top:auto 来实现 Sticky Footer 的布局效果
body {min-height: 100vh;display: flex;flex-direction: column;
}body * {flex-shrink: 0;
}footer {margin-top: auto;
}Demo 地址 https://codepen.io/airen/full/RwyQvJG 百分百无滚动布局
百分百无滚动布局在 Web 中也是很常见的一种布局比如下面这样的一个案例这是一个真实的案例2019年双11主互动项目中的弹窗 图中红色虚框中的内容是带有滚动的 。因为容器的高度是固定的100vh内容很有可能会超过容器的高度。
我把整个弹窗Modal分为两个部分
!-- 整个 Modal 高度是 100vh --
modalmodal-header!-- 固定高度 --/modal-headermodal-content!-- 滚动容器flex: 1 --/modal-content
/modal很典型的一个 Flexbox 布局
modal {height: 100vh;display: flex;flex-direction: column;
}modal-header {height: 120px; /* 一个固定高度值 */
}modal-content {flex: 1 1 0%; /* 或 flex: 1*/overflow-y: auto; /* 内容超过容器高度时出现滚动条 */
}看上去似乎没有问题但实际上我们在 iOS 系统上触发了一个 Flexbox 的 Bug就是在滚动容器上显示设置 overflow-y:scroll 滚动依旧失效 。造成这个 Bug 是因为我们上面的 CSS 代码触发了 Flex 项目的边缘情况。如果要避免这个 Bug 的出现需要对结构做出一定的调整 对应上图的 HTML 代码如下
div classmain-container !-- flex-direction: column --div classfixed-containerFixed Container/div!-- eg. height: 100px --div classcontent-wrapper!-- min-height: 0, 这个很重要 --div classoverflow-container!-- 滚动容器overflow-y: auto flex: 1 --div classoverflow-contentOverflow Content/div!-- 内容容器 --/div/div
/div关键的 CSS 代码
.main-container {display: flex;flex-direction: column;
}.fixed-container {height: 100px; /* 固定容器的高度值任何一个你想的固定值 */
}.content-wrapper {display: flex;flex: 1; /* 可以是 flex: 1 1 0% */min-height: 0; /* 这个很重要 */
}.overflow-container {flex: 1;overflow-y: auto; /* 内容超出滚动容器高度时会出现滚动条 */
}来看一个具体 Demo 的效果 Demo 地址 https://codepen.io/airen/full/JjvpzPY 关键部分是 设置 flex:1 的 Flex 项目需要显式设置 min-height 的值为 0 即滚动容器的父元素 。即 在设置了 flex:1 的 Flex 项目上应该尽可能地重置它的最小尺寸值当主轴在水平方向时flex-direction: row设置min-width 或 min-inline-size的值为 0 当主轴在垂直方向时flex-direction: column设置 min-height 或 min-block-size的值为 0 。
小作业使用 Flexbox 构建一个弹窗Modal的布局效果 12 列网格布局
12 列网格布局最早源于 960gs 网格布局系统它和 CSS 原生的网格系统不是同一个东西。简单地说960gs 就是将页面分成12列有列宽和列间距然后页面的布局划分到具体的列上面如下图所示 早期的 960gs 都是使用 CSS 的浮动float来构建的不过现在很多 CSS 框CSS Frameworks中的网格系统都采用 Flexbox 来构建比如 Bootstrap的网格系统 现在就是采用 Flexbox 布局构建的。
相对而言使用 Flexbox 技术构建 960gs 网格系统要比浮动技术简单得多你只需要在一个 Flex 容器放置所需要的列数每一列对应着一个 Flex 项目。比如
!-- 12列flex 容器中包含 12 个 flex 项目 --
flex-containerflex-item 1 of 12/flex-item!-- 中间省略 10个 flex-item --flex-item 1 of 12/flex-item
/flex-container!-- 6列 flex 容器中包含 6个 flex 项目 --
flex-containerflex-item 1 of 6 /flex-item!-- 中间省略 4 个 flex-item --flex-item1 of 6 /flex-item
/flex-container!-- 4列 flex 容器中包含 4 个 flex 项目 --
flex-containerflex-item 1 of 4 /flex-item!-- 中间省略 2 个 flex-item --flex-item1 of 4 /flex-item
/flex-container!-- 3列flex 容器中包含 3 个 flex 项目 --
flex-containerflex-item 1 of 3/flex-itemflex-item 1 of 3/flex-itemflex-item 1 of 3/flex-item
/flex-container!-- 2列 flex 容器中包含 2个 flex 项目 --
flex-containerflex-item 1 of 2/flex-itemflex-item 1 of 2/flex-item
/flex-container对于 CSS 而言主要使用 Flexbox 的 gap 属性来设置列与列之间的间距然后在 Flex 项目上使用 flex 属性即可比如
flex-container {display: flex;gap: var(--gap, 1rem)
}flex-item {flex: 1 1 0%;min-width: 0; /* 建议加上 */
}Demo 地址 https://codepen.io/airen/full/qBYxwXK 当然你也可以根据实际需要给 Flex 项目指定明确的值即给 Flex 项目的 flex-basis 初始化一个值同时 flex-grow 和 flex-shrink 都重置为 0 告诉浏览器该 Flex 项目不能扩展和收缩 比如上图所示
auto 标记的列表示 flex 的值为 1 1 0% 或 1 1 auto50% 、33.33% 和25% 标记的列表示flex-basis 的值为 var(--flex-basis) 同时 flex-grow 和 flex-shrink 都重置为 0
这样的场景可以借助 CSS 自定义属性会让你编码更容易一些
div classgriddiv classrowdiv classcolumnAuto/divdiv classcolumnAuto/div/divdiv classrowdiv classcolumnAuto/divdiv classcolumnAuto/divdiv classcolumnAuto/div/divdiv classrowdiv classcolumnAuto/divdiv classcolumnAuto/divdiv classcolumnAuto/divdiv classcolumnAuto/div/div
/divdiv classgriddiv classrowdiv classcolumn fixed style--flex-basis: 50%50%/divdiv classcolumnAuto/divdiv classcolumnAuto/div/divdiv classrowdiv classcolumn fixed style--flex-basis: 33.33%33.33%/divdiv classcolumnAuto/div/divdiv classrowdiv classcolumn fixed style--flex-basis: 25%25%/divdiv classcolumnAuto/divdiv classcolumn fixed style--flex-basis: 33.33%33.33%/div/div
/div.grid {display: flex;flex-direction: column;gap: var(--gap-row);
}.row {display: flex;gap: var(--gap-column);
}.column {flex:1 1 var(--flex-basis, 0%);min-width: 0;
}.column.fixed {flex: 0 0 var(--flex-basis);
}Demo 地址https://codepen.io/airen/full/ZEorZVa 九宫格布局
九宫格简单地说就是一个 3 × 3 的网格三行三列它也常用于 Web 布局中而且你可以基于它演变出很多种不同的布局风格 在 Web 布局中我们把这些布局效果都称为 九宫格布局 。它们常被运用于 Web 中展示图片它有自己的专业术语称之为图片墙 Image Galler 。这样的布局对于图片展示来说可以更好地突出需要展示的图片。 虽然使用 Flexbox 可以构建一个网格布局但 Flexbox 布局毕竟是一种一维布局 用它来构建上图这样的九宫格布局效果还是有一定的局限性需要通过 HTML 结构强力配合才能实现。比如下面这个示例 实现上图的布局效果所需要的 HTML 结构可能会像下面这样
div classcarddiv classcard__headingh3 classcard__title现代 Web 布局/h3p classcard__describe使用 Flexbox 技术构建九宫格布局/p/divdiv classcard__griddiv classcard__rowdiv classcard__columnfigureimg srccat.png alt //figure/divdiv classcard__columnfigureimg srccat.png alt //figurefigureimg srccat.png alt //figurefigureimg srccat.png alt //figurefigureimg srccat.png alt //figure/div/div/div
/div关键的 CSS 代码
.card {display: flex;flex-direction: column;gap: 1rem;
}.card__grid {display: flex;flex-direction: column;
}.card__row {display: flex;gap: 1rem;
}.card__column {flex: 1 1 calc((100% - 1rem) / 2);min-width: 0;display: flex;flex-wrap: wrap;gap: 1rem;
}.card__column:nth-child(2) figure {flex: 1 1 calc((100% - 1rem) / 2);min-width: 0;
}这里有一个关键就是 Flex 项目的 flex-basis 值使用了 calc() 根据列数和列间距计算得出来的即
列宽flex-basis 100%容器宽度Flex 容器- 列数 - 1× (列间距)÷ 列数就我们这个示例是 2 列列间距是 1rem 所以 flex-basis 的初始值设置为 calc((100% - 1rem) / 2) 。最终得到的效果如下 Demo 地址 https://codepen.io/airen/full/yLjKzgp 你甚至可以使用 12 列网格布局的方式来完成九宫格的布局。但很多时候九宫格布局中的每个元素 Flex 项目具有一定的宽高比 比如上图的布局效果。它是一个由几行组成的布局而且每行的两张图片都有固定的宽高比。每行的两张图片有相同的高度并且会填满整行我们知道每行就是一个 Flex 容器。图片的宽高比从 16:9 到 3:2 不等。
自 2021 年开始你可以在 CSS 中直接使用 aspect-ratio 属性设置元素的宽高比不需要使用 padding-top 或 padding-bottom 来模拟了。比如
.aspect-ratio-box {width: 400px;aspect-ratio: 16 / 9;
}这样你就可以得到一个宽高比是 16:9 的盒子浏览器会根据元素的 width 和宽高比 aspect-ratio 的值计算出 height 的值 Demo 地址 https://codepen.io/airen/full/oNdqobL 当然浏览器也会根据元素的高度 height 值和宽高比 aspect-ratio 的值计算出宽度 width 的值比如
.aspect-ratio-box {aspect-ratio: 16 / 9;height: 225px;
}/* 可以根据 宽高比 和 高度 的值计算出 宽度的值 */
aspect-ratio width ÷ height 16 ÷ 9 1.778
width height × aspect-ratio 225 x (16 ÷ 9) 400上面就是 CSS 的 aspect-ratio 属性最基础的使用有关于它更详细的介绍这里不展开。我们回到示例中来。先把上面的示例简化一下比如说在一个 Flex 容器中有两个 Flex 项目它们的高度是相同的其中一个 Flex 项目的宽高比是 4:3 另一个 Flex 项目的宽高比是 2:3 。你可能像下面这样将 aspect-ratio 运用到 Flex 项目上
div classcontainer grid-rowdiv classitem grid-column style--ratio: 4 / 34:3/divdiv classitem grid-column style--ratio: 2 / 32:3/div
/div
.container {display: flex;align-items: flex-start;
}.item {aspect-ratio: var(--ratio);flex: 1 1 0%;
}正如你所见两个 Flex 项目的宽度相等但高度不同。你可能会认为将 Flex 项目的高度 height 设置为 100% 即可事实并非如你所愿因为 CSS 的 height 取% 百分比值时如果父元素Flex 容器未显式设置 height 的值那么 Flex 项目即使设置 height:100% 浏览器计算出来的也会是 0 。 Demo 地址 https://codepen.io/airen/full/eYrMeWq 这也并不是无解在 Flexbox 布局中有两种解决方案。先来看第一种解决方案就是 Flex 容器的宽高比要等于它的所有 Flex 项目的宽高比之和。比如上面这个示例在 Flex 容器上需要显式设置它的宽高比为 6:3 即
Flex 容器的 aspect-ratio (4 ÷ 3) (2 ÷ 3) 6 ÷ 3 6 : 3div classcontainer grid-rowdiv classitem grid-column style--ratio: 4 / 34:3/divdiv classitem grid-column style--ratio: 2 / 32:3/div
/div.container {display: flex;align-items: flex-start;aspect-ratio: 6 / 3;
}.item {aspect-ratio: var(--ratio);flex: 1 1 0%;height: 100%; /* 这个很重要 */
}Flex 容器设置了 aspect-ratio 值之后浏览器就可以计算出它的高度值此时在 Flex 项目上显式设置 height: 100% 才有了意义保证了同一行的 Flex 项目是相等的宽度根据各自的 aspect-ratio 计算得到。这个时候你看到的效果如下 Demo 地址 https://codepen.io/airen/full/WNJzdYw 注意如果你不想花太多时间去做数学计算的话可以借助 CSS 自定义属性来辅助你
div classcontainer grid-rowdiv classitem grid-column4:3/divdiv classitem grid-column2:3/div
/div:root {--ratio-4-3: 4 / 3;--ratio-2-3: 2 / 3;--flex-container-ratio: calc(var(--ratio-4-3) var(--ratio-2-3));
}.container {display: flex;align-items: flex-start;aspect-ratio: var(--flex-container-ratio);
}.item {aspect-ratio: var(--ratio)flex: 1 1 0%;height: 100%; /* 这个很重要 */
}.item:nth-child(1) {--ratio: var(--ratio-4-3);
}.item:nth-child(2) {--ratio: var(--ratio-2-3);
}Demo 地址 https://codepen.io/airen/full/jOxzZPm 不过这个方案有一定的缺陷存在必须知道 Flex 项目的数量及其容器上的宽高比 。容器中的 Flex 项目一旦发生变化或容器中的 Flex 项目宽高比发生变化开发者就需要重新计算 Flex 容器的宽高比否则布局就不是按照相应的宽高比构建的。另外就是 Flex 容器要是设置了 gap 值对 Flex 项目的计算也有一定的影响。
接着我们来看另一种解决方案该方案 不需要根据 Flex 项目的宽高比来计算 Flex 容器的宽高比 我们可以利用 Flex 项目的 flex-grow 属性的特性来完成所需的布局 。简单地说如果 Flex 项目的宽高比的“分母”相同则只需要在相应的 Flex 项目设置它的 flex-grow 值为“分子 ”同时显式设置 flex-basis 的值为 0% 。比如前面的示例我们可以像这样来编写你的 CSS:
.container {display: flex;
} .item {flex-basis: 0%;aspect-ratio: var(--ratio);
}.item:nth-child(1) {flex-grow: 4;
}.item:nth-child(2) {flex-grow: 2;
}Demo 地址 https://codepen.io/airen/full/YzLaeEP 如果 Flex 项目的宽高比的分母不同你同样需要借助 CSS 自定义属性来完成这样会让事情变得简单些
div classcontainer rowdiv style--ratio: 3 / 2; classitem column3:2/divdiv style--ratio: 16 / 9; classitem column16:9/divdiv style--ratio: 1 / 1; classitem column1:1/div
/div.container {display: flex;
}.item {flex-basis: 0%;aspect-ratio: var(--ratio);flex-grow: calc(var(--ratio))
}就是把 Flex 项目的 flex-grow 值为宽高比的计算值比如 Flex 项目的宽高比是 4 : 3 那么对应的 flex-grow 值就是 1.333333 即 4 ÷ 3 1.3333。这种方案还有一个优势那就是 Flex 容器的 gap 值不会影响 Flex 项目的宽高比的计算。
.container {display: flex;gap: 5px;
}.item {flex-basis: 0%;aspect-ratio: var(--ratio);flex-grow: calc(var(--ratio))
}Demo 地址 https://codepen.io/airen/full/OJZvQop 添点料进去加上img那么具有宽高比的图片墙九宫格布局效果就有了 Demo 地址 https://codepen.io/airen/full/QWrmmGZ 小作业请使用 Flexbox 和 aspect-ratio 构建下图这样的布局效果 具有不同对齐方式的导航栏
在 Web 应用或 Web 页面中导航栏导航菜单是 Web 中必不可少的一部分。我想很多同学在实际开发中碰到各式各样的导航栏的布局效果抛开其他的 UI 样式不谈只聊导航栏的对齐就足以让不少同学感到头痛。
就导航栏对齐方式来说很多同学都认为 “使用 Flexbox 的对齐方式” 就足以搞定事实上呢并非如此。虽然 Flexbox 的对齐方式很强大但有些场景我们是不能使用 Flexbox 来布局或者说使用 Flexbox 布局并不是最合适的。比如下图中红色框中的导航栏的对齐效果如果使用 Flexbox 就不太适合 正如你看到的上图中红色框是不太适合使用 Flexbox 来布局但蓝色框中的布局效果使用 Flexbox 就比较适合。
以下图中的导航栏为例 很常见的几种对齐方式
居中对齐居左对齐两端对齐居右对齐。
这四种对齐方式在 Flexbox 布局中真的是太容易。前面三个只需要在相应的 Flex 容器中设置 justify-content 属性的值即可最后一个需要稍微加点样式因为你无法直接使用 justify-content 的 space-between 就能达到所需要的效果因此只需在相应的 Flex 项目上设置 margin-left 为 auto 即可
!-- 样式一 --
header classcontainerNavMenu /
/header!-- 样式二 和 样式三 --
header classcontainerLogo /NavMenu /
/header!-- 样式四 --
header classcontainerLogo /NavMenu /Cart /
/header.container {display: flex;algin-items: center;
}.container:nth-child(1) {justify-content: center;
}.container:nth-child(3) {justify-content: space-between;
}.container:nth-child(4) .cart{margin-left: auto;
} Demo 地址 https://codepen.io/airen/full/ExLELgm 灵活的弹性框
Flexbox 布局最大的优势之一就是使用该技术构建的布局灵活性适配性很强。Flex 项目的大小能很好适应它的容器Flex 容器。比如下面这个两列布局左侧栏固定宽度主内容列能随着它的父容器大小自适应即父容器变大它变宽父容器小它变窄 div classcontaineraside/asidemain/main
/div其中原理很简单只需要将 main 元素的 flex 设置为 1 1 auto 或者 1 1 0% 即可。这样一来 main 就会根据 Flex 容器的空间自动调整自身的大小
.container {display: flex;
}aside {width: var(--fixed-width, 200px);
}main {flex: 1 1 0%;min-width: 0;
}Demo 地址 https://codepen.io/airen/full/GRdxGpg 这样的效果还经常配合文本截取的特性一起使用。比如一行长文本当 Flex 容器有足够空间时显示所有文本当 Flex 容器空间变小无法展示所有文本时文本会被剪切并在文本末尾添加指示器三个点 ...
div classtargetdiv classtarget__titlestrongFlexbox Layout:/strong Text here is very very long that it mightget truncate if this box get resized too small/divdiv classtarget__emoji/div
/div.target {display: flex;align-items: center;gap: 1rem;
}.target__title {overflow: hidden;min-width: 0;text-overflow: ellipsis;white-space: nowrap;
}.target__emoji {width: max-content;margin-left: auto;flex-shrink: 0;
}Demo 地址 https://codepen.io/airen/full/zYjWaZJ 注意在这个示例中弹性框 .target__title 使用了 flex 的默认值即 flex: 0 1 auto 。
再来看一个关于 text-overflow: ellipsis 在 Flexbox 布局中的实例。比如下面这样的一个场景在我们平时的开发中也是很常见的 设计师期望的是“徽标过多时最好提供省略号指示器并不是直接截断或断行”。对于开发者来说可能会使用像下面这样的一个 HTML 结构来构建徽标列表
!-- HTML --
ul classbadgesliFast food/li!-- ... --liFruits/li
/ul你可能会认为直接给 .badges 元素添加下面几行代码就可以达到 Web 设计师预期的效果
.badges { display: flex;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;
}这样的处理方式最终在浏览器中呈现出来的效果是“溢出容器的徽标被裁剪了” 如果把 text-overflow 相关的样式设置到 li 标签上
.badges li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
} 虽然不会像上面一样把溢出的徽标裁剪掉但这样做的话虽然能在容器空间中将徽标罗列出来但会在每个徽标上添加省略号的指示器也不符合预期效果 如果li元素是一个 Flex 容器的话达到上图效果还需要额外添加一个标签来包裹文本 ul classbadges lispanFast food/span/li !-- ... -- lispanFruits/span/li
/ul不过在 CSS 中还是有方案可以达到设计师预期想要的效果的 达到上图的效果在 CSS 中有两种方式可以实现先来看第一种即 使用 line-clamp替代text-overflow .badges { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; } .badges li { display: inline-flex; /* inline-block */ } 另外一种还是继续使用 text-overflow但需要改变每个li视觉模型即 将 display 设置为 inline-block .badges { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .badges li { display: inline-block; /* inline-flex */ } Demo 地址 https://codepen.io/airen/full/KKRoexo 小作业请使用 Flexbox 和 文本截取等功能构建下图这样的一个布局效果列表项标题较长时文本多会被截断并且提供省略号指示符...反之则不会