移動端佈局面試題 全面考察你的CSS功底(居中篇)

語言: CN / TW / HK

前言

由於移動網際網路的飛速發展,現在基本沒有哪個前端說自己只開發 PC 端,移動端什麼的我不管。

甚至好多前端主要的工作內容就是開發移動端,因為移動端的內容五花八門:微信小程式、支付寶小程式、京東小程式、快應用、微信公眾平臺、微信小遊戲、混合App、H5等…

開啟招聘軟體,可以看到目前的崗位對前端的要求是越來越高了,上天入地無所不能,螢幕前的你也可以開啟軟體看一眼要求,是不是至少都有類似這麼幾條中的一兩個:熟練掌握移動端前端技術、有微信小程式開發經驗優先、有混合App開發經驗優先,即使不是那種專門做移動端網站的公司,有不少也都寫著會移動端優先…

所以移動端的佈局就至關重要了,因為無論一個網站的頁面背後有著多麼複雜的互動邏輯、多龐大的使用者量、多麼海量的資料、多麼高的併發… 它終究還是得有個頁面吧!不能讓使用者一訪問網站就直接給人家看資料庫吧!

有人的地方就有江湖 有頁面的地方就有佈局

佈局可不僅僅只是把資料整齊的羅列在頁面上這麼簡單,一個合適的佈局可以令使用者的操作非常順暢。同時在不同的場景下也應選擇不同的佈局,如果選錯佈局的話很可能會導致使用者對頁面的操作不那麼的絲滑,哪怕最初呈現出來的資料都是一樣的。

由於移動端的螢幕並不像電腦螢幕那麼大,而且長寬比也有很大的區別,所以造就了移動端佈局與 PC 端佈局有著很大的不同,那麼接下來我們就來看一下各式各樣的常見佈局。

居中佈局

其實居中佈局大家在日常生活中基本都見過,只是當時沒怎麼留意罷了。

沒給使用者留下深刻印象的佈局反而是好佈局,因為使用者的注意力都在內容上了,證明此時的佈局令使用者操作順暢。

而給使用者留下印象的佈局一般就不太好了(一些與眾不同的炫酷佈局除外):

這個按鈕怎麼放這了,我都誤碰好幾次了;關閉按鈕在哪呢?怎麼關啊這個;這個商品的簡介在哪呢?應該點哪購買啊?這個佈局怎麼這麼亂看的我都暈了,哎算了算了,以後不來這個網站了……

不同的佈局用來對應不同的場景,用對場景的話會令使用者的操作比較舒服順暢,但用錯場景的話使用者可能會有些懵,不利於引導使用者按自己想要的方式去操作。

這種佈局是主內容處於頁面的正中央位置,常見於登入、註冊、提示使用者、或點選頭像檢視大圖等場景,通常會新增一層灰色的透明遮罩:

這麼做的目的除了突出主題之外,還有一個比較重要的點就是可以令使用者感覺到自己並沒有離開當前頁面,只不過是在當前頁面中出現了一個小框而已,這樣可以有效減少使用者的陌生感。

不僅如此,居中佈局還能夠有效引導使用者進行自己希望使用者所進行的操作,用強烈的對比感去引導使用者:

利用CSS庫實現

藉助市面上已有的 CSS 庫,我們可以很輕易的做到居中佈局,尤其是可以用到中文關鍵字,這非常有利於我們的記憶,它就是 chinese-layout

然後我們再用一箇中文漸變色的 CSS 庫來美化我們的介面:chinese-gradient

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 在這裡用link標籤引入中文佈局 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/chinese-layout">

  <!-- 在這裡用link標籤引入中文漸變色 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/chinese-gradient">
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示 */
    html, body { height: 100%; }

    body {
      /* 先在父元素上設定grid佈局 */
      display: grid;
      grid: var(--居中);

      /* 給個好看的漸變色 */
      background: var(--霾灰);
    } 

    .center {
      /* 指定子元素在中心位置 */
      grid-area: 中;

      /* 給子元素設定寬高,不然寬高為0導致什麼也看不見 */
      width: 150px;
      height: 150px;

      /* 給一個好看的背景色 */
      background: var(--胭脂粉);
    }
  </style>
