移動的端常見問題
ios
滑動不流暢
上下滑動頁面會產(chǎn)生卡頓忿檩,手指離開頁面东抹,頁面立即停止運動。整體表現(xiàn)就是滑動不流暢蜒简,沒有滑動慣性瘸羡。
-
原來在
iOS 5.0
以及之后的版本,滑動有定義有兩個值auto
和touch
搓茬,默認值為auto
犹赖。-webkit-overflow-scrolling: touch; /* 當手指從觸摸屏上移開,會保持一段時間的滾動 */ -webkit-overflow-scrolling: auto; /* 當手指從觸摸屏上移開卷仑,滾動會立即停止 */
-
在滾動容器上增加滾動 touch 方法
.wrapper { -webkit-overflow-scrolling: touch; }
-
設置 overflow
設置外部
overflow
為hidden
,設置內(nèi)容元素overflow
為auto
峻村。內(nèi)部元素超出 body 即產(chǎn)生滾動,超出的部分 body 隱藏锡凝。body { overflow-y: hidden; } .wrapper { overflow-y: auto; }
頁面放大或縮小不確定性行為
雙擊或者雙指張開手指頁面元素粘昨,頁面會放大或縮小。
-
移動端常規(guī)寫法
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
因此我們可以設置
maximum-scale
窜锯、minimum-scale
與user-scalable=no
用來避免這個問題<meta name=viewport content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0, user-scalable=no">
click 點擊事件延時與穿透
監(jiān)聽元素
click
事件张肾,點擊元素觸發(fā)時間延遲約300ms
。點擊蒙層锚扎,蒙層消失后吞瞪,下層元素點擊觸發(fā)。
iOS
中的 safari驾孔,為了實現(xiàn)雙擊縮放操作芍秆,在單擊300ms
之后,如果未進行第二次點擊翠勉,則執(zhí)行click
單擊操作妖啥。也就是說來判斷用戶行為是否為雙擊產(chǎn)生的。但是对碌,在App
中荆虱,無論是否需要雙擊縮放這種行為,click
單擊都會產(chǎn)生300ms
延遲朽们。-
使用
touchstart
替換 click
el.addEventListener("touchstart", () => { console.log("ok"); }, false);
-
在 ```vue`` 中使用
<button @touchstart="handleTouchstart()">點擊</button>
-
使用
fastclick
庫import FastClick from 'fastclick'; FastClick.attach(document.body, options);
iPhone X
系列安全區(qū)域適配問題
頭部劉海兩側(cè)區(qū)域或者底部區(qū)域克伊,出現(xiàn)劉海遮擋文字,或者呈現(xiàn)黑底或白底空白區(qū)域华坦。
-
設置
viewport-fit
為cover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
- 使用
safe area inset
變量
/* 適配 iPhone X 頂部填充*/ @supports (top: env(safe-area-inset-top)){ body, .header{ padding-top: constant(safe-area-inset-top, 40px); padding-top: env(safe-area-inset-top, 40px); padding-top: var(safe-area-inset-top, 40px); } } /* 判斷iPhoneX 將 footer 的 padding-bottom 填充到最底部 */ @supports (bottom: env(safe-area-inset-bottom)){ body, .footer{ padding-bottom: constant(safe-area-inset-bottom, 20px); padding-bottom: env(safe-area-inset-bottom, 20px); padding-top: var(safe-area-inset-bottom, 20px); } }
-
safe-area-inset-left
:安全區(qū)域距離左邊邊界距離 -
safe-area-inset-right
:安全區(qū)域距離右邊邊界距離 -
safe-area-inset-top
:安全區(qū)域距離頂部邊界距離 -
safe-area-inset-bottom
:安全區(qū)域距離底部邊界距離
safe-area-inset-top
,
safe-area-inset-right,
safe-area-inset-bottom,
safe-area-inset-leftsafe-area-inset-*
由四個定義了視口邊緣內(nèi)矩形的
top,
right,
bottom和
left的環(huán)境變量組成愿吹,這樣可以安全地放入內(nèi)容,而不會有被非矩形的顯示切斷的風險惜姐。對于矩形視口犁跪,例如普通的筆記本電腦顯示器椿息,其值等于零。對于非矩形顯示器(如圓形表盤坷衍,
iPhoneX` 屏幕)寝优,在用戶代理設置的四個值形成的矩形內(nèi),所有內(nèi)容均可見枫耳。 - 使用
H5
調(diào)試相關方案策略
-
vconsole
控制臺插件import Vconsole from 'vconsole' new Vconsole()
eruda
手機端調(diào)試只要在我們的```html``文件中寫入下面這些代碼乏矾,在手機上,也能想瀏覽器控制臺一樣進行查看迁杨。
<script src="http://cdn.jsdelivr.net/npm/eruda"></script>
<script>
eruda.init();
</script>
H5
頁面播放視頻
-
在
H5
頁面播放視頻钻心,不全屏播放,在video標簽添加playsinline
和x5-playsinline
設置為true就行<video id="my-video" class="video-js" controls preload="auto" data-setup=" {} " playsinline="true" x5-playsinline="true"> </video>
橫屏適配
-
很多視口我們要對橫屏和豎屏顯示不同的布局铅协,所以我們需要檢測在不同的場景下給定不同的樣式:
- JavaScript檢測橫屏
window.addEventListener('resize',() =>{ if(window.orientation === 180 || window.orientation === 0) { //正常方向或屏幕旋轉(zhuǎn)180度 console.log('豎屏') } if(window.orientation === 80 || window.orientation === -90) { //屏幕順時鐘旋轉(zhuǎn)90度或屏幕逆時針旋轉(zhuǎn)90度 console.log('橫屏') } })
CSS檢測橫屏
@media screen and (orientation:portrait){ /*豎屏...*/ } @media screen and (orientation:landscape){ /*橫屏...*/ }
移動端解決0.5px
方案
設備像素比:dpr=window.devicePixelRatio捷沸,也就是設備的物理像素與邏輯像素的比值
-
0.5px 方案
/*這是css方式*/ .border { border: 1px solid #999 } @media screen and (-webkit-min-device-pixel-ratio: 2) { .border { border: 0.5px solid #999 } } /*ios dpr=2和dpr=3情況下border相差無幾,下面代碼可以省略*/ @media screen and (-webkit-min-device-pixel-ratio: 3) { .border { border: 0.333333px solid #999 } }
-
viewport + rem
-
同時通過設置對應
viewport
的rem
基準值狐史,這種方式就可以像以前一樣輕松愉快的寫1px了痒给。
在devicePixelRatio=2
時,設置meta
:<meta name="viewport" content="width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
實現(xiàn)
<!DOCTYPE html> <html lang="en"> <head> <title>移動端1px問題</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <meta name="viewport" id="WebViewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <style> html { font-size: 11px; } body { padding: 1rem; } * { padding: 0; margin: 0; } .item { padding: 1rem; border-bottom: 1px solid gray; font-size: 1.2rem; } </style> <script> var viewport = document.querySelector("meta[name=viewport]"); var dpr = window.devicePixelRatio || 1; var scale = 1 / dpr; //下面是根據(jù)設備dpr設置viewport viewport.setAttribute( "content", + "width=device-width," + "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no" ); var docEl = document.documentElement; var fontsize = 10 * (docEl.clientWidth / 320) + "px"; docEl.style.fontSize = fontsize; </script> </head> <body> <div class="item">border-bottom: 1px solid gray;</div> <div class="item">border-bottom: 1px solid gray;</div> </body> </html>
移動端適配方案
-
rem適配
rem
適配的本質(zhì)是布局等比例的縮放骏全,通過動態(tài)設置html
的font-size
來改變rem
的大小苍柏。<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
-
引入flexible
-
flexible
方案是阿里早期開源的一個移動端適配解決方案,引用
flexible后姜贡,我們在頁面上統(tǒng)一使用
rem`來布局试吁。(function(win, lib) { var doc = win.document; var docEl = doc.documentElement; var metaEl = doc.querySelector('meta[name="viewport"]'); var flexibleEl = doc.querySelector('meta[name="flexible"]'); var dpr = 0; var scale = 0; var tid; var flexible = lib.flexible || (lib.flexible = {}); if (metaEl) { console.warn('將根據(jù)已有的meta標簽來設置縮放比例'); var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/); if (match) { scale = parseFloat(match[1]); dpr = parseInt(1 / scale); } } else if (flexibleEl) { var content = flexibleEl.getAttribute('content'); if (content) { var initialDpr = content.match(/initial\-dpr=([\d\.]+)/); var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/); if (initialDpr) { dpr = parseFloat(initialDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } if (maximumDpr) { dpr = parseFloat(maximumDpr[1]); scale = parseFloat((1 / dpr).toFixed(2)); } } } if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,對于2和3的屏鲁豪,用2倍的方案潘悼,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他設備下律秃,仍舊使用1倍的方案 dpr = 1; } scale = 1 / dpr; } docEl.setAttribute('data-dpr', dpr); if (!metaEl) { metaEl = doc.createElement('meta'); metaEl.setAttribute('name', 'viewport'); metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); if (docEl.firstElementChild) { docEl.firstElementChild.appendChild(metaEl); } else { var wrap = doc.createElement('div'); wrap.appendChild(metaEl); doc.write(wrap.innerHTML); } } function refreshRem(){ var width = docEl.getBoundingClientRect().width; if (width / dpr > 540) { width = 540 * dpr; } var rem = width / 10; docEl.style.fontSize = rem + 'px'; flexible.rem = win.rem = rem; } win.addEventListener('resize', function() { clearTimeout(tid); tid = setTimeout(refreshRem, 300); }, false); win.addEventListener('pageshow', function(e) { if (e.persisted) { clearTimeout(tid); tid = setTimeout(refreshRem, 300); } }, false); if (doc.readyState === 'complete') { doc.body.style.fontSize = 12 * dpr + 'px'; } else { doc.addEventListener('DOMContentLoaded', function(e) { doc.body.style.fontSize = 12 * dpr + 'px'; }, false); } refreshRem(); flexible.dpr = win.dpr = dpr; flexible.refreshRem = refreshRem; flexible.rem2px = function(d) { var val = parseFloat(d) * this.rem; if (typeof d === 'string' && d.match(/rem$/)) { val += 'px'; } return val; } flexible.px2rem = function(d) { var val = parseFloat(d) / this.rem; if (typeof d === 'string' && d.match(/px$/)) { val += 'rem'; } return val; } })(window, window['lib'] || (window['lib'] = {}));
使用vw爬橡,vh布局
vh、vw
方案即將視覺視口寬度window.innerWidth
和視覺視口高度window.innerHeight
等分為 100 份棒动。如果視覺視口為
375px
糙申,那么1vw=3.75px
,這時UI
給定一個元素的寬為75px
(設備獨立像素)船惨,我們只需要將它設置為75/3.75=20vw
柜裸。-
這里的比例關系我們也不用自己換算,我們可以使用
PostCSS
的postcss-px-to-viewport
插件幫我們完成這個過程粱锐。寫代碼時疙挺,我們只需要根據(jù)UI
給的設計圖寫px
單位即可。module.exports = { plugins: [ require('autoprefixer'), require('postcss-import'), require('postcss-url'), require('postcss-preset-env'), require('postcss-aspect-ratio-mini'), require('postcss-write-svg'), require('postcss-px-to-viewport')({ viewportWidth: 750, viewportHeight: 1334, unitPrecision: 3, viewportUnit: 'vw', selectorBlackList: [ '.ignore', '.hairlines', '.footer' ], minPixelValue: 1, mediaQuery: true }), require('cssnano') ] }
-
快速生成HTML代碼結(jié)構(gòu)
#page>div.logo+ul#navigation>li*5>a{Item $}
可以轉(zhuǎn)換為
<div id="page">
<div class="logo"></div>
<ul id="navigation">
<li><a href="">Item 1</a></li>
<li><a href="">Item 2</a></li>
<li><a href="">Item 3</a></li>
<li><a href="">Item 4</a></li>
<li><a href="">Item 5</a></li>
</ul>
</div>
-
使用
>
運算符將元素相互嵌套div>ul>li 生成 <div> <ul> <li></li> </ul> </div>
-
使用
+
運算符將元素彼此放置在同一水平上:div+p+bq 生成 <div></div> <p></p> <blockquote></blockquote>
-
使用括號將復雜縮寫的子樹分組
div>(header>ul>li*2>a)+footer>p 生成 <div> <header> <ul> <li><a href=""></a></li> <li><a href=""></a></li> </ul> </header> <footer> <p></p> </footer> </div>