1. 程式人生 > 其它 >移動Web前端的疑難雜症整理

移動Web前端的疑難雜症整理

移動web頁面多端螢幕適配

邏輯畫素(logical pixel)

CSS畫素就是邏輯畫素,CSS畫素是Web程式設計的概念,在普通螢幕下,1個CSS畫素對應1個物理畫素(1:1)。

邏輯畫素 ≈ 裝置獨立畫素。

裝置畫素比 (device pixel ratio)

裝置畫素比 = 裝置畫素 / 裝置獨立畫素

iphone5 為例: 640X1136 / 320X568 = 2

自適應(Adaptive)方案

應對在瀏覽器的寬度變化不調整網頁元素的位置,縮放網頁元素,以適應在可用空間。

優點:實現簡單,針對移動端進行適配,獨立維護。

缺點:多端的操作可能沒有一致性,無法聚集多端的SEO權重。

使用rem單位,固定頁面寬度居中自適應。

以iphone6為基準,設計稿是750px。

設計稿寬度/100 = 7.5 把1rem=100px轉換,比值是7.5。

也就是 設計稿寬度與rem的比值是7.5。

320px /7.5 = 42.6666(html的font-size值)

寫出不同裝置媒體查詢font-size值。

@media only screen and (min-width: 320px) {
    html {
        font-size: 42.6666px
    }
}

...

設計稿元素高寬/100 就得出元素的高寬rem。

div {
    height: 100px;
    width: 100px;
}

/*轉rem*/

div {
    height: 1rem;
    width: 1rem;
}

使用rem或者em單位的效能略低於px。(原因是px是絕對單位,rem與em是相對單位)

使用rem與em單位效果是差不多,唯一的區別是rem是根據html標籤的字型大小,em是根據相對當前元素(或者是父元素)的字型大小。

延伸:

rem 與 em 轉化 px 單位計算。

/* rem */
html {
    font-size: 16px;
}
div {
    width: 10rem;  /* 16px*10 = 160px; */
    height: 10rem; /* 16px*10 = 160px; */
}

/* em */
.header {
    font-size: 16px;
    width: 100%;
    height: 10em;  /* 16px*10=160px; */
}

響應式(Responsive)方案

應對在瀏覽器的寬度變化通過調整網頁元素的位置,以適應在可用空間。

優點:實現簡單,完美適配各種不同螢幕的,多端的操作一致性,可以聚集多端的SEO權重。

缺點:程式碼量大,不易於維護與除錯。

  1. 使用CSS媒體查詢。

html

<meta name="viewport" content="width=device-width, initial-scale=1.0">

媒體查詢一定要設定meta viewport。

css

.btn {
  width: 140px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  border: 1px solid;
}

@media only screen and (max-width: 768px) {
  .btn {
    width: 120px;
  }
}
@media only screen and (max-width: 375px) {
  .btn {
    width: 80px;
  }
}

注意媒體查詢CSS程式碼順序。

注意@viewport 屬性已經廢棄了。廢棄文件

延伸:

如何優化響應式網站?

根據當前裝置螢幕邏輯畫素對應載入不同的CSS與JavaScript程式碼。

CSS

<!-- 預設文件 -->
<link href="pc.css" rel="stylesheet" media="print">
<!-- 文件寬度小於 600 畫素 -->
<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">

JavaScript

var documentWdith = window.innerWidth|| document.documentElement.clientWidth || document.body.clientWidth;

var el = document.getElementById("canvas");

if(documentWdith<600){
  // 移動裝置方法
  el.addEventListener("touchstart", ()=>{
    // 觸控事件
  });
}else{
  // 電腦裝置方法
  el.addEventListener("click", ()=>{
    // 點選事件
  });
}

*不建議通過UA獲取使用者的瀏覽器資訊,因為很多移動瀏覽器可以設定自定義UA。*

移動端通用相容問題

  1. 點選延時300毫秒。

300原因

*值得慶幸的是,所有移動端瀏覽器都已經解決這個問題了。*

  1. 頁面回彈效果。

如果頁面是全屏,不超過可視高度的話,建議禁用touchmove事件。

如果頁面不是全屏,超過可視高度的話,就不要禁用touchmove事件。

*雖然有辦法阻擋X5核心(QQ瀏覽器核心)的“網頁有XXX提供”的這些資訊,但是並沒有真正阻擋iphone的回彈效果,拖拽還是會回彈。*

延伸:iOS safari 如何阻止“橡皮筋效果”? --知乎)

  1. 頁面返回不重新整理。

