CSS — 实现两栏、三栏、水平垂直居中等各种常见布局及各种常见图形

760 阅读11分钟

图形

1. 三角形

border

.triangle {
  width: 0;
  height: 0;
  border: 100px solid;
  border-color: red green blue black;
}

直角等腰三角形👇

.triangle {
  width: 0;
  height: 0;
  border: 100px solid transparent;
  border-top-color: red;
  border-left-color: red;
}

等腰三角形👇

.triangle2 {
  width: 0;
  height: 0;
  border: 100px solid transparent;
  border-top-color: red;
}

等边三角形👇:

/* 左右两边高度是100,上下两边是 100*根号3 */
.triangle3 {
  width: 0;
  height: 0;
  border: solid transparent;
  border-bottom-color: red;
  border-width: 173px 100px;
}

clip-path

clip-path 中的 polygon 属性可以用来绘制多边形。点的顺序是顺时针方向(第四象限)

直角等腰三角形👇:

.triangle4 {
  width: 100px;
  height: 100px;
  background-color: green;
  clip-path: polygon(0 0, 0 100%, 100% 0);
}

等腰三角形👇:

.triangle5 {
  width: 100px;
  height: 100px;
  background-color: green;
  clip-path: polygon(0 0, 100% 0, 50% 50%);
}

等边三角形👇:

.triangle6 {
  width: 100px;
  height: 87px;
  background-color: green;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

2. 扇形

border-radius ➕ 盒子设置宽高

利用边框圆角的属性设置盒子的某一个角为圆角,然后其他角设置为 0,然后给整个盒子加背景色,就只显示出一个扇形脚。

.sector1 {
  width: 100px;
  height: 100px;
  border-radius: 100% 0 0;
  background: red;
}

border

原理是利用边框颜色可以分别设置的属性,设置其中一条边框有颜色。其他边框没有颜色,再把整个盒子变为圆角盒子没有宽高,只有边框,突出扇形。

.sector2 {
  width: 0;
  height: 0;
  border: 100px solid transparent;
  border-top-color: red;
  border-radius: 50%;
}

clip-path

.sector3 {
  width: 100px;
  height: 100px;
  border-radius: 100%;
  background-color: red;
  /* 第三个点的 x 在 0-100 变化,则对应着 0-90度*/
  clip-path: polygon(50% 50%, 0 0, 100% 0);
  
  /* 第四个点的 y 在 0-100 变化,对应着90-180度*/
  /* clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%); */
  
  /* 第五个点 x 在 100-0 变化,对应着 180-270度*/
  /* clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 10% 100%); */
  
  /* 第六个点 y 在 100-0 变化,对应着 270-360度*/
  /* clip-path: polygon(50% 50%, 0 0, 100% 0, 100% 100%, 0 100%, 0 10%); */
}

3. 宽高自适应的正方形

vw

.square1 {
  width: 10%;  /* width: 10vw; */
  height: 10vw;
  background: tomato;
}

margin/padding

利用元素的 margin/padding 百分比是相对父元素 width 的性质来实现。

.square2 {
  width: 20%;
  height: 0;
  padding-top: 20%;
  background: orange;
}

margin-top

利用子元素的 margin-top 的值来实现。

.square3 {
  width: 30%;
  overflow: hidden;
  background: yellow;
}
.square3::after {
  content: '';
  display: block;
  margin-top: 100%;
}

布局

1. 水平居中

子元素是行内元素

  • 父元素是块级元素
    父元素设置text-align: center
    <div class="horizontally_parent1">
      <span>我是行内元素</span>
    </div>
    <style>
      .horizontally_parent1 {
        width: 200px;
        text-align: center;
      }
    </style>
    
  • 父元素不是块级元素
    先将父元素设置为块级元素,再将父元素设置text-align: center
    <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. 水平垂直居中

绝对定位 ➕ 负边距

父元素、子元素都有宽高

<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

父元素、子元素都有宽高

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

问题 (2).png 绝对定位是相对于哪个元素进行计算的呢?
相对于最近的非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>

持续补充中......加油.png