前端響應式佈局原理與實踐

xmanlin發表於2020-03-06

前言

作為一個前端開發者,響應式網站開發是必備技能之一。響應式有它的很好的優點,也有它一定的缺點。這就需要我們在開發的時候做出取捨。對於內容較少、主要為展示類網站,故採用響應式;對於內容多,管理類的網站採用分開開發的方式,不同裝置採用不同的一套程式碼。本文會主要探討響應式佈局原理和技巧,並結合例項來加深印象。

響應式與自適應

我們很多人其實把這響應式和自適應兩種網站當成一回事,但事實上這兩種網站的佈局方式是有一定的區別的。我們可以來看看這兩種方法的概念以及分別對應解決的問題。

什麼是響應式佈局?

響應式佈局就是一個網站能夠相容多個終端,可以根據螢幕的大小自動調整頁面的的展示方式以及佈局,我們不用為每一個終端做一個特定的版本。響應式網站的幾個標誌:

  1. 同時適配PC + 平板 + 手機等;
  2. 標籤導航在接近手持終端裝置時改變為經典的抽屜式導航;
  3. 網站的佈局會根據視口來調整模組的大小和位置;
    在這裡插入圖片描述

什麼是自適應佈局?

自適應佈局是指網頁能夠在不同大小的終端裝置上自行適應顯示,也就是讓一個網站在不同大小的裝置上顯示同一樣的頁面,讓同一個頁面適應不同大小螢幕,根據螢幕的大小,自動縮放。自適應佈局的幾個標誌:

  1. 大多隻是適配單個終端的主流N個主流視口;
  2. 當視口大小低於設定的最小視口時,介面會出現顯示不全,並且出現橫向滑動條;
  3. 總體框架不變,橫線佈局的版塊太多會有所減少。
    在這裡插入圖片描述

如何選擇

總的來說,這兩種方式的原來是相似的,都是先檢測裝置,根據不同的裝置採用不同的CSS。那開發中我們該如何去選擇?這就要結合響應式與自適應的優缺點來看。

響應式佈局的優點: 1、靈活性強;2、能夠快捷解決多裝置顯示適用問題。

缺點: 1、效率較低,相容各裝置工作量大;2、程式碼較為累贅,載入時間會加長;3、在一定程度上改變了網站原有的佈局結構。

自適應佈局的優點: 1、對網站複雜程度相容更大;2、程式碼更高效;3、測試和運營都相對容易和精準。

缺點: 1、同一個網站需要為不同的裝置開發不同的頁面,增加的開發的成本。

上面兩種方法各有自己的優缺點,所以我們在開發的時候,要從實際的專案出發。對於頁面不是太複雜的情況下,我們可以利用響應式佈局;而對於頁面中資訊較多,佈局較為複雜的情況,我們可以採用自適應佈局的方式。

響應式佈局設計步驟

介紹完基本的概念,我們來看看響應式佈局的基本步驟,主要分為下面幾步: 1.設定meta標籤

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
複製程式碼

2.使用@Media查詢來設定樣式,這是響應式佈局的核心

@media screen and (max-width: 1920px) { ... }
複製程式碼

3.設定佈局分界點,即通過設定多種檢視寬度樣式來控制頁面佈局

@media screen and (max-width: 1920px) { ... }

@media screen and (max-width: 1700px) { ... }
複製程式碼

其實還是很簡單的,就是在適配的時候稍微有點點繁瑣。

佈局分界點

對於@Media查詢的分界點,這個可以根據自己的專案來調整,設定合適自己專案的佈局分界點。在設定分界點時,要注意先後順序,當使用max-width數值大的在前面,數值小的在後面;當使用min-width時,數值小的放前面,數值大的放後面。下面列出了我在專案開發時所設定的部分佈局分界點:

@media screen and (max-width: 1920px) { ... }

@media screen and (max-width: 1700px) { ... }

@media screen and (max-width: 1600px) { ... }

@media screen and (max-width: 1440px) { ... }

