乐趣区

关于前端:漫谈移动端-viewport-视口设置的一些用途以及可能遭遇的各种问题

漫谈挪动端 viewport 视口设置的一些用处以及可能遭逢的各种问题

咱们通过 viewport 视口设置,能够实现对挪动端设施窗口的尺寸管制,这是个非常有用的性能,并且因为当初 viewport 曾经反对动静批改了,所以还能在页面加载之后再依据需要对其进行调整,但实际上这个设置,尤其是动静批改,是存在许多问题的,XJ 为了解决这些问题,甚至还特意写了个 xj.viewport 插件,当然在这篇文章中插件不是重点,但插件的开发 (踩坑) 过程却是这篇文章诞生的根底。

本文次要分为三局部,一是讲 XJ 在开发过程中对于 viewport 的一些额定认知,二是讲利用 viewport 在挪动端进行一些有用的尺寸设置,三是讲在挪动端进行 viewport 设置时可能会遭逢到的各种 BUG 和解决方案,如果你之前对 viewport 的意识仅限于在 <head> 中设置 <meta name="viewport" content="width=device-width,initial-scale=1" />,那么浏览本篇文章后肯定会有些意外播种的。


01. 一些 viewport 相干的基础性知识点

以下内容是 XJ 在开发实际中对 viewport 视口的一些发现和了解,波及到了根底属性的一些设置细节以及应用倡议,这里须要提前阐明的是,上面咱们提到设施的各种尺寸,都是指现实尺寸而不是设施分辨率(现实尺寸又被称为 CSS 像素),例如 iPhone8 的现实尺寸是 375 x 667 而设施分辨率是 750 x 1334,这波及到设施像素比既 DPR 问题,你能够参考 挪动 web 开发之像素和 DPR 这篇文章。

————

01.01. 同时设置 width 和 initial-scale 属性

width 属性用于定义窗口的宽度,能够是个明确的数值如 500,也能够设置为设施的原始宽度既 device-width,如 iPhone4 的屏幕宽高为 320 x 480device-width 在 iPhone4 中就是 320px,而 iPhone8 的屏幕宽高是 375 x 667device-width 在 iPhone8 中就 375px,也就是说 device-width 是个绝对尺寸,在不同型号的设施中并不相同,它取决于设施的原始宽度尺寸。

initial-scale 属性用于设置窗口的初始比例,但它是并非是以以后 width 属性的设置作为根底,而是以 device-width 既设施的原始宽度作为根据,例如在 iPhone8 中,initial-scale=1 则窗口宽度就是 375px,因为 375/1=375initial-scale=0.75 则窗口宽度就是 500px,因为 375/0.75=500,很多人都误以为 initial-scale 属性是以以后的 width 为根底,这是不对的。

那么窗口宽度到底是由 width 属性还是 initial-scale 属性决定的?实际上这是个兼容问题,有的环境是只设置 width 属性就够了,有的环境是只设置 initial-scale 属性就够了,然而思考到兼容,最好是同时设置并保持一致,例如说想在 iPhone8 实现宽度尺寸为 500px,则 meta 标签的 content 属性就该设置为 width=500,initial-scale=0.75,这个 0.75 来自于 375/500

那么当这两个属性不同时会怎么?依据实测是浏览器会以大的那个值为准,例如在 iPhone8 设置 width=500,initial-scale=1,这种状况下窗口宽度会等于 500px,但初始进入页面可能仍然会以设施的原始尺寸既 375px 来显示(在实在设施中很可能会这样),因为 initial-scale=1,这个 1 就是 device-width375px,此时界面无奈展现所有内容,得横向滚动能力看到右侧的货色。

这个时候就须要用户对界面进行捏合操作了,得放大窗口既将 scale 放大为 0.75 后窗口的宽度才会变成 500px,多一步操作总是不现实的(尽管浏览器会记住这个尺寸操作),但每次都须要计算后再设置适合的 initial-scale 属性也很烦,这其实也是 XJ 写 xj.viewport 插件的起因,该插件可通过简略的设置让 initial-scale 属性和 width 属性主动保持一致,省去了手动计算的麻烦。

