传统盒模型布局方式
我们的传统布局方式就是通过盒模型,使用 display
属性(文档流布局) + position
属性(定位布局) + float
属性(浮动布局)。这个大家都比较熟悉,没有掌握的同学再去恶补一下基础
文档流布局
这是最基本的布局方式,就是按照文档的顺序一个一个显示出来,块元素独占一行,行内元素共享一行,这个相信大家都比较熟悉了,就不再赘述了
浮动布局
浮动方式布局就是使用 float
属性,使元素脱离文档流,浮动起来。这个大家也比较熟悉,就不再赘述了。
定位布局
我们也可以通过 position
属性来进行定位,这个大家也比较熟悉了,就不再赘述了。
flex 布局
仅仅通过上述的三种布局方式还是有一些缺陷,比如我们不能只使用一个属性来实现垂直居中布局,所以就产生了第四种布局方式:flex 布局。
什么是 flex 布局
2009年,W3C 提出了一种新的方案—-Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。
flex 是一种新型的布局方式,使用该布局方式可以实现几乎所有你想要的效果。但是要注意其浏览器的兼容性,flex 只支持 ie 10+,所有还是要根据你的项目情况使用(没错,我们要求至少 ie 9,(ಥ_ಥ))。
使用 flex 布局
flex 的使用方法很简单,只需要将其 display
属性设置为 flex
就可以,也可以设置行内的 flex,记得 Webkit 内核的浏览器,必须加上 -webkit
前缀。注意,设为 Flex 布局以后,子元素的 float
、clear
和 vertical-align
属性将失效。
.ele{
display: -webkit-flex;
display: flex;
display: inline-flex;
display: -webkit-inline-flex;
}
在 flex 中,最核心的概念就是容器和轴,所有的属性都是围绕容器和轴设置的。其中,容器分为父容器和子容器。轴分为主轴和交叉轴(主轴默认为水平方向,方向向右,交叉轴为主轴顺时针旋转 90°)。
在使用 flex 的元素中,默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
主轴开始的位置称为 main start
,主轴结束的位置称为 main end
。
同理,交叉轴开始的位置称为 cross start
,交叉轴结束的位置称为 cross end
。
在使用 flex 的子元素中,占据的主轴空间叫做 main size
,占据的交叉轴空间叫做 cross size
。
父容器属性
父容器上有六个属性
- flex-direction:主轴的方向。
- flex-wrap:超出父容器自容器的排列样式。
- flex-flow:flex-direction
属性和 flex-wrap
属性的简写形式。
- justify-content:子容器在主轴的排列方向。
- align-items:子容器在交叉轴的排列方向。
- align-content:多根轴线的对齐方式。
flex-direction 属性
flex-direction 属性决定主轴的方向(主轴的方向不一定是水平的,这个属性就是设置主轴的方向,主轴默认是水平方向,从左至右,如果主轴方向设置完毕,那么交叉轴就不需要设置,交叉轴永远是主轴顺时针旋转 90°)。
.ele {
flex-direction: row; // 默认值,主轴为水平方向,起点在左端。
flex-direction: row-reverse; // 主轴为水平方向,起点在右端。
flex-direction: column; // 主轴为垂直方向,起点在上。
flex-direction: column-reverse; // 主轴为垂直方向,起点在下。
}
flex-wrap 属性
flex-wrap
属性决定子容器如果在一条轴线排不下时,如何换行。
.ele {
flex-wrap: nowrap; // 默认,不换行
flex-wrap: wrap; // 换行,第一行在上方。
flex-wrap: wrap-reverse // 换行,第一行在下方。
justify-content 属性
justify-content
属性定义了子容器在主轴上的对齐方式。
.ele{
justify-content: flex-start; // 默认,左对齐
justify-content: flex-end; // 右对齐
justify-content: center; // 居中
justify-content: space-between; // 两端对齐,项目之间的间隔都相等。
justify-content: space-around; // 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
}
```![justify-content 属性](http://img.blog.csdn.net/20170813202345666?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vuc2hpbmU5NDAzMjY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
<div class="se-preview-section-delimiter"></div>
#### flex-flow 属性
`flex-flow` 属性是 `flex-direction` 属性和 `flex-wrap` 属性的简写形式,默认值为 `row nowrap`。
<div class="se-preview-section-delimiter"></div>
```css
.ele {
flex-flow: <flex-direction> || <flex-wrap>;
}
align-items 属性
align-items
属性定义自容器在交叉轴上如何对齐。
具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
.ele{
align-items: flex-start; // 交叉轴的起点对齐。
align-items: flex-end; // 交叉轴的终点对齐。
align-items: center; // 交叉轴的中点对齐。
align-items: baseline; // 项目的第一行文字的基线对齐。
align-items: stretch; // 默认,如果项目未设置高度或设为auto,将占满整个容器的高度。
}
align-content 属性
align-content
属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.ele{
align-content: flex-start; // 与交叉轴的起点对齐
align-content; flex-end; // 与交叉轴的终点对齐。
align-content: center; // 与交叉轴的中点对齐。
align-content: space-between;// 与交叉轴两端对齐,轴线之间的间隔平均分布。
align-content: space-around; // 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
align-content: stretch; // 默认 轴线占满整个交叉轴。
}
子容器属性
子容器也有 6 个属性:
- order:子容器的排列顺序
- flex-grow:子容器剩余空间的拉伸比例
- flex-shrink:子容器超出空间的压缩比例
- flex-basis:自容器在不伸缩情况下的原始尺寸
- flex:子元素的 flex
属性是 flex-grow
,flex-shrink
和 flex-basis
的简写
- align-self
order 属性
order
属性定义项目的排列顺序。数值越小,排列越靠前,默认为 0。
.ele{
order: num;
}
flex-grow 属性
flex-grow
属性定义子容器的伸缩比例。按照该比例给子容器分配空间。
.ele{
flex-grow: <number>; /* default 0 */
}
flex-shrink 属性
flex-shrink
属性定义了子容器弹性收缩的比例。如图,超出的部分按 1:2 的比例从给子容器中减去。此属性要生效,父容器的 flex-wrap
属性要设置为 nowrap
.ele{
flex-shrink: <number>; /* default 0 */
}
flex-basis 属性
flex-basis
属性定义了自容器在不伸缩情况下的原始尺寸,主轴为横向时代表宽度,主轴为纵向时代表高度。
.ele{
flex-basis: <length> | auto; /* default auto */
}
flex 属性
子元素的 flex
属性是 flex-grow
,flex-shrink
和 flex-basis
的简写,默认值为 0
1
auto
。后两个属性可选。
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
align-self 属性
子容器的 align-self
属性允许单个项目有与其他项目不一样的对齐方式,可覆盖父容器 align-items
属性。默认值为 auto
,表示继承父元素的 align-items
属性,如果没有父元素,则等同于 stretch
。
.ele{
align-self: auto; // 继承父元素的 align-items 属性
align-self: flex-start; // 交叉轴的起点对齐。
align-self: flex-end; // 交叉轴的终点对齐。
align-self: center; // 交叉轴的中点对齐。
align-self: baseline; // 项目的第一行文字的基线对齐。
align-self: stretch; // 默认,如果项目未设置高度或设为auto,将占满整个容器的高度。
}
grid 网格布局
flex 布局虽然强大,但是只能是一维布局,如果要进行二维布局,那么我们还需要使用 grid。
grid 布局又称为“网格布局”,可以实现二维布局方式,和之前的 表格table
布局差不多,然而,这是使用 CSS 控制的,不是使用 HTML 控制的,同时还可以依赖于媒体查询根据不同的上下文得新定义布局。
网格布局还可以让我们摆脱现在布局中存在的文档流限制,换句话说,你的结构不需要根据设计稿从上往上布置了。这也意味着您可以自由地更改页面元素位置。这最适合你在不同的断点位置实现你最需要的布局,而不再需要为响应你的设计而担心HTML结构的问题。
和 table
布局不同的是,grid
布局不需要在 HTML 中使用特定的标签布局,所有的布局都是在 CSS 中完成的,你可以随意定义你的 grid 网格。
没有 HTML 结构的网格布局有助于使用流体、调整顺序等技术管理或更改布局。通过结合 CSS 的媒体查询属性,可以控制网格布局容器和他们的子元素,使用页面的布局根据不同的设备和可用空间调整元素的显示风格与定位,而不需要去改变文档结构的本质内容。
浏览器兼容性如下:
grid 网格布局中的基本概念
此部分直接摘自CSS Grid布局:什么是网格布局
网格线(Grid Lines)
网格线组成了网格,他是网格的水平和垂直的分界线。一个网格线存在行或列的两侧。我们可以引用它的数目或者定义的网格线名称。
网格轨道(Grid Track)
网格轨道是就是相邻两条网格线之间的空间,就好比表格中行或列。所在在网格中其分为grid column和grid row。每个网格轨道可以设置一个大小,用来控制宽度或高度。
网格单元格(Grid Cell)
网格单元格是指四条网格线之间的空间。所以它是最小的单位,就像表格中的单元格。
网格区域(Grid Area)
网格区域是由任意四条网格线组成的空间,所以他可能包含一个或多个单元格。相当于表格中的合并单元格之后的区域。
使用 grid 布局
使用 grid 布局很简单,通过display属性设置属性值为 grid 或 inline-grid 或者是 subgrid(该元素父元素为网格,继承父元素的行和列的大小) 就可以了。
网格容器中的所有子元素就会自动变成网格项目(grid item),然后设置列(grid-template-columns)和 行(grid-template-rows)的大小,设置 grid-template-columns
有多少个参数生成的 grid 列表就有多少个列。
注:当元素设置了网格布局,column、float、clear、vertical-align属性无效。
如果没有设置 grid-template-columns
,那么默认只有一列,宽度为父元素的 100%,例如
比如我们设置如下的 HTML,
<div class="grid-container">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item item3">3</div>
<div class="item item4">4</div>
<div class="item item5">5</div>
<div class="item item6">6</div>
</div>
在 CSS 中,我们不设置 grid-template-columns
,只设置 grid-template-row
.grid-container{
display: grid;
grid-template-rows: 50px 80px 100px;
background: pink;
}
.item{
border: 2px solid palegoldenrod;
color: #fff;
text-align: center;
font-size: 20px;
}
显示如下
设置了 grid-template-columns
的话,设置了几个参数,就有几列(不超过 grid item 的个数),然后设置的 grid-template-row
参数就是每一列的高度(超出列数的高度无效)
比如:
.grid-container{
padding: 20px;
display: grid;
grid-template-rows: 50px 100px 60px 80px;
grid-template-columns: 50px 40px 100px 80px;
background: pink;
}
.item{
border: 2px solid palegoldenrod;
color: #fff;
}
虽然我们设置了四个 grid-template-rows
,但是因为只有两行,所以只有前两个值生效。效果如下:
当然,我们也可以像 flex 一样设置每一列的宽度:
.grid-container{
padding: 20px;
display: grid;
grid-template-rows: 50px 100px 60px;
grid-template-columns: 1fr 1fr 2fr;
background: pink;
}
注意到我们使用了一个新的单位:fr
css fr 单位是一个自适应单位,fr单位被用于在一系列长度值中分配剩余空间,如果多个已指定了多个部分,则剩下的空间根据各自的数字按比例分配。
tips:fr 是基于网格容器可用空间来计算的(flex 也是一样),所以我们可以和其他单位混合使用,如果需要的话
是不是找到了 flex 的感觉,这样设置效果如下:
行或列最小和最大尺寸
minmax()
函数来创建行或列的最小或最大尺寸,第一个参数定义网格轨道的最小值,第二个参数定义网格轨道的最大值。可以接受任何长度值,也接受 auto
值。auto
值允许网格轨道基于内容的尺寸拉伸或挤压。
.grid-container{
padding: 20px;
display: grid;
grid-template-rows: minmax(100px,200px) minmax(50px,200px);
grid-template-columns: 1fr 1fr 2fr;
background: pink;
height: 300px;
}
我们将第一行的高度设置为 minmax(100px,200px)
,第二行的高度设置为minmax(50px,200px)
,容器总高度设置为 300px
,这时每一列的高度要怎么算呢?
先判断总高度是小于第一列高度的最大值和第二列高度的最大值之和的,如果大于最大值之和,那么第一列和第二列的高度都为设置的最大值,如果是小于最小值之和的话,那么第一列和第二列的高度都为设置的最小值。
现在问题来了,我们这种情况是总高度是小于第一列高度的最大值和第二列高度的最大值之和的,这样就是先用 总高度 300px
- 第一列最小高度 100px
- 第二列最小高度 50px
= 150px
。
第一列高度:第一列最小高度 100px
+ 150px/2
= 175px
;
第二列高度:第一列最小高度 50px
+ 150px/2
= 125px
;
效果如下:
重复行或者列
repeat()
属性可以创建重复的网格轨道。这个适用于创建相等尺寸的网格项目和多个网格项目。
repeat()
也接受两个参数:第一个参数定义网格轨道应该重复的次数,第二个参数定义每个轨道的尺寸。
.grid-container{
padding: 20px;
display: grid;
grid-template-columns: repeat(2,100px);
grid-template-rows: repeat(3,100px);
background: pink;
}
效果如下:
间距
grid-column-gap
:创建列与列之间的距离。
grid-row-gap
:行与行之间的距离。
.grid-container{
padding: 20px;
display: grid;
grid-template-columns: repeat(2,100px);
grid-template-rows: repeat(3,100px);
grid-column-gap: 50px;
grid-row-gap: 15px;
background: pink;
}
或者使用 grid-gap
是 grid-row-gap
和 grid-column-gap
两个属性的缩写。
通过网格线定位 grid item
我们可以通过表格线行或者列来定位 grid item。比如:
<div class="grid-container">
<div class="item item1">1</div>
<div class="item item2">2</div>
<div class="item item3">3</div>
<div class="item item4">4</div>
<div class="item item5">5</div>
<div class="item item6">6</div>
</div>
.grid-container{
padding: 20px;
display: grid;
grid-template-columns: repeat(2,100px);
grid-template-rows: repeat(3,100px);
grid-column-gap: 50px;
grid-row-gap: 15px;
background: pink;
}
.item{
border: 2px solid palegoldenrod;
color: #fff;
text-align: center;
font-size: 20px;
}
.item1{
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: 3;
background: #fffa90;
color: #000;
}
效果:
grid-row
是 grid-row-start
和 grid-row-end
的简写。grid-column
是 grid-column-start
和 grid-column-end
的简写。
如果只提供一个值,指定了 grid-row-start
和 grid-column-start
的值。
如果提供两个值,第一个值是 grid-row-start
或者 grid-column-start
的值,第二个值是 grid-row-end
或者 grid-column-end
的值,两者之间必须要用/隔开。
grid-row: 2;
grid-column: 3 / 4;
这四个值可以用 grid-area
缩写,分别对应 grid-row-start
、grid-column-start
、grid-row-end
、grid-column-end
:
grid-area: 2 / 2 / 3 / 3;
合并单元行与合并单元列
这个就和 excel 中的合并单元行/列是相同的(这个需要设置在 grid item 中),
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
grid-row-end: 4;
也可以使用 grid-row
和 grid-column
简写的形式,关键词 span
后面紧随数字,表示合并多少个列或行,/
前面是从第几行/列开始。
grid-row: 2 / span 3;
grid-column: span 2;
.grid-container{
padding: 20px;
display: grid;
grid-template-columns: repeat(4,100px);
grid-template-rows: repeat(3,100px);
grid-column-gap: 50px;
grid-row-gap: 15px;
background: pink;
}
.item{
border: 2px solid palegoldenrod;
color: #fff;
text-align: center;
font-size: 20px;
}
.item1{
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 2;
grid-row-end: 4;
}
效果如图:
自定义网格线名称
在 grid 中,是可以自定义网格线的名称的,然后使用定义好的网格线来进行布局,[col1-start]
网格线名称一定要使用 []
括住。
<div class="grid-container">
<div class="item a">a</div>
<div class="item b">b</div>
<div class="item c">c</div>
<div class="item d">d</div>
<div class="item e">e</div>
<div class="item f">f</div>
<div class="item g">g</div>
<div class="item h">h</div>
<div class="item i">i</div>
<div class="item j">j</div>
</div>
.grid-container{
text-align: center;
height: 400px;
padding: 100px;
display: grid;
grid-column-gap: 5px;
grid-row-gap: 5px;
background: pink;
grid-template-columns: [col1-start] 100px [col1-end] 5px [col2-start] 100px [col2-end] 5px [col3-start]
100px [col3-end] 5px [col4-start] 100px [col4-end];
grid-template-rows: [row1-start] auto [row1-end] 5px [row2-start] auto [row2-end] 5px [row3-start] auto
[row3-end] 5px [row4-start] auto [row4-end] 5px [row5-start] auto [row5-end];
}
.a { grid-column: col1-start / col3-end; grid-row: row1-start;
background: #ffffff;}
.b { grid-column: col4-start / col4-end; grid-row: row1-start / row5-end; background: orange; }
.c { grid-column: col1-start; grid-row: row2-start; background: #ffffff;}
.d { grid-column: col2-start; grid-row: row2-start; background: #ffffff;}
.e { grid-column: col3-start; grid-row: row2-start; background: #ffffff;}
.f { grid-column: col1-start / col2-end; grid-row: row3-start; background: #ffffff;}
.g { grid-column: col3-start; grid-row: row3-start; background: #ffffff;}
.h { grid-column: col1-start; grid-row: row4-start; background: #ffffff;}
.i { grid-column: col2-start / col3-end; grid-row: row4-start; background: #ffffff;}
.j { grid-column: col1-start / col3-end; grid-row: row5-start; background: #ffffff;}
最后的显示效果是这样的(文字和辅助线是后台添加的):
通过网格区域命名和定位网格项目
什么是网格区域:
网格区域(grid-area)是一个逻辑空间,主要用来放置一个或多个网格单元格(Grid Cell)。他是由四条网格线(Grid line),网格区域每边一条,四边相交组织的网格轨道(Grid Track)。简单点理解,网格区域是有四条网格线交织组成的网格空间,这个空间中可能是一个网格单元格,也可能是多个网格单元格。
定义网格区域
在CSS Grid Layout中定义网格区域有两种方式,一种是通过网格线来定义,另一种是通过grid-template-areas来定义。接下来看看两种定义网格区域的方法在具体使用过程中有何不同。
网格线定义网格区域
使用网格线定义网格区域的方法非常的简单,首先依赖于 grid-template-columns
和 grid-template-rows
显式定义网格线,甚至是由浏览器隐式创建网格线,然后通过 grid-area
属性通过取网格线,组成网格线交织区域,那么这个区域就是所讲的网格区域。在使用 grid-area
属性调用网格线,其遵循的规则是 grid-area: row-start
/ column-start
/ row-end
/ column-end
。
grid-template-areas
定义网格区域
除了使用网格线的交组来定义网格区域之外,在 CSS Grid Layout 中还可以通过 grid-template-areas
属性来定义网格区域的名称,然后需要放在对应网格区域的元素,可以通过 grid-area
属性来指定。而且重复区域可以使用同一个名称来实现跨区域。另外对于空的轨道区域,可以使用点号 .
来代表
<div class="grid-container">
<div class="header ">header</div>
<div class="content ">content</div>
<div class="sidebar ">sidebar</div>
<div class="footer ">footer</div>
</div>
.grid-container{
text-align: center;
padding: 20px;
display: grid;
grid-column-gap: 5px;
grid-row-gap: 5px;
background: pink;
grid-template-areas: "header header header header header"
"sidebar content content content content"
"footer footer footer footer footer";
grid-template-rows: 50px 150px 50px;
grid-template-columns: 200px 200px 200px;
}
.header { grid-area:header; background: #fff}
.content { grid-area: content; background: #fffa90}
.sidebar { grid-area: sidebar; background: #5bc0de}
.footer { grid-area: footer; background: #ffff00}
我发现这样布局的一个优点,在不设置高度的情况下(父容器和 grid-template-rows
的值,或者 grid-template-rows
设置为 auto
时,slider
和 content
的高度是一致的,并且会根据其内的高度自适应)
例如:
参考文献:
- 学习CSS Grid
- CSS Grid布局:网格区域
- CSS Grid布局:网格单元格布局
- CSS Grid布局:什么是网格布局
.grid-container{
text-align: center;
padding: 20px;
display: grid;
grid-column-gap: 5px;
grid-row-gap: 5px;
background: pink;
grid-template-areas: "header header header header header"
"sidebar content content content content"
"footer footer footer footer footer";
grid-template-rows: 50px 150px 50px;
grid-template-columns: 200px 200px 200px;
}
.header { grid-area:header; background: #fff}
.content { grid-area: content; background: #fffa90}
.sidebar { grid-area: sidebar; background: #5bc0de}
.footer { grid-area: footer; background: #ffff00}
我发现这样布局的一个优点,在不设置高度的情况下(父容器和 grid-template-rows
的值,或者 grid-template-rows
设置为 auto
时,slider
和 content
的高度是一致的,并且会根据其内的高度自适应)
例如:
参考文献:
- 学习CSS Grid
- CSS Grid布局:网格区域
- CSS Grid布局:网格单元格布局
- CSS Grid布局:什么是网格布局