剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

神三元發表於2019-10-13

一、讓一個元素水平垂直居中,到底有多少種方案?

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

水平居中

  • 對於行內元素: text-align: center;

  • 對於確定寬度的塊級元素:

  1. width和margin實現。margin: 0 auto;

  2. 絕對定位和margin-left: -width/2, 前提是父元素position: relative

  • 對於寬度未知的塊級元素
  1. table標籤配合margin左右auto實現水平居中。使用table標籤(或直接將塊級元素設值為display:table),再通過給該標籤新增左右margin為auto。

  2. inline-block實現水平居中方法。display:inline-block和text-align:center實現水平居中。

  3. 絕對定位+transform,translateX可以移動本身元素的50%。

  4. flex佈局使用justify-content:center

垂直居中

  1. 利用line-height實現居中,這種方法適合純文字類

  2. 通過設定父容器相對定位,子級設定絕對定位,標籤通過margin實現自適應居中

  3. 彈性佈局flex:父級設定display: flex; 子級設定margin為auto實現自適應居中

  4. 父級設定相對定位,子級設定絕對定位,並且通過位移transform實現

  5. table佈局,父級通過轉換成表格形式,然後子級設定vertical-align實現。(需要注意的是:vertical-align: middle使用的前提條件是內聯元素以及display值為table-cell的元素)。

二、浮動佈局的優點?有什麼缺點?清除浮動有哪些方式?

浮動佈局簡介:當元素浮動以後可以向左或向右移動,直到它的外邊緣碰到包含它的框或者另外一個浮動元素的邊框為止。元素浮動以後會脫離正常的文件流,所以文件的普通流中的框就變現的好像浮動元素不存在一樣。

優點

這樣做的優點就是在圖文混排的時候可以很好的使文字環繞在圖片周圍。另外當元素浮動了起來之後,它有著塊級元素的一些性質例如可以設定寬高等,但它與inline-block還是有一些區別的,第一個就是關於橫向排序的時候,float可以設定方向而inline-block方向是固定的;還有一個就是inline-block在使用時有時會有空白間隙的問題

缺點

最明顯的缺點就是浮動元素一旦脫離了文件流,就無法撐起父元素,會造成父級元素高度塌陷。

清除浮動的方式

  1. 新增額外標籤
<div class="parent">
    //新增額外標籤並且新增clear屬性
    <div style="clear:both"></div>
    //也可以加一個br標籤
</div>
複製程式碼
  1. 父級新增overflow屬性,或者設定高度
<div class="parent" style="overflow:hidden">//auto 也可以
    //將父元素的overflow設定為hidden
    <div class="f"></div>
</div>
複製程式碼
  1. 建立偽類選擇器清除浮動(推薦)
//在css中新增:after偽元素
.parent:after{
    /* 設定新增子元素的內容是空 */
      content: '';  
      /* 設定新增子元素為塊級元素 */
      display: block;
      /* 設定新增的子元素的高度0 */
      height: 0;
      /* 設定新增子元素看不見 */
      visibility: hidden;
      /* 設定clear:both */
      clear: both;
}
<div class="parent">
    <div class="f"></div>
</div>
複製程式碼

三、 使用display:inline-block會產生什麼問題?解決方法?

問題復現

問題: 兩個display:inline-block元素放到一起會產生一段空白。