最初再提一点,在做 Demo 测试的时候,查看以后窗口的尺寸是比拟容易的,如果是应用 Chrome 的挪动模仿性能,那么间接审查元素即可,如果是在挪动端,那么用 document.documentElement.clientWidth 属性也能够得悉,然而以后窗口的比例既 scale 缩放就不好通晓,好在较新的浏览器当初都已反对 visualViewport 对象,所以咱们应用 visualViewport.scale 属性就能够晓得窗口比例了。

————

01.02. 间接实现 height 属性以定义窗口的高度

height 属性和 device-height 属性值,其实也在 viewport 的规范之中,只是到目前为止,素来就没有任何浏览器实现过它罢了,规范和理论不相符是前端的特色嘛,但不反对不代表咱们就没法实现,如果你想定义挪动端窗口的高度,可通过 widthinitial-scale 属性来实现,因为挪动设施的屏幕,宽高比例是固定的,也就是说在肯定的宽度下就会有对应的一个高度,实现办法就在此中。

例如 iPhone8 的屏幕分辨率是 375 x 667,如果想让窗口的高度为 800px(这里暂不思考地址栏和工具栏对屏幕尺寸的影响),那么 viewport 设为 width=450,initial-scale=0.8333 即可,450 源自 375 * 800 / 6670.8333 源自 375/450,宽度计算说白了就只是个 “Cross Multiplication” 既 穿插相乘 而已,这是小学数学的知识点,遗记可百度一下来温故知新,这里就不解释了。

将窗口宽度设置为咱们想要的那个指标宽度,因为挪动端屏幕是具备固定比例的,所以天然可失去咱们想要的指标高度,实践上来讲是这样,但实际上这个高度很可能是不精准的,因为高度是 width 属性和 initial-scale 属性依据等比例原理计算出来的,而有些浏览器并不反对 width 属性的小数那局部(可能被四舍也可能被五入),所以得进去的高度值可有能跟目标值有 ±1±2 的偏差。

些许偏差倒还没什么,更麻烦的是挪动端有些浏览器如 Safari(IOS) 在页面滚动时,会呈现地址栏和工具栏的收起或放下,这就导致了挪动端页面的高度会频繁变动,但咱们并不能跟着变动响应,因为重设 viewport 会引起页面的回流和重绘,此时页面就会产生抖动或闪动,甚至窗口的比例都会被重置,这种状况下用户体验就会很糟,所以总结就是,窗口高度可被定义但不精准,如何响应也是个大问题。

————

01.03. 别设置 user-scalable=no 禁止用户缩放

user-scalable 属性用于管制用户是否可对界面进行缩放,minimum-scalemaximum-scale 属性则用于定义缩放的最小值和最大值,但实际上这三个属性在 IOS10+ 中就不再被反对了,因为 Safari 的开发团队认禁用缩放性能和限度缩放级别会影响拜访性,导致视力不佳的人难以浏览和了解页面内容,尽管禁止缩放会让页面变得更像 APP,但能缩放原本是 HTML 的一种劣势,干嘛要像 APP 呢?

不倡议设置这三个属性来禁止缩放,还有另一个起因是,挪动设施可能存在屏幕旋转既 orientation 的操作,而屏幕旋转后窗口的尺寸就可能发生变化,窗口比例也可能须要从新调整,此时就须要用户进行捏合操作将界面缩放到适合尺寸,如果 user-scalable 被设置为 nominimum-scalemaximum-scale 被设置为 1(也会导致不可缩放),则界面可能就会始终放弃一个不现实的状态。


02. 利用 viewport 来进行各种尺寸设置

上面是应用 viewport 来设置挪动端窗口尺寸的一些案例,须要留神的是,不应用插件的 Demo 并没有做 resize 事件监听,所以得按 F5 刷新能力重置尺寸,实际上这里的 resize 事件并不好监听,因为设置视窗的 content 属性也会引起 resize 事件,导致事件可能进入死循环,更不要说挪动端窗口的尺寸有诸多问题和 BUG,如果把这些问题全思考在内,代码会变得十分复杂,所以只能简化了。

————

02.01. 为视窗设置一个固定宽度

