1. 程式人生 > >Web移動端 自適應縮放介面

Web移動端 自適應縮放介面

在開發App端的網頁時,要適配iphone、ipad、ipod、安卓等各種機型,一般是直接使用em、px轉em、介面縮放。

本章是通過將介面縮放,等比例顯示在各機型上。過程中遇到了些問題和大坑~

然後下面是具體的自適應嘗試~

方案一 設定tranform/scale

首先設定內容固定寬度、自動高度(以下舉例)

  width: 375px;   height: auto; 通過獲取視窗的寬度與固定寬度相除,獲得縮放比例 const scaleValue=window.innerWidth / 375 在html層,新增一段script:  1 <script dangerouslySetInnerHTML={{ __html: this.getScript() }}></script> 

新增一段設定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的注入,對服務端渲染機制的一個黑科技~

上面的方案完成後,看看效果。然後坑出來了:

  1. 專案設定的absolue元素width 100%失效了 -- 可以設定固定的寬度解決
  2. 彈框position=fixed位置飛到天邊去了 -- 這個無法規避

網上找到了一篇文章 CSS3 transform對普通元素的N多渲染影響 ,介紹了transform的一堆坑。

我這個專案一些佈局需要position=fixed,所以tranform不適合~放棄

這個坑的其它介紹可以參考下:

  • transform限制position:fixed的跟隨效果

  • 關於在transform下的子元素設定fixed無效的困惑

總結:

  1. position:fixed不支援,所以想做標題欄置頂,上面方案是無法實現的。
  2. ipad有遺留問題:微信瀏覽器,橫豎屏切換時,有些機型在開啟一瞬間,橫向拖動有空白問題。這個問題無法處理~
  3. 以上方案因為使用了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的網頁,改動渲染方面的相關規則。有點坑~

https://apple.stackexchange.com/questions/377216/css-zoom-does-not-work-ipad-os-v13-latest-safari

https://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

總結:

  1. 以上方案不支援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   }

此方案的一些小遺留問題:

  1. ipad不支援position:fixed,所以無法實現標題欄置頂等功能

  2. 微信瀏覽器,橫豎屏切換時,有些機型在開啟一瞬間,有空白問題

參考:

  1. IOS環境下固定定位position:fixed帶來的問題與解決方案
  2. 小技巧css解決移動端ios不相容position:fixed屬性,無需外掛
  3. 踩坑路上——IOS Safari瀏覽器下固定定位position:fixed帶來的問題與解決方案
  4. iphone safari不支援position fixed的解決辦法
  5. orientationchange事件、監測微信移動端橫豎屏