如程式碼:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
      .container {
        width: 800px;
        height: 200px;
      }

      .left {
        font-size: 14px;
        background: red;
        display: inline-block;
        width: 100px;
        height: 100px;
      }

      .right {
        font-size: 14px;
        background: blue;
        display: inline-block;
        width: 100px;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="left"></div>
      <div class="right"></div>
    </div>
  </body>
</html>
複製程式碼

效果如下:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

產生空白的原因

元素被當成行內元素排版的時候,元素之間的空白符(空格、回車換行等)都會被瀏覽器處理,根據CSS中white-space屬性的處理方式(預設是normal,合併多餘空白),原來HTML程式碼中的回車換行被轉成一個空白符,在字型不為0的情況下,空白符佔據一定寬度,所以inline-block的元素之間就出現了空隙。

解決辦法

1. 將子元素標籤的結束符和下一個標籤的開始符寫在同一行或把所有子標籤寫在同一行

<div class="container">
  <div class="left"></div><div class="right"></div>
</div>
複製程式碼

2. 父元素中設定font-size: 0,在子元素上重置正確的font-size

.container{
  width:800px;
  height:200px;
  font-size: 0;
}
複製程式碼

3. 為子元素設定float:left

.left{
  float: left;
  font-size: 14px;
  background: red;
  display: inline-block;
  width: 100px;
  height: 100px;
}
//right是同理
複製程式碼

四、佈局題:div垂直居中,左右10px,高度始終為寬度一半

問題描述: 實現一個div垂直居中, 其距離螢幕左右兩邊各10px, 其高度始終是寬度的50%。同時div中有一個文字A,文字需要水平垂直居中。

思路一:利用height:0; padding-bottom: 50%;

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
      *{
        margin: 0;
        padding: 0;
      }
      html, body {
        height: 100%;
        width: 100%;
      }
      .outer_wrapper {
        margin: 0 10px;
        height: 100%;
        /* flex佈局讓塊垂直居中 */
        display: flex;
        align-items: center;
      }
      .inner_wrapper{
        background: red;
        position: relative;
        width: 100%;
        height: 0;
        padding-bottom: 50%;
      }
      .box{
        position: absolute;
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 20px;
      }
    </style>
  </head>
  <body>
    <div class="outer_wrapper">
      <div class="inner_wrapper">
        <div class="box">A</div>
      </div>
    </div>
  </body>
</html>
複製程式碼

強調兩點:

  1. padding-bottom究竟是相對於誰的?

答案是相對於父元素的width值

那麼對於這個out_wrapper的用意就很好理解了。 CSS呈流式佈局,div預設寬度填滿,即100%大小,給out_wrapper設定margin: 0 10px;相當於讓左右分別減少了10px。

  1. 父元素相對定位,那絕對定位下的子元素寬高若設為百分比,是相對誰而言的?

相對於父元素的(content + padding)值, 注意不含border

延伸:如果子元素不是絕對定位,那寬高設為百分比是相對於父元素的寬高,標準盒模型下是content, IE盒模型是content+padding+border。

思路二: 利用calc和vw

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }

      html,
      body {
        width: 100%;
        height: 100%;
      }

      .wrapper {
        position: relative;
        width: 100%;
        height: 100%;
      }

      .box {
        margin-left: 10px;
        /* vw是視口的寬度, 1vw代表1%的視口寬度 */
        width: calc(100vw - 20px);
        /* 寬度的一半 */
        height: calc(50vw - 10px);
        position: absolute;
        background: red;
        /* 下面兩行讓塊垂直居中 */
        top: 50%;
        transform: translateY(-50%);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 20px;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <div class="box">A</div>
    </div>
  </body>
</html>
複製程式碼

效果如下:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

五、CSS如何進行品字佈局?

第一種

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>品字佈局</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    body {
      overflow: hidden;
    }
    div {
      margin: auto 0;
      width: 100px;
      height: 100px;
      background: red;
      font-size: 40px;
      line-height: 100px;
      color: #fff;
      text-align: center;
    }

    .div1 {
      margin: 100px auto 0;
    }

    .div2 {
      margin-left: 50%;
      background: green;
      float: left;
      transform: translateX(-100%);
    }

    .div3 {
      background: blue;
      float: left;
      transform: translateX(-100%);
    }
  </style>
</head>

<body>
  <div class="div1">1</div>
  <div class="div2">2</div>
  <div class="div3">3</div>
</body>

</html>
複製程式碼

效果:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

第二種(全屏版)

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>品字佈局</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      div {
        width: 100%;
        height: 100px;
        background: red;
        font-size: 40px;
        line-height: 100px;
        color: #fff;
        text-align: center;
      }

      .div1 {
        margin: 0 auto 0;
      }

      .div2 {
        background: green;
        float: left;
        width: 50%;
      }

      .div3 {
        background: blue;
        float: left;
        width: 50%;
      }
    </style>
  </head>

  <body>
    <div class="div1">1</div>
    <div class="div2">2</div>
    <div class="div3">3</div>
  </body>
</html>
複製程式碼

效果:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

六、CSS如何進行聖盃佈局

聖盃佈局如圖:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

而且要做到左右寬度固定,中間寬度自適應。

1.利用flex佈局

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
    *{
      margin: 0;
      padding: 0;
    }
    .header,.footer{
        height:40px;
        width:100%;
        background:red;
    }
    .container{
        display: flex;
    }
    .middle{
        flex: 1;
        background:yellow;
    }
    .left{
        width:200px;
        background:pink;
    }
    .right{
        background: aqua;
        width:300px;
    }
	</style>
</head>
<body>
    <div class="header">這裡是頭部</div>
    <div class="container">
        <div class="left">左邊</div>
        <div class="middle">中間部分</div>
        <div class="right">右邊</div>
    </div>
    <div class="footer">這裡是底部</div>
</body>
</html>
複製程式碼

2.float佈局(全部float:left)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .header,
    .footer {
      height: 40px;
      width: 100%;
      background: red;
    }

    .footer {
      clear: both;
    }

    .container {
      padding-left: 200px;
      padding-right: 250px;
    }

    .container div {
      position: relative;
      float: left;
    }

    .middle {
      width: 100%;
      background: yellow;
    }

    .left {
      width: 200px;
      background: pink;
      margin-left: -100%;
      left: -200px;
    }

    .right {
      width: 250px;
      background: aqua;
      margin-left: -250px;
      left: 250px; 
    }
  </style>
</head>

<body>
  <div class="header">這裡是頭部</div>
  <div class="container">
    <div class="middle">中間部分</div>
    <div class="left">左邊</div>
    <div class="right">右邊</div>
  </div>
  <div class="footer">這裡是底部</div>
</body>

</html>
複製程式碼

這種float佈局是最難理解的,主要是浮動後的負margin操作,這裡重點強調一下。

設定負margin和left值之前是這樣子:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

左邊的盒子設定margin-left: -100%是將盒子拉上去,效果:

.left{
  /* ... */
  margin-left: -100%;
}
複製程式碼

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

然後向左移動200px來填充空下來的padding-left部分

.left{
  /* ... */
  margin-left: -100%;
  left: -200px;
}
複製程式碼

效果呈現:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

右邊的盒子設定margin-left: -250px後,盒子在該行所佔空間為0,因此直接到上面的middle塊中,效果:

.right{
  /* ... */
  margin-left: -250px;
}
複製程式碼

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

然後向右移動250px, 填充父容器的padding-right部分:

.right{
  /* ... */
  margin-left: -250px;
  left: 250px;
}
複製程式碼

現在就達到最後的效果了:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

3.float佈局(左邊float: left, 右邊float: right)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .header,
    .footer {
      height: 40px;
      width: 100%;
      background: red;
    }
    .container{
      overflow: hidden;
    }

    .middle {
      background: yellow;
    }

    .left {
      float: left;
      width: 200px;
      background: pink;
    }

    .right {
      float: right;
      width: 250px;
      background: aqua;
    }
  </style>
</head>

<body>
  <div class="header">這裡是頭部</div>
  <div class="container">
    <div class="left">左邊</div>
    <div class="right">右邊</div>
    <div class="middle">中間部分</div>
  </div>
  <div class="footer">這裡是底部</div>
</body>

</html>
複製程式碼

4. 絕對定位

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .header,
    .footer {
      height: 40px;
      width: 100%;
      background: red;
    }
    .container{
      min-height: 1.2em;
      position: relative;
    }

    .container>div {
      position: absolute;
    }

    .middle {
      left: 200px;
      right: 250px;
      background: yellow;
    }

    .left {
      left: 0;
      width: 200px;
      background: pink;
    }

    .right {
      right: 0;
      width: 250px;
      background: aqua;
    }
  </style>
</head>

<body>
  <div class="header">這裡是頭部</div>
  <div class="container">
    <div class="left">左邊</div>
    <div class="right">右邊</div>
    <div class="middle">中間部分</div>
  </div>
  <div class="footer">這裡是底部</div>
</body>

</html>
複製程式碼

5.grid佈局

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    body{
        display: grid;
    }
    #header{
        background: red;
        grid-row:1;
        grid-column:1/5;
    }
        
    #left{
        grid-row:2;
        grid-column:1/2;
        background: orange;
    }
    #right{
        grid-row:2;
        grid-column:4/5;
        background: cadetblue;
    }
    #middle{
        grid-row:2;
        grid-column:2/4;
        background: rebeccapurple
    }
    #footer{
        background: gold;
        grid-row:3;
        grid-column:1/5;
    }
  </style>
