前言
CSS作为表现层的重要组成部分,它的布局具有举足轻重的地位,为了开发出一个合格的网站界面,几种常见布局也是必备知识, 其中的一些概念基于CSS基本概念与使用中所讲的,因此对基本概念有困惑建议阅读基础内容
布局原理
- 为了在实际的布局中理解其原理需要掌握以下知识点
CSS布局基本单位
元素类型与display
的值决定了box的类型。不同的box会参与不同的Formatting context
-
box类型
-
block-level box
display
属性为block
,list-item
,table
的元素, 会生成block-level box, 并且参与block formatting context -
inline-level box
display
属性为inline
,inline-block
,inline-table
的元素, 会生成inline-lebel box并且参与inline formatting context
-
Formatting context是页面中一块渲染区域, 并且有一套渲染规则, 决定子元素如何定位以及和其他元素的关系和相互作用
BFC只有block-level box参与, 规定了内部的block-level box如何布局, 并且与这个区域外部毫不相干
-
BFC布局规则
- 内部box会在垂直方向, 一个接一个放置
- BFC的区域不会与float box重叠
-
内部的box垂直方向距离由margin决定, 属于同一个BFC的两个相邻块级box的margin会发生重叠
- 两个方式来使其不重叠, 其一是使两个元素属于不同BFC, 其二是使两个元素不相邻
- 计算BFC高度时, 浮动元素也参与计算
- BFC就是页面上的一个隔离的独立容器, 容器里面的子元素不会影响到外面的元素, 反之也是如此
出现BFC的情况
- 根元素(html)
float
属性不为none
postion
为absolute
或fixed
overflow
不为visible
display
为inline-block
,table-cell
,flex
,inline-flex
haslayout
IE6,7特有的概念用以替代他们不具有的BFC特性
如果一个元素没有布局, 则它的尺寸和位置由最近拥有布局的祖先元素控制
IE团队是为了减少性能开销才将元素变成拥有布局和没有布局这两种情况
-
默认拥有布局的元素
html, body, table, tr, td, img, hr, input, select, textarea, button, iframe, embed, object, applet, marquee
-
触发haslayout的办法
-
IE6或IE7支持
float
为left
或right
display
为inline-block
position
为absolute
width
为除auto
外的值height
为除auto
外的值zoom
为除normal
外的值writing-mode
为tb-rl
-
IE7支持
min-height
:任意值min-width
:任意值max-height
: 除none
外max-width
: 除none
外overflow
,overflow-x
,overflow-y
: 除visible
外任意值, 仅用于块元素position: fixed
-
垂直水平居中
-
已知高宽的水平居中
- 将需要定位的元素设置为绝对定位
-
使用绝对定位的元素自身规则使其垂直水平居中
-
对于所有绝对定位元素它的几项属性一定满足以下两条要求:
水平方向上:
left
+right
+margin
+padding
+width
= 包含块的宽度垂直方向上:
top
+bottom
+margin
+padding
+height
= 包含块的高度
因此可以将
left
,top
,bottom
,right
设置为0再设置固定高宽(padding默认值为0), 此时包含块剩余高宽会自动设置给margin为了让margin自动接收到正确的值需要将
margin
设置为auto
, 最终便实现了垂直水平居中由于高宽默认值为
auto
, 因此未设置其高宽时默认会将绝对定位元素的高宽撑满父元素 -
-
未知高宽的水平居中
- 设置绝对定位,
left
和top
设置为50%
- 使用
transform: translate3D(-50%, -50%, 0)
兼容性较差, IE10及以上
- 设置绝对定位,
line-height
行高定义为两行字的基线间距离, 常用于单行文本垂直居中
内容区:顶线到底线间的距离
行内框:内容区加上 (行高-字体大小)/2
的值
行框:一行中最大的行内框的值
如果要处理大量文本, 建议把行高设置比字体大, 因为当行高比内容区小时, 上下缺少的高度渲染会根据不同浏览器进行变化
格式化css时一般会统一设置line-height
为1, 即font-size
的一倍, 纯数字为行高因子
行高因子继承时, 是行高因子, 其他的百分比, 像素等是继承计算值
垂直居中
-
vertical-align
用来指定
inline-block
的垂直当给图片垂直居中时可以通过伪元素after设置一个内联块状元素来使与图片同一行的行内框撑满父元素
再给图片设置
vertical-align: middle
就能使图片垂直居中
浮动
在浮动float中已经详细介绍了浮动的概念,在此处做一些应用浮动来布局的补充
开启浮动时元素层数可以理解为一个元素占两层, 第一层为盒模型, 第二层为文字, 且只有盒模型提升了半层, 此理论只在浮动有效, 当使用其他语句改变元素层级时仍然看成只有一层
清除浮动
-
给父元素设置高度, 扩展性差
给父元素设置成BFC, 在IE6,7中用开启haslayout解决
- 给父元素设置
overflow:hidden
, 移动端常用 - 给父元素设置定位
-
给父元素设置浮动
定位盒子或者浮动盒子的宽高会默认由内容撑开而其余的宽高默认为包含块的100%
- 空div标签清除浮动, 在IE6中可能会造成最小高度问题且违反结构行为样式分离原则
- 当给
div
设置高度时, 在IE6中最小只能设置成font-size
的最小值12px
, 但是即使将font-size
设置成0
时也依然会有2px
的高度, 继续设置overflow: hidden
才能解决
- 当给
br
标签用html属性clear来清除浮动,在IE6中无效且违反结构行为样式分离原则- 伪元素清除浮动, 在IE6,7中不支持, 但使用
zoom
可解决, PC端常用
包含块
一个元素的尺寸和位置经常受其包含块的影响。大多数情况下,包含块就是这个元素最近的祖先块元素的内容区,但也不是总是这样
在大多数浏览器, 初始包含块是一个视窗大小的矩形
- 对于浮动元素, 包含块是最近的块级祖先元素的内容边界构成
- 对于非根元素,
position
是relative
或static
, 包含块由最近的块级框的内容边界构成 -
对于非根元素,
position
是absolute
, 包含块为最近的position
不是static
的祖先元素如果祖先元素为块级元素, 包含块则为该元素的内边距边界
如果没有祖先, 元素包含块为初始包含块
left
,top
,bottom
,right
,width
,height
默认值为auto
, 不可继承
margin
, padding
默认值为0
, 不可继承
border-width
默认值为medium
width
, left
, padding
, margin
的百分比是包含块的width
的
height
, top
的百分比是包含块的height
的
html与body的高度问题
- 需要视图,
html
,body
高度三合一时后两者都必须设置height:100%
, 没有设置html
高度时,body
高度都由内容撑开 html
或者body
其中之一使用overflow:scroll
时, 都是让document
出现滚动条html
和body
都设置时,html
的scroll
设置给document
,body
的才设置给body
-
常被用来禁用系统默认滚动条, 代码为:
html, body{ height: 100%; overflow: hidden; }
- 当使用此代码后再使
body
具有overflow:scroll
使body
滚动条模拟视图滚动条时, 可以使用绝对定位模拟固定定位, 常用于移动端或解决IE6没有fixed的问题
兼容性简述
-
可以发现在CSS的知识点中反复提及了兼容的方案,而浏览器兼容问题是css中比较庞大的知识,随着时代进步老旧浏览器市场份额的下降一些兼容代码也可以抛弃了,但是一些基本的兼容思想仍然需要具有
-
检测低版本IE
兼容中最头疼在于兼容IE, css中可以直接使用hack来做到,但是在某些情况下需要使用js控制表现时要关注兼容性问题
js中结合b标签的
innerHTML
与条件hack, 最后判断innerHTML
内的标签是否存在来决定版本function isIE(version){ var b = document.createElement("b"); b.innerHTML = "<!--[if IE "+version+"]><i></i><![endif]-->" return b.getElementByTagname("i").length == 1; }
可以使用caniuse.com网站来检查api兼容性
常见布局
-
实现可用的三列布局具有以下要求
- 两边固定, 当中自适应
- 中间要完全显示
- 当中列要优先加载
- 绝对定位来三列布局
- 中间不能设置最小宽度, 不推荐
- 浮动来三列布局
- 中间页面会最后加载
- 圣杯布局
- 使用浮动搭建基本布局
- 调整左右的
margin-left
使其处于同一行 - 类
center
使用padding
向内预留两栏的位置模仿圣杯的形状, 同时设置box-sizing
为border-box
使其总宽度不变 - 代码实现
<!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> *{ margin: 0; padding: 0; } .clearfix:after{ content: ""; display: block; clear: both; } .content{ min-width: 600px; background-color: #ccc; } .center{ width: 100%; height: 800px; background-color: #aaa; float: left; padding: 0 200px; box-sizing: border-box; } .left{ width: 200px; height: 800px; margin-left: -100%; background-color: #acf; float: left; } .right{ width: 200px; height: 800px; margin-left: -200px; background-color: #acf; float: left; } </style> </head> <body> <div class="content clearfix"> <div class="center"> </div> <div class="left"></div> <div class="right"></div> </div> </body> </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>sameheight</title>
<style>
*{
margin: 0;
padding: 0;
}
.content{
width: 900px;
border: 1px solid #acf;
overflow: hidden;
}
.clearfix:after{
content: "";
display: block;
clear: both;
}
.left,.right{
float: left;
width: 400px;
background-color: #ccc;
padding-bottom: 1000px;
margin-bottom: -1000px;
border: 1px dashed #aaa;
}
</style>
</head>
<body>
<div class="content clearfix">
<div class="left">
a <br>
a <br>
a <br>
a <br>
a <br>
a <br>
a <br>
a <br>
a <br>
</div>
<div class="right">
a <br>
a <br>
a <br>
a <br>
a <br>
</div>
</div>
</body>
</html>
双飞翼布局
- 与圣杯布局基本类似, 但是此处使用
margin
来模仿飞翼达到圣杯布局中填充的效果 - 类
center
内中用一个块元素来充当真正存放内容的元素, 并给其与左右两栏相同宽度的margin
代码实现
<!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>
*{
margin: 0;
padding: 0;
}
.clearfix:after{
content: "";
display: block;
clear: both;
}
.content{
min-width: 600px;
background-color: #ccc;
}
.center{
width: 100%;
height: 800px;
background-color: #aaa;
float: left;
}
.inner-center{
margin: 0 200px;
}
.left{
width: 200px;
height: 800px;
margin-left: -100%;
background-color: #acf;
float: left;
}
.right{
width: 200px;
height: 800px;
margin-left: -200px;
background-color: #acf;
float: left;
}
</style>
</head>
<body>
<div class="content clearfix">
<div class="center">
<div class="inner-center"></div>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
粘连布局
- 有一块内容
<main>
- 当
<main>
的高度足够长时,<footer>
跟在<main>
的后面 - 当
<main>
元素比较短的时候, 我们希望<footer>
能够“粘连”在底部 1.给wrap设置最小高度 2.给main设置相等于footer高度的下内边距, 为了不让footer遮挡住main里的文字,因为main高度是百分比所以视图中没有给footer占位的地方 3.给footer设置相等于自身高度的上外边距, 值为负
<!--html布局-->
<div class="wrap">
<div class="main"></div>
</div>
<div class="footer"></div>
代码实现
<!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>粘连布局</title>
<style>
*{
padding: 0;
margin: 0;
}
html,body{
height: 100%;
}
.content{
min-height: 100%;
background-color: #ccc;
padding-bottom: 200px;
box-sizing: border-box;
}
.footer{
height: 200px;
background-color: #acf;
margin-top: -200px;
}
</style>
</head>
<body>
<div class="content">
<div class="main">
a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>>a<br/>a<br/>a<br/>a<br/>>a<br/>a<br/>a<br/>a<br/>>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>
</div>
</div>
<div class="footer"></div>
</body>
</html>
其他常用的知识
- 有很多时候需要将一段文字超出块元素的部分以省略号代替
实现代码
.text-overflow{
white-spacing: nowrap; /*强制不换行*/
text-overflow: ellipsis; /*决定如何对溢出文本应用样式*/
overflow: hidden;
display: block; /*保持元素长宽固定,
如display为inline-block宽度会被内容撑开,
使多余部分不会出现省略号*/
}