在开发 App 端的网页时, 要适配 iPhone,iPad,ipod, 安卓等各种机型, 一般是直接使用 em,px 转 em, 界面缩放.
本章是通过将界面缩放, 等比例显示在各机型上. 过程中遇到了些问题和大坑~
然后下面是具体的自适应尝试~
方案一 设置 tranform/scale
首先设置内容固定宽度, 自动高度(以下举例)
- width: 375px;
- height: auto;
通过获取窗口的宽度与固定宽度相除, 获得缩放比例
const scaleValue=Windows.innerWidth / 375
在 html 层, 添加一段 script:
1<script dangerouslySetInnerHTML={{ __html: this.getScript() }}></script>
添加一段设置 zoom 值的函数:
- getScript() {
- return `
- const zoomValue=Windows.innerWidth / 375;
- document.documentElement.style.transform="scale("+zoomValue+")";
- document.documentElement.style.transformOrigin="left top";
- `;
- }
注:
以上也可以直接写 script, 我上面返回一段 HTML 是因为项目是通过服务端渲染的.
样式的设置必须在界面加载之前, 否则会因界面显示变更出现闪现问题.
因为添加了服务端渲染, 所以无法在界面一开始初始时, 无法获取 Windows,document 等对象. 而上面 HTML 的注入, 对服务端渲染机制的一个黑科技~
上面的方案完成后, 看看效果. 然后坑出来了:
项目设置的 absolue 元素 width 100% 失效了 -- 可以设置固定的宽度解决
弹框 position=fixed 位置飞到天边去了 -- 这个无法规避
网上找到了一篇文章 CSS3 transform 对普通元素的 N 多渲染影响 , 介绍了 transform 的一堆坑.
我这个项目一些布局需要 position=fixed, 所以 tranform 不适合~ 放弃
这个坑的其它介绍可以参考下:
transform 限制 position:fixed 的跟随效果 https://www.jianshu.com/p/6f96b79ad566
关于在 transform 下的子元素设置 fixed 无效的困惑
总结:
position:fixed 不支持, 所以想做标题栏置顶, 上面方案是无法实现的.
iPad 有遗留问题: 微信浏览器, 横竖屏切换时, 有些机型在打开一瞬间, 横向拖动有空白问题. 这个问题无法处理~
以上方案因为使用了 scale, 同时窗口的宽高 Windows.innerHeight 无法准确获取, 需要除以比例, 详见 windowSizeWithScaleHelper
方案二 设置 zoom
在上一个方案的基础上, 尝试 zoom 缩放:
- getScript() {
- return `
- const zoomValue=Windows.innerWidth / 375;
- document.documentElement.style.zoom = zoomValue;
- `;
- }
emmm, 很简单, 调试效果看起来很不错. 模拟机上, 看起来都正常~
但是坑来了: 真机有问题, 发现在 iPad 的 Safari 上, 页面是放大了, 但是字段根本就没变化!
原因竟然是: 苹果在 iPad 的网页, 改动渲染方面的相关规则. 有点坑~
实现没办法, 我后面尝试, 通过 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 更新:
- getScript() {
- return `
- const zoomValue=Windows.innerWidth / 375;
- var viewport = document.querySelector("meta[name=viewport]");
- viewport.content="width=device-width,initial-scale="+zoomValue+", maximum-scale="+zoomValue+", minimum-scale="+zoomValue+",user-scalable=no, minimal-ui"
- `;
- }
运行代码, emmm, 有一些小问题.
margin:auto, 在某些布局下会让页面偏移 -- 删除就好
设置 background-image 的区域, 背景图片并没有填充满 -- 添加 width:100% 解决
position:fixed, 宽高显示有问题 -- 设置固定宽度, 比如 375px, 固定高度; 如果需要全屏, 可以使用 height: 100vh
fixed 布局建议: 以弹框为例
添加 fixed 布局的容器, 水平竖直方向靠边距离分别设置一个就行了, left:0,bottom:0.
然后添加 absolute 布局的内容容器. 如果需要居中, 可以在 JS 中设置 bottom=Windows.innerHeight / 2 - 元素的高度 / 2
总结:
以上方案不支持 fixed 布局, 修改完成后, iPad 的水平滚动条依然存在, 无法解决
兼容适配
采用第二个 zoom 缩放方案, 同时对 iPad 机型特殊处理, 另外采用 scale 缩放方案.
完整代码如下:
1. 初始化适配(支持服务端渲染)
HTML-header 添加 script
- {/* App contentAutoFit */}
- <script dangerouslySetInnerHTML={{ __html: this.getZoomScript() }}></script>
自适应可执行代码文本
- // 返回自适应 HTML 字符串
- getZoomScript() {
- return `
- const zoomValue = Windows.innerWidth / 375;
- const userAgentInfo = Windows.clientInformation.appVersion;
- // 如果是 iPad
- if (userAgentInfo.indexOf("iPad") != -1 || userAgentInfo.indexOf("Macintosh") != -1) {
- // 内容自适应 - 设置 transform-scale.
- //fixed 布局时需要修改下 left/margin-left 等, 同时窗口的宽高无法准确获取, 需要除以比例, 详见 windowSizeWithScaleHelper
- //iPad 有遗留问题: 微信浏览器加载时, 横竖屏切换一瞬间, 有空白问题. 不过可以忽略~
- document.documentElement.style.transform = "scale(" + zoomValue + "," + (zoomValue < 1 ? 1 : zoomValue) + ")";
- document.documentElement.style.transformOrigin = "left top";
- var HTML = document.querySelector("html");
- HTML.style.width = '375px';
- HTML.style.overflow = 'hidden';
- HTML.style.overflowY = 'auto';
- } else {
- // 内容自适应 - 设置 zoom. 通过 zoom 来缩放界面, 在 iPad 的 Safari 浏览器等会存在字体无法缩放的兼容问题.
- document.documentElement.style.zoom = zoomValue;
- }
- // 内容自适应 - 设置 viewport, 整体 okay. 但是 iPad 的水平滚动条无法解决
- // var viewport = document.querySelector("meta[name=viewport]");
- // viewport.content = "width=device-width,initial-scale=" + zoomValue + ", maximum-scale=" + zoomValue + ", minimum-scale=" + zoomValue + ",user-scalable=no, minimal-ui"
- `;
- }
2. 添加加载及界面变更刷新机制
- componentDidMount() {
- Windows.onresize = this.adjustContentAutoFit;
- // 解决微信横竖屏问题
- Windows.addEventListener("orientationchange", this.adjustContentAutoFit);
- // 解决加载过程中, 切换横竖屏, 导致界面没有适配的问题
- this.adjustContentAutoFit();
- }
- componentWillUnmount() {
- Windows.removeEventListener("orientationchange", this.adjustContentAutoFit);
- }
- // 监听窗口尺寸变更, 刷新自适应
- adjustContentAutoFit() {
- const zoomValue = Windows.innerWidth / 375;
- const userAgentInfo = Windows.clientInformation.appVersion;
- // 如果是 iPad
- if (userAgentInfo.indexOf("iPad") != -1 || userAgentInfo.indexOf("Macintosh") != -1) {
- // 内容自适应 - 设置 transform-scale.
- //fixed 布局时需要修改下 left/margin-left 等, 同时窗口的宽高无法准确获取, 需要除以比例, 详见 windowSizeWithScaleHelper
- //iPad 有遗留问题: 微信浏览器, 横竖屏切换时, 有些机型在打开一瞬间, 有空白问题. 不过可以忽略~
- document.documentElement.style.transform = "scale(" + zoomValue + "," + (zoomValue < 1 ? 1 : zoomValue) + ")";
- document.documentElement.style.transformOrigin = "left top";
- var HTML = document.querySelector("html") as HTMLElement;
- HTML.style.width = '375px';
- HTML.style.overflow = 'hidden';
- HTML.style.overflowY = 'auto';
- } else {
- // 内容自适应 - 设置 zoom. 通过 zoom 来缩放界面, 在 iPad 的 Safari 浏览器等会存在字体无法缩放的兼容问题.
- document.documentElement.style.zoom = zoomValue;
- }
- // 内容自适应 - 设置 viewport, 整体 okay. 但是 iPad 的水平滚动条无法解决
- // var viewport = document.querySelector("meta[name=viewport]");
- // viewport.content = "width=device-width,initial-scale=" + zoomValue + ", maximum-scale=" + zoomValue + ", minimum-scale=" + zoomValue + ",user-scalable=no, minimal-ui"
- }
此方案的一些小遗留问题:
iPad 不支持 position:fixed, 所以无法实现标题栏置顶等功能
微信浏览器, 横竖屏切换时, 有些机型在打开一瞬间, 有空白问题
参考:
iOS 环境下固定定位 position:fixed 带来的问题与解决方案 https://www.jianshu.com/p/70e051b73e33
小技巧 CSS 解决移动端 iOS 不兼容 position:fixed 属性, 无需插件
踩坑路上 --iOS Safari 浏览器下固定定位 position:fixed 带来的问题与解决方案
iPhone Safari 不支持 position fixed 的解决办法
来源: https://www.cnblogs.com/kybs0/p/13228133.html