移动端适配(必须要知道的,亲测有效)
關于移動端適配(必須要知道的,親測有效)
- 一、各種單位概念理解
- 二、移動,web開發
- 三、移動端適配
- 1、視口(viewport)概念
- 2、視口(viewport)適配(代碼)
- 3、rem單位適配
- flexible方案
- 豎屏、橫屏、ipad、PC最全的適配JS
- 4、長屏短屏布局適配
- 5、橫豎屏適配
- css媒體查詢(CSS Media Queries)
- window.orientation旋轉事件
- window.innerHeight/window.innerWidth
- 軟鍵盤彈出-影響橫豎屏判斷的坑
- 強制橫豎屏時遇到的坑
- 橫豎屏切換,全屏背景的坑
- 在游戲接入中-H5隱藏某些模塊
- 6、iphone適配
- 概念
- h5、小程序適配代碼
- 7、常見適配問題
- 1px問題
- 圖片模糊問題
移動端適配,在開發中經常會遇到的問題:
一、各種單位概念理解
英寸:屏幕的物理大小,如電腦顯示器的17、22,手機顯示器的4.8、5.7等使用的單位都是英寸。一般說的屏幕的尺寸都是屏幕對角線的長度。1英寸 = 2.54 厘米
像素:像素即一個小方塊,它具有特定的位置和顏色。圖片、電子屏幕(手機、電腦)就是由無數個具有特定顏色和特定位置的小方塊拼接而成。像素可以作為圖片或電子屏幕的最小組成單位。
分辨率:屏幕分辨率(一個屏幕具體由多少個像素點組成。),圖像分辨率(指圖片含有的像素數。)。同一尺寸的屏幕、圖片,分辨率越高,越清晰。
PPI(Pixel Per Inch):每英寸包括的像素數。PPI越高,越清晰。
DPI(Dot Per Inch):即每英寸包括的點數。DPI和PPI是等價的。
DIP或DP 設備獨立像素:用來告訴不同分辨率的手機,它們在界面上顯示元素的大小是多少
dpr(device pixel ratio)設備像素比:物理像素和設備獨立像素的比值
//web let dpr = window.devicePixelRatio;//css 使用媒體查詢min-device-pixel-ratio區分 @media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ }//React Native PixelRatio.get()web前端長度單位詳解(px、em、rem、%、vw/vh、vmin/vmax、vm、calc())
二、移動,web開發
移動端開發
1、在iOS、Android和React Native開發中樣式單位其實都使用的是設備獨立像素。
2、移動端開發中,UI給我們的原型圖一般是基于iphone6(750*1334)的像素給定的。
3、為了適配所有機型,我們在寫樣式時需要把物理像素轉換為設備獨立像素。
web開發
web端用到最多的單位是px,即CSS像素。當頁面縮放比例為100%時,一個CSS像素等于一個設備獨立像素
頁面的縮放系數 = 理想視口寬度 / 視覺視口寬度
三、移動端適配
1、視口(viewport)概念
視口共包括三種:布局視口、視覺視口和理想視口,它們在屏幕適配中起著非常重要的作用。
布局視口:在PC瀏覽器上,布局視口就等于當前瀏覽器的窗口大小(不包括borders 、margins、滾動條)。在移動端,布局視口被賦予一個默認值,大部分為980px
// 獲取布局視口大小 document.documentElement.clientWidth / clientHeight視覺視口:用戶通過屏幕真實看到的區域。默認等于當前瀏覽器的窗口大小(包括滾動條寬度)
// 獲取視覺視口大小 window.innerWidth / innerHeight理想視口:網站頁面在移動端展示的理想大小。在瀏覽器調試移動端時頁面上給定的像素大小就是理想視口大小,它的單位正是設備獨立像素。
screen.width / height // 獲取理想視口大小獲取瀏覽器各種視口大小:
2、視口(viewport)適配(代碼)
<meta> 元素 元數據信息。 告訴瀏覽器如何解析頁面??梢越柚?lt;meta>元素的viewport來幫助我們設置視口、縮放等,從而讓移動端得到更好的展示效果 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
為了在移動端讓頁面獲得更好的顯示效果,我們必須讓布局視口、視覺視口都盡可能等于理想視口。
設置width=device-width就相當于讓布局視口等于理想視口
設置initial-scale=1;就相當于讓視覺視口等于理想視口
這時,1個CSS像素就等于1個設備獨立像素,而且我們也是基于理想視口來進行布局的,所以呈現出來的頁面布局在各種設備上都能大致相似。
3、rem單位適配
flexible方案
核心代碼:
// set 1rem = viewWidth / 100function setRemUnit() {var rem = docEl.clientWidth / 7.5docEl.style.fontSize = rem + 'px'}setRemUnit()豎屏、橫屏、ipad、PC最全的適配JS
<script type="text/javascript">// 設備區分 (安卓、火狐、平板、PC)var os = function() {var ua = navigator.userAgent,isAndroid = /(?:Android)/.test(ua),isFireFox = /(?:Firefox)/.test(ua),isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),isPC = !(/Android|webOS|iPhone|iPod|BlackBerry/i.test(ua));return {isTablet: isTablet,};}();(function (window, document) {function resize() {var docEl = document.documentElement;var clientWidth = docEl.clientWidth;var clientHeight = docEl.clientHeight;if (clientWidth < clientHeight) { // 手機豎屏docEl.style.fontSize = clientWidth / 7.5 + "px";} else { // 手機橫屏 docEl.style.fontSize = clientHeight / 7.5 + "px";}if(os.isTablet) { //ipad if(clientWidth >= 1366) {docEl.style.fontSize = clientWidth / 1366 * 100 + "px";} else {docEl.style.fontSize = clientWidth / 1024 * 100 + "px";}}if (os.isPC) { // pcif(clientWidth >= 1920) {docEl.style.fontSize = 1920 / 19.20 + "px";} else {docEl.style.fontSize = clientWidth / 19.20 + "px";}} }resize();// reset rem unit on page resizewindow.addEventListener("resize", function () {resize()});window.addEventListener('pageshow', function (e) {if (e.persisted) {resize()}});}(window, document)); </script>4、長屏短屏布局適配
rem(font size of the root element)是指相對于根元素的字體大小的單位。雖然不同手機的寬高尺寸不一樣,但是設置了root font-size之后,每個手機的寬度都是等量的rem,可以理解為每個手機的寬度都是一樣的,區別在于高度不一樣。
有些單屏頁面內容很少,在短屏上超出一屏、剛好,在長屏上只占頁面頂上一小部分,布局會顯得不協調。
長屏短屏布局適配方案:
1、css媒體查詢,適當擴展間距讓內容撐滿更多高度
2、垂直定位盡量用%,不要用固定單位
5、橫豎屏適配
css媒體查詢(CSS Media Queries)
@media screen and (orientation: portrait) {/* 豎屏 */ } @media screen and (orientation: landscape) {/*橫屏 css*/ }window.orientation旋轉事件
通過綁定orientationchange旋轉事件來判斷橫豎屏。
在 iOS 平臺以及大部分 Android 手機都有支持這個屬性,它返回一個與默認屏幕方向偏離的角度值:
0:代表此時是默認屏幕方向
90:代表順時針偏離默認屏幕方向90度
-90:代表逆時針偏離默認屏幕方向90度
180:代表偏離默認屏幕方向180度
如下圖所示:
在實際應用中,對于 iPhone 和大部分 Android 是沒有180度的手機豎屏翻轉的情況的,但是 iPad 是存在的。
function recordOrient() {if (window.orientation === 180 || window.orientation === 0) {//豎屏} else if (window.orientation === 90 || window.orientation === -90) {// 橫屏} }recordOrient(); window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {recordOrient(); }, false);彈框型js完美方案:
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" /> <title></title> <script type="text/javascript">(function (window, document) {function resize() {var docEl = document.documentElement;let clientWidth = docEl.clientWidth;let clientHeight = docEl.clientHeight;var k = 375;if (window.orientation === 180 || window.orientation === 0) {//豎屏} else if (window.orientation === 90 || window.orientation === -90) {//橫屏// k = 320;}if (clientWidth <= k) { //豎屏docEl.style.fontSize = clientWidth / 750 * 100 + "px";} else { //橫屏docEl.style.fontSize = k / 750 * 100 + "px";}}resize();// reset rem unit on page resizewindow.addEventListener("resize", function () {resize()});window.addEventListener('pageshow', function (e) {if (e.persisted) {resize()}});}(window, document));</script>頁面型完美解決方案:
(function (win, doc) {if (!win.addEventListener) return;var html = document.documentElement;function setFont() {var html = document.documentElement;var k = 750;html.style.fontSize = html.clientWidth / k * 100 + "px";}setFont();setTimeout(function () {setFont();}, 300);doc.addEventListener('DOMContentLoaded', setFont, false);win.addEventListener('resize', setFont, false);win.addEventListener('load', setFont, false);})(window, document);window.innerHeight/window.innerWidth
通過比較頁面的寬高,當頁面的高大于等于寬時則認為是豎屏,反之則為橫屏。
function detectOrient(){if(window.innerHeight >= window.innerWidth) {// 豎屏}else {// 橫屏 } } detectOrient(); window.addEventListener('resize',detectOrient);軟鍵盤彈出-影響橫豎屏判斷的坑
在 Android 下,如果頁面中出現軟鍵盤彈出的情況(存在有 Input 的元素)時,頁面有時會因為軟鍵盤的彈出而導致頁面回縮,即頁面的寬度(豎屏時)或者高度(橫屏時)被改變。
所以通過 CSS多媒體查詢(CSS Media Queries) 、 window.matchMedia() 方法、window.innerWidth /window.innerHeight的頁面寬高比對方法來實現的橫豎屏判斷方法,都會因此受到影響,出現判斷失誤的情況(vivo x9、華為p9、Samsung SCH-i699 機型,在豎屏時由于軟鍵盤彈出導致頁面高度小于寬度,被錯誤地判定為橫屏)。
在這樣的情況下,這幾種方式也變得不可靠。
解決方案:類似的,在橫屏判斷中,給橫屏一個最小判斷寬度,低于那個寬度就還是判斷為豎屏
CSS 媒體查詢:給一個橫屏的最小寬度,即使高度很小,通過寬度還是可以區分橫豎屏 @media screen and (orientation: portrait) {/* 豎屏 */ } @media screen and (orientation: landscape) and (min-width: 560px) {/* 橫屏 */ }vue 軟件盤彈出 css解決方案:
<template><div ref="app" id="app"><keep-alive><router-view v-if="$route.meta.keepAlive"></router-view></keep-alive><router-view v-if="!$route.meta.keepAlive"></router-view><shine-landscape></shine-landscape> // 組件</div> </template> <style lang="less" scoped> // 橫屏 && 軟鍵盤彈出橫屏 @media screen and (orientation: landscape) and (min-width: 560px) {/deep/ .shine-landscape{display: block;} }/style>js 解決方案:
let sw = window.screen.width;let sh = window.screen.height;let cw = document.documentElement.clientWidth;if(cw == sw) {// 豎屏this.showShineLandscape = false}if(cw == sh) {// 橫屏this.showShineLandscape = true}強制橫豎屏時遇到的坑
【問題】在 iOS 鎖屏情況下,強制豎屏不成功
【方案】做一個橫屏適配頁,內容可以是提示開啟鎖屏并自動旋轉手機屏幕
【注意】做適配時,如果發現在 iOS平臺,橫屏時頁面左右會有默認安全區域空白,我們需要定義頁面寬高等于手機視口寬高
【問題】做了強制橫豎屏,絕對不能使用window.orientation判斷來做橫豎屏適配,因為 ios平臺 旋轉屏幕會改變橫豎屏的值從而切換樣式,但視圖布局為始終保持強制的狀態,這就會導致旋轉屏幕時頁面樣式混亂。
【方案】:還是建議CSS多媒體查詢,比較簡單,解決缺陷的方式也簡單
【問題】橫豎屏旋轉canvas需要重新繪制
【問題】頁面中凡是 canvas繪制而成的局部視圖,橫豎屏旋轉,樣式不會跟著調整,
【方案】監聽旋轉屏幕事件,旋轉后刷新重繪canvas部分
橫豎屏切換,全屏背景的坑
【問題】ios安全區域頁面留白,背景容器100%的漏洞
【解決方案】 背景容器設置100vw,vh
在游戲接入中-H5隱藏某些模塊
從游戲頁面操作跳轉到H5頁面。采用了window.location的跳轉方式,這里不能忘記手動攜帶該有的參數,否則從這里開始接下來所有頁面都失去了判斷的參數,項目中該去掉的模塊就會出現
/*** 獲得時間戳*/ function randomTimeStamp() {return parseInt(new Date().getTime() / 1000) + ''; } /*** 檢測flag* @param search*/ function checkFlag(search) {if (/[&|?](flag=[\d]+)/.test(search)) {search = search.replace(/[&|?](flag=[\d]+)/, (str) => {let splitStrs = str.split('=');return splitStrs[0] + '=' + randomTimeStamp();})} else {if (search) {search += '&flag=' + randomTimeStamp();} else {search += '?flag=' + randomTimeStamp();}} return search; } /*** 拼接地址* @param path: 路由* @param flag: 是否需要刷新*/ function locationUrl(path, flag = true) {let url = '';if (flag) {let search = checkFlag(location.search);url = location.protocol + '//' + location.host + location.pathname + search + '#/' + path;} else {url = location.protocol + '//' + location.host + location.pathname + location.search + '#/' + path;}window.location = url; }this.locationUrl('Index');6、iphone適配
概念
安全區域適配
iphone x\xr\xs\11 pro 取消了物理按鍵,改成底部小黑條,這一改動導致網頁出現了比較尷尬的屏幕適配問題。
對于網頁而言,頂部(劉海部位)的適配問題瀏覽器已經做了處理,所以我們只需要關注底部與小黑條的適配問題即可(即常見的吸底導航、返回頂部等各種相對底部 fixed 定位的元素)。如下圖:
安全區域:一個可視窗口范圍,處于安全區域的內容不受圓角(corners)、齊劉海(sensor housing)、小黑條(Home Indicator)影響。
viewport-fit:iOS11 新增特性,蘋果公司為了適配 iPhoneX 對現有 viewport meta 標簽的一個擴展,用于設置網頁在可視窗口的布局方式,可設置 三個值:
auto \ contain: 可視窗口完全包含網頁內容(左圖)。頁面內容顯示在safe area內
cover:網頁內容完全覆蓋可視窗口(右圖)。頁面內容充滿屏幕。
env() 和 constant():iOS11 新增特性,Webkit 的一個 CSS 函數,用于設定安全區域與邊界的距離,有四個預定義的變量:
safe-area-inset-left:安全區域距離左邊邊界距離
safe-area-inset-right:安全區域距離右邊邊界距離
safe-area-inset-top:安全區域距離頂部邊界距離
safe-area-inset-bottom:安全區域距離底部邊界距離
【注意】:
1)網頁默認不添加擴展的表現是 viewport-fit=contain,需要適配 iPhoneX 必須設置 viewport-fit=cover,不然 constant 函數是不起作用的,這是適配的必要條件
2)env() 是官方文檔中提到將來要替換 constant (),目前還不可用。
為此目前我們可以看作 constant:針對iOS < 11.2以下系統,env:針對于iOS >= 11.2的系統
使用的時候 env() 必須寫在 constant () 后面
h5、小程序適配代碼
第一步:設置網頁在可視窗口的布局方式 (viewport-fit=cover")
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />第二步:頁面主體內容限定在安全區域內
body {padding-top: constant(safe-area-inset-top); padding-top: env(safe-area-inset-top); padding-bottom: constant(safe-area-inset-bottom);padding-bottom: env(safe-area-inset-bottom); }第三步:相對底部 fixed 定位的元素適配
1、fixed吸底 元素(bottom = 0)
2、fixed 非完全吸底元素(bottom ≠ 0),比如 “返回頂部”、“側邊廣告” 等
<div class="back-top ipx-margin-safe-area">返回頂部</div>第四步:使用 @supports 隔離兼容樣式(可有可無)
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {/* 通過加內邊距 padding 擴展高度 */.ipx-padding-safe-area{padding-bottom: constant(safe-area-inset-bottom);padding-bottom: env(safe-area-inset-bottom);}... }7、常見適配問題
1px問題
【問題】:在設備像素比大于1的屏幕上,我們寫的1px實際上是被多個物理像素渲染,這就會出現1px在有些屏幕上看起來很粗的現象
【方案】:偽類 + transform 基于media查詢判斷不同的設備像素比對線條進行縮放
圖片模糊問題
【問題】:我們平時使用的圖片大多數都屬于位圖(png、jpg…)。在dpr > 1的屏幕上,位圖的一個像素可能由多個物理像素來渲染,然而這些物理像素點并不能被準確的分配上對應位圖像素的顏色,只能取近似值,所以相同的圖片在dpr > 1的屏幕上就會模糊
【方案】:在dpr=2的屏幕上展示兩倍圖(@2x),在dpr=3的屏幕上展示三倍圖(@3x)
1、媒體查詢縮放(只適用于背景圖)
@media only screen and (-webkit-min-device-pixel-ratio:2){.bg1{transform: scaleY(0.5);} } @media only screen and (-webkit-min-device-pixel-ratio:3){.bg1{transform: scaleY(0.33);} }2、image-set
.avatar {background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x ); }3、使用img標簽的srcset屬性
<img src="conardLi_1x.png"srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">4、使用svg可縮放矢量圖
總結
以上是生活随笔為你收集整理的移动端适配(必须要知道的,亲测有效)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse中文版代码自动补全设置
- 下一篇: 【算法学习】蝙蝠算法简介