flexbox布局是CSS3中新增的属性,它可以很轻松地帮我们解决掉一些常见的布局问题,比如导航栏。 我们用普通的方法写导航栏,通常会在ul, li 结构写好后,让li 元素左浮动,然后再给ul 清浮动。但用flex布局,直接给ul 一个display:flex 样式就可以了。如果不相信,可以试一试。新建一个文件夹flexbox, 然后再新建index.html ,在其中写一个ul li 列表,
<ul> <li>电脑</li> <li>手机</li> <li>平板</li> </ul>
然后在内嵌样式style标签中,写下 ul { display:flex}, 三个li 水平排列了,再也不用float:left了,更不用时时记着清浮动了。当然这只是flexbox 布局最简单的使用,但这也体现了flexbox布局的强大。
ul { display:flex }
CSS样式的学习,就是不停地实验其属性,然后看这个属性在浏览器中的表现形式,如果有一个工具,在我们更改样式后,它能自动刷新浏览器显示更改后的属性就好了,省得按F5了,还能直观地看到样式的变化。屏幕左边是浏览器,右边是编辑器,我们在编辑器中更改了样式,然后盯着浏览器,这时左手按一个ctrl +s 保存, 浏览器自动刷新,样式变化,我们可以清晰看到变化的过程,完美。幸好,我们有webpack 和gulp等构建工具,它们可以帮助我们。gulp+ browsersync 的搭配非常完美,gulp的官网有其使用介绍,webpack 自带的webpack-dev-server 也不错, 我们这里简单使用一个webpack.
当使用webpack构建工具时,我们的代码就变成了node 项目。对于一个项目,node建议要有一个package.json 文件,记录项目的版本,开发时的依赖等。在flexbox文件夹中,按shift键,点击鼠标右键,在出现的右键菜单中点击“在此处打开命令窗口” ,出现cmd命令窗口,在其中输入npm init -y, 就可以快速创建package.json文件。刚才说了要用到webpack-dev-server, 使用它就要先安装它,在命令窗口中接着输入npm install webpack webpack-dev-server -D. 我们这里要写css 文件,而webpack 把css 也是看作一种资源,在js文件中引进,所以要用loader进行解析,npm install css-loader style-loader -D 安装loader. 在该文件夹下,再新建webpack.config.js 文件,它是webpack 的配置文件,webpack 进行打包的时候,就是依靠它里面的定义的规则进行打包。
webpack.config.js文件如下:
var path = require('path'); module.exports = { entry:'./index.js', output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test:/\.css$/, use: ['style-loader','css-loader'] } ] } }
最后就是如何启动webpack-dev-server 了,这时打开package.json文件,找到script 字段,然后改为如下内容:
"scripts": { "dev": "webpack-dev-server --open" },
好了,在命令窗口中只要输入npm run dev就可以启动服务了,配置完成了。那我们先写一点内容,看看配置有没有问题。css书写之前,都是先清除元素的默认样式,新建一个reset.css 文件,
ul { margin: 0; padding: 0; list-style: none; }
新建index.js 文件,引入reset.css,
require('./reset.css')
再修改一下html 文件,body 标签最下面写 <script src="bundle.js"></script>,还要把内嵌的style 标签去掉
<body> <ul> <li>电脑</li> <li>手机</li> <li>平板</li> </ul> <script src="bundle.js"></script> </body>
在命令窗口中输入npm run dev, 可以看到它打开了浏览器,默认样式成功清除了,打开的浏览器是你平时上网用的默认浏览器。为了以后学习flexbox, 我们把样式调整好看一些,新建index.css
ul { width: 600px; height: 300px; border: 1px solid red; } li { width: 100px; height: 100px; background-color: #8cacea; margin: 8px; }
在index.js 中再引入它
require('./reset.css') require('./index.css')
按ctrl +s 保存后,浏览器自动刷新,变成如下样子,我们配置没有问题。样式不是太好看,嗯,就这样吧。
基础工作完成了,开始使用flexbox吧。使用flexbox布局,首先要定义一个flex容器。容器,容器,肯定是指父元素,因为它包含子元素,可以称之为容器,在我们这个例子中就是ul,给ul设置怎样的样式才能使之成了flex 容器,display: flex, 或display:inline-flex. 两者都会使ul变成了flex容器,区别是设置display:flex 后,ul 仍然是块级元素,独占一行,而display:inline-flex 则使ul 成了行内元素,可以和其他行内元素进行水平排列。我们可以在ul 后面添加一个span标签测试一下,html 修改如下
<ul>
</ul> <span>测试ul 是行内元素还是块级元素</span>
给ul添加dispaly: flex 属性,
ul { width: 600px; height: 300px; border: 1px solid red; display: flex; /*增加 display: flex;属性*/ }
页面如下展示,span 元素另起一行,可见ul仍是块级元素。
把ul 的display: flex 换成display:inline-flex
ul { width: 600px; height: 300px; border: 1px solid red; display: inline-flex; /*增加 display: inline-flex;属性*/ }
页面展示效查如下,display: inline-flex , 确实使ul变成了一个行内元素,在水平方向上进行排列。
不管设置成什么,ul 都成了flex容器,因为我们发现, li元素由原来的垂直排列变成了水平排列。这时元素li也有了另外一个名称,叫flex items(flex 项目)。flex容器中的每一个子元素都称之为一个flex项目。 这就是flex布局中非常重要的两个概念:flex 容器和flex 项目。
当一个元素成为了flex容器后,它默认存在两根轴,主轴(main axis)和 侧轴(cross axis), 它就是我们平常理解的水平轴和垂直轴,因为在一个平面中,只有这两根轴,flex布局也是平面布局,它也不例外,那为什么不叫水平轴和垂直轴?因为主轴的方向是不固定的,它即可以是水平方向,也可以是垂直方向。当主轴是水平方向时,侧轴就是垂直方向,当主轴是垂直方向时,侧轴就是水平方向。 它有两种可能,所以不能简单称之为水平轴或垂直轴。
主轴是什么方向也很重要,因为它影响了flex 项目的排列。就像上图展示,如果主轴是水平方向,flex 项目就是水平方向依次排列。如果主轴是垂直方向,那么flex项目就会沿着垂直方向依次排列。所以当一个元素成为flex 容器时,我们首先要确定的就是主轴的方向。正好flex-direction属性提供这样的设置。
flex-direction 定义主轴的方向,相应地也确定了侧轴的方向,因为只有这两个轴且它们是垂直关系。它有四个属性值:row || row-reverse || column || column-reverse。
row: 主轴为水平方向,起点为容器的左侧。
ul { width: 600px; height: 300px; border: 1px solid red; display: flex; flex-direction: row; }
页面展示如下,可以看到和没有设置这个属性之前表现一致,因为这是它的默认属性, 甚至我们不设置这个属性,它的值也是row.
row-reverse: 主轴方向为水平方向,不过起点为容器的右侧。flex-direction属性值改为 row-reverse, flex项目在水平方向上从右向左排列
column: 主轴为垂直方向,起点为容器的顶部。
column-reverse: 主轴为垂直方向,不过起点为容器的底部。元素从下从上排列了,
在依次设置这四个属性值的时候,请注意第一个元素(电脑)的位置。
设置了主轴方向后,flex项目就按照主轴的方向进行排列,比如我们这里设置了flex-direction:row,元素默认从左边向右排列,这时我们想让元素进行居中显示或靠右显示, flex布局能不能做到? 能, 这里要用到just-content 属性, 它就是定义flex 项目在主轴上怎样排列, 有五个属性值: flex-start , flex-end, center, space-between, space-around,现在依次给 ul 设置这五个属性值。
ul { width: 600px; height: 300px; border: 1px solid red; display: flex; flex-direction: row; justify-content: flex-start; }
flex-start: 从主轴的起点开始排列,由于flex-direction:row ,主轴的起点在左侧,所以它从左向右显示, 这也是它的默认属性,也解释了只设置flex-direction:row时,元素从左向右显示.
flex-end: 从主轴的终点开始排列,起点在左侧,从左向右, 那么终点就是右侧,flex容器的右侧, flex 项目从右向左排列.
flex-center: 在主轴的中间进行排列.
space-between: 当主轴方向有剩余空间时, 整个剩余空间在三个flex项目之间进行平分.
space-around: 也是当主轴方向上有剩余空间时, 剩余容间要包围flex 项目,和space-between 相比,第一个元素和第三个元素与flex容器的两侧有空间。如查你仔细测量的话,它的距离是 两个flex项目之间的距离的1/2.
现在我们一直在水平方向上进行操作,垂直方向上呢? 垂直方向上能不能操作, 这又是另外一个属性align-items了, 它就规定了flex 项目在侧轴上怎么排列,在我们这里就垂直方向上怎么排列,它也有5个属性: flex-start ,flex-end center, stretch, baseline
flex-start, flext-end, center 和just-content 一样,只不过这里指的是侧轴的起点,终点,和中间位置. 简单用图片展示一下,为了更为明显地看到垂直方向上的排列,我们把li 三个元素的高度设为都不一样, 同时给ul 添加 align-items 属性, 先从flex-start 开始
ul { width: 600px; height: 300px; border: 1px solid red; display: flex; flex-direction: row; justify-content: space-around; align-items: flex-start; } li { width: 100px; margin: 8px; padding: 4px; background-color: #8cacea; } li:nth-child(1) { height: 30px; } li:nth-child(2) { height: 60px; } li:nth-child(3) { height: 90px; }
flex-start: 在侧轴的起始点对齐, flex项目顶部对齐
flex-end: 在侧轴的终点处对齐, fllex项目底部对齐。
center: 在侧轴的中间对齐, flex项目中心点在侧轴的中心上。
stretch: 在英文中它有拉伸的意思, 在这里主要指, 如果flex项目没有设置高度,或高度为auto的话,那么它会在侧轴方向上进行拉伸,占满整个侧轴的空间。现在把第一个li(电脑)的高度去掉, 就可以看到效果. 它是align-items的默认属性, 只不过,我们在一开始的时候就设置了高度把它覆盖掉了.
baseline:主要指的是如果flex项目中有内容 , 它会按照内容中的第一行文字的底部进行对齐. 如果没有内容,则按项目的底部对齐。我们这时正好有内容, 所以它就会按这三个字的底部进行对齐.现在恢复第一个体li 的高度为30px , 我们没有看到太大变化,像flex-start, 这是给第三个li 设一个line-height:90px,
li:nth-child(1) { height: 30px; } li:nth-child(2) { height: 60px; } li:nth-child(3) { height: 90px; line-height: 90px; }
现在看到变化了,内容第一行文字底部对齐。
现在把文字去掉,
<ul> <li></li> <li></li> <li></li> </ul>
可以看到它们按照底部对齐.
现在是我们只有三个flex项目,flex 容器一行内就可以把它们全放下,但如果项目增多怎么办,比如5个,8个,一行有可能放不下,放不下之后怎么办,是在一行显示,还是在多行显示, 这就到了flex-wrap属性。flex-wrap: 定义了当我们的flex项目非常多时,在flex容器中一行放不下时,元素怎么排列,到底换不换行。 它有三种属性值: nowrap, wrap 和wrap-reverse。
现在我们先增加几个li再说,先增加3个,这里把所有的li高度都调成了一样100px, 看到它们仍在一行显示,但每一个项目的宽度似乎变小了. 这里要注意,在html 中增加元素,浏览器并不会自动刷新, 在这里需要手动刷新一下, webpack-dev-server 并没有监测html的变化。
<ul> <li>电脑</li> <li>手机</li> <li>平板</li> <li>平板</li> <li>平板</li> <li>平板</li> </ul>
再增加3个li, 一共9个li
<ul> <li>电脑</li> <li>手机</li> <li>平板</li> <li>平板</li> <li>平板</li> <li>平板</li> <li>手机</li> <li>手机</li> <li>手机</li> </ul>
可以看到它们仍在一行,不过宽度确实变窄了, 这就是 flex-wrap 的默认值no-wrap在起作用,nowrap 表示不换行,这么多项目始终在一行排列,这就导致了所有的项目都要进行缩小处理。这时给ul 添加 flex-wrap: nowrap,可以看到没有什么变化,默认值本来就是这样。
现在把nowrap 换成wrap, 同时把flex容器 ul的高度调高,其它属性设置默认样式,就是不设置其他属性
ul { width: 600px; height: 700px; border: 1px solid red; display: flex; flex-wrap: wrap; }
可以看到如下效果,wrap 表示可以换行,那么一行放不下的元素,就会放到下一行,形成了多行。
wrap-reverse , 可能你已经猜到了,它也是表示可以换行,不过方向和wrap相反而已。在wrap 中的第一行在顶部,到了wrap-reverse下就到了底部,相当于围绕横轴旋转180度,可以自己试一下。
当有多行显示的时候,我们发现一行和一行的之间的距离太大了,有没有办法调节一下行与行之间的距离? 这就要考虑align-content 的属性了。align-content: 就是控制当flex 项目进行多行显示时,且在侧轴上有剩余空间时,行与行之间怎么排列。它的取值有6个, flex-start, flex-end, center, stretch, space-between,space-around.
我们给ul设置align-content: stretch, 可以看到没有什么变化,这是它的默认属性。这个属性里有两个意思:
1. 如果flex项目有高度时,行与行之间的距离相等,均分了侧轴的剩余空间, 如上图所示,我们可以在ps中测量一下,第一行和第二行的距离 与第二行和第三行的距离相等
2. 如果flex项目没有高度或高度为auto时,项目进行拉伸,占满整个侧轴。去掉li的高度
flex-start, flex-end, center, space-around, space-between 和 justify-content 调整主轴之间的剩余空间表现一致,这里就不再展示了. 这里注意的时,align-content起作用的前提: 1, 在侧轴上必须在多行显示, flex-wrap: wrap , 如果只有一行是不起作用的, 2, 在侧轴上必须有剩余空间.
还有最后一个属性flex-flow 就完事了, flex-flow: 它是flex-direction 和flex-wrap 两个属性的简写,flex-flow: flex-direction 的取值 flex-wrap 的取值, 如: flex-flow: row wrap, 它和分开写没有什区别, 就是 border 属性一样, 可以分开写,也可以合在一起写, 这也就不介绍了,