效果
要求:
- left和right固定宽度,content是自适应宽度的
- 整个盒子的高度是三者的最大值
- content需要比left和right提前渲染
尝试
left、right、content都是块级元素
- flex似乎可以
- display似乎也可以
- gird好像也可以
但是上面三种都不能满足第3点:
content需要比left和right提前渲染
为了满足提前渲染,我们得将content的html标签放在left和right之前,
<div class="box">
<div class="content ">
content
</div>
<div class="left ">
left
</div>
<div class="right ">
right
</div>
</div>
但是这样写的代价就是一般的布局手段都失效了
再次尝试
我们想让left放到content左侧,right放到right的右侧,但是正常文档流没法实现,那只能往非标准流布局想。
- 定位:父元素相对定位,left和right绝对定位,就能实现我们想要的布局。但是父元素的高度计算是不算上绝对定位的元素的,即不满足第二点
- 浮动:浮动的块级元素能在一列上排布,但它只能达到下图的效果。
对于上图,我们如何让left能覆盖content呢?
如果我们能让left的
占位宽度为0,那么left就能浮动到content的右上角,
margin负值会导致占位宽度的变化,比如某div宽度为100px,然后设置margin-left:-50px,那么该div的占位宽度只有50px,而它展示的宽度依旧是100px,且向左偏移50px。
通过这种方式,我们设置left的margin-left为-自身宽度,那么left的占位宽度:0,就会浮动到content的右侧,然后往左偏移,从而让left覆盖在content之上。 好,我们使用float并给left加一个margin-left:-100px看看(left的宽度就是100px)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.float-left {
float: left;
border: 1px solid #ccc;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
}
.box {
overflow: hidden;
}
.content {
width: 100%;
height: 100px;
background-color: skyblue;
}
.left {
height: 100px;
margin-left: -100px;
width: 100px;
background-color: tomato;
}
.right {
height: 100px;
width: 100px;
background-color: pink;
}
</style>
<body>
<div class="box">
<div class="content float-left">
content
</div>
<div class="left float-left">
left
</div>
<div class="right float-left">
right
</div>
</div>
</body>
</html>
left覆盖content成功了!
各位可以在浏览器改一下这个margin-left的值,看看效果。
当我们将left的margin-left:-100%(父元素内容宽度的100%),且right的margin-left:-100px时(right使用的方式和原理和left一样,只不过换成了margin-right):
left就到了content的左上角了,right紧贴在content的右侧,在窗口之外了。
我们给父元素设置padding-left和padding-right:100px后
然后将left相对定位左移动后:
很好,完美实现了3个要求。
这就是圣杯布局 -> 一个🏆有两个把手
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.float-left {
float: left;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
}
.box {
padding-left: 100px;
padding-right: 100px;
overflow: hidden;
}
.content {
width: 100%;
height: 100px;
background-color: skyblue;
}
.left {
height: 100px;
margin-left: -100%;
width: 100px;
background-color: tomato;
position: relative;
left: -100px;
}
.right {
height: 100px;
width: 100px;
background-color: pink;
margin-right: -100px;
}
</style>
<body>
<div class="box">
<div class="content float-left">
content
</div>
<div class="left float-left">
left
</div>
<div class="right float-left">
right
</div>
</div>
</body>
</html>
双飞翼布局
回顾一下,圣杯布局思路过程
- html上的布局是content -> left -> right
- 三个元素都设置float
- 通过设置left的margin-left:100%、right的margin-right:自身宽度、来让left和right分别处于content的左上角和右上角
- 然后设置父元素的padding-left和padding-right,然后left和right通过相对定位进行移动。
对于第四步,如果我们能在content内部放置一个innerContent,然后给这个innerContent设置margin-left和margin-right,然后left和right固定在Conten的左上角和右上角,这样就不需要使用相对位移了。来看看效果。
<!DOCTYPE html>
<html lang="en">
head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
.flex-row-center-center{
display: flex;
box-sizing: border-box;
justify-content: center;
align-items: center;
font-size: 20px;
}
.float-left {
float: left;
}
.box{
overflow: hidden;
}
.content {
width: 100%;
}
.innerContent {
height: 100px;
margin: 0 100px;
background-color: skyblue;
}
.left {
width: 100px;
height: 100px;
background-color: tomato;
margin-left: -100%;
}
.right {
width: 100px;
height: 100px;
background-color: violet;
margin-left: -100px;
}
</style>
<body>
<div class="box">
<div class="content float-left ">
<div class="innerContent flex-row-center-center">
innerContent
</div>
</div>
<div class="float-left left flex-row-center-center">left</div>
<div class="float-left right flex-row-center-center">right</div>
</div>
</body>
</html>
这就是双飞翼布局 -> 👼有两个翅膀
两种布局的缺点
圣杯布局
- html上的布局是content -> left -> right
- 三个元素都设置float
- 通过设置left的margin-left:100%、right的margin-right:自身宽度、来让left和right分别处于content的左上角和右上角
- 然后设置父元素的padding-left和padding-right,然后left和right通过相对定位进行移动。
注意第三步,left到了content的左上角,如果left的宽度比content宽的话,效果如下:
content的宽度 = 可视化窗口的宽度 - 我们设置的padding左右 = left的margin-left:100%中的100%。
这个100%还没left的宽度大,所以不能让left的占位宽度为0,所以没法到content的右侧。
那这时,可能有人问,那我强行设置left的margin-left:-left的宽度,那left的占位宽度不就是0了吗,这样就可以到content的右侧了。
是的,是的,确实可以,如下图。
但是之后给left相对定位时,怎么设置position的left呢?
如果position的left为100%,那这个100%是content的宽度,明显不对。
缺点是:当left宽度比content的宽度大时,布局没法实现
双飞翼
双飞翼布局没有这问题,因为content的宽度是整个父元素的宽度,left是父元素的子元素,一般不会超过父元素宽度的所以不会出现上面的问题。
缺点是:会多一层html标签