盒模型 | 如何处理盒模型内数据溢出?如何实现各种布局?

188 阅读10分钟

盒模型简介

按display属性来定义盒子类型的话,有block、inline和inline-block几种类型的盒子:

元素类型width与heightmargin与padding前后有无换行符
block有效水平、垂直方向都有效
inline无效水平方向有效
inline-block有效水平、垂直方向都有效

而block元素下又根据box-sizing分成了三种不同宽度计算模式的盒子:

box-sizing属性盒子宽度计算公式
content-box默认。width = content
border-boxwidth = content + padding + border的宽度

box-sizing的意义是什么?

使用box-sizing的目的是对元素的总宽度做一个控制,假设两个同行元素想要占满整个屏幕,只需要设置box-sizing:border-box;width:50%即可。

如何处理盒子内容溢出?

可以使用 overflow、overflow-x、overflow-y、text-overflow 来控制。

属性常用属性值注意点
overflowhidden:隐藏超出部分
scroll:超出部分滚动显示
需要限定盒子边界,也就是设置width和height的值,如果没有设置对应(水平和垂直)方向的值,那么该属性在对应方向上将不会生效。
overflow-xhidden:隐藏超出部分
scroll:超出部分滚动显示
需要设置width的值
overflow-yhidden:隐藏超出部分
scroll:超出部分滚动显示
需要设置height的值
text-overflowhidden:水平方向超出部分文本隐藏需要设置width的值

text-overflow还可以结合white-space实现超出部分省略,并且在末尾补充省略号的操作:

<style type="text/css">
div{
        overflow:hidden;
        text-overflow: ellipsis;
        white-space: nowrap; 
        width: 300px;
        border: solid 1px orange;
}
</style>

布局

1. 水平居中

子元素是行内元素

  • 父元素是块级元素
    父元素设置text-align: center

    <div class="horizontally_parent1">
      <span>我是行内元素</span>
    </div>
    <style>
      .horizontally_parent1 {
        width: 200px;
        text-align: center;
      }
    </style>
    
  • 父元素不是块级元素
    先将父元素设置为块级元素,再将父元素设置text-align: center

    html
     代码解读
    复制代码
    <span class="horizontally_parent2">
      <span>我是行内元素</span>
    </span>
    <style>
      .horizontally_parent2 {
        display: block;
        width: 200px;
        text-align: center;
      }
    </style>
    

子元素是块级元素

  • 子元素定宽
    子元素设置 margin: 0 auto;

    <div class="horizontally_parent3">
      <div class="child">
        我是有宽度的块级元素
      </div>
    </div>
    <style>
      .horizontally_parent3 {
        width: 500px;
        height: 300px;
        background: red;
        .child {
          width: 200px;
          height: 100px;
          margin: 0 auto;
        }
      }
    </style>
    
  • 子元素不定宽

    1. 设置子元素为非块级元素;
    2. 父元素设置text-align: center
    <div class="horizontally_parent4">
      <div class="child">
        我是没有宽度的块级元素
      </div>
    </div>
    <style>
      .horizontally_parent4 {
        width: 500px;
        background: red;
        text-align: center;
        .child {
          display: inline;
        }
      }
    </style>
    
  • 使用定位属性
    设置父元素为相对定位;子元素为绝对定位;设置子元素的left: 50%,让子元素的左上角水平居中。

    • 子元素定宽
      设置绝对子元素的 margin-left: -子元素宽度的一半px ;或者设置transform: translateX(-50%)

      <div class="horizontally_parent5">
        <div class="child">
          我是使用定位属性有宽度的块级元素
        </div>
        <br clear="both" />
      </div>
      <style>
        .horizontally_parent5 {
          width: 600px;
          background: red;
          position: relative;
          .child {
            position: absolute;
            left: 50%;
            width: 300px;
            margin-left: -150px;
          }
        }
      </style>
      
    • 子元素不定宽
      利用 css 新增属性transform: translateX(-50%)

      <div class="horizontally_parent6">
        <div class="child">
          我是使用定位属性没有宽度的块级元素
        </div>
      </div>
      <style>
        .horizontally_parent6 {
          width: 500px;
          height: 50px;
          background: red;
          position: relative;
          .child {
            position: absolute;
            left: 50%;
            width: 200px;
            transform: translateX(-50%);
          }
        }
      </style>
      
  • flex + justify-content
    利用 flexbox,只需要给待处理的块状元素的父元素添加属性dispaly: flex;justify-content: center;

    <div class="horizontally_parent7">
      <div class="child">
        我是使用flex布局的块级元素
      </div>
    </div>
    <style>
      .horizontally_parent7 {
        width: 500px;
        background: red;
        display: flex;
        justify-content: center;
      }
    </style>
    
  • flex + margin
    父元素设置为 flex 布局,子元素只用 margin 居中。

    <div class="horizontally_parent8">
      <div class="child">
        我是使用flex布局的块级元素
      </div>
    </div>
    <style>
      .horizontally_parent8 {
        width: 500px;
        background: red;
        display: flex;
        .child {
          margin: 0 auto;
        }
      }
    </style>
    