往返快取(Back/Forward cache)是瀏覽器的一種瀏覽器記憶體快取機制。

解決方案:

var isPageHide = false;
window.addEventListener("pageshow", function () {
  if (isPageHide) {
    window.location.reload();
  }
});
window.addEventListener("pagehide", function () {
  isPageHide = true;
});
  1. 1px 邊框問題。

由於移動端螢幕的裝置畫素邏輯畫素並不相等,所以產生在某些移動端的螢幕上1px邊框略顯粗。

解決方案:

.row-1px {
    position: relative;
}
.row-1px:after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    border-bottom: 1px solid #e6e6e6;
    color: #000;
    height: 200%;
    -webkit-transform-origin: left top;
    transform-origin: left top;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    pointer-events: none;
    box-sizing: border-box;
}
  1. 輸入法擋住輸入框。

在混合應用開發中,移動端內建瀏覽器元件設定了全屏。那麼問題來了,假如是一個表單頁面,裡面有很多的輸入框,點選最頂部的輸入框的時候,移動端就會喚起輸入法軟體,於是就擋住最底部的輸入框,導致無法看到輸入框裡面的內容。

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
        <title>移動端輸入法擋住輸入框</title>
        <style>
            input {
                width: 100%;
                line-height: 1.5rem;
                border: 1px solid red;
            }
            
            .block-fill {
                height: 500px;
            }
        </style>
    </head>

    <body>

        <div id="main">
            <!--佔位div-->
            <div class="block-fill"></div>
            <!--聚焦(方法一)-->
            <input id="input" type="text"></input>
            <!--聚焦(方法二)-->
            <!--<input id="input" type="text" onfocus="focusInput()"></input>-->
        </div>

    </body>
    <script>
        //方法一:
        //獲取頁面高度
        var clientHeight = document.body.clientHeight;
        //設定監聽聚焦事件
        document.body.addEventListener("focus", function(e) {
            var focusElem = document.getElementById('input')
        }, true);
        //設定監聽視窗變化時間
        window.addEventListener("resize", function() {
            if(focusElem && document.body.clientHeight < clientHeight) {
                //使用scrollIntoView方法來控制輸入框
                focusElem.scrollIntoView(false);
            }
        });
        //方法二:
       //設定監聽聚焦事件,延時滾動螢幕
       funtion focusInput(){
            setTimeout(function() {
                 document.body.scrollTop=document.body.scrollHeight
            }, 100)
       }
    </script>

</html>
  1. 劉海屏適配問題

使用viewport的viewport-fit屬性。

<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">

viewport-fit屬性也是由蘋果公司推出的屬性,並非標準屬性。

使用margin與padding屬性對頁面佈局撐開。

.iphonex-mt{
      margin-top: constant(safe-area-inset-top);
      margin-top: env(safe-area-inset-top);
 }
 .iphonex-mb{
      margin-bottom: constant(safe-area-inset-bottom);
      margin-bottom: env(safe-area-inset-bottom);
 }
 .iphonex-pl{
      padding-left: constant(safe-area-inset-left);
      padding-left: env(safe-area-inset-left);
 }
 .iphonex-pr{
      padding-right: constant(safe-area-inset-right);
      padding-right: env(safe-area-inset-right);
 }

延伸:Designing Websites for iPhone

  1. setTimeout 、setInterval函式凍結問題

PC端瀏覽器(Firefox、Chrome 和 Safari)
場景:瀏覽器最小化、非啟用當前標籤頁面。
例子:非啟用當前標籤頁面執行settimeout小於1秒的定時任務,會調整為1秒。

mobile端瀏覽器(Firefox、Chrome 和 Safari)
場景:瀏覽器進入後臺、非啟用當前標籤頁面。
例子:非啟用當前標籤頁面執行settimeout小於1秒的定時任務,會暫停執行。

解決方案:

  1. 監聽頁面狀態,重置定時任務
document.addEventListener('visibilitychange', function() {     
   if(document.hidden) { 
      // 清除定時器         
   }else { 
      // 重置定時器        
   } 
});
  1. 使用requestIdleCallback函式繼續執行定時任務。

window.requestIdleCallback() - MDN

實驗室性方法,慎用。

延伸:

從Chrome 88開始,在特定情況下,用於非啟用頁面的setTimeout、setInterval將被限制為1分鐘。

timer-throttling-in-chrome-88developer.chrome.com/blog/timer-throttling-in-chrome-88/