css 布局
学习 css 的主要目的是为了记住各种属性么?NO,最重要的是理解 css 的定位机制与盒子模型。
接下来,从布局的角度来学习 css 的定位机制和盒子模型,学习之前还是先来提几个问题
- 1. 进行 css 布局前为什么要学习定位机制和盒子模型?
- 2. 在实际的工作中到会用到哪些 css 布局?
1.css 基础
1.1 盒子模型
css 是用来为页面元素添加样式的,在最开始的时候,开发网页是先将各个尺寸定下来,然后使用最传统的 position/float 把元素挪到对应的位置,页面上的元素就好像一个个盒子一样,很明显能够得出一个结论:盒子模型是布局的基础,所以在学习 css 布局前要先来学习盒子模型,盒子模型包括 content,padding,border,margin 四大部分,如下图:
盒子模型一般分为标准盒子模型和 IE 盒子模型,前者由 w3c 规定,后者由微软规定,这两种盒子模型可以通过 box-sizing 来进行切换,它们最大的区别就是 width 属性作用的范围,标准盒子的 width=content,IE 盒子的 width=content + padding + border,看下图:
除了标准盒子和 IE 盒子这种分类方法,一般还将盒子模型分成块级盒子模型和行内盒子模型,这个是根据不同的 display 属性值划分的, 下面是 display 的可能取值:
块级盒子模型的图在上面已经贴出了,下面是行内盒子模型的图:
1.1.1 盒子模型的 margin 负值
前面说了盒子模型包括什么内容,对于任意的盒子模型来说,它的四部分内容可以给它们设值也可以不设值,这四个值中 margin 部分有很多可以探讨的内容,比如它可以设置负值,这一部分之所以复杂,是因为它与 display 的不同值混合时会有很多不同的情况,比如 margin 设负值后可能会带来重叠,那具体重叠的情况是怎样的?说不同的重叠情况前,先来理解一下,margin 负值是什么意思?margin 的值其实是相对于基线来进行移动,对于 top,left 方向,它们是以其他元素的边框为基线,对于 right,bottom 方向它们是以自身 border 为基线,具体看下图:
接下来看看不同的 display 会对 margin 重叠造成什么影响
-
1. 表现(测试地址:https://demo.xiaohuochai.site…)
- 1.1 block 元素可以使用四个方向的 margin 值
- 1.2 inline 元素使用上下方向的 margin 值无效
- 1.3 inline-block 使用上下方向的 margin 负值看上去无效
-
2. 重叠(测试地址:https://demo.xiaohuochai.site…)
- 2.1 两个 block 元素重叠时,后面元素可以覆盖前面元素的背景,但无法覆盖其内容
- 2.2 当两个 inline 元素,或两个 line-block 元素,或 inline 与 inline-block 元素重叠时,后面元素可以覆盖前面元素的背景和内容
- 2.3 当 inline 元素 (或 inline-block 元素) 与 block 元素重叠时,inline 元素 (或 inline-block 元素) 覆盖 block 元素的背景,而内容的话,后面的元素覆盖前面的元素
-
3. 浮动(测试地址:https://demo.xiaohuochai.site…)
- 3.1 block 元素与浮动元素重叠时,其边框和背景在该浮动元素之下显示,而内容在浮动元素之上显示
- 3.2 inline 或 inline-block 元素与浮动元素重叠时,其边框、背景和内容都在该浮动元素之上显示
-
4. 定位(测试地址:https://demo.xiaohuochai.site…)
- 4.1 定位元素 (position 不为 static) 覆盖其他元素的背景和内容
- 4.2 将 relative 属性值应用于 inline 元素,由于无法改变其行内元素的本质,所以其上下 margin 依然存在问题
1.1.2 盒子模型的边距合并
margin 合并(collapse)是指块级元素的上外边距与下外边距有时会合并为单个外边距, 这种现象只发生在和当前文档流方向的相垂直的方向上,它分为同级元素和父子元素两种,首先是同级元素,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.center{
width: 500px;
background: pink;
margin: 80px auto;
padding: 10px;
}
</style>
</head>
<body>
<div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>
<div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>
</body>
</html>
接着是父子元素,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.center{
width: 500px;
background: pink;
margin: 80px auto;
}
.inCenter{
background: blue;
margin: 40px 0;
padding: 10px;
}
</style>
</head>
<body>
<div class="center">
<div class="inCenter">hello</div>
</div>
</body>
</html>
1.1.3 盒子模型的 margin 居中
最后这个比较简单,是在布局中常用的一种水平居中的方法,当页面元素的宽度是确定的值的时候,设置 margin:0 auto;元素会进行居中,这是因为 auto 代表左右自适应,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.center{
width: 500px;
background: pink;
margin: 80px auto;
padding: 10px;
}
</style>
</head>
<body>
<div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>
</body>
</html>
1.1.4 BFC
前面出现的边距重叠我们只是列出了问题但是没有解决,这是因为要解决这样的问题,需要了解另外一个知识,这个知识涉及到了定位机制的内容 BFC,写在这里,就作为一个承前启后的部分,那 BFC 到底是什么?
BFC(Block formatting context)直译为 ” 块级格式化上下文 ”。它是一个独立的渲染区域,只有 Block-level box 参与,它规定了内部的 Block-level Box 如何布局,并且与这个区域外部毫不相干。
简单来说,BFC 就是页面上单独开的一块渲染区域,有的人把它叫做 css 世界的结界,非常的形象,那它是如何被触发的?又为什么能解决边距重叠?
首先是触发规则:
- 根元素
- float 属性不为 none
- position 为 absolute 或 fixed
- display 为 inline-block, table-cell, table-caption, flex, inline-flex
- 不为 visible
接着是渲染规则:
- 内部的 Box 会在垂直方向,一个接一个地放置。
- Box 垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
- 每个元素的 margin box 的左边,与包含块 border box 的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- 的区域不会与 float box 重叠。
- BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算 BFC 的高度时,浮动元素也参与计算
最后看它怎样解决边距重叠, 同样的代码,只需要添加一句 overflow:hidden 触发 BFC,之所以能解决重叠是因为触发了新的 bfc 后与外部环境就隔开了,彼此不会影响。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.center1{
width: 500px;
background: pink;
margin: 80px auto;
padding: 10px;
}
.wrapper{overflow: hidden;}
.center2{
width: 500px;
background: pink;
margin: 80px auto;
padding: 10px;
}
</style>
</head>
<body>
<div class="center1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>
<div class="wrapper">
<div class="center2">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.center{
width: 500px;
background: pink;
margin: 80px auto;
overflow:hidden;
}
.inCenter{
background: blue;
margin: 40px 0;
padding: 10px;
}
</style>
</head>
<body>
<div class="center">
<div class="inCenter">hello</div>
</div>
</body>
</html>
1.2 定位机制
1.2.1 position 定位
上面说了盒子模型,知道了 css 操纵的内容具体是什么样的,接下来就需要把这些盒子放在页面上,在 css 的定位机制中,position:absolute、relative、static、fixed 有这几个取值,先来看看这些取值的不同
position:absolute 是将元素以浏览器视口为原点或者以最近的定位元素为原点来进行定位,具体看下面的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.wrapper{
width:500px;
height:500px;
background: pink;
margin:200px 500px;
}
.absolute{
width: 100px;
height:100px;
position:absolute;
top:50px;
left:50px;
background: green;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="absolute">absolute</div>
</div>
</body>
</html>
接着是 position:relative,他是相对于自身的位置进行偏移,具体看下面的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.wrapper{
width:500px;
height:500px;
background: pink;
margin:200px 500px;
}
.relative{
width: 100px;
height:100px;
position:relative;
top:50px;
left:50px;
background: green;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="relative">relative</div>
</div>
</body>
</html>
1.2.2 float 定位
上面的是 position 定位流,除了 position 定位流,css 还有 float 定位流,原本 css 发明这个属性并不是用来定位的,但是它确实在定位时很方便,css 的 float 定位会发生高度坍塌,也就是当设置了 float 时,会使得原本的元素脱离原来的 div,使用上面说的 BFC 就可以解决这个问题,设置 clear 也可以解决,具体看下面的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.wrapper{
background: pink;
margin:200px 500px;
border:1px solid #000;
/*overflow:hidden;*/
}
.clear{clear:both;}
.float{
width: 100px;
height:100px;
float:left;
background: green;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="float">relative</div>
//<div class="clear"></div>
</div>
</body>
</html>
2.css 布局实战
2.2.1 传统布局
经过上面的基础知识,对于 css 的盒子模型和定位机制有了比较好的理解,接下来,就可以来检验一下,完成这几种布局需求:
- 2 栏布局
- 圣杯布局
- 高度自适应布局
- 水平垂直居中布局
1.2 栏布局:一遍定宽一遍自适应 / 一栏不定宽,一栏自适应 /
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
body,div{padding: 0 ;margin-bottom: ;:20px;}
.left,.right{height: 200px;}
.left{float: left;width: 200px;background-color:skyblue;}
.right{margin-left: 200px; background-color: greenyellow;}
</style>
</head>
<body>
<div class="left">left 固定 200px</div>
<div class="right">right 自适应 </div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
body,div{padding: 0 ;margin:0;}
.left,.right{height: 200px;padding: 10px;}
.left{float: left;background-color:skyblue;}
.right{overflow:hidden;background-color: yellow;}
</style>
</head>
<body>
<div class="left">left 不固定 </div>
<div class="right">right 自适应 </div>
</body>
</html>
2. 圣杯布局:上中(左中右)下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.top{
width: 100%;
height: 40px;
background-color: #cccccc;
}
.footer{
width: 100%;
height: 50px;
background-color: #abdc44;
}
/* 左右固定,中间自适应 */
/*Start*/
.container{
width: 100%;
height: 100%;
position: relative;
}
.left{
position: absolute;
left: 0;
top: 0;
width: 400px;
height: 600px;
background-color: black;
}
.center{
width: auto; /* 如果没有这一句,那么,center 这个 div 的文字就不会自动换行 */
margin: 0 400px;
height: 600px;
background-color: yellow;
}
.right{
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 600px;
background-color: red;
}
/*End*/
</style>
</head>
<body>
<div class="top">this is top</div>
<div class="container">
<div class="left">this is left</div>
<div class="center">this is center</div>
<div class="right">this is right</div>
</div>
<div class="footer">this is footer</div>
</body>
</html>
3. 高度自适应布局:高度自适应
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
.container {
width: 1200px;
background: pink;
overflow: hidden;
}
div.item {
float:left;
width:300px;
padding-bottom: 5000000px;
margin-bottom: -500000px;
background: blue;
border:1px solid #000;
}
</style>
</head>
<body>
<div class="container">
<div class="item">aaa</div>
<div class="item">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia excepturi porro debitis quisquam corporis illum dolorum doloribus, similique esse veritatis harum hic, voluptatem veniam necessitatibus neque, animi, alias incidunt quasi!</div>
<div class="item">sss</div>
</div>
</body>
</html>
5. 水平垂直居中定位:已知宽高 / 未知宽高
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
#father {
width: 500px;
height: 300px;
background-color: skyblue;
position: relative;
}
#son {
width: 100px;
height: 100px;
background-color: green;
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -50px;
}
</style>
</head>
<body>
<div id="father">
<div id="son"> 我是块级元素 </div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
<style>
#father {
width: 500px;
height: 300px;
background-color: skyblue;
position: relative;
}
#son {
background-color: green;
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
}
</style>
</head>
<body>
<div id="father">
<div id="son"> 我是块级元素 </div>
</div>
</body>
</html>
2.2.2 flex 布局
不知道大家实现刚才的一系列的布局是什么感受,我的感受是累,那有没有一种好用的布局方式,不用去使用各种属性来自我创造直接就能来用呢?flex 布局
Flex 的基本概念就是容器和轴,容器包括外层的父容器和内层的子容器, 父容器设为 flex 后,它的所有子元素自动成为容器成员
父容器属性:flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
子容器属性:order
flex-grow
flex-shrink
flex-basis
flex
align-self
是的,它就是这么简单,接下来把上面的布局实现一下,看它到底多方便
- 2 列布局
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>css3 转换 </title>
<style>
.grid {
display: flex;
margin: 20px;
}
.grid-cell0 {
border-radius:20px;
width: 200px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
.grid-cell1 {
flex:1;
border-radius:20px;
width: 200px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
.grid-cell2 {
border-radius:20px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
.grid-cell3 {
flex:1;
border-radius:20px;
width: 200px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
</style>
</head>
<body>
<div class="grid">
<div class="grid-cell0"> 固定 </div>
<div class="grid-cell1"> 自适应 </div>
</div>
<div class="grid">
<div class="grid-cell2"> 不固定 </div>
<div class="grid-cell3"> 自适应 </div>
</div>
</body>
</html>
- 圣杯布局
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>css3 转换 </title>
<style>
* {
margin: 0;
padding: 0;
text-align: center;
}
.holy-grid {
display: flex;
flex-direction: column;
min-height: 100vh; /* 相对于视口的高度。视口被均分为 100 单位的 vh */
}
header, footer {
text-align: center;
flex: 0 0 100px;
height:100px;
background: #aaa;
}
.holy-grid-content {
display: flex;
flex: 1;
}
.holy-grid-content-items {flex: 1;}
.holy-grid-content-left {
flex: 0 0 150px;
background:blue;
text-align: center;
}
.holy-grid-content-right {
flex: 0 0 150px;
background:pink;
text-align: center;
}
</style>
</head>
<body class="holy-grid">
<header class="holy-grid-items">#header</header>
<div class="holy-grid-content holy-grid-items">
<div class="holy-grid-content-items holy-grid-content-left">
# left
</div>
<div class="holy-grid-content-items holy-grid-content-center">
# center
</div>
<div class="holy-grid-content-items holy-grid-content-right">
# right
</div>
</div>
<footer class="holy-grid-items">#footer</footer>
</body>
</html>
- 高度自适应布局
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>flex 嵌套 之 高度自适应 </title>
<style media="screen">
body, html {height: 90%;}
.flex {
display: -webkit-flex;
display: flex;
flex-direction: column;
}
.item {flex: auto;}
.overflow {overflow: auto;}
.outer {
height: 70%;
border: 1px solid silver;
}
.contener {
background: pink;
border: 1px solid silver;
}
.contener>div{padding: 5px;}
</style>
</head>
<body>
<h1>flex 嵌套布局 </h1>
<div class="flex outer">
<div style="background-color: silver; padding: 10px;"> 外容器 自适应内容的区域 ... ...</div>
<div class="flex item overflow" style="padding: 15px;"> <!-- 嵌套的 item 加 flex 样式 及 overflow: auto 属性 -->
<div class="flex contener overflow"> <!-- overflow: auto 高度自适应必须 -->
<div style="background-color: yellow;">
<h3> 内容器 - 头部信息 </h3>
</div>
<div class="item overflow"> <!-- overflow: auto 高度自适应必须 -->
内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br>
内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br>
内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br> 内容溢出滚动部分 <br>
</div>
<div style="background-color: yellow;">
<h3> 内容器 - 尾部信息 </h3>
</div>
</div>
</div>
</div>
</body>
</html>
- 水平垂直居中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>css3 转换 </title>
<style>
#father {
width: 500px;
height: 300px;
background-color: skyblue;
display: flex;
justify-content: center;
align-items: center;
}
#son {background-color: green;}
</style>
</head>
<body>
<div id="father">
<div id="son"> 我是块级元素 </div>
</div>
</body>
</html>
除了上面的这些布局,他还能实现均匀布局,非均匀布局
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>css3 转换 </title>
<style>
.grid {
display: flex;
margin: 20px;
}
.grid-cell {
flex: 1;
border-radius:20px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
</style>
</head>
<body>
<div class="grid">
<div class="grid-cell">cell1</div>
<div class="grid-cell">cell2</div>
<div class="grid-cell">cell3</div>
</div>
<div class="grid">
<div class="grid-cell">cell1</div>
<div class="grid-cell">cell2</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>css3 转换 </title>
<style>
.grid {display: flex;}
.grid-cell,.cell-full,.cell-1of2,.cell-1of3 {
border-radius:20px;
height:180px;
background:#eee;
margin:10px;
text-align:center;
}
.grid-cell {flex: 1;}
.cell-full {flex: 0 0 100%;}
.cell-1of2 {flex: 0 0 50%;}
.cell-1of3 {flex: 0 0 33.3333%;}
.cell-1of4 {flex: 0 0 25%;}
</style>
</head>
<body>
<div class="grid">
<div class="grid-cell cell-1of2">flex</div>
<div class="grid-cell">flexxxxxx</div>
<div class="grid-cell">sdfsdf</div>
</div>
<div class="grid">
<div class="grid-cell cell-1of3">flex</div>
<div class="grid-cell">flexxxxxx</div>
<div class="grid-cell">sdfsdf</div>
</div>
<div class="grid">
<div class="grid-cell cell-1of4">flex</div>
<div class="grid-cell">flexxxxxx</div>
<div class="grid-cell">sdfsdf</div>
</div>
</body>
</html>
经过这个过程,终于找到了一种适合的布局方法,这种方法适用于 pc 端和移动端,在移动端布局的时候,会经常听到 rem 布局,这是什么意思?要说明这个,还需要先来说说 css 中的单位,css 常见的单位如下:
然后再来说说浏览器适配问题,通过百度流量统计研究院的数据可知,现在浏览器主流尺寸是:
- PC 端(1920*1080)
- 移动端(640*360)
在开发网页时,针对 PC 端和移动端适配有 2 种方案
- ①写两套代码,用 JS 判断设备后使用对应代码
- ②写一套代码,用媒体查询判断后修改样式,一般以 1200 为界限。`
针对这些情况,常见的移动端布局有 rem 布局
最后就来演示一下 rem
function intiSize(){// 获取当前浏览器窗口宽度(这里的实质就是 body 宽度)
var win_w=document.body.offsetWidth;
// 定义变量 var fontSize;
if(win_w>640){fontSize=24;}
else{// 如果浏览器窗口宽度 (这里的实质就是 body 宽度) 值小于 320,取 320
win_w=Math.max(320,win_w); fontSize=win_w/320*12 }
// 设置根元素的大小 document.getElementsByTagName('html')[0].style.fontSize=fontSize+'px';}
// 浏览器窗口宽度发生变化时条用这个函数,方便与改变窗口大小时候调试
onresize=intiSize;intiSize();
在上面动态的获取了设备宽度,然后根据设计尺寸和设备尺寸的比例来设置了 fontsize,这个意思就是 1rem = win_w/320*12px,这样在写页面的时候只要写 rem 这个单位,自适应问题就迎刃而解了,这就是 rem,一个相对尺寸
ok,css 布局完毕
本篇资料来源贴在下面,大家去看看:
行内盒子模型:https://biaoyansu.com/9.15
浅谈 margin 负值: https://zhuanlan.zhihu.com/p/…
css 单位:http://www.w3school.com.cn/cs…