Web移動端 自適應縮放介面
- 2020 年 7 月 6 日
- 筆記
- HTML/CSS/JS, JavaScript/TypeScript
在開發App端的網頁時,要適配iphone、ipad、ipod、Android等各種機型,一般是直接使用em、px轉em、介面縮放。
本章是通過將介面縮放,等比例顯示在各機型上。過程中遇到了些問題和大坑~
方案一 設置tranform/scale
首先設置內容固定寬度、自動高度(以下舉例)
添加一段設置zoom值的函數:
1 getScript() { 2 return ` 3 const zoomValue=window.innerWidth / 375; 4 document.documentElement.style.transform="scale("+zoomValue+")"; 5 document.documentElement.style.transformOrigin="left top"; 6 `; 7 }
註:
以上也可以直接寫script,我上面返回一段html是因為項目是通過服務端渲染的。
樣式的設置必須在介面載入之前,否則會因介面顯示變更出現閃現問題。
因為添加了服務端渲染,所以無法在介面一開始初始時,無法獲取window、document等對象。而上面html的注入,對服務端渲染機制的一個黑科技~
上面的方案完成後,看看效果。然後坑出來了:
- 項目設置的absolue元素width 100%失效了 — 可以設置固定的寬度解決
- 彈框position=fixed位置飛到天邊去了 — 這個無法規避
網上找到了一篇文章 CSS3 transform對普通元素的N多渲染影響 ,介紹了transform的一堆坑。
我這個項目一些布局需要position=fixed,所以tranform不適合~放棄
這個坑的其它介紹可以參考下:
總結:
- position:fixed不支援,所以想做標題欄置頂,上面方案是無法實現的。
- ipad有遺留問題:微信瀏覽器,橫豎屏切換時,有些機型在打開一瞬間,橫向拖動有空白問題。這個問題無法處理~
- 以上方案因為使用了scale,同時窗口的寬高window.innerHeight無法準確獲取,需要除以比例,詳見windowSizeWithScaleHelper
方案二 設置zoom
在上一個方案的基礎上,嘗試zoom縮放:
1 getScript() { 2 return ` 3 const zoomValue=window.innerWidth / 375; 4 document.documentElement.style.zoom = zoomValue; 5 `; 6 }
emmm,很簡單,調試效果看起來很不錯。模擬機上,看起來都正常~
但是坑來了:真機有問題,發現在ipad的safari上,頁面是放大了,但是欄位根本就沒變化!
原因竟然是:蘋果在ipad的網頁,改動渲染方面的相關規則。有點坑~
//apple.stackexchange.com/questions/377216/css-zoom-does-not-work-ipad-os-v13-latest-safari
//stackoverflow.com/questions/7907760/why-the-font-size-wont-change-with-browser-zoom-in
實現沒辦法,我後面嘗試,通過userAgent對ipad機型(ipad、macintosh)特殊處理,直接獲取所有包含了文字的div、p、span等元素,放大font-size。
發現可以處理,沒毛病!但是也有些缺陷,沒辦法在一開始處理字體,因為元素還沒有初始化,而等介面載入後再刷字體大小,介面會閃現一次。
方案三 設置viewport-scare
在html中添加默認viewport:
1 <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1,user-scalable=no, minimal-ui"></meta>
ps:minimal-ui 與本文無關,它可以在safari載入網頁時隱藏地址欄與導航欄
添加viewport更新:
1 getScript() { 2 return ` 3 const zoomValue=window.innerWidth / 375; 4 var viewport = document.querySelector("meta[name=viewport]"); 5 viewport.content="width=device-width,initial-scale="+zoomValue+", maximum-scale="+zoomValue+", minimum-scale="+zoomValue+",user-scalable=no, minimal-ui" 6 `; 7 }
運行程式碼,emmm,有一些小問題。
- margin:auto,在某些布局下會讓頁面偏移 — 刪除就好
- 設置background-image的區域,背景圖片並沒有填充滿 — 添加width:100%解決
- position:fixed,寬高顯示有問題 — 設置固定寬度,比如375px,固定高度;如果需要全螢幕,可以使用height: 100vh
fixed布局建議:以彈框為例
添加fixed布局的容器,水平豎直方向靠邊距離分別設置一個就行了,left:0,bottom:0。
然後添加absolute布局的內容容器.如果需要居中,可以在js中設置bottom=window.innerHeight / 2 – 元素的高度/2
總結:
- 以上方案不支援fixed布局,修改完成後,ipad的水平滾動條依然存在,無法解決
兼容適配
採用第二個zoom縮放方案,同時對ipad機型特殊處理,另外採用scale縮放方案。
完整程式碼如下:
1. 初始化適配(支援服務端渲染)
html-header添加script
1 {/* app contentAutoFit */} 2 <script dangerouslySetInnerHTML={{ __html: this.getZoomScript() }}></script>
自適應可執行程式碼文本
1 //返回自適應html字元串 2 getZoomScript() { 3 return ` 4 const zoomValue = window.innerWidth / 375; 5 const userAgentInfo = window.clientInformation.appVersion; 6 //如果是ipad 7 if (userAgentInfo.indexOf("iPad") != -1 || userAgentInfo.indexOf("Macintosh") != -1) { 8 //內容自適應 - 設置transform-scale。 9 //fixed布局時需要修改下left/margin-left等,同時窗口的寬高無法準確獲取,需要除以比例,詳見windowSizeWithScaleHelper 10 //ipad有遺留問題:微信瀏覽器載入時,橫豎屏切換一瞬間,有空白問題。不過可以忽略~ 11 document.documentElement.style.transform = "scale(" + zoomValue + "," + (zoomValue < 1 ? 1 : zoomValue) + ")"; 12 document.documentElement.style.transformOrigin = "left top"; 13 var html = document.querySelector("html"); 14 html.style.width = '375px'; 15 html.style.overflow = 'hidden'; 16 html.style.overflowY = 'auto'; 17 } else { 18 //內容自適應 - 設置zoom。通過zoom來縮放介面,在ipad的safari瀏覽器等會存在字體無法縮放的兼容問題。 19 document.documentElement.style.zoom = zoomValue; 20 } 21 // 內容自適應 - 設置viewport,整體okay。但是ipad的水平滾動條無法解決 22 // var viewport = document.querySelector("meta[name=viewport]"); 23 // viewport.content = "width=device-width,initial-scale=" + zoomValue + ", maximum-scale=" + zoomValue + ", minimum-scale=" + zoomValue + ",user-scalable=no, minimal-ui" 24 `; 25 }
2. 添加載入及介面變更刷新機制
1 componentDidMount() { 2 window.onresize = this.adjustContentAutoFit; 3 //解決微信橫豎屏問題 4 window.addEventListener("orientationchange", this.adjustContentAutoFit); 5 //解決載入過程中,切換橫豎屏,導致介面沒有適配的問題 6 this.adjustContentAutoFit(); 7 } 8 componentWillUnmount() { 9 window.removeEventListener("orientationchange", this.adjustContentAutoFit); 10 } 11 //監聽窗口尺寸變更,刷新自適應 12 adjustContentAutoFit() { 13 const zoomValue = window.innerWidth / 375; 14 const userAgentInfo = window.clientInformation.appVersion; 15 //如果是ipad 16 if (userAgentInfo.indexOf("iPad") != -1 || userAgentInfo.indexOf("Macintosh") != -1) { 17 //內容自適應 - 設置transform-scale。 18 //fixed布局時需要修改下left/margin-left等,同時窗口的寬高無法準確獲取,需要除以比例,詳見windowSizeWithScaleHelper 19 //ipad有遺留問題:微信瀏覽器,橫豎屏切換時,有些機型在打開一瞬間,有空白問題。不過可以忽略~ 20 document.documentElement.style.transform = "scale(" + zoomValue + "," + (zoomValue < 1 ? 1 : zoomValue) + ")"; 21 document.documentElement.style.transformOrigin = "left top"; 22 var html = document.querySelector("html") as HTMLElement; 23 html.style.width = '375px'; 24 html.style.overflow = 'hidden'; 25 html.style.overflowY = 'auto'; 26 } else { 27 // 內容自適應 - 設置zoom。通過zoom來縮放介面,在ipad的safari瀏覽器等會存在字體無法縮放的兼容問題。 28 document.documentElement.style.zoom = zoomValue; 29 } 30 // 內容自適應 - 設置viewport,整體okay。但是ipad的水平滾動條無法解決 31 // var viewport = document.querySelector("meta[name=viewport]"); 32 // viewport.content = "width=device-width,initial-scale=" + zoomValue + ", maximum-scale=" + zoomValue + ", minimum-scale=" + zoomValue + ",user-scalable=no, minimal-ui" 33 }
此方案的一些小遺留問題:
-
ipad不支援position:fixed,所以無法實現標題欄置頂等功能
-
微信瀏覽器,橫豎屏切換時,有些機型在打開一瞬間,有空白問題
參考:
- IOS環境下固定定位position:fixed帶來的問題與解決方案
- 小技巧css解決移動端ios不兼容position:fixed屬性,無需插件
- 踩坑路上——IOS Safari瀏覽器下固定定位position:fixed帶來的問題與解決方案
- iphone safari不支援position fixed的解決辦法
- orientationchange事件、監測微信移動端橫豎屏