在上面的例子中,咱们通过动静计算,将视窗的宽度固定为 512px,不论设施的原始宽度是多少,也不论是竖屏或横屏模式,反正设施的宽度尺寸当初总是 512px 了,但固定窗口的宽度尺寸有什么用呢?实际上并没有什么用,大屏设施如 ipad 遭逢到一个小尺寸,会让内容显得臃肿,小屏设施如 iPhone8 遭逢到一个大尺寸,会让内容过小而不看不清,这个例子只是简略展现如何动静设置尺寸罢了。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <style>body{margin:0;font:20px/1.5 Menlo,Consolas,"Hiragino Sans GB","Microsoft YaHei",Monospace;}</style>
    </head>
    <body>
        <div id="windowSize">width=512/height=512</div>
        <div id="viewportContent">width=512,initial-scale=1</div>
        
        <script>
        var ele_html = document.querySelector('html');
        var ele_meta = document.querySelector('meta[name="viewport"]');
        ele_meta.content = 'width=512,initial-scale=' + (ele_html.clientWidth / 512);
        
        document.getElementById('windowSize').textContent = 
        'width='+ele_html.clientWidth+'/height='+ele_html.clientHeight;
        document.getElementById('viewportContent').textContent = ele_meta.content;
        </script>
    </body>
</html>

↓ View & Code ↑

下面这个 Demo 并没有做 resize 事件监听,所以得手动刷新才行,在本文的最初一章咱们会提到设置 viewport 视口将会遭逢的各种 BUG 和问题,到时你就会晓得为什么 XJ 没在这里监听 resize 事件了,如果你懒得本人解决兼容问题,或是想节约开发工夫,兴许能够试试 xj.viewport 插件,它应用起来非常简略,并且因为解决了兼容问题,所以能主动响应无需手动刷新,上面是一个简略的例子。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <!-- 在 meta 后引入 xj.viewport 插件,而后在 meta 设置 xj-viewport="{width:512}" 即可 -->
        <meta name="viewport" xj-viewport="{width:512}" content="width=device-width,initial-scale=1" />
        <script src="https://cdn.jsdelivr.net/gh/xjZone/[email protected]/dist/xj.viewport.min.js"></script>
        <style>body{margin:0;font:20px/1.5 Menlo,Consolas,"Hiragino Sans GB","Microsoft YaHei",Monospace;}</style>
    </head>
    <body>
        <div id="windowSize">width=512/height=512</div>
        <div id="viewportContent">width=512,initial-scale=1</div>
        <script>
        var ele_windowSize = document.getElementById('windowSize');
        var ele_viewportContent = document.getElementById('viewportContent');
        
        window.addEventListener('resize', function(){
            ele_windowSize.textContent = 'width=' + xj.viewport.
            width() + '/height=' + xj.viewport.height();
            ele_viewportContent.textContent = xj.viewport.get();}, false);
        </script>
    </body>
</html>

↓ View & Code ↑

————

02.02. 为视窗设置一个最小宽度

在上面的例子中,如果视窗的宽度小于 416px 就设置为 416px,如果视窗的宽度大于 416px 则不做解决,你必定会问设置一个最小宽度有什么用?这个就很有用了,例如说你拿到的设计稿宽度是 375px,但实际上市场里还是存在一些窗口宽度有余 375px 的设施,例如说 iPhone5/5C/SE,窗口宽度就只有 320px,此时将最小宽度设置为 375px,就不必放心小屏设施呈现尺寸有余的问题了。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <style>body{margin:0;font:20px/1.5 Menlo,Consolas,"Hiragino Sans GB","Microsoft YaHei",Monospace;}</style>
    </head>
    <body>
        <div id="windowSize">width=416/height=416</div>
        <div id="viewportContent">width=416,initial-scale=1</div>
        
        <script>
        var ele_html = document.querySelector('html');
        var ele_meta = document.querySelector('meta[name="viewport"]');
        if(ele_html.clientWidth < 416){ele_meta.content = 'width=416,initial-scale=' + (ele_html.clientWidth / 416);
        };
        
        document.getElementById('windowSize').textContent = 
        'width='+ele_html.clientWidth+'/height='+ele_html.clientHeight;
        document.getElementById('viewportContent').textContent = ele_meta.content;
        </script>
    </body>
</html>

↓ View & Code ↑