@media screen and (max-width: 1280px) { ... }

@media screen and (min-width: 992px) and (max-width: 1200px) { ... }

@media screen and (min-width: 768px) and (max-width: 991px) { ... }

@media screen and (max-width: 767px) { ... }
複製程式碼

那我們什麼時候用min-width,什麼時候用max-width呢?通常來說,如果是移動端優先,則用min-width;如果是PC端優先,則用max-width

佈局單位

熟悉常用的佈局單位還是很重要的,常用的佈局單位包括畫素(px),百分比(%),emremvw/vh。我們可以合理的運用這些佈局解決方案,來提高我們開發時的效率和質量。

畫素

畫素是網頁佈局的基礎,一個畫素表示計算機螢幕所能顯示的最小區域。畫素分為兩種型別:css畫素和物理畫素。兩者區別如下:

css畫素:為web開發者提供,在css中使用的一個抽象單位; 物理畫素:只與裝置的硬體密度有關,任何裝置的物理畫素都是固定的。

百分比

當瀏覽器的寬度或者高度發生變化時,通過百分比單位可以使得瀏覽器中的元件的寬和高隨著瀏覽器的變化而變化,從而實現響應式的效果。一般我們的直觀理解都會認為子元素的百分比完全相對於直接父元素,這種理解沒問題,比如heightwidth屬性。但是在css的盒模型中不止有heightwidth屬性,還有paddingbordermargin等屬性,所以這就值得我們去具體分析一下。

我們先寫好html程式碼,然後通過不同的css程式碼來看看會呈現出什麼樣的情況:

<div class="parent">
    <div class="child">子元素</div>
</div>
複製程式碼

1.子元素的height和width

當子元素的heightwidth使用百分比時,是相對於直接父元素的heightwidth進行變化的。

.parent{
    width: 200px;
    height: 200px;
    background: #aaaaaa;
}
.child{
    width: 50%;
    height: 50%;
    background: red;
}
複製程式碼

在這裡插入圖片描述

2.子元素的top、bottom 、left和right

子元素的topbottom如果設定百分比,則相對於直接非static定位(預設定位)的父元素的高度; 子元素的leftright如果設定百分比,則相對於直接非static定位(預設定位的)父元素的寬度。

.parent{
    width: 200px;
    height: 200px;
    background: #aaaaaa;
    position: relative;
}
.child{
    width: 50%;
    height: 50%;
    background: red;
    position: absolute;
    top: 50%;
    left: 50%;
}
複製程式碼

在這裡插入圖片描述

3.子元素的padding

子元素的padding如果設定百分比,不論是垂直方向或者是水平方向,都相對於直接父親元素的width,而與父元素的height無關。

.parent{
    width: 300px;
    height: 400px;
    background: #aaaaaa;
}
.child{
    width: 50%;
    height: 50%;
    background: red;
    padding-top: 20%;
    padding-left: 20%;
}
複製程式碼

前端響應式佈局原理與實踐

開啟控制檯,檢視子元素,我們可以看見padding-toppadding-left都為父元素width的20% ——60px:

在這裡插入圖片描述

4.子元素的margin

子元素的marginpadding是一樣的,子元素的margin如果設定成百分比,不論是垂直方向還是水平方向,都相對於直接父元素的width

5.子元素的border-radius

border-radius設定為百分比則是相對於自身的寬度

.parent{
    width: 200px;
    height: 200px;
    background: #aaaaaa;
}
.child{
    width: 50%;
    height: 50%;
    background: red;
    border-radius: 50%;
}
複製程式碼

在這裡插入圖片描述

em和rem

emrem相對於px更具靈活性,他們都是相對長度單位,而他們之間的區別可以用一句話來概括:em相對於父元素,rem相對於根元素。 em是相對於父元素的font-sizerem則是相對於html元素的font-size

vw/vh

vw/vh是與檢視視窗有關的單位,vw表示相對於檢視視窗的寬度,vh表示相對於檢視視窗高度,除了vwvh外,還有vminvmax兩個相關的單位。

