移動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權重。
缺點:程式碼量大,不易於維護與除錯。
- 使用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。*
移動端通用相容問題
- 點選延時300毫秒。
*值得慶幸的是,所有移動端瀏覽器都已經解決這個問題了。*
- 頁面回彈效果。
如果頁面是全屏,不超過可視高度的話,建議禁用touchmove事件。
如果頁面不是全屏,超過可視高度的話,就不要禁用touchmove事件。
*雖然有辦法阻擋X5核心(QQ瀏覽器核心)的“網頁有XXX提供”的這些資訊,但是並沒有真正阻擋iphone的回彈效果,拖拽還是會回彈。*
延伸:iOS safari 如何阻止“橡皮筋效果”? --知乎)
- 頁面返回不重新整理。
往返快取(Back/Forward cache)是瀏覽器的一種瀏覽器記憶體快取機制。
解決方案:
var isPageHide = false;
window.addEventListener("pageshow", function () {
if (isPageHide) {
window.location.reload();
}
});
window.addEventListener("pagehide", function () {
isPageHide = true;
});
- 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;
}
- 輸入法擋住輸入框。
在混合應用開發中,移動端內建瀏覽器元件設定了全屏。那麼問題來了,假如是一個表單頁面,裡面有很多的輸入框,點選最頂部的輸入框的時候,移動端就會喚起輸入法軟體,於是就擋住最底部的輸入框,導致無法看到輸入框裡面的內容。
<!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>
- 劉海屏適配問題
使用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
- setTimeout 、setInterval函式凍結問題
PC端瀏覽器(Firefox、Chrome 和 Safari)
場景:瀏覽器最小化、非啟用當前標籤頁面。
例子:非啟用當前標籤頁面執行settimeout小於1秒的定時任務,會調整為1秒。
mobile端瀏覽器(Firefox、Chrome 和 Safari)
場景:瀏覽器進入後臺、非啟用當前標籤頁面。
例子:非啟用當前標籤頁面執行settimeout小於1秒的定時任務,會暫停執行。
解決方案:
- 監聽頁面狀態,重置定時任務
document.addEventListener('visibilitychange', function() {
if(document.hidden) {
// 清除定時器
}else {
// 重置定時器
}
});
- 使用requestIdleCallback函式繼續執行定時任務。
window.requestIdleCallback() - MDN
實驗室性方法,慎用。
延伸:
從Chrome 88開始,在特定情況下,用於非啟用頁面的setTimeout、setInterval將被限制為1分鐘。
timer-throttling-in-chrome-88developer.chrome.com/blog/timer-throttling-in-chrome-88/