table表格布局
早期以table为主,早期的表格解析并不是流式的,如果表格很长 浏览器会把整个表格的代码都下载完后再渲染解析,这样会造成用户等待的时间过长。
事实上现在的浏览器性能都很高了,也可以对表格布局进行流式的加载,这种问题不是很突出了,所以现在表格的布局也没有很明显的缺点,除了语义化不够明确。
表格有一些好的特性,表格本来就是方框的,它的横向和竖向的格子天生就有的,不需要我们去想办法并列起来,所以用起来非常方便。
html代码:
<table>
<tr>
<td class="left">左</td>
<td class="right">右</td>
</tr>
</table>
css代码:
table {
width: 800px;
height: 200px;
border-collapse: collapse;
}
.left {
background: red;
}
.right {
background: blue;
}
效果:
基于表格的样式,我们可以自己写一个长得像表格的元素。下面的代码全是用的div
,只是通过样式让它长得像表格。主要就是用display:table;
,display:table-row;
,display:table-cell;
。
html代码:
<div class="table">
<div class="table-row">
<div class="left table-cell">
左
</div>
<div class="right table-cell">
右
</div>
</div>
</div>
css代码:
.table {
margin-top: 20px;
display: table;
width: 800px;
height: 200px;
}
.table-row {
display: table-row;
}
.table-cell {
vertical-align: center;
display: table-cell;
}
效果:
和表格基本上是一样的,只是文字没有垂直居中,因为div
中的文字默认不是居中的,可以给div
设置vertical-align:middle;
让文字垂直居中。
盒子模型
在接着介绍其它布局之前先了解下 盒子模型。
最中间的content部分是盒子中真正显示内容的区域,为盒子设置宽高是为中间content区域设置宽高。盒子占用的空间并不是设置的宽高,因为外面还有其它内容,盒子占用的空间是content+padding+border这三个区域。padding是盒子的留白区域,是content内容区到border边框之间的留白。margin是盒子离其它元素的距离。
display / position属性
display 确定元素的显示类型。它有以下几种值:
- block,块级元素,有独立宽高,默认情况下独占一行。
- inline,内联元素,和文本一样,默认不会占据一行,设置宽高无效。
- inline-block,内联块级元素,可以设置宽高,可以和内联元素在一行显示。
既然inline-block可以想文本一样对齐,那可以设置多种对齐方式:
<body>
<div class="block">
block
</div>
<div class="inline">inline</div>
<div class="inline">inline</div>
<div class="inline-block">inline-block</div>
</body>
<style>
.block{
height:200px;
background:red;
}
.inline{
display: inline;
background: green;
}
.inline-block{
display: inline-block;
width:200px;
height:100px;
background:blue;
vertical-align: bottom;
}
</style>
效果:
position 确定元素的位置。它有以下几种值:
-
static,默认值,表示静态布局,就是按照文档流一个一个去布局的,
-
relative,相对位置,是相对元素自己本身进行的偏移,relative偏移时不会改变它占据的空间。
html代码:
<body> <div class="p1"> position:static </div> <div class="p2"> position:relative </div> <div class="p5"> p5 </div> </body>
css代码:
<style> div{ background:red; width:100px; height:100px; } .p2{ position: relative; left:10px; top:-10px; background:blue; } </style>
效果:
这里蓝色区块relative偏移时不会改变它占据的空间,所以p5占据的空间仍然是按照原来的位置计算的,并没有紧挨着蓝色区块的下边,不会因为relative偏移而改变布局的计算。
-
absolute,绝对位置,会从文档流中脱离,相当于独立的存在,不会影响到其它元素的布局。它是相对最近的relative或者absolute父元素定位的,它会一级一级往上找最近的relative或者absolute父元素。
html代码:
<body> <div class="p1"> position:static </div> <div class="p2"> position:relative </div> <div class="p3"> position:absolute <!-- <div class="p3-3" style="position:absolute;width:50px;height:50px;background:yellow"> </div> --> </div> <div class="p5"> p5 </div> </body>
css代码:
<style> div{ background:red; width:100px; height:100px; } .p2{ position: relative; left:10px; top:-10px; background:blue; } .p3 { position: absolute; left: 80px; top: 30px; background: green; } </style>
效果:
这里绿色区块absolute后并没有影响到其它元素的布局,
- fixed,固定位置,跟absolute一样也是脱离文档流的,不会对其它元素的布局产生干扰,它是相对于屏幕定位。
可以通过z-index
属性(就像Z轴一样)来控制元素的层级关系。
position:absolute / fixed的区别:
前者相对最近的absolute / relative;后者相对屏幕(viewport)。
float + margin浮动布局
技巧性的布局,并不是为布局而生,主要是为了图文混排。
顾名思义,就是让元素浮动起来。浮动元素会脱离文档流,也就是和 absolute 一样不会对其它元素的定位产生干扰,但是float元素不会脱离文本流。
看个栗子直观的感受下:
html代码:
<body>
<div class="container">
<span class="p1">
float
</span>
<div class="p2">
很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字
</div>
</div>
</body>
css代码:
<style>
.container{
background:red;
width:400px;
margin:20px;
}
.p1{
background:green;
float:left;
width:200px;
height:50px;
}
</style>
效果:
绿色块浮动之后会脱离文档流,不会对其它元素的布局造成影响,所以红色块占据了整个container。但是 float 影响了 p2块 中文字的展现,p2块中的文字绕开了float元素。事实上这是float本身的含义,float本来就是用来做图文混排的。
float元素对自身的影响:
- 形成 “块”(BFC),这个“块”会形成自己的布局方式,比如上面的例子中 .p2元素是一个span元素,span元素是内联元素设置宽高本来应该是无效的,但是这里却设置了宽高,这是因为span元素浮动产生了BFC块,如果把浮动去掉会发现span元素的宽高就会失效,说明正式float让span内联元素可以设置宽高。
- 位置会尽量靠上,
- 位置会尽量靠左(右)
这里是先会尽量靠上然后靠左(右),靠上太窄的话就会往下移。举例:
html代码:
<div class="container">
<span class="p1">
float
</span>
<div class="p2">
很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字很长的文字
</div>
</div>
<div class="container container2">
<span>写几个字</span>
<span class="p1">
float
</span>
<span class="p1">
float
</span>
</div>
css代码:
.container{
background:red;
width:400px;
margin:20px;
}
.p1{
background:green;
float:left;
width:200px;
height:50px;
}
改变span的宽度:宽度不够会往下掉
float元素对兄弟元素的影响:
- 上面一般贴非float元素
- 旁边贴float元素,也就是靠左或靠右贴float元素或者边边(上面的例子中,当container的宽足够放三个span元素时,float元素会贴在一起)
- 不影响其它块级元素的位置
- 影响其它块级元素的内部文本
float元素对父级元素的影响: - 会从父级布局中消失,浮动的元素不会占据父元素的布局空间,消失意味着父级看不见它也不会管它宽高,所以父级的高度会塌陷
如何防止父级元素高度塌陷?有几种方法: - float元素会让元素变成BFC,BFC元素会接管自己的宽高。这样可以让父元素也变成BFC接管自己的宽高,给父元素设置
overflow:auto;
或者overflow:hidden;
- 下面一段css是经典的清除浮动的方法,在父元素上加上
.learFloat
类:.clearFloat::after{ content: 'aaa'; /* 保障这个伪元素的两边都是干净的,没有浮动元素 */ clear:both; /* ::after伪元素默认是内联元素,这里改成block */ display: block; /* 到上面其实浮动就可以清除了,但我们加入了无关的东西,接着把高度设为0就不占高度了 */ height:0; /* 让伪元素不要显示内容,这样content中的文本就没有了 */ visibility: hidden; }
试一下左右布局:
html代码:
<body>
<div class="container">
<div class="left">
左
</div>
<div class="right">
右
</div>
</div>
</body>
css代码:
<style>
.container{
width:800px;
height:200px;
}
.left{
background:red;
float:left;
height:100%;
width:200px;
}
.right{
background:blue;
height:100%;
}
</style>
效果:这里需要注意,左边红色块浮动没问题,右边蓝色占一整行没问题,但是蓝色块里面的文本的位置很难控制,比如给蓝色块加padding-left:50px;
会不生效。
此时给右边蓝色块加上margin-left
把左边的空出来,这样蓝色块中的文本才会可控。
inline-block 布局
它的布局思路是 像文本一样排block元素,它没有高度塌陷和清除浮动等问题,但是它有个独特的问题就是 要处理间隙。
为什么会有间隙?可以把inline-block元素想象成一段文字,文字和文字之间是有间隙的。有几种解决办法:
- 把父元素的字体设置成
font-size:0
。 - 间隙其实是来自html中标签之间的空白:
去掉标签之间的空白也会清除间隙:
完整代码:
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<style>
.container{
width:800px;
height:200px;
font-size:0;
}
.left{
font-size:14px;
background:red;
display: inline-block;
width:200px;
height:200px;
}
.right{
font-size:14px;
background:blue;
display: inline-block;
width:600px;
height:200px;
}
</style>
</head>
<body>
<div class="container">
<div class="left">
左
</div>
<div class="right">
右
</div>
</div>
</body>
</html>
可以发现用inline-block进行布局是很方便的,但是使用inline-block进行布局想做自适应的东西相对来说比较麻烦。
flexbox布局
这是CSS规范第一次提供真正用于布局的方式,天生就是用来布局的,前面提到的float主要是用来进行图文混排的, inline-block也不是用来布局的。
它是一个弹性盒子,也就是每一个盒子是有弹性的可以伸缩的,而且盒子本来就是并列的,不需要我们另外处理,其实只要解决了并列问题,布局问题就基本解决了,同时它还提供了关于宽度方面的控制。
html代码:
<body>
<div class="container">
<div class="left">
左
</div>
<div class="right">
右
</div>
</div>
</body>
css代码:
<style>
.container{
width:800px;
height:200px;
display: flex;
}
.left{
background: red;
display: flex;
width:200px;
}
.right{
background: blue;
display: flex;
flex:1;
}
</style>
效果:
响应式设计和布局
通俗的讲就是让我们的页面可以在不同的设备上正常使用,一般主要处理屏幕大小问题,主要方法:
- 需要从设计源头就想办法进行适配,隐藏 + 折行 + 自适应空间。
- rem / viewport / media query
要适配移动端首先要做的就是在html头部加上<meta name="viewport" content="width=device-width, initial-scale=1.0">
,这里的width=device-width
是指可视区域的大小等于屏幕的大小。如果不加,在很多手机上尤其是iPhone会默认页面宽度是980px,屏幕宽度很小却要显示980个像素,在手机上的直观感觉就是页面被缩小了。如果使用width=device-width
,在iPhone5中相当于我的页面宽度变成320px,如果是iPhone6则是375px,让页面和屏幕的像素进行匹配。
举例:
<!DOCTYPE html>
<html lang="en">
<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>responsive</title>
<style>
.container{
margin:0 auto;
max-width:800px;
display: flex;
border:1px solid black;
}
.left{
display: flex;
width: 200px;
background:red;
margin:5px;
}
/* 当设备宽度小于等于640px时下面代码生效 */
@media (max-width: 640px){
.left{
display: none;
}
}
.right{
display: flex;
flex: 1;
background:blue;
margin:5px;
}
</style>
</head>
<body>
<div class="container">
<div class="left">
这里是一些不重要的内容,比如友情链接、广告
</div>
<div class="right">
这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。这里是一些重要的内容,比如一篇文章,文章是整个页面的核心内容。
</div>
</div>
</body>
</html>
效果:
设备宽度iPhone5是320px,iPhone6是375px。下面的代码在iPhone5和iPhone6中的显示不一样:
html代码:
<body>
<div class="container">
<div class="intro">
介绍1
</div>
<div class="intro">
介绍2
</div>
<div class="intro">
介绍3
</div>
<div class="intro">
介绍4
</div>
</div>
</body>
css代码:
<style>
.container {
margin: 0 auto;
max-width: 800px;
border: 1px solid black;
}
.intro {
display: inline-block;
width: 180px;
height: 180px;
line-height: 180px;
text-align: center;
border-radius: 90px;
border: 1px solid red;
margin: 7px;
}
/* 在移动端直接block并且居中显示 */
@media (max-width: 640px) {
.intro {
margin: .3rem auto;
display: block;
}
}
</style>
在不同尺寸屏幕上的效果:
在iPhone6中圆圈只占据了小部分空间,既然屏幕大小不一样,那文字和圆圈大小也要重新设置来适配不同屏幕的大小。
我们可以改变viewport的值,也就是改变页面宽度。上面我们设置的是width = device-width
,页面宽度等于设备宽度,iPhone5是320px,iPhone6是375px。如果统一成固定大小320px ,,会发现在iPhone6中圈圈部分会等比放大跟iPhone5一样。
以上是使用固定viewport的width值来处理适配。
也可以使用rem
的单位,上面的大小使用的是像素(px),像素大小是固定的。
通过媒体查询改变不同设备下html的font-size
:
<style>
html {
font-size: 20px;
}
.container {
margin: 0 auto;
max-width: 800px;
border: 1px solid black;
}
.intro {
display: inline-block;
width: 9rem;
height: 9rem;
line-height: 9rem;
text-align: center;
border-radius: 4.5rem;
border: 1px solid red;
margin: .3rem;
}
@media (max-width: 375px) {
html {
font-size: 24px;
}
}
@media (max-width: 320px) {
html {
font-size: 20px;
}
}
@media (max-width: 640px) {
.intro {
margin: .3rem auto;
display: block;
}
}
</style>
rem单位不一定非常精确,要预留余地,对精确性要求非常高的地方不要用rem。