單位 含義
vw 相對於視窗的寬度,視窗寬度是100vw
vh 相對於視窗的高度,視窗高度是100vh
vmin vw和vh中的較小值
vmax vw和vh中的較大值

這個單位和百分比很類似,但是還是有區別的:

單位 含義
% 大部分相對於祖先元素,也有相對於自身的情況比如(border-radius、translate等)
vw/vm 相對於視窗的尺寸

響應式佈局實踐

好了,說了這麼多,我們現在可以結合上面的理論知識,來完成一個響應式佈局的demo。下面我會貼出部分程式碼來講一些思路,完整的程式碼放在了我的github上面。

初始佈局

首先,我們進行整體的佈局,這個demo主要分為三部分:頭部、內容、底部,類似於簡單的企業官網。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>響應式佈局實踐</title>
    <link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div id="root">
    <!-- 頭部 -->
    <header>
        <div class="header-box">
            <div class="logo">
                logo
            </div>
            <nav class="main-nav">
                <ul class="nav-list">
                    <li id="nav-item" class="main-nav-item">
                        <ul class="nav-main-list">
                            <li class="list-item">首頁</li>
                            <li class="list-item">文章</li>
                            <li class="list-item">論壇</li>
                            <li class="list-item">娛樂</li>
                            <li class="list-item">聯絡</li>
                        </ul>
                    </li>
                    <li class="main-nav-login">
                        <div class="login-box">登入 | 註冊</div>
                    </li>
                </ul>
            </nav>

        </div>
    </header>

    <!-- 內容 -->
    <div id="container">
        <div class="container-header"></div>
        <div class="content">
            <!-- 內容一-->
            <div class="content-box content-box1">
                <div class="content-box1-text"></div>
                <div class="content-box1-img">
                    <div class="img-radius"></div>
                </div>
            </div>
            <!-- 內容二-->
            <div class="content-box content-box2">
                <div class="content-box2-text"></div>
                <div class="content-box2-text"></div>
                <div class="content-box2-text"></div>
            </div>
            <!-- 內容三-->
            <div class="content-box content-box3">
                <div class="content-box3-text"></div>
                <div class="content-box3-text"></div>
                <div class="content-box3-text"></div>
                <div class="content-box3-text"></div>
                <div class="content-box3-text"></div>
                <div class="content-box3-text"></div>
            </div>
        </div>
    </div>

    <!-- 底部 -->
    <footer></footer>
</div>

</body>
</html>
複製程式碼

在這個demo中,最初的css程式碼是在1920px下進行編寫的,這個就是我們的初始樣式。 初始樣式程式碼比較長,就不貼在文章裡面了,看這裡>>> index.css 我們先來看看初始的效果:

在這裡插入圖片描述
在實際開發的時候,有些模組中包含的內容,使得這些模組不能無限制的進行縮小。所以在index.css的初始佈局中,我們對一些模組的大小進行了限制,設定了min-width

中大屏適配

前面我們提到,佈局分界點是要根據實際的專案來進行劃分的,我針對這個專案進行了以下的劃分,大家也可以根據自己的想法來進行劃分。

1201px~1280px

我們先看看把寬度調到1201px時會出現什麼情況:

在這裡插入圖片描述
我們可以看見部分模組超出了父元素的寬度,使得頁面變得參差不齊了,所以我們就要對佈局進行調整了:

@media screen and (max-width: 1280px) {
     /* 內容一  */
    .content-box1{
        flex-wrap: wrap;
        height: 650px;
    }
    .content-box1-text{
        width: 90%;
        margin: 0 auto;
    }
    .content-box1-img{
        display: flex;
        align-items: center;
        margin: 0 auto;
    }
}
複製程式碼

再來看佈局情況:

在這裡插入圖片描述

992px~1200px

這時候出現的情況:

在這裡插入圖片描述
我們看到,佈局又混亂了,然後我們需要繼續調整佈局:

@media screen and (min-width: 992px) and (max-width: 1200px) {
    /* 內容二 */
    .content-box2{
        height: 400px;
    }
    .content-box2-text{
        height: 300px;
        min-width: 200px;
    }

    /* 內容三 */
    .content-box3{
        justify-content: space-around;
    }
}
複製程式碼

再來看看佈局情況:

在這裡插入圖片描述

768px~991px

在這個分界點時,同樣會出現佈局問題,所以要進一步實現調整,因為是重複操作,這裡就不貼圖和程式碼了。我們可以重點看看下面的適配。

手機端適配

在boostrap的柵格系統中,把<768px的螢幕歸為手機。我們也可以以此作為參考。此時佈局調整不僅僅是內容的調整,我們的導航欄也要發生改變——由橫向導航欄變為點選出現的縱向導航欄(具體需求,具體實現,這裡只是提出一種普遍的變換方法)。如下圖所示:

在這裡插入圖片描述
要想實現上圖中的效果我們需要做哪些事情呢?

  1. 寫一個按鈕,如右圖右上角的按鈕,樣子是不是很熟悉;
  2. 導航條樣式重寫,由橫向導航條變為縱向導航條;
  3. 利用js實現點選按鈕,導航條顯示與隱藏的切換。

按鈕

我們先在類名為nav-list的末尾加入以下HTML程式碼:

...

<li class="phone-show">
    <div id="nav-btn" class="nav-btn">
        <span></span>
        <span></span>
        <span></span>
    </div>
</li>

...
複製程式碼

然後對按鈕樣式進行美化:

@media screen and (max-width: 767px){
    ...
    .phone-show{
        display: block;
        height: 60px;
        width: 60px;
    }
    .nav-btn{
        height: 100%;
        width: 100%;
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        justify-content: space-around;
    }
    .nav-btn span{
        display: inline-block;
        height: 10px;
        width: 60px;
        background: coral;
    }
}
複製程式碼

看看效果:

前端響應式佈局原理與實踐

導航樣式修改

這個我們可以巧妙的運用一個相對定位和絕對定位的關係實現導航條樣式和位置的修改:

@media screen and (max-width: 767px){
    .header-box{
        position: relative;
    }
    
    ...
    
    /* 手機端樣式 */
    .main-nav-item{
        display: none;
        position: absolute;
        width: 10rem;
        right: 0;
        top: 8rem;
        border-radius: 0 0 .5rem .5rem;
    }
    .nav-main-list{
        width: 100%;
        background: #ffffff;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        border-radius: 0 0 .5rem .5rem;
    }
    .list-item{
        width: 100%;
        margin: 0 1rem;
        border-bottom: 1px solid #eeeeee;
    }
}
複製程式碼

看看效果:

前端響應式佈局原理與實踐

導航條顯示和隱藏切換

利用js來控制切換的思路很簡單,我們在網頁開啟時,先把導航隱藏掉,然後定義一個變數hide,初始值為true,點選按鈕時進行判斷:如果hide值為true,則讓導航顯示;反之隱藏。

let btn = document.getElementById("nav-btn");
let  nav =  document.getElementById("nav-item");

let hide = true;

btn.addEventListener('click', function () {
    if (hide){
        nav.style.display = "block";
        hide = false;
    } else {
        nav.style.display = "none";
        hide = true;
    }
});
複製程式碼

前端響應式佈局原理與實踐
最後再進行一些細節方面的調整,我們的響應式佈局demo就初步完成了。文章使用了大量flex佈局,雖然用起來很方便,可以提高我們的效率,但是相容性方面在實際開發的時候也是應該去注意的。我們在日常的開發的時候,一般來講不會這麼簡單,所以還是也根據實際情況去進行調整,以滿足實際的需求。 完整demo點選這裡——demo地址

參考

自適應和響應式的區別有哪些你知道嗎?

響應式和自適應有什麼區別?

響應式佈局的常用解決方案對比(媒體查詢、百分比、rem和vw/vh)

最後

文中若有不準確或錯誤的地方,歡迎指出~

相關文章