2. 垂直居中

单行的行内元素

只需要设置单行行内元素的行高 = 盒子高度即可

<div class="verticalcenter_parent1">
  <span class="child">
    我是单行行内元素
  </span>
</div>
<style>
  .verticalcenter_parent1 {
    width: 500px;
    height: 100px;
    background: red;
    .child {
      line-height: 100px;
    }
  }
</style>

多行的行内元素

给父元素设置 display: table-cellvertical-align:middle

<div class="verticalcenter_parent2">
  <span class="child">
    我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素我是多行行内元素
  </span>
</div>
<style>
  .verticalcenter_parent2 {
    width: 500px;
    height: 100px;
    background: red;
    display: table-cell;
    vertical-align: middle;
  }
</style>

块级元素

  • 使用定位属性
    设置父元素为相对定位;设置子元素为绝对定位;设置子元素的top:50% ,让子元素在左上角垂直居中。

    • 定高度
      设置绝对子元素的 margin-top:-子元素高度的一半px

      <div class="verticalcenter_parent3">
        <div class="child">
          我是使用定位属性有高度的块级元素
        </div>
      </div>
      <style>
        .verticalcenter_parent3 {
          width: 500px;
          height: 100px;
          background: red;
          display: table-cell;
          position: relative;
          .child {
            height: 50px;
            position: absolute;
            top: 50%;
            margin-top: -25px;
            background-color: green;
          }
        }
      </style>
      
    • 不定高度
      使用 css3 新增属性 transform:translateY(-50%)

      <div class="verticalcenter_parent4">
        <div class="child">
          我是使用定位属性没有高度的块级元素
        </div>
      </div>
      <style>
        .verticalcenter_parent4 {
          width: 500px;
          height: 100px;
          background: red;
          display: table-cell;
          position: relative;
          .child {
            height: 50px;
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background-color: green;
          }
        }
      </style>
      
  • flex + align-items
    使用 flexbox 布局,只需要给待处理的块状元素的父元素添加属性display:flex; align-items:center;

    <div class="verticalcenter_parent5">
      <div class="child">
        我是使用flex布局的块级元素
      </div>
    </div>
    <style>
      .verticalcenter_parent5 {
        width: 500px;
        height: 100px;
        background: red;
        display: flex;
        align-items: center;
        .child {
          height: 50px;
          background-color: green;
        }
      }
    </style>
    

3. 水平垂直居中

绝对定位 ➕ 负边距

父元素、子元素都有宽高

html
 代码解读
复制代码
<div class="center1">
  <div class="child">
    我是子元素
  </div>
  <br clear="both" />
</div>
<style>
  .center1 {
    position: relative;
    background: red;
    width: 500px;
    height: 100px;
    .child {
      background-color: green;
      width: 100px;
      height: 50px;
      position: absolute;
      top: 50%;
      left: 50%;
      margin: -25px 0 0 -50px;
    }
  }
</style>

绝对定位 ➕ margin:auto

父元素、子元素都有宽高

html
 代码解读