</head>
<body>
  <div class="center"></div>
</body>
</html>
複製程式碼

執行結果:

絕對定位實現

居中佈局通常分為兩種,一種是固定寬高,另一種是非固定寬高。

固定寬高很好理解,顧名思義就是寬高都寫死。 而非固定寬高通常都是靠裡面的內容來撐起盒子的高度,內容時多時少。

這兩種方式也造就了不一樣的技術實現,絕對定位法適合固定寬高:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示, 並有一個灰色背景 */
    html, body { height: 100%; background: gray; }

    /* 先在父元素上設定相對定位 */
    body { position: relative } 

    .center {
      /* 絕對定位 */
      position: absolute;

      /* 上下左右全部為0 */
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;

      /* 給定寬高 */
      width: 70%;
      height: 25%;

      /* 令外邊距自動填充 */
      margin: auto;

      /* 白色背景 */
      background: white;
    }
  </style>
</head>
<body>
  <div class="center"></div>
</body>
</html>
複製程式碼

執行結果:

  • 如果不給定寬高,盒子將會和父元素一樣大,因為絕對定位上下左右都是 0,意為緊貼著父元素的邊。
  • 給了固定寬高,但沒寫 margin 的話盒子會固定在左上角,因為 top 和 left 的優先順序更高。
  • 給了 margin: auto; 的話,瀏覽器會自動填充邊距,令其居中。
  • 此種實現方式優點是相容性很好,幾乎沒用到任何 CSS 的新特性,全部都是經典屬性。

絕對定位 + 負邊距

此種方法也是適用於固定寬高:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示, 並有一個灰色背景 */
    html, body { height: 100%; background: gray; }

    /* 先在父元素上設定相對定位 */
    body { position: relative }

    .center {
      /* 絕對定位 */
      position: absolute;

      /* 上方和左方為50% */
      top: 50%;
      left: 50%;

      /* 給定寬高 */
      width: 300px;
      height: 200px;

      /* 上外邊距為負的給定高度的一半 */
      margin-top: -100px;

      /* 左外邊距為負的給定寬度的一半 */
      margin-left: -150px;

      /* 白色背景 */
      background: white;
    }
  </style>
</head>
<body>
  <div class="center"></div>
</body>
</html>
複製程式碼

執行結果:

⚠️ 注意,"絕對定位+負邊距"這種方法不適合那種寬百分之多少、高百分之多少這種相對單位,取而代之的是具體的數值。

因為邊距的百分比和寬高的百分比相對的不是同一參考物,它是相對於父元素的寬來計算的,這點要注意。

絕對定位 + 平移

有時中間盒子的內容是要靠後臺傳過來的資料決定的,如果寫死的話,當資料較多時就會發生溢位,資料較少時又會空出一大片,所以我們需要一種更加智慧的方式來實現居中佈局。

絕對定位 + 平移絕對定位 + 負邊距的改進版,那麼具體都改進了哪些方面呢? 負邊距的百分比並不是相對於自身,而是相對於父元素,所以只能寫具體的畫素值,顯得不夠智慧。

而平移相對於自身,只需要無腦寫 -50% 就可以了:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示, 並有一個灰色背景 */
    html, body { height: 100%; background: gray; }

    /* 先在父元素上設定相對定位 */
    body { position: relative }

    .center {
      /* 絕對定位 */
      position: absolute;

      /* 上方和左方為50% */
      top: 50%;
      left: 50%;

      /* 不用給寬高,但是可以給個內邊距防止內容與盒子過於貼合 */
      padding: 10px;

      /* 這個50%是相對於自身寬高而言的 */
      transform: translate(-50%, -50%);

      /* 白色背景 */
      background: white;
    }
  </style>
</head>
<body>
  <div class="center">
    用內容撐開盒子
  </div>
</body>
</html>
複製程式碼

執行結果:

  • margin 的百分比是相對於父元素的寬;
  • translate 函式的百分比是相對於自身;
  • 不僅適用於未知寬高,也同樣適用於固定寬高的居中佈局。

網格 Grid 實現