</head>

<body>
    <div id="header">header</div>
    <div id="left">left</div>
    <div id="middle">middle</div>
    <div id="right">right</div>     
    <div id="footer">footer</footer></div>
       
</body>

</html>
   
複製程式碼

看看grid佈局,其實也挺簡單的吧,裡面的引數應該不言而喻了。

另外說一點,到2019年為止,grid現在絕大多數瀏覽器已經可以相容了,可以著手使用了。

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

當然,還有table佈局,年代比較久遠了,而且對SEO不友好,知道就可以,這裡就不浪費篇幅了。

七、CSS如何實現雙飛翼佈局?

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

有了聖盃佈局的鋪墊,雙飛翼佈局也就問題不大啦。這裡採用經典的float佈局來完成。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .container {
        min-width: 600px;
    }
    .left {
        float: left;
        width: 200px;
        height: 400px;
        background: red;
        margin-left: -100%;
    }
    .center {
        float: left;
        width: 100%;
        height: 500px;
        background: yellow;
    }
    .center .inner {
        margin: 0 200px; 
    }
    .right {
        float: left;
        width: 200px;
        height: 400px;
        background: blue;
        margin-left: -200px;
    }
  </style>
</head>

<body>
  <article class="container">
    <div class="center">
        <div class="inner">雙飛翼佈局</div>
    </div>
    <div class="left"></div>
    <div class="right"></div>
