介绍
传统的布局解决方案,主要是基于盒模型,然后依赖display、position、float来进行布局,对于一些比较特殊的布局并不方便,比如垂直水平居中
在2009年,W3C就推出了一种新的布局方案,也就是flex布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
盒模型
盒模型主要由四个部分组成,由内而外分别为content、padding、border、margin
盒模型在分类上,有两种模式,分别是标准盒模型(默认)和IE盒模型,两者的区别在于如何计算元素的宽高
标准:content+padding+margin(向外扩)
IE:content(包含margin、padding),如果需要使用该盒模型,可以通过设置box-sizing:border-box属性来启用(向内缩)
布局原理
但是需要注意的是,设为Flex布局以后,子元素的float、clear和vertical-align(用来指定行内、行内区块的垂直对齐方式)属性将失效
flex布局也称为弹性布局,可以为盒模型提供最大的灵活性,任何一个容器都可以指定为flex布局
它的核心原理是基于容器和项目的关系,通过定义主轴和交叉轴来实现灵活的布局。
1、容器的属性
- flex-direction:row(默认)、row-reverse、column、column-reverse,确定项目主轴方向
- flex-wrap:nowrap(默认)、wrap、wrap-reverse,换行属性
- flex-flow:该属性是1和2的简写形式,默认值为row nowrap
- justify-content:flex-start(默认)、flex-end、center、space-between、space-around(每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍)、space-evenly(每个项目两边的距离相等)、stretch(进行均分,空余空间在盒子左侧),主轴对齐方式
- align-items:flex-start、flex-end、center、baseline(项目的第一行文字的基线对齐)、stretch(默认,没有设置高度或者设置为auto,将撑满容器),交叉轴的对齐方式
- align-content:flex-start、flex-end、center、space-between、space-around、stretch(默认值),定义了多根交叉轴轴线的对齐方式
align-items与align-content的区别:align-items 控制单行内项目的对齐,而 align-content 控制多行之间的对齐
只有当容器内的项目出现多行/多列时,align-content 才会生效
在单行布局中,align-content 属性不起作用
2、项目的属性
- order:定义项目的排列顺序。数值越小,排列越靠前,默认为0。
- flex-grow:定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
- flex-shrink:定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
- flex-basis:定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。它可以设为跟width或height属性一样的值,则项目将占据固定空间。
在使用该属性时候,会出现优先级问题,优先级如下:max-width > flex-basis > width
- flex:为2、3、4三个属性的简写,默认值为0 1 auto,后两个属性是可选属性。在开发的过程中,通常会使用flex属性,而不会去单独设置。
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
根据属性可以得知,前者表示表示项目可以根据可用空间放大或缩小,初始大小由内容决定,后者表示表示项目不会放大或缩小,保持其初始大小。
想要具体了解flex属性的,可以参考这篇文章:juejin.cn/post/747559…
- align-self:auto(默认值)、flex-start、flex-end、center、baseline、stretch,允许单个项目有与其他项目不一样的对齐方式,可以覆盖align-items属性。
继承父元素的align-items属性,如果没有父元素,则等同于stretch。
优势
- 简化布局代码:通过简单的 CSS 属性即可实现复杂的布局效果。
- 灵活的排列方式:支持水平或垂直排列,并可以轻松切换方向。
- 响应式设计:项目的大小可以动态调整,适应不同的屏幕尺寸。
- 对齐和分布空间:提供多种对齐和分布空间的方式,如居中、均匀分布等。
常见使用场景
- 导航栏
- 居中实现
- 卡片布局
- 撑满剩余空间
代码
完整的代码都在下方了,如果需要的话,可以复制下来自己感受一下
import React from "react";
import "./index.less";
const Index = () => {
return (
<>
<section>
<h1>0、盒模型</h1>
<div className="card">
<div className="item1"></div>
<div className="item2"></div>
</div>
</section>
<section>
<h1>1、flex-direction、flex-warp:确定项目主轴方向以及换行</h1>
<div className="flex-container1">
<div className="item">1</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
<div className="item">5</div>
</div>
</section>
<section>
<h1>2、justify-content:设置主轴的对齐方式</h1>
<div className="flex-container2">
<div className="item">1</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
<div className="item">5</div>
</div>
</section>
<section>
<h1>3、align-items:设置交叉轴的对齐方式</h1>
<div className="flex-container3">
<div className="item">
<h1>1</h1>
</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
<div className="item">5</div>
</div>
</section>
<section>
<h1>4、align-content:定义了多根交叉轴轴线的对齐方式</h1>
<div className="flex-container4">
<div className="item">1</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
<div className="item">5</div>
<div className="item">6</div>
<div className="item">7</div>
<div className="item">8</div>
<div className="item">9</div>
</div>
</section>
<section>
<h1>5、order:定义项目的排列顺序</h1>
<div className="flex-container5">
<div className="item item1">order为1</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
<div className="item">5</div>
</div>
</section>
<section>
<h1>
6、flex-grow:默认为0,均分剩余的空间。计算规则:将剩余空间除以所有flex-grow属性之和,然后按照比例分给带有该属性的盒子
</h1>
<div className="flex-container6">
<div className="item1">100px,flex-grow:1</div>
<div className="item2">100px,flex-grow:1</div>
<div className="item3">100px,flex-grow:3</div>
</div>
</section>
<section>
<h1>
7、flex-shrink:默认为1。计算规则:将不足的空间除以带有flex-shrink的盒子,然后再进行对应的缩小比例,需要注意的是,该属性默认为1,如果不进行设置,那么默认所有的盒子参与缩小。
</h1>
<div className="flex-container7">
<div className="item1">200px 3</div>
<div className="item2">100px 1</div>
<div className="item3">100px 1</div>
</div>
</section>
<section>
<h1>8、flex-basis:默认为auto。计算规则:默认就是项目本身的大小</h1>
<div className="flex-container8">
<div className="item1">100px 250px</div>
<div className="item2">100px auto</div>
<div className="item3">100px auto</div>
</div>
</section>
<section>
<h1>9、flex</h1>
<div className="flex-container9">
<div className="item1">400px </div>
<div className="item2">400px </div>
<div className="item3">400px </div>
</div>
</section>
<section>
<h1>
10、align-self:默认为auto,允许单个项目有与其他项目不一样的对齐方式,可以覆盖align-items属性
</h1>
<div className="flex-container10">
<div className="item1">1</div>
<div className="item2">2</div>
<div className="item3">3</div>
</div>
</section>
<section>
<h1>常见使用场景</h1>
<h2>导航栏示例</h2>
<section className="demo-section">
<nav className="demo-nav">
<a href="#">首页</a>
<a href="#">产品</a>
<a href="#">服务</a>
<a href="#">关于</a>
</nav>
</section>
<h2>居中实现示例</h2>
<section className="demo-section">
<div className="center-container">
<div className="center-item">完美居中</div>
</div>
</section>
<h2>卡片布局示例</h2>
<section className="demo-section">
<div className="card-list">
<div className="cards">卡片1</div>
<div className="cards">卡片2</div>
<div className="cards">卡片3</div>
</div>
</section>
<h2>撑满剩余空间示例</h2>
<section className="demo-section">
<div className="flex-space">
<div className="fixed-width">固定宽度</div>
<div className="flex-grow">自动撑满剩余空间</div>
</div>
</section>
</section>
</>
);
};
export default Index;
body {
padding: 20px;
}
.card {
margin-bottom: 20px;
.item1 {
width: 100px;
height: 100px;
background-color: #ccc;
margin: 10px;
padding: 10px;
}
.item2 {
width: 100px;
height: 100px;
background-color: #ccc;
margin: 10px;
padding: 10px;
box-sizing: border-box;
}
}
.flex-container1 {
display: flex;
border: 1px solid red;
width: 400px;
flex-direction: row;
flex-wrap: nowrap;
margin-bottom: 20px;
.item {
width: 100px;
height: 100px;
}
}
.flex-container2 {
display: flex;
border: 1px solid red;
width: 1000px;
justify-content: flex-start;
margin-bottom: 20px;
.item {
width: 100px;
height: 100px;
}
}
.flex-container3 {
display: flex;
border: 1px solid red;
width: 1000px;
flex-wrap: nowrap;
align-items: stretch;
height: 100px;
margin-bottom: 20px;
.item {
width: 100px;
}
}
.flex-container4 {
display: flex;
border: 1px solid red;
width: 300px;
height: 400px;
flex-wrap: wrap;
align-content: center; // 用来设置行的对齐方式
.item {
width: 100px;
height: 100px;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
}
}
.flex-container5 {
display: flex;
border: 1px solid red;
width: 1000px;
flex-wrap: nowrap;
align-items: stretch;
height: 100px;
margin-bottom: 20px;
.item {
width: 100px;
}
.item1 {
order: 1;
}
}
.flex-container6 {
display: flex;
border: 1px solid red;
width: 500px;
height: 100px;
margin-bottom: 20px;
.item1 {
width: 100px;
background-color: lightcoral;
flex-grow: 1;
}
.item2 {
width: 100px;
background-color: lightgreen;
flex-grow: 1;
}
.item3 {
width: 100px;
background-color: lightblue;
flex-grow: 3;
}
}
.flex-container7 {
display: flex;
border: 1px solid red;
width: 300px;
height: 100px;
margin-bottom: 20px;
.item1 {
width: 200px;
background-color: lightcoral;
// flex-shrink: 0; // 不参与压缩
// flex-shrink: 3; // 压缩比重高
min-width: 150px;
}
.item2 {
width: 100px;
background-color: lightgreen;
}
.item3 {
width: 100px;
background-color: lightblue;
}
}
.flex-container8 {
display: flex;
border: 1px solid red;
width: 500px;
height: 100px;
margin-bottom: 20px;
.item1 {
width: 100px;
background-color: lightcoral;
// flex-basis: auto;
// flex-basis: 250px; // 不设置就是原本的值
// max-width: 200px; // 优先级最高
}
.item2 {
width: 100px;
background-color: lightgreen;
}
.item3 {
width: 100px;
background-color: lightblue;
}
}
.flex-container9 {
display: flex;
border: 1px solid red;
width: 1000px;
height: 100px;
margin-bottom: 20px;
.item1 {
width: 400px;
flex: none;
background-color: lightcoral;
}
.item2 {
width: 400px;
flex: none;
background-color: lightgreen;
}
.item3 {
width: 400px;
flex: none;
background-color: lightblue;
}
}
.flex-container10 {
display: flex;
border: 1px solid red;
width: 500px;
height: 200px;
margin-bottom: 20px;
align-items: center;
.item1 {
width: 100px;
height: 100px;
background-color: lightcoral;
align-self: start; // 单独设置,可以有不同的排列方式
}
.item2 {
width: 100px;
height: 100px;
background-color: lightgreen;
}
.item3 {
width: 100px;
height: 100px;
background-color: lightblue;
}
}
// 导航栏示例
.demo-section {
border: 1px solid #000000;
margin-bottom: 20px;
.demo-nav {
display: flex;
background-color: #333;
padding: 15px;
}
.demo-nav a {
color: white;
text-decoration: none;
padding: 10px 20px;
}
}
// 居中实现示例
.center-container {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
background-color: #f0f0f0;
.center-item {
padding: 20px;
background-color: #333;
color: white;
}
}
// 卡片布局示例
.card-list {
display: flex;
justify-content: space-between;
.cards {
flex: 0 1 calc(33.333% - 20px);
min-width: 100px;
height: 100px;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
}
}
// 撑满剩余空间示例
.flex-space {
display: flex;
gap: 20px;
.fixed-width {
width: 200px;
padding: 20px;
background-color: #f0f0f0;
}
.flex-grow {
flex: 1;
padding: 20px;
background-color: #f0f0f0;
}
}