设置最小宽度能够让咱们不必再放心设施屏幕小于设计稿而款式出错的问题,有个最小尺寸兜底总是好的,当然跟下面的例子一样,因为 resize 事件难以监听,所以尺寸变动后还是得手动按 F5 来刷新,然而 xj.viewport 插件也还是提供了对应的解决方案,照样是设置简略且能主动响应尺寸变动,在 meta 标签后引入插件,而后为 meta 标签增加 xj-viewport="{minWidth:416}" 属性就能够了。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <!-- 在 meta 后引入 xj.viewport 插件,而后在 meta 设置 xj-viewport="{minWidth:416}" 即可 -->
        <meta name="viewport" xj-viewport="{minWidth:416}" content="width=device-width,initial-scale=1" />
        <script src="https://cdn.jsdelivr.net/gh/xjZone/[email protected]/dist/xj.viewport.min.js"></script>
        <style>body{margin:0;font:20px/1.5 Menlo,Consolas,"Hiragino Sans GB","Microsoft YaHei",Monospace;}</style>
    </head>
    <body>
        <div id="windowSize">width=416/height=416</div>
        <div id="viewportContent">width=416,initial-scale=1</div>
        <script>
        var ele_windowSize = document.getElementById('windowSize');
        var ele_viewportContent = document.getElementById('viewportContent');
        
        window.addEventListener('resize', function(){
            ele_windowSize.textContent = 'width=' + xj.viewport.
            width() + '/height=' + xj.viewport.height();
            ele_viewportContent.textContent = xj.viewport.get();}, false);
        </script>
    </body>
</html>

↓ View & Code ↑

————

02.03. 配合 fullPage 定义窗口

