陈广鹏的博客

vuePress-theme-reco 陈广鹏    2020 - 2020
陈广鹏的博客 陈广鹏的博客

Choose mode

  • dark
  • auto
  • light
首页
分类
  • Vue
  • javaScript
  • 算法
  • 设计模式
  • leetcode
  • 浏览器工作原理
  • css
  • 性能优化
标签
归档
Ajax系列
联系
  • GitHub
  • 掘金
author-avatar

陈广鹏

10

文章

18

标签

首页
分类
  • Vue
  • javaScript
  • 算法
  • 设计模式
  • leetcode
  • 浏览器工作原理
  • css
  • 性能优化
标签
归档
Ajax系列
联系
  • GitHub
  • 掘金
  • css布局篇——双栏布局与三栏布局

    • 双栏布局
      • 思路
      • 实现
      • 浮动
      • 创建一个BFC
      • 创建BFC后的双栏效果
    • 三栏布局
      • 通过position + margin实现三栏布局
      • 通过浮动实现三栏布局
    • 圣杯布局和双飞翼布局
      • 负边距
      • 圣杯布局
      • 双飞翼布局
      • 总结
    • flex布局

    css布局篇——双栏布局与三栏布局

    vuePress-theme-reco 陈广鹏    2020 - 2020

    css布局篇——双栏布局与三栏布局


    陈广鹏 2020-02-08 14:00:12 布局

    近些年,随着前端技术的不断发展,前端所扮演的角色越来越重要,职责也越来越大。前端早已不仅仅做简单的内容展示页面,也不仅仅负责简单的表单交互了。日益繁杂的前端技术下,JavaScript在我们心中占据着日益重要的地位,而相应的,很多人开始忽略了html和css。

    JavaScript固然重要,但是回过头来想,作为一名前端工作者,难道我们可以避免和页面打交道吗?答案是,否!

    那么,假设给你一个设计稿,我们又该如何去着手呢?

    本篇章主讲双栏布局和三栏布局的一些较为古老及实用的原理及实现。说它古老主要也是因为我们不会涉及flex这一类魔法一般的布局方式,虽然我也知道用flex就能轻松实现很多布局。

    做这个文章,一方面也是自己做个学习记录,当做温习一番。另一方面,也希望能够帮助看到这篇文章的新手一些启发,开启更加深入的探索之路。

    # 双栏布局

    双栏布局非常常见,往往是以一个定宽栏和一个自适应的栏并排展示存在。比如:

    双栏布局

    实现双栏布局也很简单,接下来介绍简单的 float + margin 实现方法。

    假设左边栏固定,右边栏自适应。

    # 思路

    • 使用float 左浮左边栏
    • 右边模块使用margin-left 撑出内容块做内容展示

    # 实现

    html内容结构

    <body>
        <div class="box">
            <div class="left">左边</div>
            <div class="right">右边</div>
        </div>
        内容内容内容
    </body>
    
    1
    2
    3
    4
    5
    6
    7

    css规则

    .left {
        float: left;
        width: 200px;
        background-color: gray;
        height: 400px;
    }
    .right {
        margin-left: 210px;
        background-color: lightgray;
        height: 200px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    效果

    双栏布局

    Emmm...双栏实现了,但是下面的其他内容怎么跑上去了?答案是我们使用了浮动。

    # 浮动

    浮动会导致元素脱离原来普通的文档流。元素可以向左或者向右浮动,直到接触到包含框或者其他框为止。在原来文档流中,体现的就是好像在原来位置被删除了似的。

    因此,以上浮动导致了父元素高度塌陷,其他内容块会自动排版上去。解决的办法有:

    1. 增加清除浮动元素或者伪元素清除浮动,相关元素添加清除样式:

      clear:both;
      
      1
    2. BFC(Block Formatting Context),块级格式化上下文。BFC规定了内部的块级元素的布局方式。使用BFC可以用来包含浮动元素。常见的做法是为父元素添加:

      overflow:hidden;
      
      1

    # 创建一个BFC

    消除浮动的其中一个方式就是创建BFC。然而,创建BFC不仅仅只有**“overflow:hidden;”**一种方式,事实上,我们可以通过这几种方法显示触发BFC:

    • float的值不为none。
    • overflow的值不为visible。
    • position的值不为relative和static。
    • display的值为table-cell, table-caption, inline-block中的任何一个。

    回归正题,我们的双栏布局(事实上其他涉及浮动的布局也一样)父元素高度塌陷的问题的得以解决,比如,我们只需要为 .box 元素添加样式:

    overflow: hidden;
    
    1

    # 创建BFC后的双栏效果

    消除了浮动的双栏布局

    # 三栏布局

    三栏布局也是我们常常会使用到的布局之一。它的特点主要是:两边定宽,中间自适应。

    # 通过position + margin实现三栏布局

    # 思路

    1. 父元素相对定位,通过绝对定位将左右两栏固定
    2. 通过margin设置左右边距,留出内容块

    # 实现

    html内容结构

    <div class="box">
        <div class="left">左边</div>
        <div class="middle">中间</div>
        <div class="right">右边</div>
    </div>
    
    1
    2
    3
    4
    5

    设置css规则

    .box {
        position: relative;
    }
    .left {
        position: absolute;
        top: 0;
        left: 0;
        width: 200px;
        height: 200px;
        background-color: gray;
    }
    .right {
        position: absolute;
        top: 0;
        right: 0;
        width: 200px;
        height: 200px;
        background-color: gray;
    }
    .middle {
        margin-left: 210px;
        margin-right: 210px;
        background-color: lightgray;
        height: 200px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    效果

    position+margin实现三栏布局

    # 通过浮动实现三栏布局

    # 思路

    1. 左右两栏使用float浮动到相应位置
    2. 中间栏通过margin属性进行撑开

    # 实现

    html内容结构

    <div class="box">
        <div class="left">左边</div>
        <div class="right">右边</div>
        <div class="middle">中间</div>
    </div>
    
    1
    2
    3
    4
    5

    设置css规则

    .box {
        overflow: hidden;
    }
    .left {
        float: left;
        background-color: gray;
        width: 200px;
        height: 200px;
    }
    .right {
        float: right;
        background-color: gray;
        width: 200px;
        height: 200px;
    }
    .middle {
        height: 200px;
        background-color: lightgray;
        margin-left: 210px;
        margin-right: 210px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    效果

    通过浮动实现三栏架构

    # 缺点

    当然,通过浮动实现的三栏布局有一个很明显的缺点,就是我们的代码层面上来讲html内容结构不正确,我们必须把.middle元素放在最下面而不是中间位置,这是float所产生的的布局影响所导致的。

    # 圣杯布局和双飞翼布局

    圣杯布局最早源于发表于2006年的In Search of the Holy Grail · An A List Apart Article ,而双飞翼布局则是源自淘宝UED。

    圣杯布局和双飞翼布局也是两边定宽,中间自适应的三栏布局。并且中间栏要放在父元素的第一儿子位置,以优先渲染。因此,有些人会说这带来了代码层面上html内容结构的不正确。然而,这么做的好处就是可以让更为重要的中间部分优先渲染,从这个角度来讲,这或许是更加好的结构。

    圣杯布局和双飞翼布局两者既有相似的地方,也有不同的地方,接下来来比较一下。

    在此之前,先来看看可爱的负边距。

    # 负边距

    为什么要讲到负边距呢?

    一方面负边距是我们常常忽略的非常好用的技巧,在我们的布局方面具有非常重要的意义;另一方面这玩意儿兼容性贼好,我们也不用怕兼容性方面的问题。

    说起负边距,我们可以想到的就是margin在正边距时候的反方向。我们可以来看看。

    # 普通文档流的负边距

    # 实现

    html内容结构

    <div class="box">
        <div class="content">
            我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容
            我是内容我是内容我是内容我是内容
            <span class="span red">哈哈哈哈哈</span>我是内容我是内容我是内容我是内容
            我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容
            我是内容我是内容我是内容我是内容我是内容我是内容我是内容我是内容
        </div>
        <div class="other-content">
            我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块
            我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块
            我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块我是另一块
        </div>
        哈哈哈哈哈哈
        </div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    css规则

    .box {
        margin: auto;
        width: 600px;
    }
    .content {
        margin: -20px;
        background-color: lightgray;
    }
    .span {
        margin: -10px;
    }
    .red {
        background-color: red;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    效果

    负边距

    # 总结

    正如上面所示,我们为.content和.span这两个分别代表块级元素和行辈元素的东西设置了margin为-20px和-10px。布局也相应产生了变化。

    • 灰色的框子,内容向左上角拉了过去。.content下方的.other-content文字也来到了它上面。
    • 红色行内元素,也向左边偏移,右边的元素被拉了过来。
    • 最后面没有任何设置的"哈哈哈哈哈哈"内容也依然紧跟着.other-content元素显示。

    我们不难看出,负值情况下

    • margin-top和margin-left会影响自身向指定方向偏移
    • margin-right和margin-bottom会影响相邻元素向指定方向偏移
    • 通过margin偏移后,原先空出来的位置也会由后面元素填不上。
    • 当然,块级元素和行内元素在表现上稍有不同。

    另一种情况,负值margin也能够影响元素的宽度,前提是该元素width属性为auto的情况下。这里也给出详细例子,比方我们给一个元素左右边距为-200px。

    html内容结构

    <div class="box">
        <div class="container"></div>
    </div>
    
    1
    2
    3

    css规则

    .box {
        width: 200px;
        border: 1px solid black;
        margin: auto;
    }
    .container {
        margin: 0 -200px;
        background-color: lightgray;
        width: auto;
        height: 200px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    效果

    负边距

    当然,目前为止我们都是在普通文档流里面。

    # 脱离文档流的负边距

    # 绝对定位 + 负边距

    假设我们对一个元素进行绝对定位,并且给相应的负边距。

    # 实现

    html内容结构

    <div class="box">
        <div class="pos">
            绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位
            绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位绝对定位
        </div>
        <div class="pos2">
            内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容
            内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容
            内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容
        </div>
    </div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    css规则

    .box {
        position: relative;
        height: 200px;
        margin: 200px;
        border: 1px solid black;
    }
    .pos {
        width: 200px;
        height: 200px;
        position: absolute;
        margin: -20px;
        border: 1px solid gray;
    }
    .pos2 {
        width: 200px;
        height: 200px;
        position: absolute;
        border: 1px solid red;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    效果图

    负边距

    # 总结

    从效果上可以看出来,对于绝对定位而言,负边距在top和left位置上,会把元素往指定方向拉,而right和bottom方向则没什么影响,因为脱离了普通文档流,不会引起其他相邻元素变化。

    tips: **“绝对定位+负边距”**我们也常常用来实现居中布局。

    # 浮动 + 负边距

    思考以下三个场景:

    1. 三个左浮动的块,分别设置负边距,几个浮动块会是怎样?
    2. 两个左浮动的块,左边的块左边距设置为-100%,右边的块会左移吗?
    3. 两个左浮动的块,第一个width占满,第二个左边距设置负值为自身width大小,会如何?
    # 实现

    html内容结构

    <!-- demo1 -->
    <div class="box">
        <div class="float float1">1</div>
        <div class="float float2">2</div>
        <div class="float float3">3</div>
    </div>
    <!-- demo2 -->
    <div class="box">
        <div class="float4">1</div>
        <div class="float5">2</div>
    </div>
    <!-- demo3 -->
    <div>
        <div class="row">6</div>
        <div class="float6">2</div>
    </div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    css规则

    .box {
        width: 800px;
        height: 210px;
        margin: 50px auto 10px auto;
        border: 1px solid black;
    }
    /* 第一个demo */
    .float {
        float: left;
        margin: -50px;
        width: 200px;
        height: 200px;
    }
    .float1 {
        background-color: gray;
    }
    .float2 {
        background-color: yellow;
    }
    .float3 {
        background-color: red;
        margin: 0;
    }
    
    /* 第二格demo */
    .float4 {
        background-color: gray;
        float: left;
        width: 200px;
        height: 200px;
        margin-left: -200px;
    }
    .float5 {
        background-color: lightgray;
        width: 200px;
        height: 200px;
        float: left;
    }
    
    /* 第三个demo */
    .row {
        width: 100%;
        height: 200px;
        background-color: lightgray;
        float: left;
    }
    .float6 {
        background-color: gray;
        float: left;
        width: 200px;
        height: 200px;
        margin-left: -200px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53

    效果

    # 总结

    可以看出:

    1. demo1中,1和2两个元素设置了所有边距为负值,都会往左上方偏移。同时,元素2会在水平方向占元素1一半。元素3则会被元素2拉向左边,占元素2的四分之一。
    2. demo2中,元素1左偏移了自身width的距离,原先位置空着,元素2紧接着补上。
    3. demo3中,两个元素都是左浮动,元素6的width为100%,当元素2左偏移自身width的距离以后,完全到了上一行。

    因此,我们也可以看出,负边距对浮动的元素具有和普通文档流中同样类似的效果。并且,在后边的元素也可以通过负边距实现覆盖前边元素。

    在布局中,我们就常常使用到**“float + 负边距”**的魔力。

    # 圣杯布局

    # 思路

    1. 左中右三个元素分别左浮动。
    2. 中间元素占据第一位置优先渲染,设置该元素width为100%
    3. 左元素设置左边距为-100%以使得左元素上升一行并且处于最左位置,右元素设置左边距为自身宽度的负值使得右元素上升一行处于最右位置。
    4. 设置父元素的左右padding为左右两个元素留出空间,以展示中间元素内容。
    5. 设置左右元素为相对定位,左元素的left和右元素的right为内边距的宽度的负值。

    # 实现

    html内容结构

    <div class="box">
        <div class="middle">中间</div>
        <div class="left">左边</div>
        <div class="right">右边</div>
    </div>
    
    1
    2
    3
    4
    5

    css规则

    .box {
        overflow: hidden;
        padding: 0 210px;
    }
    .middle {
        float: left;
        width: 100%;
        height: 200px;
        background-color: lightgray;
    }
    .left {
        float: left;
        width: 200px;
        height: 200px;
        background-color: gray;
        margin-left: -100%;
        position: relative;
        left: -210px;
    }
    .right {
        float: left;
        width: 200px;
        height: 200px;
        background-color: gray;
        margin-left: -200px;
        position: relative;
        right: -210px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

    效果

    圣杯布局

    # 双飞翼布局

    # 思路

    1. 左中右三个元素分别左浮动。
    2. 中间元素占据第一位置优先渲染,设置该元素width为100%
    3. 左元素设置左边距为-100%以使得左元素上升一行并且处于最左位置,右元素设置左边距为自身宽度的负值使得右元素上升一行处于最右位置。
    4. 设置中间元素的子元素左右边距为左右元素留空位,以展示中间元素内容。

    # 实现

    html内容结构

    <div class="box">
        <div class="middle">
            <div class="content">中间</div>
        </div>
        <div class="left">左边</div>
        <div class="right">右边</div>
    </div>
    
    1
    2
    3
    4
    5
    6
    7

    css规则

    .box {
        overflow: hidden;
    }
    .middle {
        float: left;
        width: 100%;
    }
    .middle .content {
        margin: 0 210px;
        height: 200px;
        background-color: lightgray;
    }
    .left {
        float: left;
        width: 200px;
        height: 200px;
        background-color: gray;
        margin-left: -100%;
    }
    .right {
        float: left;
        width: 200px;
        height: 200px;
        background-color: gray;
        margin-left: -200px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    效果

    双飞翼布局

    # 总结

    圣杯布局跟双飞翼布局的实现上,在前部分是一样的。同样都是左右栏定宽,中间栏自适应。采用浮动和负边距使左右栏与中间栏并排。不同之处大部分在于中间元素的的展示方式上。

    圣杯布局采用父元素设置边距的方法,左右元素设置相对定位辅助。而双飞翼布局在中间采用嵌套子元素方法,通过设置子元素外边距来展示。

    对比看来,双飞翼比圣杯多了一个嵌套元素,但是少了左右元素的定位。

    # flex布局

    在flex之前,无论是我们的单栏布局也好,双栏布局也罢,甚至更为复杂的三栏布局、垂直居中等等,我们一般都会借助浮动 (float)、定位(position)、边距(margin)来实现我们各种各样的布局样式,直到我们遇到了flex。

    flex(弹性布局)给了我们在布局方面更多的可能性,它可以更加简便、响应的布局我们的页面。我们常常可以利用它魔法一般的属性来打造我们想要的布局样式。并且,flex现在几乎得到了所有的浏览器的支持,兼容性方面已经越来越不需要太过担忧了。

    更多关于flex兼容性的问题可以查看can I use

    然而,本篇章并不打算写flex,仅仅讲解以往实现双栏和三栏布局的一些方式。于我而言,我更愿意用单独一个篇章来写flex这个主题,而不是放在这个主题来讲。并且之后我也会专门来写这个主题。