</article>
</body>

</html>
複製程式碼

八、什麼是BFC?什麼條件下會觸發?渲染規則?應用場景有哪些?

1.什麼是BFC?

W3C對BFC的定義如下: 浮動元素和絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不為"visiable"的塊級盒子,都會為他們的內容建立新的BFC(Block Fromatting Context, 即塊級格式上下文)。

2.觸發條件

一個HTML元素要建立BFC,則滿足下列的任意一個或多個條件即可: 下列方式會建立塊格式化上下文:

  • 根元素()
  • 浮動元素(元素的 float 不是 none)
  • 絕對定位元素(元素的 position 為 absolute 或 fixed)
  • 行內塊元素(元素的 display 為 inline-block)
  • 表格單元格(元素的 display為 table-cell,HTML表格單元格預設為該值)
  • 表格標題(元素的 display 為 table-caption,HTML表格標題預設為該值)
  • 匿名錶格單元格元素(元素的 display為 table、table-row、 table-row-group、table-header-group、table-footer-group(分別是HTML table、row、tbody、thead、tfoot的預設屬性)或 inline-table)
  • overflow 值不為 visible 的塊元素 -彈性元素(display為 flex 或 inline-flex元素的直接子元素)
  • 網格元素(display為 grid 或 inline-grid 元素的直接子元素) 等等。

3.BFC渲染規則

(1)BFC垂直方向邊距重疊

(2)BFC的區域不會與浮動元素的box重疊

(3)BFC是一個獨立的容器,外面的元素不會影響裡面的元素

(4)計算BFC高度的時候浮動元素也會參與計算

4.應用場景

1. 防止浮動導致父元素高度塌陷

現有如下頁面程式碼:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
      .container {
        border: 10px solid red;
      }
      .inner {
        background: #08BDEB;
        height: 100px;
        width: 100px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="inner"></div>
    </div>
  </body>
</html>
複製程式碼

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航
接下來將inner元素設為浮動:

  .inner {
    float: left;
    background: #08BDEB;
    height: 100px;
    width: 100px;
  }
複製程式碼

會產生這樣的塌陷效果:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

但如果我們對父元素設定BFC後, 這樣的問題就解決了:

.container {
    border: 10px solid red;
    overflow: hidden;
}
複製程式碼

同時這也是清除浮動的一種方式。

2. 避免外邊距摺疊

兩個塊同一個BFC會造成外邊距摺疊,但如果對這兩個塊分別設定BFC,那麼邊距重疊的問題就不存在了。

現有程式碼如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .container {
      background-color: green;
      overflow: hidden;
    }

    .inner {
      background-color: lightblue;
      margin: 10px 0;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="inner">1</div>
    <div class="inner">2</div>
    <div class="inner">3</div>
  </div>
</body>

</html>
複製程式碼

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航

此時三個元素的上下間隔都是10px, 因為三個元素同屬於一個BFC。 現在我們做如下操作:

  <div class="container">
    <div class="inner">1</div>
    <div class="bfc">
      <div class="inner">2</div>
    </div>
    <div class="inner">3</div>
  </div>
複製程式碼

style增加:

.bfc{
    overflow: hidden;
}
複製程式碼

效果如下:

剖析一些經典的CSS佈局問題,為前端開發+面試保駕護航
可以明顯地看到間隔變大了,而且是原來的兩倍,符合我們的預期。

關於CSS佈局問題,先分享到這裡,後續會不斷地補充,希望對你有所啟發。如果對你有幫助的話,別忘了幫忙點個贊哦。

參考文獻:

如何居中一個元素(終結版)

深入理解BFC

CSS三欄佈局的4種方法

相關文章