CSS3 终极布局指南
我很想写一些能帮助人们的文章,即使我的水平不够没办法帮助您,我也希望这篇文章不要误导你。当然人是有极限的,如果文章真的有错误,您能帮我指出来,我就非常感谢您了。
对于同一个页面布局,几乎每个人的写法都不一样,有人喜欢Flex弹性盒子布局,有的人则喜欢Float浮动布局,有些人喜欢Margin负值布局,等等。从来就没有一种统一的布局方案,现在大伙写代码也就放飞自我,只要能在规定的环境上跑起来,不会乱就行了。但是,身为脑瘫正经前端,我们还是有必要分出在不同情况应使用的布局。
这一篇博客比起作为文章,不如作为工具书。当你对布局迷茫时,不妨打开看看。我们可以不求甚解,只需要先把所有布局掌握熟练。
正常布局(语义化布局)
正常布局,按照浏览器的内置CSS渲染
大道至简在远古时代,CSS还有没被发明,浏览器渲染HTML的时候,只是按照规定好的如标题、段落、表格等格式渲染。且不同的浏览器对于相同元素的渲染也是不同的,现在这项传统艺能保留到了今天。
不过到了今天,正常布局也稍微被W3C重视了一下。在HTML5的规定中,新增加了不少语义化的元素。所谓语义化元素就是让大家规定它就是来做这件事的。
新增加的语义化元素。
标签名称 | 作用 |
---|---|
hearder | header 标签定义文档的页面组合,通常是一些引导和导航信息。 |
nav | nav 标签定义显示导航链接不是所有的成组的超级链接都需要放在nav标签里。nav标签里应该放入一些当前页面的主要导航链接。 例如在页脚显示一个站点的导航链接(如首页,服务信息页面,版权信息页面等等),就可以使用nav标签,当然,这不是必须的。 |
article | article标签装载显示一个独立的文章内容。例如一篇完整的论坛帖子,一则网站新闻,一篇博客文章等等,一个用户评论等等 artilce可以嵌套,则内层的artilce对外层的article标签有隶属的关系。例如,一个博客文章,可以用article显示,然后一 些评论可以以article的形式嵌入其中。 |
section | section 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。 |
aside | aside 用来装载非正文类的内容。例如广告,成组的链接,侧边栏等等。 |
hgroup | hgroup 标签用于对网页或区段的标题元素(h1-h6)进行组合。例如,在一个区段中你有连续的h系列的标签元素,则可以用hgroup将他们括起来。 |
time | time 标签定义公历的时间(24 小时制)或日期,时间和时区偏移是可选的。该元素能够以机器可读的方式对日期和时间进行编码,这样, 举例说,用户代理能够把生日提醒或排定的事件添加到用户日程表中,搜索引擎也能够生成更智能的搜索结果。 |
mark | mark 标签定义带有记号的文本。请在需要突出显示文本时使用 <mark> 标签。 |
figure | figure标签规定独立的流内容(图像、图表、照片、代码等等)。figure 元素的内容应该与主内容相关,但如果被删除,则不应对文档流产生影响。 |
可以看到HTML5规定中增加了不少新的标签,但是这些标签大部分并不是为了补充正常的文档布局的,而是服务于搜索引擎的爬虫。**不要觉得页面布局只是给人看的!**对于布局清晰地页面,搜索引擎的爬虫也会给出更高的分数。
应用场景
- 作为布局的基石。
- 开发较为单一的页面,比如电子书阅读页面,面向视力障碍人士的报纸页面等。
带来的问题
挫
使用浏览器默认的CSS意味着你不可定制自己的页面,对于像<ul>
、<table>
这样的标签,你也只能忍受上世纪的设计风格了。
不兼容
先前说了,每个浏览器对于基础的HTML节点的渲染都不一样,也就是说你写的页面在IE上是一个风格,换到Safari上又是一种风格。
没有自适应
有一说一,正常布局(语义化)还是用来当基石比较好,对于响应式、自适应那还得看下面伙计的发挥。
解决方案
解决挫的方法就是使用style属性,也就是使用CSS美化我们的页面。解决不兼容的问题则需要初始化CSS,大伙应该在不少的页面的头部见过一大坨css代码吧,就像下面Google页面。(部分)
body{color:#000;margin:0}body{background:#fff}a.gb1,a.gb2,a.gb3,.link{color:#1a0dab !important}.ts{border-collapse:collapse}.ts td{padding:0}#res,#res .j{line-height:1.2}.g{line-height:1.2;text-align:left;}.ti,.bl{display:inline}.ti{display:inline-table}#rhs_block{padding-bottom:15px}a:link,.w,#prs a:visited,#prs a:active,.q:active,.q:visited,.kl:active,.tbotu{color:#1a0dab}.mblink:visited,a:visited{color:#609}.cur,.b{font-weight:bold}.j{width:42em;font-size:82%}.s{max-width:48em}.sl{font-size:82%}
页面初始化也是很重要的,它可以使我们的代码健壮的运行在各个环境的浏览器上。
Float浮动布局
什么是浮动?
如果首先要认识一个物品,认识一个东西的最好方式是了解为什么会产生它,也就是要翻它的历史。——NaoTan·Ma·Nong
看上图,啊,报社最爱的环绕,一堆文字环绕一张图片,这样的布局使得页面紧凑,并且有较好的阅读体验。如果我们要在HTML中实现这样的布局应当怎么设置呢?手动设置换行?不行,缺少灵魂。如果能使文字绕过图片排列下来就好了。
于是Float属性出世,它不仅解决了文字环绕问题,并且带来了新的布局方案。
.side-bar{
float:left;
}
.main-content{
float:left;
}
浮动元素的排列
当一个元素被设置为浮动元素时,首先,它会被移除文档流,设置float:left|right
则元素会向设置方向排列,直到遇到父元素边框(或者说最大宽度)或者另一个浮动元素时停止。
当设置父元素display:flex
时,子元素的浮动值无效!
浮动解决的布局问题
使用浮动我们可以解决传统的两列布局、三列布局的自适应。下面代码是用浮动实现的两列布局。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>两列布局</title>
<style>
body,
html {
margin: 0;
background-color: rgb(228, 228, 228);
}
header {
margin-bottom: 20px;
}
footer {
margin-top: 20px;
}
.layout {
height: 50px;
border: 1px solid black;
}
aside {
width: 25%;
float: left;
border: solid 1px black;
height: 500px;
}
article {
width: 70%;
border: solid 1px black;
height: 500px;
float: right;
}
</style>
</head>
<body>
<header class="layout"></header>
<div style="overflow:auto;">
<aside>
</aside>
<article>
</article>
</div>
<footer class="layout"></footer>
</body>
</html>
效果如下
浮动带来的问题
父元素高度坍缩
一般来说新手在学习浮动布局之后,遇到的第一个问题就是父元素高度坍缩。什么是高度坍缩?
看上图,在父元素的四个子元素均为浮动元素,由于浮动元素的特性浮动元素脱离文档流,所以父元素不会被撑起高度。
如何解决?答案很简单,使用BFC块级格式上下文。当父元素为BFC的时候,内部计算高度会带上浮动元素的高度。
不希望浮动时清除浮动
使用clear
属性可以使元素清除周围的浮动。
如上图,对段落文字清除浮动,导致原本环绕的文字,另起一行。顺便解决了高度坍缩的问题。
总结
浮动在带来方便的同时也引入了新的问题,如果能处理好这些问题那么浮动也可以当做布局的主力,但是都已经9102年了,我们应该追随CSS3的布局方案,尽量少使用浮动。
定位布局
收拾房子的时候总会把物品按照相应的位置放置,这样会让房间看上去更加整洁。所以,我们CSS也是可以这样做的。
使用position
属性,调整元素的位置。position
一共有四种定位类型:定位元素、相对定位、绝对定位、粘性定位,五种取值:static、relative、absolute、fixed、sticky。
名称 | 描述 | 定位类型 |
---|---|---|
static | 该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top , right , bottom , left 和 z-index 属性无效。 |
定位元素 |
relative | 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。 | 相对定位 |
absolute | 不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。 | 绝对定位 |
fixed | 不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。 |
绝对定位 |
sticky | 盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时 ),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky 对 table 元素的效果与 position: relative 相同。 |
粘性定位 |
一般使用position
属性时,会使用其相对定位与绝对定位、粘性定位,它们都使用top
、bottom
、left
、right
来调整自身位置,但是调整的基准不一样。
定位的应用
static
static是元素正常出现在文档流中的定位,文档流中的排列为自上而下,自左至右。一般来说block元素自占一行,inline元素横向排列。
正常情况下在我们的页面中大部分元素为static
定位,对于一些特殊需求我们需要使用其他定位。比如像wiki中的关键词,鼠标移动上去的时候,关键词下面显示式卡片。
relative
relative是在实现一些特殊布局的时候经常使用的一种定位方式。设置为relative的元素并不会脱离文档流,但是可以通过top
、bottom
、left
、right
调整元素对于默认基准的位置。
.box {
display: inline-block;
width: 100px;
height: 100px;
background: red;
color: white;
}
#two {
position: relative;
top: 20px;
left: 20px;
background: blue;
}
使用相对定位可以实现一些炫酷的效果。
.content{
text-align: center;
margin: 20px;
}
.card{
position: relative;
display: inline-block;
width: 200px;
height: 200px;
background-color: darkgray;
top: 210px;
right: 170px;
visibility: hidden;
}
span:hover+.card{
visibility:visible;
}
<div class="content">
<span>鼠标移到我身上!</span>
<div class="card">
</div>
</div>
效果
但是,使用相对定位依然会出现一些问题。relative定位并不会脱离文档流,所以.content
元素的高度为200px
。
absolute
与relative
定位不同的是absolute
是脱离文档流的,而且相对基准是position属性不为static的祖先元素,如果祖先都是static则元素相对body定位。并且,对于absolute元素,如果不设置top/bottom/left/right的话依然排列在正常布局位置。
html,
body {
margin: 0;
}
.content {
position: relative;
/* top: 50px; */
margin-top: 50px;
}
.static {
position: static;
}
.relative {
position: relative;
margin: 20px 0;
}
.absolute {
display: inline-block;
width: 50px;
height: 50px;
background-color: lightcoral;
position: absolute;
}
.non-ab {
display: inline-block;
width: 50px;
height: 50px;
background-color: darkblue;
margin-left: 100px;
}
<div class="content">
<div style="height: 50px;"></div>
<div class="static">
<div class="non-ab">
</div>
<div class="absolute">
</div>
</div>
<div class="relative">
<div class="absolute">
</div>
<div class="non-ab">
</div>
</div>
</div>
上面的代码很有意思,有兴趣的同学可以放在codepen
上面跑一下子。这个例子验证了absolute
的排列方式。当我们知道我们在做什的时候,也就不需要墨守成规(对于absolute元素的父元素统一设置relative属性)了。
高度坍缩
只要是脱离了文档流的元素都会出现高度坍缩,所以在使用absolute
属性时,请确保父元素不会因此而改变。
对比float
Float与absolute都会使元素脱离文档流,但是众所周知对相同元素设置float与设置absolute会出现不同的效果。这是因为float与absolute本身的排列不一样。
float:脱离文档流,排列时以父元素为基准,并且会为占用其他浮动元素的位置。
absolute:脱离文档流,排列时分情况:第一种情况,对于未设置left、right、top、bottom
属性的元素,排列在正常显示位置,并不占用空间。第二种情况,设置位置属性的元素,基于非static祖先元素排列。
上面两者比较显著的差异为float会影响下一个float元素,但是absolute元素不会。
总结
说absolute为绝对定位也并不贴切,它也是基于祖先元素定位的,只是脱离了文档流。我个人还是比较推荐在处理元素相对位置问题上使用absolute属性的,但前提是您已经深刻理解了absolute的排列方式。
fixed
不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。
fixed
属性会创建新的层叠上下文。当元素祖先的transform
属性非none
时,容器由视口改为该祖先。
fixed元素也会脱离文档流,并且和absolute元素一样,当不设置任何left、top、bottom、right
值的时候,元素依然按照正常定位的位置放置。
祖先未使用transform:none
当祖先元素未使用transform:none
的时候,fixed元素相对于该祖先元素进行定位。
在上面的图片中,我设置小黄块为fiexd属性,并让父元素设置为 使用transform:matrix(1, 0, 0, 1, 0, 0);
,这时候小黄块并没有相对于body
进行定位,当滚动条下拉时,小黄块定位固定在父元素左上角。
使用
fiexd元素一般用在如:to-top
按钮,或者侧边悬浮面板,或者悬浮导航栏之中。
sticky 粘性定位
盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为
table 时
),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky
对table
元素的效果与position: relative
相同。
上面我们使用了fiexd
与transform
,发生了我们意想不到的效果,那就是fixed元素并未相对于body进行移动,也没有在父元素中进行标准的fixed定位。现在我们使用以下sticky属性来看一下效果。
<style>
.box{
box-sizing: border-box;
height: 150px;
border:solid 3px black;
margin: 0 0 20px 0;
overflow: auto;
}
.block{
width: 50px;
height: 50px;
background-color: orange;
}
.sticky-1{
position:sticky;
top: 0px;
}
</style>
<div class="box box-1">
<p>下面这个小黄块设置为sticky</p>
<div class="sticky-1 block">
</div>
<p>
hahah
</p>
<p>
hahah
</p>
<p>hahaha</p>
<p>hahaha</p>
</div>
当我们向下滚动的时候神奇的事情发生了。
小黄块固定到了父元素的top:0
位置了,不仅如此,再向上滑动后,小黄块又回复了当时的位置,而且占用了文档本身的位置。
使用这个特性我们可以制作浮动的Header组件,当用户向下滑动至窗口上侧的时候,Header组件也跟随窗口滑动。
Flex布局
对于前端工程师来说,最让人头疼的莫过于自适应布局。对于不同分辨率的设备要做到页面统一,在CSS3出现之前,还是挺不容易的。还有就是前端工程师头疼的一个布局问题:垂直居中。
CSS3中新出了一种布局技术:CSS弹性盒子布局,我们来看一下MDN是如何介绍的。
CSS 弹性盒子布局是 CSS 的模块之一,定义了一种针对用户界面设计而优化的 CSS 盒子模型。在弹性布局模型中,弹性容器的子元素可以在任何方向上排布,也可以“弹性伸缩”其尺寸,既可以增加尺寸以填满未使用的空间,也可以收缩尺寸以避免父元素溢出。子元素的水平对齐和垂直对齐都能很方便的进行操控。通过嵌套这些框(水平框在垂直框内,或垂直框在水平框内)可以在两个维度上构建布局。
接下来,我会使用Flex布局技术,设计一些我们常使用页面布局,并指出优点与缺点。但是,我们首先要来看一下浏览器的支持程度。
浏览器支持
特性 | Firefox (Gecko) | Chrome | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
基础支持 | 20.0 (20.0) | 21.0-webkit 29.0 | 10.0-ms 11.0 | 12.10 | 6.1-webkit |
主流的浏览器全部支持Flex属性。注:与社会脱轨的IE9并不支持Flex,如果想写出兼容IE9的页面,请不要使用Flex。
Flex使用介绍
使用flex务必清楚一些属性概念。
-
Flex容器:对于一个基本元素(不含任何CSS属性,如
div
),设置display:flex
,即可创建一个Flex容器。 -
Flex子项:父元素为Flex容器的元素,称之为Flex子项,其排布受到父元素影响。注:一定是父元素为Flex容器的元素,祖先不算。
-
排布方向:指Flex子项在Flex容器中的排布方向。排布方向有两种:
column
、row
。在Flex容器上使用flex-direction: column|row(默认);
即可设置。 -
主轴:指的Flex容器中是与排列方式相同的方向的轴。如设置Flex容器
direction: column;
则其主轴为竖直方向。 -
交叉轴:指的Flex容器中是与排列方式相反的方向的轴。如设置Flex容器
direction: column;
则其主轴为水平方向。我们一定要清楚上面的基础概念,这对深入使用Flex有很大的帮助。下面我会介绍一些Flex常用的属性,主要分为两部分:对Flex容器、对Flex子项。
Flex容器属性
flex-direction 排布方向
flex-direction
属性指定了内部元素是如何在 flex 容器中布局的,定义了主轴的方向(正方向或反方向)。
flex-direction
属性接受以下值:
- row:子项目在flex容器中横向,从左至右排列。
- row-reverse:表现和row相同,也是横向,但是是从右到左。
- column:子项在容器中竖向排列,从上至下。
- 这里不贴图了
- column-reverse:表现和
column
相同,子项在容器中竖向排列,从下至上。- 这里不贴图了
flex-wrap 控制换行
CSS flex-wrap 指定 flex 元素单行显示还是多行显示 。如果允许换行,这个属性允许你控制行的堆叠方向。
取值:
- nowrap(默认)
- flex 的元素被摆放到到一行,这可能导致溢出 flex 容器。 cross-start 会根据
flex-direction
的值 相当于 start 或 before。
- flex 的元素被摆放到到一行,这可能导致溢出 flex 容器。 cross-start 会根据
- wrap
- flex 元素 被打断到多个行中。cross-start 会根据
flex-direction
的值选择等于start 或before。cross-end 为确定的 cross-start 的另一端。
- flex 元素 被打断到多个行中。cross-start 会根据
- wrap-reverse
- 和 wrap 的行为一样,但是 cross-start 和 cross-end 互换。
flex-flow [排布方向/控制换行]的简称
CSS flex-flow 属性是 flex-direction 和 flex-wrap 的简写。
示例:flex-flow: column-reverse wrap;
justify-content 子项目在主轴上的排布
CSS justify-content 属性定义了浏览器如何分配顺着父容器主轴的弹性元素之间及其周围的空间。
justify-content同时受到父容器主轴的影响。
取值:
-
start
从行首开始排列。每行第一个元素与行首对齐,同时所有后续的元素与前一个对齐。
-
flex-start
(默认)从行首开始排列。每行第一个弹性元素与行首对齐,同时所有后续的弹性元素与前一个对齐。
-
flex-end
从行尾开始排列。每行最后一个弹性元素与行尾对齐,其他元素将与后一个对齐。
-
center
伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同。
-
left
伸缩元素一个挨一个在对齐容器得左边缘,如果属性的轴与内联轴不平行,则left的行为类似于start
-
right
元素以容器右边缘为基准, 一个挨着一个对齐,如果属性轴与内联轴不平行,则
right
的行为类似于start.
-
space-between
在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐。
-
space-around
- 在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半。
-
space-evenly
- flex项都沿着主轴均匀分布在指定的对齐容器中。相邻flex项之间的间距,主轴起始位置到第一个flex项的间距,主轴结束位置到最后一个flex项的间距,都完全一样。
- 看上去与
space-around
的排布很相似,但其实还是有一些区别的。space-evenly
会在每一行均匀分布间隙,而space-around
是均匀分布项目。 - 借一张图
看上去我们要学的属性很多,但是其实我们只需要记住我们常用的几个属性就行:flex-start
、flex-end
、space-between
、center
、space-around
、space-evenly
。以上这几个就是我们常用的属性值,通过设置主轴方向、设置排列方式,我们可以灵活地组织我们的元素。
align-items 子项目在交叉轴排布
CSS align-items属性将所有直接子节点上的align-self值设置为一个组。 align-self属性设置项目在其包含块中在交叉轴方向上的对齐方式。
取值:
-
normal
这个关键字的效果取决于我们处在什么布局模式中:在绝对定位的布局中,对于被替代的绝对定位盒子,这个效果和
start
的效果的一样;对于其他所有绝对定位的盒子,这个效果和stretch
的效果一样。 在绝对定位布局的静态位置上,效果和stretch
一样。对于那些弹性项目而言,效果和stretch
一样。对于那些网格项目而言,效果和stretch
一样,除了有部分比例或者一个固定大小的盒子的效果像start
。这个属性不适用于会计盒子和表格。 -
flex-start
元素向侧轴起点对齐。
-
flex-end
元素向侧轴终点对齐。
-
center
元素在侧轴居中。如果元素在侧轴上的高度高于其容器,那么在两个方向上溢出距离相同。
因为align-items
其实和justify-content
我这里就不放一些图片凑字数了。
align-content 定义多根轴线排布
该属性对单行弹性盒子模型无效。(即:带有flex-wrap: nowrap)。
CSS的align-content属性设置了浏览器如何沿着伸缩盒子容器(flexbox container)的纵轴和网格容器(Grid Container)的主轴在内容项之间和周围分配空间。
它的取值和align-items
差不多,经常有人会把他们搞混。
align-content
一般定义多行的交叉轴排列。
绝大多数情况下我们使用align-items
即可实现我们的需求。
Flex子项属性
order 子项排布靠前排名
CSS order 属性规定了弹性容器中的可伸缩项目在布局时的顺序。元素按照
order
属性的值的增序进行布局。拥有相同order
属性值的元素按照它们在源代码中出现的顺序进行布局。
取值:
-
<integer>
表示此可伸缩项目所在的次序组。
flex-grow 子项放大比例
CSS flex-grow 属性定义弹性盒子项(flex item)的拉伸因子
取值:
-
<number>
默认值0,即如果存在剩余空间,也不放大。负值无效。
flex-shrink 子项缩小比例
CSS flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。
总而言之,你定了这个属性,其他项目会先压榨你的空间,然后再均匀缩小其他项目。
flex-basis 默认的宽度
flex-basis
属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto
,即项目的本来大小。
注:分配多余空间之前!!
也就是说你给的flex-basis
值大于当前分配空间时,依然会被压缩。
flex 放大/缩小/默认宽度 简写
flex
属性是flex-grow
, flex-shrink
和 flex-basis
的简写,默认值为0 1 auto
。后两个属性可选。
align-self 独自在交叉轴的排布方式
align-self
属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性。默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
。
这个属性了不得,它也是我们经常用的子项目属性之一。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
就像上面的图,他可以决定子项目的交叉轴单独排列方式。
Flex响应式例子
使用我们刚才学到的知识,我们可以轻易设计响应式的布局比如,在大屏上应显示如下布局
当屏幕分辨率降低时,我们应该在中心保留正文部分,达到下面效果。
这是我们最常用的三栏布局,并且我们考虑到了针对不同屏幕的使用者呈现不同的布局效果。
下面是这个布局的代码。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flex例子</title>
<style>
html,
body {
margin: 0;
}
header {
height: 50px;
border: solid 5px black;
box-sizing: border-box;
background-color: gray;
margin-bottom: 20px;
}
.content {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-around;
}
aside {
order: 3;
flex: 1 0 200px;
height: auto;
border: solid 5px black;
box-sizing: border-box;
background-color: gray;
}
article {
text-align: center;
order: 2;
flex: 1 0 800px;
height: 500px;
border: solid 5px black;
box-sizing: border-box;
background-color: gray;
}
.order-1 {
order: 1;
}
footer{
}
</style>
</head>
<body>
<header></header>
<div class="content">
<article>
<h1>我是正文</h1>
<p>我会最先刷新出来</p>
</article>
<aside class="order-1">
<h1>我是左边栏</h1>
<p>这里一般可以放一些文章信息</p>
<p>比如作者的其他文章、分类、专栏</p>
</aside>
<aside>
<h1>这里是右边栏</h1>
<p>页面制作者可以考虑放一些广告</p>
<p>我会自动换行到最下面 保证阅读体验</p>
</aside>
</div>
<footer></footer>
</body>
</html>
细心的读者发现我们在html里面的布局是
<article>
<h1>我是正文</h1>
<p>我会最先刷新出来</p>
</article>
<aside class="order-1">
</aside>
<aside>
</aside>
我们把正文,写到了最前面。这样页面在加载的的时候会最先加载正文部分。当CSS OM构建完成时,正文就会回到页面最中心,因为CSS OM的构建速度大部分取决于网速(下载css)所以我们是感受不到这个改变的。
Grid 布局
熟练使用Flex之后,我们确信flex能解决绝大部分的布局难题,剩下一小部分也可以使用定位布局来解决。那么Grid布局的优势在哪些地方呢?
Flex布局属于一维布局,单纯控制Flex容器中的一列,或者一行。我们通常不会使用Flex来定义页面的整体布局,而是更多用它来解决某一个组件中的布局。
Grid布局更多是来定义整体的布局,通过网格线将页面划分不同的区域。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DU4t4qPs-1570616123211)(%E7%BB%88%E6%9E%81%E5%B8%83%E5%B1%80%E6%8C%87%E5%8D%97.assets/basic-form-1570602316379.png)]
类比一下,Grid就好像一个书架,上面有不同的格子。Flex就是格子中的排布。
Grid布局的动机
使用一些CSS控制页面布局,搭建响应式页面。这已经是前端工程师必备技能了,但是使用一些古老的方式,比如浮动、margin
负值法,建立的布局往往会出现无法预测的行为。也无法直观的给人布局的美感。有些Web开发人员会使用display:table
来进行布局,但是这些布局往往在响应式的效果上不佳。可控制
、响应式
、符合直觉
这些问题都需要被解决。
Grid网格布局应运而生。通过我们自定义一些属性,我们的页面往往既健壮又符合直觉。
浏览器支持
虽然现在Grid布局依然只是处于CR
阶段(w3c的推荐候选标准),但是已经有不少浏览器完全支持这种布局方案了,而且不少框架的栅格布局,就是使用grid进行实现的。
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | Android webview | Chrome for Android | Firefox for Android | Opera for Android | Safari on iOS | Samsung Internet | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
grid |
57 | 16 | 52 | No support | 44 | 10.1 | 57 | 57 | 52 | 43 | 10.3 | 6.0 |
除了IE基本上浏览器都兼容,所以说IE真是个好东西,逼着我们写兼容。
Grid概念介绍
网格容器:我们通过在元素上声明 display:grid
或 display:inline-grid
来创建一个网格容器。
网格元素:网格容器的直接子元素为网格元素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thm2uX3Q-1570616123212)(assets/1570604160943.png)]
<div class="grid">
<div class="item"><span>1</span></div>
<div class="item"><span>2</span></div>
<div class="item"><span>3</span></div>
<div class="item"><span>4</span></div>
</div>
这里设置class="grid"
的div
为网格容器,而class="item"
的div
是网格元素,在最内部的span
标签并不是网格元素。
fr
单位:fr
单位通常与CSS网格布局一起使用。 fr
单位是CSS网格布局规范的一部分,代表网格容器中剩余空间的一小部分。请把它理解为flex中的flex:0 1 auto
中数字的单位。
Grid使用
设置网格容器
使用display:grid
或者display: inline-grid;
设置容器成为网格容器。
注:设为网格布局以后,容器子元素(项目)的
float
、display: inline-block
、display: table-cell
、vertical-align
和column-*
等设置都将失效。
显示定义网格
通过使用
grid-template-columns
和grid-template-rows
属性创建列和行来显式设置网格。
定义行
在网格容器中使用grid-template-rows
属性值可以定义行的高度。
取值
none
:这个关键字表示不明确的网格。所有的行和其大小都将由grid-auto-rows
属性隐式的指定。
<length>
:长度单位值,如px
、em
、rem
。
<percentage>
:百分比单位。如取值80%
。
max-content
:是一个用来表示以网格项的最大的内容来占据网格轨道的关键字。
min-content
:是一个用来表示以网格项的最大的最小内容来占据网格轨道的关键字。
auto
:如果该网格轨道为最大时,该属性等同于 <max-content>
,为最小时,则等同于 <min-content>
。
minmax(min, max)
:是一个来定义大小范围的属性,大于等于min值,并且小于等于max值。如果max值小于min值,则该值会被视为min值。最大值可以设置为网格轨道系数值<flex>
,但最小值则不行。
使用例:
我们在网格容器中设置grid-template-rows:100px 80px;
,可以看到第一行的高度变成了100px
,第二行高度变成了80px
,我们并没有设置后面的高度,所以其他的项目按照原本大小显示。
定义列
在网格容器中使用grid-template-columns
属性值可以定义行的高度。
取值和grid-template-rows
基本相同,这里不再赘述。
使用例:
grid-template-columns: 90px 150px auto;
看到这里大伙应该差不多理解了grid的排列了吧,从上至下,从左至右,依次填入设计好的网格中。但是一个一个设计行列宽度,会很费时间,于是css提供给我们一个repeat()
方法。
repeat()
repeat()
方法接收两个参数,第一个参数用来表示重复几次,第二个参数用来表示重复的值。
如:repeat(10,100px)
,表示重复10次100px。而repeat(2,50px 80px)
注意中间只有一个逗号,表示50px 80px
重复两次。
用法:
.grid{
display: grid;
grid-template-rows: repeat(2,50px 80px);
grid-template-columns: repeat(3,90px);
}
效果:
网格间隙
在
grid-column-gap
和grid-row-gap
属性来创建列和行之间的间距。网格间隙仅在列和行之间创建,而不沿着网格容器的边缘。
grid-gap
同时设置行列间距。
例:
grid-row-gap: 20px;
grid-column-gap: 5rem;
间隙大小值可以是任意非负,长度值(px
,%
,em
等)。
grid-gap
是grid-row-gap
和的简写grid-column-gap
。
如果指定了两个值,则第一个表示grid-row-gap
,第二个表示grid-column-gap
。
网格线
网格线从容器的最起始边到结束边。如上图,图中为2×3的网格。行网格线一共有4条,列网格线一共有三条。网格线对于我们设置子项跨网格起到很大作用。
跨网格的子项目
通过设置
grid-column-start: 2;
grid-column-end: 4;
我们看到第5个div
占据了两个格子。
当然我们也可以通过
grid-row-start:1;
grid-row-end: 3;
来使div
占据竖向网格,效果如下:
每次书写绑定的两个css,我们难免会不爽,所以css也为我们这个属性提供了简写。
grid-row: 2 / 5;
grid-column: 2 / 4;
通过这种用法,也可以实现上面的效果。
当然,w3c甚至想到了我们可能连数数都会数错,所以我们可以用span
的关键字来指定子项目跨越网格线的数目。
grid-row: 2 / span 3;
grid-column: span 2;
效果如下:
关于Grid,我就说这么多。因为网上教程真的有多又好,我如果只是在这里搬运基础,那么就有点显得做无用功了。这里我推荐大家来https://learncssgrid.com/,这里学习Grid其他的知识。
参考
- HTML5语义化标签属性-HTML5属性手册
- All About Floats | CSS-Tricks
- 清除浮动的四种方式及其原理理解
- 【前端Talkking】CSS系列——CSS深入理解之absolute定位
- CSS 弹性盒子布局
- Flex 布局教程:语法篇
- CSS Grid Layout Module Level 1
- grid - CSS(层叠样式表) | MDN
- CSS Grid 网格布局教程
声明
脑瘫码农 纯靠自学 如有错误 望请指正 共同学习 不胜感激