题目要求:针对如下DOM结构,编写CSS,实现三栏水平布局,其中left、right分别位于左右两侧,left宽度为200px,right宽度为300px,main处在中间,宽度自适应。
要求:允许增加额外的DOM节点,但不能修改现有节点顺序。
main
left
right
圣杯布局与双飞翼布局针对的都是三列左右栏固定中间栏边框自适应的网页布局(想象一下圣杯是主体是加上两个耳朵;鸟儿是身体加上一对翅膀),圣杯布局是Kevin Cornell在2006年提出的一个布局模型概念,在国内最早是由淘宝UED的工程师(传说是玉伯)改进并传播开来,在中国也有叫法是双飞翼布局,它的布局要求有几点:
三列布局,中间宽度自适应,两边定宽;
中间栏要在浏览器中优先展示渲染;
允许任意列的高度最高;
可以看出我们题目的要求跟圣杯布局和双飞翼布局要求一样。
下面我们看看具体的实现方法。
1.设置基本样式
/*3.圣杯布局法*/
.left, .main, .right {
min-height: 130px;
}
.left {
background: green;
width: 200px;
}
.main {
background-color: blue;
}
.right {
background-color: red;
width: 300px;
}
为了高度保持一致给left main right都加上min-height:130px。
2.圣杯布局是一种相对布局,首先设置父元素container的位置:
.container {
padding: 0 300px 0 200px;
}
实现效果是左右分别空出200px和300px区域,效果如图:
3.将主体部分的三个子元素都设置左浮动
.left, .main, .right {
min-height: 130px;
float: left;
}
出现了如下情况,怎么办,别着急慢慢来:
4.设置main宽度为width:100%,让其单独占满一行
.main {
background-color: blue;
width: 100%;
}
5.设置left和right 负的外边距
我们的目标是让left、main、right依次并排,但是上图中left和right都是位于下一行,这里的技巧就是使用负的margin-left:
.left {
margin-left: -100%;
background-color: green;
width: 200px;
}
.right {
margin-left: -300px;
background-color: red;
width: 300px;
}
负的margin-left会让元素沿文档流向左移动,如果负的数值比较大就会一直移动到上一行。关于负的margin的应用也是博大精深,这里肯定是不能详细介绍了。
设置left部分的margin-left为-100%,就会使left向左移动一整个行的宽度,由于left左边是父元素的边框,所以left继续跳到上一行左移,一直移动到上一行的开头,并覆盖了main部分(仔细观察下图,你会发现main里面的字“main”不见了,因为被left遮住了),left上移过后,right就会处于上一行的开头位置,这时再设置right部分margin-left为负的宽度,right就会左移到上一行的末尾。
6.接下来只要把left和right分别移动到这两个留白就可以了。可以使用相对定位移动 left和right部分。
.left, .main, .right {
position: relative;
min-height: 130px;
float: left;
}
.left {
left: -200px;
margin-left: -100%;
background: green;
width: 200px;
}
.right {
right: -300px;
margin-left: -300px;
background-color: red;
width: 300px;
}
至此,我们完成了三列中间自适应的布局,也就是传说中的圣杯布局。完整的代码如下:
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之圣杯布局title>
<style type="text/css">
.container {
padding: 0 300px 0 200px;
}
.left, .main, .right {
position: relative;
min-height: 130px;
float: left;
}
.left {
left: -200px;
margin-left: -100%;
background: green;
width: 200px;
}
.right {
right: -300px;
margin-left: -300px;
background-color: red;
width: 300px;
}
.main {
background-color: blue;
width: 100%;
}
style>
head>
<body>
<div class="container">
<div class="main">maindiv>
<div class="left">leftdiv>
<div class="right">rightdiv>
div>
body>
html>
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。不同在于解决 “中间栏div内容不被遮挡”问题的思路不一样。
他的HTML结构发生了变化:
<div class="container">
<div class="main">
<div class="content">maindiv>
div>
<div class="left">leftdiv>
<div class="right">rightdiv>
div>
直接贴出代码,读者可以自行参透他们的异同:
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之双飞翼布局title>
<style type="text/css">
.left, .main, .right {
float: left;
min-height: 130px;
text-align: center;
}
.left {
margin-left: -100%;
background: green;
width: 200px;
}
.right {
margin-left: -300px;
background-color: red;
width: 300px;
}
.main {
background-color: blue;
width: 100%;
}
.content{
margin: 0 300px 0 200px;
}
style>
head>
<body>
<div class="container">
<div class="main">
<div class="content">maindiv>
div>
<div class="left">leftdiv>
<div class="right">rightdiv>
div>
body>
html>
双飞翼布局比圣杯布局多使用了1个div,少用大致4个css属性(圣杯布局container的 padding-left和padding-right这2个属性,加上左右两个div用相对布局position: relative及对应的right和left共4个属性,;而双飞翼布局子div里用margin-left和margin-right共2个属性,比圣杯布局思路更直接和简洁一点。简单说起来就是:双飞翼布局比圣杯布局多创建了一个div,但不用相对布局了。
想知道更多关于圣杯布局和双飞翼布局,请参考:
圣杯布局和双飞翼布局的作用和区别
CSS布局 – 圣杯布局 & 双飞翼布局
Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。
任何一个容器都可以指定为 Flex 布局,所以Flex 布局将成为未来布局的首选方案。
对于Flex布局的一些具体语法实现,可参见阮一峰大神的Flex 布局教程:语法篇;网友 JailBreak 为Flex布局制作了 Demo,可以参考。
想了解Flex布局的具体实例可参见阮一峰大神的Flex 布局教程:实例篇;想直接查看Flex布局实例,你可以到直接到codepen查看Demo。
接下来讲一下此实例的具体实现:
1.首先将container块设置为一个Flex容器
.container{
display: flex;
min-height: 130px;
}
那么container下属的main、left和right这三个子元素自动成为容器成员,称为 Flex 项目(flex item),简称”项目”。
2.对这三个项目做初始设置
.main{
background-color: blue;
}
.left{
background-color: green;
}
.right{
background-color: red;
}
项目根据内容进行弹性布局:
3.通过order属性设置排列顺序
可以看出三个项目的排序方式不一样了,main排在了第一个,要让main在中间,left在左边,可以通过Flex容器下的项目的属性“order”属性来设置:
.left{
order: -1;
background-color: green;
}
对于order属性:定义项目的排列顺序,越小越靠前,默认为0。
4.通过项目属性flex-grow设置main的放大比例,将空余的空间用main来填充,使三个项目不满一整行;默认为0,也就是对剩余空间不做处理。
.main{
flex-grow:1;
background-color: blue;
}
5.通过项目属性flex-basis 设置left和right的固定宽度
.left{
order: -1;
flex-basis: 200px;
background-color: green;
}
.right{
flex-basis: 300px;
background-color: red;
}
这样就实现了我们的目标,是不是很简单?这就是flex布局的魅力。。。
6.最后,完整的代码如下:
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之Flex布局title>
<style type="text/css">
.container{
display: flex;
min-height: 130px;
}
.main{
flex-grow: 1;
background-color: blue;
}
.left{
order: -1;
flex-basis: 200px;
background-color: green;
}
.right{
flex-basis: 300px;
background-color: red;
}
style>
head>
<body>
<div class="container">
<div class="main">maindiv>
<div class="left">leftdiv>
<div class="right">rightdiv>
div>
body>
html>
绝对定位使元素的位置与文档流无关,因此不占据空间。这一点与相对定位不同,相对定位实际上被看作普通流定位模型的一部分,因为元素的位置相对于它在普通流中的位置。
提示:因为绝对定位的框与文档流无关,所以它们可以覆盖页面上的其它元素。可以通过设置 z-index 属性来控制这些框的堆放次序。
言归正传:
绝对定位,就相当于万金油一样的存在,不论什么样的布局,使用绝对定位都能实现,所以对于具体的实现过程就不赘述,下面直接上代码,不懂的call我:
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之绝对定位布局title>
<style type="text/css">
.container{
position: relative;
}
.main,.right,.left{
top: 0;
height: 130px;
}
.main{
margin: 0 300px 0 200px;
background-color: blue;
}
.right{
position: absolute;
width: 300px;
right: 0;
background-color: red;
}
.left{
position: absolute;
width: 200px;
background-color: green;
left: 0;
}
style>
head>
<body>
<div class="container">
<div class="main">maindiv>
<div class="left">leftdiv>
<div class="right">rightdiv>
div>
body>
html>
实现结果当然是一样的啦!
(完)