大家可能或多或少聽過一些 Grid 的大名,深入瞭解過的人會覺得它很強大,但沒深入瞭解過的人對它的印象可能就是:相容性不好

但隨著時間的推移,在移動端只要不考慮特別低版本的手機的話基本上都可以用了。

即使你對 Grid 沒什麼興趣,覺得在移動端用 Flex 就已經足夠了的。把它最簡單的用法記住了也不會費太大勁。因為畢竟如果你能給面試官寫出一個最新的技術,面試官也會對你刮目相看的:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示, 並有一個灰色背景 */
    html, body { height: 100%; background: gray; }

    /* 中央盒子的直接父元素 */
    body {
      /* 令其變成網格佈局 */
      display: grid;

      /* 令其子元素居中 */
      place-items: center;
    }

    .center {
      /* 不用給寬高,但是可以給個內邊距防止內容與盒子過於貼合 */
      padding: 10px;
      
      /* 白色背景 */
      background: white;
    }
  </style>
</head>
<body>
  <div class="center">用內容撐開盒子</div>
</body>
</html>
複製程式碼

執行結果: 其實關鍵程式碼異常的簡單,幾乎沒什麼特別大的學習成本,就這麼兩行:

/* 令其變成網格佈局 */
display: grid;

/* 令其子元素居中 */
place-items: center;
複製程式碼

Flex 彈性盒子

移動端佈局王者 Flex :

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    /* 令html和body全屏顯示, 並有一個灰色背景 */
    html, body { height: 100%; background: gray; }

    /* 找到中央盒子的直接父元素 */
    body {
      /* 令其變成彈性佈局 */
      display: flex;
    }

    .center {
      /* 自動外邊距 */
      margin: auto;

      /* 白色背景 */
      background: white;

      /* 不用給寬高,但是可以給個內邊距防止內容與盒子過於貼合 */
      padding: 10px;
    }
  </style>
</head>
<body>
  <div class="center">用內容撐開盒子</div>
</body>
</html>
複製程式碼

執行結果: Flex 幾乎沒有不會的吧?超級好用,簡單實惠又便捷,如果這個都不會的話可以去看看阮一峰老師的部落格,裡面有著很詳細的入門教程:

另外,張鑫旭的部落格寫的也很不錯:

表格佈局

在居中佈局這種場景下,表格佈局也很適用:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 清除預設樣式 */
    * { padding: 0; margin: 0; }

    body {
      /* 令body全屏顯示 */
      width: 100vw;
      height: 100vh;

      /* 顯示為表格的格子 */
      display: table-cell;

      /* 水平居中 */
      text-align: center;

      /* 垂直居中 */
      vertical-align: middle;

      /* 灰色背景 */
      background: gray;
    }

    .center {
      /* 顯示為行內塊元素 */
      display: inline-block;

      /* 不用給寬高,但是可以給個內邊距防止內容與盒子過於貼合 */
      padding: 10px;

      /* 白色背景 */
      background: white;
    }
  </style>
</head>
<body>
  <div class="center">用內容撐開盒子</div>
</body>
</html>
複製程式碼

執行結果: 此佈局的關鍵點在於:

  • 父元素上 3 個樣式設定:

    • display: table-cell;
    • text-align: center;
    • vertical-align: center;
  • 子元素上設定:

    • display: inline-block;

結語

看完這些有沒有很鬱悶,一個小小的居中佈局都這麼多種實現方式,而且這還不是全部的實現方式,我只挑了幾款市面上常見的,可能大家會覺得有這個必要記這麼多嘛!

其實這個問題就顯得仁者見仁智者見智了,一方面面試造火箭,工作擰螺絲的現狀讓大家很苦惱。明明覺得自己技術還不錯,至少公司要的都能給實現出來,但面試的時候面對面試官的刁難自己卻無能為力。

也許下一次面試時並不會遇到一個面試官讓你以各種方式實現居中佈局,但開拓一下眼界總是好的,因為變換一下思路有助於大家在遇見覆雜佈局的時候可以快速選型。

該文章首發於前端學不動公眾號

對了,這篇文章是連載形式的,居中佈局僅僅只是一個開始,點贊 + 關注 我們下個佈局見!

往期精彩文章