复制代码
<div class="center2">
  <div class="child">
    我是子元素
  </div>
</div>
<style>
  .center2 {
    position: relative;
    width: 500px;
    height: 100px;
    background: red;
    .child {
      width: 100px;
      height: 50px;
      background-color: green;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
  }
</style>

绝对定位是相对于哪个元素进行计算的呢?

相对于最近的非static定位的祖先元素的padding属性进行偏移计算。

绝对定位 ➕ CSS3

父元素有宽高,子元素没有宽高

<div class="center3">
  <div class="child">
    我是子元素
  </div>
</div>
<style>
  .center3 {
    position: relative;
    width: 500px;
    height: 100px;
    background: red;
    .child {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: green;
    }
  }
</style>

flex 布局

父元素和子元素都不需要设置宽高

<div class="center4">
  <div class="child">
    我是子元素
  </div>
</div>
<style>
  .center4 {
    display: flex;
    justify-content: center;
    align-items: center;
    background: red;
    .child {
      background-color: green;
    }
  }
</style>

flex / grid 布局 ➕ margin: auto

父元素和子元素都不需要设置宽高

<div class="center4">
  <div class="child">
    我是子元素
  </div>
</div>
<style>
  .center5 {
    background: red;
    /* display: grid; */
    display: flex;
    .child {
      margin: auto;
      background-color: green;
    }
  }
</style>

4. 左右两栏布局(左侧固定,右侧自适应)

float ➕ margin

<div class="two_columns1">
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .two_columns1 {
    overflow: hidden;
    .left {
      width: 100px;
      background: red;
      float: left;
    }
    .right {
      margin-left: 100px;
      background: green;
    }
  }
</style>

float ➕ overflow

<div class="two_columns2">
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .two_columns2 {
    overflow: hidden;
    .left {
      width: 100px;
      background: red;
      float: left;
    }
    .right {
      overflow: hidden;
      background: green;
    }
  }
</style>

float ➕ calc 计算宽度

<div class="two_columns5">
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .two_columns5 {
    .left {
      width: 100px;
      background: red;
      float: left;
    }
    .right {
      width: calc(100% - 100px);
      float: right;
      background: green;
    }
  }
</style>

flex 布局

<div class="two_columns3">
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .two_columns3 {
    display: flex;
    .left {
      width: 100px;
      background: red;
    }
    .right {
      flex: 1;
      background: green;
    }
  }
</style>

grid 布局

<div class="two_columns4">
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .two_columns4 {
    display: grid;
    grid-template-columns: auto 1fr;
    .left {
      width: 100px;
      background: red;
    }
    .right {
      background: green;
    }
  }
</style>

5. 上面 100px,下面自适应

flex 布局

<div class="container1">
  <div class="top"></div>
  <div class="bottom"></div>
</div>
<style>
  .container1 {
    width: 200px;
    height: 100%;
    display: flex;
    flex-direction: column;
    margin-right: 15px;
  }
  
  .top {
    height:100px;
    background: red;
  }

  .bottom {
    flex:1;
    background: green;
  }
</style>

定位

<div class="container2">
  <div class="top"></div>
  <div class="bottom"></div>
</div>
<style>
  .container2 {
    width: 200px;
    height: 100%;
    margin-right: 15px;
    position: relative;
  }
  
  .top {
    background: red;
    height: 100px;
  }

  .bottom {
    width: 100%;
    background: green;
    position: absolute;
    top: 100px;
    bottom: 0;
  }
</style>

6. 三栏布局(两边固定,中间自适应)

圣杯布局

特点: 比较特殊的三栏布局,同样也是两固定宽度,中间自适应,唯一的区别是 dom 结构必须是先写中间列部分,这样实现中间列可以优先加载。

实现步骤:

  • 三个部分都设定为左浮动,否则左右两边内容上不去,就不可能和中间列同一行,然后设置 center 的宽度为 100%(实现中间列内容自适应),此时,left 和 right 部分会跳到下一行。
  • 通过设置 margin-left 为负值让 left 和 right 部分回到与 center 部分同一行。
  • 通过设置父容器的 padding-left 和 padding-right,让左右两边留出间隙。
  • 通过设置相对定位,让 left 和 right 部分移动到两边。

缺点:

  • center 部分的最小宽度不能小于 left 部分的宽度,否则 left 部分会掉到下一行。
  • 如果其中一列内容高度拉长,其他两列的背景并不会自动填充(借助等高布局正 padding+负 padding 可解决)
<div class="three_columns1">
  <div class="center">中间</div>
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .three_columns1 {
    padding: 0 100px;
    .left, .center, .right {
      float: left;
    }
    .left {
      background: red;
      width: 100px;
      left: -100%;
      position: relative;
      margin-left: -100px;
    }
    .center {
      background: blue;
      width: 100%;
    }
    .right {
      background: green;
      width: 100px;
      right: -100px;
      position: relative;
      margin-left: -100px;
    }
  }
</style>

双飞翼布局

特点: 同样是三栏布局,在圣杯布局基础上进一步优化,解决了圣杯布局错误问题,实现了内容与布局的分离。而且任何一栏都可以是最高栏,不会出问题。

实现步骤: (前两步与圣杯布局相同)

  • 三个部分都设定为左浮动,然后设置 center 的宽度为 100%,此时,left 和 right 部分会跳到下一行。
  • 通过设置 margin-left 为负值让 left 和 right 部分回到与 center 部分同一行。
  • center 部分增加一个内层 div,并设margin:0 200px;

缺点: 多加一层 dom 树节点,增加渲染树生成的计算量。

<div class="three_columns2">
  <div class="center">
    <div class="center_inner">中间</div>
  </div>
  <div class="left">左边</div>
  <div class="right">右边</div>
</div>
<style>
  .three_columns2 {
    .left, .center, .right {
      float: left;
    } 
    .left {
      width: 100px;
      background: red;
      margin-left: -100%;
    }
    .center {
      background: blue;
      width: 100%;
      .center_inner {
        margin: 0 100px;
      }
    }
    .right {
      width: 100px;
      background: green;
      margin-left: -100px;
    }
  }
</style>

圣杯布局 🆚 双飞翼布局:

  • 都是左右栏定宽,中间自适应的三栏布局,中间栏都放在文档流前面,保证先行渲染。
  • 解决方案基本相似:都是三栏全部设置左浮动float: left ,然后分别解决中间栏内容被覆盖问题。
  • 解决中间栏内容被覆盖问题时,圣杯布局设置父元素的 padding,双飞翼布局在中间栏外面嵌套了一个 div,并设置 margin,实际上双飞翼布局就是圣杯布局的改进方案

flex 布局

<div class="three_columns3">
  <div class="left">左边</div>
  <div class="center">中间</div>
  <div class="right">右边</div>
</div>
<style>
  .three_columns3 {
    display: flex;
    .left {
      width: 100px;
      background: red;
    }
    .center {
      flex: 1;
      background: blue;
    }
    .right {
      width: 100px;
      background: green;
    }
  }
</style>

float ➕ margin

左栏定宽左浮,右栏定宽右浮,中间栏不设宽度加 margin,且中间栏放在最下面。
缺点: 主要内容无法最先加载,当页面内容较多时会影响用户体验。

<div class="three_columns4">
  <div class="left">左边</div>
  <div class="right">右边</div>
  <div class="center">中间</div>
</div>
<style>
  .three_columns4 {
    .left {
      float: left;
      width: 100px;
      background: red;
    }
    .center {
      background: blue;
      margin: 0 100px;
    }
    .right {
      float: right;
      width: 100px;
      background: green;
    }
  }
</style>

BFC 三栏布局

<div class="three_columns5">
  <div class="left">左边</div>
  <div class="right">右边</div>
  <div class="center">中间</div>
</div>
<style>
  .three_columns5 {
    .left {
      float: left;
      width: 100px;
      background: red;
    }
    .center {
      background: blue;
      overflow: hidden;
    }
    .right {
      float: right;
      width: 100px;
      background: green;
    }
  }
</style>