八股文不用背-三栏布局、圣杯布局、双飞翼布局

225 阅读4分钟

效果

image.png 要求:

  1. left和right固定宽度,content是自适应宽度的
  2. 整个盒子的高度是三者的最大值
  3. 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>

但是这样写的代价就是一般的布局手段都失效了

再次尝试

image.png

我们想让left放到content左侧,right放到right的右侧,但是正常文档流没法实现,那只能往非标准流布局想。

  • 定位:父元素相对定位,left和right绝对定位,就能实现我们想要的布局。但是父元素的高度计算是不算上绝对定位的元素的,即不满足第二点
  • 浮动:浮动的块级元素能在一列上排布,但它只能达到下图的效果。

image.png 对于上图,我们如何让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>

image.png

left覆盖content成功了!

各位可以在浏览器改一下这个margin-left的值,看看效果。

当我们将left的margin-left:-100%(父元素内容宽度的100%),且right的margin-left:-100px时(right使用的方式和原理和left一样,只不过换成了margin-right):

image.png

left就到了content的左上角了,right紧贴在content的右侧,在窗口之外了。

我们给父元素设置padding-left和padding-right:100px后

image.png

然后将left相对定位左移动后:

image.png

很好,完美实现了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>

双飞翼布局

回顾一下,圣杯布局思路过程

  1. html上的布局是content -> left -> right
  2. 三个元素都设置float
  3. 通过设置left的margin-left:100%、right的margin-right:自身宽度、来让left和right分别处于content的左上角和右上角
  4. 然后设置父元素的padding-left和padding-right,然后left和right通过相对定位进行移动。

对于第四步,如果我们能在content内部放置一个innerContent,然后给这个innerContent设置margin-left和margin-right,然后left和right固定在Conten的左上角和右上角,这样就不需要使用相对位移了。来看看效果。

image.png

<!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>

这就是双飞翼布局 -> 👼有两个翅膀


两种布局的缺点

圣杯布局

  1. html上的布局是content -> left -> right
  2. 三个元素都设置float
  3. 通过设置left的margin-left:100%、right的margin-right:自身宽度、来让left和right分别处于content的左上角和右上角
  4. 然后设置父元素的padding-left和padding-right,然后left和right通过相对定位进行移动。

注意第三步,left到了content的左上角,如果left的宽度比content宽的话,效果如下:

image.png

content的宽度 = 可视化窗口的宽度 - 我们设置的padding左右 = left的margin-left:100%中的100%。 这个100%还没left的宽度大,所以不能让left的占位宽度为0,所以没法到content的右侧。

那这时,可能有人问,那我强行设置left的margin-left:-left的宽度,那left的占位宽度不就是0了吗,这样就可以到content的右侧了。
是的,是的,确实可以,如下图。

image.png

但是之后给left相对定位时,怎么设置position的left呢?
如果position的left为100%,那这个100%是content的宽度,明显不对。

缺点是:当left宽度比content的宽度大时,布局没法实现

双飞翼

双飞翼布局没有这问题,因为content的宽度是整个父元素的宽度,left是父元素的子元素,一般不会超过父元素宽度的所以不会出现上面的问题。

缺点是:会多一层html标签

看到这里的看官,麻烦点个赞赞吧