在上面的例子中,咱们来让 320 x 480 的内容总是能在窗口中完满显示,当窗口尺寸太小的时候就进行放大,当窗口尺寸太大的时候就进行放大,这种设置有什么用?在做 fullPage 既 “ 整屏翻页 ” 的时候就很有用了,fullPage 是种每次滚动都会滚出整个屏幕间隔,就相似于书籍翻页成果的玩意,这类我的项目在挪动端如何进行窗口适配,一贯是个难题,当初通过 viewport 设置咱们能很好的解决它了。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <style>
        html{overflow:hidden;width:100%;height:100%;color:#ffffff;}
        body{overflow:hidden;margin:0;width:100%;height:100%;background-color:#000000;}
        .pack{position:absolute;top:50%;left:50%;overflow:hidden;margin:-240px 0 0 -160px;width:320px;height:480px;}
        .page{position:relative;width:320px;height:480px;background-color:yellowgreen;}
        </style>
    </head>
    <body>
        <div class="pack">
            <div class="wrap">
                <div class="page">
                    <div id="windowSize"></div>
                    <div id="viewportContent"></div>
                </div>
            </div>
        </div>
        <script>
        (function(){
            
            // 获取以后窗口的宽高度,既 html 标签的尺寸
            var windowWidth = document.documentElement.clientWidth;
            var windowHeight = document.documentElement.clientHeight;
            
            // meta 标签的 content 属性可能须要用的变量
            var targetWidth = 'device-width';    // content 里 width 属性
            var targetInitialScale = 1;            // content 里 initial-scale 值
            var xScale = 1;                        // 横轴 initial-scale 值
            var yScale = 1;                        // 纵轴 initial-scale 值
            
            // 以后设施尺寸小于或大于指标尺寸计算比例值
            if(windowWidth < 320 || windowHeight < 480){if(windowWidth  < 320){xScale = windowWidth  / 320};
                if(windowHeight < 480){yScale = windowHeight / 480};
            }else 
            if(windowWidth > 320 && windowHeight > 480){if(windowWidth  > 320){xScale = windowWidth  / 320};
                if(windowHeight > 480){yScale = windowHeight / 480};
            };
            
            // 依据比例值算 width 和 initial-scale 属性
            if(xScale !== 1 || yScale !== 1){if(xScale <= yScale){targetWidth = 320}
                else{targetWidth = Math.round(480 * windowWidth / windowHeight) };
                targetInitialScale = Math.min(xScale, yScale);
            };
            
            // 设置 meta[name="viewport"] 的 content 值
            var ele_meta = document.querySelector('meta[name="viewport"]');
            ele_meta.content = 'width='+ targetWidth +',initial-scale='+ targetInitialScale;
            
            // 写入以后窗口的尺寸以及以后视窗的设置后果
            var ele_html = document.querySelector('html');
            document.getElementById('windowSize').textContent = 
            'width='+ele_html.clientWidth+'/height='+ele_html.clientHeight;
            document.getElementById('viewportContent').textContent = ele_meta.content;
            
        })();
        </script>
    </body>
</html>

↓ View & Code ↑

在下面的例子中,通过视窗设置,能让 320 x 480 的内容被残缺的显示进去,就是代码量有点多且在尺寸变动时还得手动刷新,改用 xj.viewport 会简略不少且无需手动刷新,在 meta 标签上增加 xj-viewport="{minWidth:320, minHeight:480, fillScreen:true,}" 即可,fillScreen 属性的意思是,如果窗口大于设置的最小宽高度,就将窗口放大到合乎设置的最小宽高度,也就是填充屏幕。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1"
         xj-viewport="{minWidth:320, minHeight:480, fillScreen:true,}" />
        <script src="https://cdn.jsdelivr.net/gh/xjZone/[email protected]/dist/xj.viewport.min.js"></script>
        <style>
        html{overflow:hidden;width:100%;height:100%;color:#ffffff;}
        body{overflow:hidden;margin:0;width:100%;height:100%;background-color:#000000;}
        .pack{position:absolute;top:50%;left:50%;overflow:hidden;margin:-240px 0 0 -160px;width:320px;height:480px;}
        .page{position:relative;width:320px;height:480px;background-color:yellowgreen;}
        </style>
    </head>
    <body>
        <div class="pack">
            <div class="wrap">
                <div class="page">
                    <div id="windowSize"></div>
                    <div id="viewportContent"></div>
                </div>
            </div>
        </div>
        <script>
        var ele_windowSize = document.getElementById('windowSize');
        var ele_viewportContent = document.getElementById('viewportContent');
        
        window.addEventListener('resize', function(){
            ele_windowSize.textContent = 'width=' + xj.viewport.
            width() + '/height=' + xj.viewport.height();
            ele_viewportContent.textContent = xj.viewport.get();}, false);
        </script>
    </body>
</html>

↓ View & Code ↑

下面两个 Demo 都只展现了窗口尺寸的设置,而没有真正的 fullPage 整屏翻页成果,上面咱们展现一个残缺的案例,业界中有不少插件如 swiper.js 和 fullpage.js 都能够实现整屏翻页的成果(后者是免费的请慎用),而上面这个 Demo 里的翻页成果是 XJ 本人写的,实际上也不简单,就是代码有些长,这其实是 xj.viewport 插件的一个 Demo 案例,如果感兴趣的话可自行查看这个页面 : fullPage。

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" 
         xj-viewport="{minWidth:400, minHeight:600, fillScreen:true, onlyMobile:false,}"/>
        <script src="https://cdn.jsdelivr.net/gh/xjZone/[email protected]/dist/xj.viewport.min.js"></script>
        
        <style>
        /* ···
        代码太长就不持续贴了,有趣味请自行查看 ↓
        https://xjZone.github.io/xj.viewport/page/demo_11_fullPage.html */

↓ View & Code ↑


03. 操作 viewport 可能遭逢的各种问题

以下内容是 XJ 在应用 viewport 时所发现的一些问题,波及到了设置 viewport 时浏览器相干的 BUG,还有动静扭转 viewport 时须要留神的点,以及对 fullPage 整屏翻页我的项目的尺寸设计倡议,因为有些问题较难复现,所以 XJ 只是简略的应用文字描述,没有附上相干的 Demo,这部分内容较为琐碎且乏味,如果你切实懒得看,能够抉择应用 xj.viewport 插件帮你设置的,这样就不必理睬这些问题了。

————

03.01. 为什么不好定义 viewport 视窗的高度值

在第一章咱们有进步窗口的高度可借助 width 属性和 initial-scale 属性得出,但那是不思考地址栏和工具栏的理想化操作,理论的上因为它们的存在且可能会跟着页面的滚动而收起或放下,所以页面的高度变动可能会十分频繁,如果咱们跟着变动而从新定义高度,就会让页面频繁缩放跳动,对此 XJ 的倡议是,当高度放大时才进行响应,也就是说窗口高度以地址栏和工具栏都存在的状况下为规范。

要设置窗口的尺寸,就得先失去以后窗口的尺寸值,但这一步在 Safari(IOS13-?) 中却并不简略,在 Safari(IOS) 横屏的状况上来应用 document.documentElement.clientHeight 属性,返回的窗口高度将包含顶部工具栏的尺寸,这其实是个 BUG,如果想得到不含工具栏的高度,得用 window.innerHeight,但 Safari(IOS) 的 window.innerHeightwindow.innerWidth 会受到视窗缩放的影响。

会受到视窗缩放的影响,就是这对属性在 viewport 被设置时会跟着变动(但 Android 这对属性则不受 viewport 设置的影响),为了在横屏时失去不含工具栏的正确高度,咱们能够借助这对属性的比例再乘以 document.documentElement.clientWidth 属性,来计算出以后不含工具栏的窗口高度值,具体写法就是 window.innerHeight / window.innerWidth * document.documentElement.clientWidth

然而 window.innerHeight 属性在 Safari(IOS13-?) 中也是有 BUG 的,那就是如果在横屏的状况下进入页面,而后立刻就获取这个属性,那么返回的值也会包含顶部的工具栏,也就是返回值会偏大,基本不精确,不过 Safari(IOS13-) 在横屏的状况下进入页面,还会很快的主动触发一次 resize 事件,在这个事件的回调中获取 window.innerHeight 属性,返回值就失常了,不会再蕴含工具栏高度。

下面提到的这两个高度 BUG,在 IOS14 仿佛曾经被修复了,而在 IOS13- 中并没有比拟好的办法能解决这些问题,只能是监听 resize 事件而后从新获取 window.innerHeight 再进行尺寸计算而已,但截止 2021-06-18 2022-09-12,IOS14+ 市场占比曾经达到 85% 99% 以上,所以这个浏览器的 BUG 其实不理睬也无所谓啦,之后就等 IOS 零碎更新迭代来主动解决这个问题吧,在这里就是做个记录而已。

————

03.02. 监听 resize 事件设置 viewport 的难点

在第二章咱们有提到通过绑定 resize 事件来实现 viewport 的动静响应会非常麻烦,那是因为有些状况下触发了 resize 事件但咱们却不能进行 viewport 设置,上面咱们将阐明这些状况,另外须要留神,因为 initial-scale 是以 device-width 为规范,所以每次在进行设置之前,得先初始化既 content="width=device-width,initial-scale=1",以获取到设施的原始现实尺寸再进行设置。

首先是在 Android 零碎中,设置 meta[name="viewport"]content 属性可能触发 resize 事件,原本这个设置就可能是因为响应 resize 事件才被执行的,后果设置后又触发 resize 事件,这就会导致 resize 事件进入死循环,所以咱们须要防止在这种状况下的响应,你能够在设置前定义一个变量,而后在 resize 事件的回调中检测到这个变量则间接 return 以防止进入这死循环。

其次是在 Android 零碎中,小键盘的弹起也可能触发 resize 事件,但小键盘不该影响窗口布局的,也就是说此时也不该响应,那么咱们就得去检测小键盘是否弹起了,但浏览器并没有提供小键盘相干的任何接口,XJ 在 xj.viewport 插件中是采纳 screen.height - document.documentElement.clientHeight >= 240 来判断,意思是赌浏览器地址栏和工具栏的高度小于 240px 而小键盘大于 240px。

再者是页面滚动也可能触发 resize 事件,在局部浏览器如 Safari(IOS) 中滚动会导致地址栏和工具栏的收起或放下,此时 resize 事件就会频繁触发,但咱们不该去响应的,因为会导致视窗频繁缩放跳动,且局部浏览器在视窗重置后,并不会将视窗的比例主动调整到最佳状态,须要用户手动去捏合放大,但这操作可能导致再次触发 resize 事件,所以如果检测到只是高度变动,最好也是不要响应。

最初是屏幕翻转既 orientation 也会触发 resize 事件,这种状况当然是须要响应且进行 viewport 设置的,但响应就须要从新获取窗口的尺寸来进行计算,可有些浏览器在屏幕翻转后立刻获取尺寸,就可能会失去翻转前的旧尺寸,也就是说尺寸的更新会存在提早,这种状况下咱们就得通过 setTimeout() 提早 250500 毫秒再进行尺寸的获取和计算,以此解决这个尺寸更新不及时的问题。

————

03.03. 对于 fullPage 整屏翻页我的项目的一些补充

在上一章咱们提到的 fullPage 我的项目,其实在中国它并没有明确的译名,个别大家会管它叫 “ 整屏翻页 ” 或 “ 整屏滚动 ” 或 “ 整页滑屏 ” 或 “ 全屏滚动 ”,之前的 Demo 是摸索如何为 fullPage 设置一个适合的窗口尺寸,因为这类玩意往往须要将所有内容塞在一个无限的页面容器中,但用户的屏幕尺寸形形色色,彼此之间区别不小,所以如何确保在不同设施上让页面放弃雷同的显示成果就成为了一个难题。

在这里咱们探讨的 fullPage 整屏翻页我的项目,特指那些在挪动端须要放弃雷同尺寸比例的我的项目,如果你是那种还得兼容 PC 端的响应式我的项目 (如 fullpage.js 的官网),那么在挪动端通过 viewport 设置来失去一个固定尺寸的做法(第二章第三节的案例) 就不适合了,但此时你仍然能够在挪动端通过 viewport 设置来失去一个最小的窗口尺寸(第二章第二节的案例),以此解决窗口过小而内容不好搁置的问题。

对于 fullPage 整屏翻页我的项目对尺寸定义的需要,实际上应用 viewport 来设置窗口尺寸并非惟一的解决方案,应用 rem 单位进行全局尺寸管制,或应用 transform:scale(n) 对界面进行缩放,都是可行的,但 rem 计划不好配合那些非 rem 单位的第三方插件,而 transform:scale(n) 计划则在页面内容和动画较多时容易引发页面解体,所以综合看上来,实际上还是 viewport 计划较为稳当。

最初谈谈 fullPage 我的项目的 UI 设计,你可能发现之前的 Demo 都是应用 320*480(640*960) 或者 400*600(800*1200) 这种 2:3 的比例,而不是用 375*667(750*1334) 这种 9:16 的比例,那是因为浏览器还存在地址栏和工具栏,屏幕的高度在扣除掉地址栏和工具栏的高度后,其实尺寸比例更加靠近于 2:3,所以这个比例下的尺寸会更适合,兴许当前你能够倡议你的设计师改一下设计稿?

设计师给咱们尺寸为 640*960800*1200 的设计稿,咱们则应用 320*480400*600 的尺寸去做页面,这波及到设施像素比既 DPR 问题(在第一章曾经提过了),XJ 比拟举荐应用 400*600 的尺寸,因为当初通过 viewport 设置,窗口可大可小,不必再放心小屏设施的尺寸兼容问题了,其次是当初大屏设施较多,高一点的分辨率不容易让页面显得含糊,当然最终还得看设计师的意思啦。


参考内容

易企秀 – 整屏翻页参考

MDN – viewport 视口
MDN – viewport 属性列表
MDN – Viewport meta tag
MDN – window.visualViewport

Clancey – viewport-fit – 解决 iphoneX 的 ” 刘海 ” 问题
Quirk Smode – orientationchange 事件的浏览器兼容

MDN – 在非矩形屏幕环境下,设置边距的款式 env())
小火柴的蓝色现实 – 挪动 web 开发之像素和 DPR

黑猫大侠 LK – css 的那些事儿 001 – 对于 initial-scale 的用法说明
leman314 – 详解 meta-viewport 中的 width 和 initial-scale 属性

Susie Kim – 在 100vh 布局中解决 iOS 的地址栏
Matt Smith – 挪动 WebKit 中 100vh 的 CSS 修复

ralStyle 贵 – 自适应的 fill-available/content 和 max/min-content
张鑫旭 – 了解 CSS3 的 max/min-content 及 fit-content 等 width 值

Alex Gibson – 对于挪动端浏览器方向问题
David Walsh – 检测挪动设施上的方向变动

XJ.Chen – xj.viewport

退出移动版