此文章是 解剖CSS布局原理 的续集,以前那篇文章讲的都是理论,本文章讲具体的实例,根据本身对布局的理解与开发经验分为如下几类。css
由于PC端和移动端布局差别较大,因此我将两端布局分开讲,本文章将针对PC端的布局进行讲解,如下代码只写关键代码。若是你发现你写了关键打代码还达不到效果,请检查是否写了不应写的样式。html
为了提升网页性能,考虑到repaint/reflow,表格元素尽可能少用,有其余选择的状况尽可能用其余布局。segmentfault
<div id="container"> <div class="box"></div> </div>
方法一:app
.box { width: 300px; margin: 0 auto; }
比较经常使用的方法ide
方法二:布局
#container { position: relative; } .box { width: 100px; position: absolute; left: 0; right: 0; margin: 0 auto; }
此方法适用于定位时的居中方式性能
方法一:flex
.box { display: table; margin: 0 auto; }
缺点:设置为表格元素,内部元素的布局有可能收到影响flexbox
方法二:spa
#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>
左列定宽:
.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; }
#container { display: table; table-layout: fixed; } .left, .right { display: table-cell; } .right { width: 100px; }
须要定宽的那列设置宽度
右列自适应:
<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; }
方法一:
<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; }
<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; }
<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
在上一个例子下去除边界间距
.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; }