前言
此文章是 解剖CSS布局原理 的续集,之前那篇文章讲的都是理论,本文章讲具体的实例,根据自己对布局的理解与开发经验分为以下几类。
因为PC端和移动端布局差异较大,所以我将两端布局分开讲,本文章将针对PC端的布局进行讲解,以下代码只写关键代码。如果你发现你写了关键打代码还达不到效果,请检查是否写了不该写的样式。
为了提高网页性能,考虑到repaint/reflow,表格元素尽量少用,有其他选择的情况尽量用其他布局。
居中布局
一、单个元素水平居中
<div id="container">
<div class="box"></div>
</div>
1. 宽度固定
方法一:
.box {
width: 300px;
margin: 0 auto;
}
比较常用的方法
方法二:
#container {
position: relative;
}
.box {
width: 100px;
position: absolute;
left: 0;
right: 0;
margin: 0 auto;
}
此方法适用于定位时的居中方式
2. 宽度不固定
方法一:
.box {
display: table;
margin: 0 auto;
}
缺点:设置为表格元素,内部元素的布局有可能收到影响
方法二:
#container {
position: relative;
}
.box {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
缺点:要用到 transform
,兼容性较差
方法三:
#container {
display: table-cell; // 这属性在这可加可不加
text-align: center;
}
.box {
display: inline-block;
}
缺点:需要涉及到父类的样式
二、单个元素垂直居中
<div id="container">
<div class="box"></div>
</div>
高度固定
方法一:
#container {
position: relative;
}
.box {
height: 50px;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
}
缺点:要用到定位,脱离文档流
方法二:
#container {
height: 400px;
line-height: 400px;
}
.box {
display: inline-block;
height: 50px;
vertical-align: middle;
}
注意,父容器设置了行高,子类要记得重置行高
高度不固定
方法一:
#container {
position: relative;
}
.box {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
缺点:要用到 transform
,兼容性较差
方法二:
#container {
display: table-cell;
verticle-align: middle;
}
缺点:由父类控制是否居中
三、多个元素水平居中
<div id="container">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
#container {
width: 200px;
height: 100px;
background: #ccc;
text-align: center;
}
span {
display: inline-block;
background: #9fc;
}
四、多个元素垂直居中
<div id="container">
<p>1</p>
<p>2</p>
<p>3</p>
</div>
#container {
height: 200px;
display: table-cell;
vertical-align: middle;
}
单行多列布局
一、等宽排列
<div id="container">
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
</div>
#container {
display: table;
table-layout: fixed;
}
.box {
display: table-cell;
}
二、两列布局
<div id="container">
<div class="left"></div>
<div class="right"></div>
</div>
1. 一列定宽,一列自适应,高度各自自适应
左列定宽:
.left {
float: left;
width: 100px;
}
.right {
margin-left: 100px;
}
右列定宽:
#container {
padding-right: 100px;
overflow: hidden;
}
.left {
float: left;
width: 100%;
}
.right {
position: relative;
float: left;
width: 100px;
right: -100px;
margin-left: -100px;
}
2. 一列定宽,一列自适应,高度相同取两者最大值
#container {
display: table;
table-layout: fixed;
}
.left,
.right {
display: table-cell;
}
.right {
width: 100px;
}
需要定宽的那列设置宽度
3、一列不定宽,一列自适应
右列自适应:
<div id="container">
<div class="left"></div>
<div class="right"></div>
</div>
.left {
float: left;
}
.right {
overflow: auto;
}
左列自适应:
<div id="container">
<div class="right"></div>
<div class="left"></div>
</div>
.left {
overflow: auto;
}
.right {
float: right;
}
三、三列布局
1、两侧定宽,中间自适应,高度各种自适应
方法一:
<div id="container">
<div class="left">定宽</div>
<div class="center">自适应</div>
<div class="right">定宽</div>
</div>
.left,
.right {
position: absolute;
top: 0;
}
.left {
left: 0;
width: 150px;
}
.center {
margin: 0 80px 0 150px;
}
.right {
right: 0;
width: 80px;
}
方法二:圣杯布局
<div id="container">
<div class="left">定宽</div>
<div class="center">自适应</div>
<div class="right">定宽</div>
</div>
#container {
padding: 0 8px 0 150;
}
.left,
.center,
.right {
position: relative;
float: left;
}
.left {
width: 150px;
left: -150px;
margin-right: -100%;
}
.center {
width: 100%;
height: 200px;
}
.right {
width: 80px;
right: -80px;
margin-left: -80px;
}
方法三:双飞翼布局
<div id="container">
<div class="wrap">
<div class="center">自适应</div>
</div>
<div class="left">定宽</div>
<div class="right">定宽</div>
</div>
.left,
.wrap,
.right {
float: left;
}
.left {
width: 150px;
margin-left: -100%;
}
.wrap {
width: 100%;
}
.center {
margin: 0 80px 0 150px;
}
.right {
width: 80px;
margin-left: -80px;
}
2、两列定宽,中间自适应,高度相同取两者最大值
<div id="container">
<div class="left">定宽</div>
<div class="center">自适应</div>
<div class="right">定宽</div>
</div>
#container {
width: 100%;
display: table;
}
.left,
.right,
.center {
display: table-cell;
}
.left {
width: 150px;
}
.right {
width: 80px;
}
多行多列布局
一、图文并茂
<div class="article">
<img src="../img/icon.png">随着HTML的成长,为了满足页面设计者的要求,HTML添加了很多显示功能。但是随着这些功能的增加,HTML变的越来越杂乱,而且HTML页面也越来越臃肿。于是CSS便诞生了。
</div>
img {
float: left;
}
二、均衡分布
1、相同间距
<ul class="list">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
方法一:用浮动
.list {
width: 500px;
height: 260px;
}
.list li {
float: left;
width: 100px;
height: 100px;
margin-left: 20px;
margin-top: 20px;
background: #c9f;
}
通过 margin
来达到等距效果,根据父容器宽高和子类宽高与个数,算出 margin-left
和 margin-top
的值
方法二:用内联块
.list {
width: 500px;
height: 260px;
font-size: 0;
}
.list li {
display: inline-block;
width: 100px;
height: 100px;
margin-left: 20px;
margin-top: 20px;
background: #c9f;
}
用内联块的话,如果子类有文本,要记得设置 font-size
2. 去除边界间距
在上一个例子下去除边界间距
.list {
width: 460px;
height: 220px;
}
.list li {
float: left;
width: 100px;
height: 100px;
margin-left: 20px;
margin-top: 20px;
background: #c9f;
}
.list li:nth-of-type(4n+1) { margin-left: 0 }
.list li:nth-of-type(-n+4) { margin-top: 0 }
若要兼容IE8,则在对应的标签上加类名,单独处理
三、瀑布流布局
如上图,所谓的瀑布流布局就是一系列盒子或图片的等宽不等高布局。
真正的瀑布流布局是这样:
- 给每张图片设置相同的宽度,第一行全部置顶,顺序排列
- 从第二行开始寻找最低高度的那一列作为下一张图片的排列位置,这时很显然第二列高度最低,就把第四张图片放在第二列下面
- 这时第一列和第三列高度相同,我们优先选择左边那列,把第五张图片放在第一列下面
- 这时第三列高度最低,第六张图片放在第三列下面,以此类推。
网上有人说用多列浮动布局、用CSS3布局、用flexbox,其实实现的都是假的瀑布流,都有可能出现三列的高度差异较大的情况,真正的瀑布流是三列高度相差不大的。以下的瀑布流的具体实现
html
<div class="list">
<img src="../img/1.jpg" class="img1">
<img src="../img/2.jpg" class="img2">
<img src="../img/3.jpg" class="img3">
<img src="../img/4.jpg" class="img4">
<img src="../img/5.jpg" class="img5">
<img src="../img/6.jpg" class="img6">
<img src="../img/7.jpg" class="img7">
<img src="../img/8.jpg" class="img8">
<img src="../img/9.jpg" class="img9">
</div>
css
.list {
position: relative;
width: 600px;
}
.list img {
position: absolute;
}
js
document.addEventListener(‘DOMContentLoaded‘, function () {
var listDOM = document.querySelector(‘.list‘);
var imgsDOM = listDOM.querySelectorAll(‘img‘);
waterfallFlowLayout(listDOM, imgsDOM, 3);
})
/**
* 瀑布流布局
*
* @param {DOM object} listDOM 存放图片列表的容器DOM
* @param {DOM object} imgsDOM 图片DOM
* @param {number} colsCount 列数
*/
function waterfallFlowLayout (listDOM, imgsDOM, colsCount) {
colsCount = colsCount || 3; // 默认3列
var currHeightArr = []; // 存放当前每列的总高度
var imgWidth = listDOM.offsetWidth / colsCount
// 遍历所有图片DOM元素
for (var i = 0; i < imgsDOM.length; i++) {
var imgDOM = imgsDOM[i];
imgDOM.style.width = imgWidth + ‘px‘; // 设置各个图片的宽度
// 如果是第一行的就直接存高度,并设置top和left
if (i < colsCount) {
currHeightArr.push(imgDOM.offsetHeight);
imgDOM.style.left = (i % colsCount) * imgWidth + ‘px‘;
imgDOM.style.top = 0;
}
// 否则
else {
var minNum = Math.min.apply(Math, currHeightArr); // 获取最小值
var index = currHeightArr.indexOf(minNum); // 获取最小值的下标
// 根据最小值下标得到对应的DOM,获取它的left赋给当前的left
imgDOM.style.left = imgsDOM[index].offsetLeft + ‘px‘;
imgDOM.style.top = minNum + ‘px‘; // 使用最小值作为当前的top
// 更新每列的总高度
currHeightArr[index] += imgDOM.offsetHeight;
}
}
}
全屏布局
<div class="head">头部</div>
<div class="sidebar">侧边导航</div>
<div class="main">主体内容</div>
<div class="foot">底部</div>
.head,
.foot,
.sidebar,
.main {
position: absolute;
}
.head {
top: 0;
left: 0;
right: 0;
height: 80px;
}
.foot {
bottom: 0;
left: 0;
right: 0;
height: 60px;
}
.sidebar {
top: 80px;
bottom: 60px;
left: 0;
width: 100px;
}
.main {
top: 80px;
bottom: 60px;
left: 100px;
right: 0;
}