基于Viewport的移动端web屏幕基本适配方案详解

1. 前言

随着手机,平板等移动设备的普及,现如今的绝大多数web应用会对桌面端和移动端进行网页适配的兼容处理。由于移动端和桌面端设备的型号和分辨率种类比较繁杂,如果专门为这些不同设备和终端分别建立网站显然成本太高,很不现实,并且它们之间的界限也很模糊。所以创建可以适配多种设备的web应用是如今web开发的基本需求。

在我们具体分析主流的适配方案之前,先让我们了解一下以下这些主要概念:

2. 各种“像素”

2.1 物理像素

物理像素(又称设备像素),即我们平常主要所说的分辨率的尺寸单位,例如电脑和手机设备的屏幕分辨率。屏幕是由一个个的物理像素点组成的。例如手机分辨率为1344 X 750表示手机分别在垂直和水平方向的物理像素点数。一般来说,屏幕的物理像素点数是固定不变的,单位为pt。

2.2 CSS像素

我们平常写的CSS样式中的px尺寸单位即是CSS像素,而每个设备屏幕也都有自己对应的CSS像素尺寸。打开我们的Chrome浏览器的移动端调试页面可看到对应页面上方有当前测试设备的相关信息,如下图示例:
image

这里的375 X 812表示的就是当前设备的CSS像素,也称之为设备独立像素。当我们在设计网页时,进行移动页面样式调试,调试的样式尺寸基准就是CSS像素,而非物理像素。即当我们在页面中放一个width=375px,height为812px的div标签时,不考虑其他因素影响,在理想视口下(关于视口的介绍见下方),则它正好可以撑满当前设备整个屏幕。

2.3 设备像素比

DPR(Device Pixel Ratio),设备像素比。它描述的是未缩放状态下,物理像素和CSS像素(设备独立像素)的初始比例关系。即表示每1px CSS像素所能包含的物理像素个数。通常情况下计算公式为DPR = 物理像素 / 设备独立像素(CSS像素)。通过此公式便可得到CSS像素。DPR越高,代表屏幕显示的精致程度越高。苹果手机的Retina高清屏则是经典案例,以DPR=2.0为例,则表示把一般的4(即2 X 2)个物理像素点数当作1(1 X 1)个CSS像素点数来用。

image

虽然DPR越高代表屏幕高清效果越好,但DPR越高会对一些网页显示素材(如图片)的质量(清晰度)要求也会越高。举个常见的比较通俗易懂的例子,进行页面开发时,对于一些图片资源,UI会给我们提供分辨率相对于原始应该在页面上显示的CSS像素大小的2倍,3倍的图片文件。这些图片正是为了兼容DPR为2.0和3.0的设备的。

比如我们一个分辨率像素为100 X 100的图片在浏览器上也是设置CSS像素为100px * 100px,在dpr为1的设备上显示没有什么问题。但是如果是dpr=2的设备即水平或垂直方向上1css像素对应2个物理像素,则水平和垂直方向上分别只需要100/2=50个css像素就可标准清晰地显示该图片,但此时如果该图片依然设置100px * 100px的CSS像素,那么实际效果图片的每一个物理像素都会被拉伸成2个物理像素(1css像素)以便能撑满100px的CSS像素,所以图片显示效果变模糊一些。这时候使用2倍图(即200 X 200的图片)且CSS像素尺寸设置不变(100px * 100px)便可解决此问题。

3. 浏览器视口

通俗的讲,移动设备上的视口(学术名称为viewport)就是设备的屏幕上能用来显示我们的网页的那一块区域。浏览器的视口主要分为以下几类:

3.1 布局视口

布局视口表示的是整个网页内容布局的矩形区域。一般移动设备的浏览器都默认设置了一个 viewport 元标签,定义一个虚拟的布局视口(layout viewport),用于解决早期的页面在手机上显示的问题。iOS, Android 一般默认都将这个视口分辨率设置为CSS像素的 980px,所以 PC 上的网页基本能在手机上呈现,只不过元素看上去很小,一般PC的网页在移动设备都是通过手动缩放来控制合适的页面显示大小。

通常来讲,布局视口的尺寸与页面根元素html标签的CSS像素大小是一致的。所以一般可通过document.documentElement.clientWidth/clientHeight来获取。(这个值不会因为html元素本身被设置了width或内部元素宽度超出当前视口宽度而变化)
image

3.2 可见视口

可见视口,又称视觉视口,它表示的是布局视口中在当前设备中可见的矩形区域的那一部分。它的尺寸大小会随着用户的手动缩放页面而变化。放大时,可见的页面CSS像素减少;缩小时,可见的页面CSS像素增多。

页面的缩放比例 = 布局视口的宽度 / 可见视口的宽度
image

3.4 理想视口

布局视口提供的默认视口尺寸并不是一个兼容多种设备的智能视口,所以提出了一个理想视口的概念。在解释理想视口之前,需要了解一下布局视口配置的相关概念:

通过在HTML中的头部head标签中添加关于viewport的meta标签可进行视口设置:

 <meta name="viewport" content="width=device-width, user-scalable=yes,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
属性取值范围作用
width正整数或device-width定义视口的宽度,单位为CSS像素
height正整数或device-height定义视口的高度,单位为CSS像素,一般不用
initial-scale0.0-10.0定义初始缩放值
minimum-scale0.0-10.0定义放大最大比例,它必须小于或等于maximum-scale设置
maximum-scale0.0-10.0定义缩小最小比例,它必须大于或等于minimum-scale设置
user-scalableyes / no定义是否允许用户手动缩放页面,默认值 yes

上面示例的meta标签代码代表的就是设置了一个理想视口。表示当前布局视口宽度与当前设备的CSS像素宽度一致,且默认不进行缩放。这样设置后,可实现页面在所有设备上默认布局视口宽度与设备屏幕宽度一致的自适应效果。

注意事项:

1:viewport的meta标签的设置只对移动端生效,不影响PC端视口。PC端视口大小一般固定为浏览器窗口的大小。

2:如果没有添加viewport的meta标签,则会默认以布局视口的默认视口尺寸(一般为CSS像素980px)为准,而此时缩放比例默认以恰好能全部显示网页内容且不出现滚动条的情况为准。

3:当initial-scale属性没有设置值时,则页面默认会显示成相对于width属性对应值的视口宽度正好能全部看见(可能会缩放)并不出现横向滚动条的情况。

4:initial-scale属性一般来说是相对于width属性值的缩放比,当width没有设置值时,则默认相对于理想视口(即device-width)的缩放比。

5:尽量不要禁用缩放(user-scalable设置为no),避免为视力或行动有障碍的用户带来不便。

4. 适配方案

如今移动端web的适配方案从根本性质上可分为两大类:自适应响应式

自适应:Adaptsive Web Design,这种适配方案通常来说同一个网站会拥有PC端,移动端两套网页代码(甚至更多)。通常移动端的页面功能和内容可能会相比PC端有所削减。而单纯针对移动端页面,则会表现“在不同尺寸的手机设备上,页面保持统一效果的等比缩放”的效果。下面所说到的百分比适配,rem适配方案,vw/wh适配方案都是移动端的自适应的主要实践。

下面是一些移动端适配具体的实现方案:

4.1 百分比适配

主要使用百分比%单位去编写页面元素的宽度,一些情况下的元素高度,边距等样式,根据可视区域实时尺寸进行调整,尽可能适应各种分辨率,通常使用max-width/min-width控制尺寸范围过大或者过小。

优点:

原理简单,无兼容性问题

缺点:

1:不适用于页面元素较多,较复杂的场景。

2:由于设备分辨率的跨度较大,元素的百分比不好把控,可能出现元素拉伸变形的问题。

3:字体大小无法自适应。

4:在CSS中百分比所相对的包含块或参考对象所遵循规则不固定,容易使布局复杂化。

4.2 rem适配

CSS中数值单位除了px,还有em和rem。em是相对于当前元素的font-size大小(如当前元素没有设置,则以父元素font-size为准)的倍数单位,适用场景较少。而rem则是相对于html根元素的font-size大小的倍数单位。如html的font-size为16px,则2rem代表32px.

rem适配方案的核心实现过程就是根据先设置好的比例关系在CSS样式中使用rem单位,通过监听视口尺寸(即设备分辨率)的变化,动态地改变根元素font-size的大小,从而实现页面元素等比缩放的自适应效果。

实现示例:

UI给的设计稿为375px,一张图片在设计稿下宽度是100px,高度为50px。则我们在编写CSS样式时,依然按照375设计稿下的尺寸数字设置width=100rem,height=50rem。然后通过js脚本修改根元素font-size为理想视口CSS宽度 / 375,单位为px。

    const resetRem = () => {
        const viewportWidth = document.documentElement.clientWidth
        document.documentElement.style.fontSize = viewportWidth / 375 + "px"
        
    }
 
    resetRem()
    window.onresize = () => {
        resetRem()
    }
    

由于许多的多年经验开发者已习惯于px单位的书写,并且由于如今前端工程化以及构建工具的发展,现多采用webpack插件(如Px2Rem)设置打包项目自动进行px到rem的转换。

vw/wh出现后,这里的rem转换方案可以替换为直接css设置根元素html的font-size为calc(100vw / 375),解决了js的耦合问题

优点:

兼容性和自适应效果好

缺点:

1:不是纯css移动适配方案,需要引入js脚本,具有一定耦合度。

2:通过 rem 计算后可能会出现小数像素,而浏览器在渲染时会进行四舍五入。所以可能会存在一定的精度问题和页面显示效果问题

3:由于是等比缩放,如果使用ipad等较大设备,则会看到夸张的字体大小和布局尺寸

4.3 vw/wh适配

vw,vh,vmax,vmin是CSS推出的视口专属单位,各单位具体含义如下:

vw : 1vw 等于 视口宽度 的 1%,即100vw等于视口宽度

vh : 1vh 等于 视口高度 的 1%,即100vh等于视口高度

vmin : 选取 vw 和 vh 中 较小 的那个

vmax : 选取 vw 和 vh 中 较大 的那个

通常我们会通过viewport的meta标签将视口设置为理想视口,即让视口宽度与屏幕设备CSS像素宽度一致。这样100vw,100vh就分别表示屏幕的宽,高度。这样更加方便计算元素与设计稿的比例关系,从而把设计稿尺寸转换为 视口单位,包括 文本,布局高宽,间距 等,使得这些元素能够随视口大小自适应调整。

使用视口单位方案为了避免重复繁多的CSS数值计算,也可使用webpack等构建工具中的类似插件(如px-to-viewport)统一将px转成视口单位

vmin和vmax的应用场景:

如果使用 vw、wh 设置CSS中元素字体大小font-size(比如 5vw),在竖屏和横屏状态下显示的字体大小是不一样的。通常手机竖屏状态下100vw就是屏幕较短那一边的宽度,横屏状态下100vw就是屏幕较长那一边的宽度,导致了font-size的实际CSS像素大小在横竖屏下不一致。此时如果
我们将font-size的单位vw改为vmin,这就使得文字大小在横竖屏下保持一致。

当然,如果你就想文字大小跟当前视口宽度成比例,认为我横屏情况下文字就应该更大,依然可以统一用vw。

优点:

视口单位的出现几乎可以算是rem适配方案的替代品,因为相比rem方案这是纯CSS移动端自适应适配方案,无需js脚本。

缺点:

存在一定兼容性问题,Android4.4以下不支持。

备注:

实际开发中,百分比,rem和vw以及px这几种单位并非相互独立,他们往往也会组合使用,去适配不同的场景需求

4.4 vw+rem+calc()移动端适配最佳实践

需求:375-414px的屏幕设备根字号大小为16px-18px
    html{
        font-size: 16px;
    }
    @media screen and (min-width: 375px) {
        /*375px屏幕作为16px根元素字号的基准,414px屏幕正好对应18px的根元素字号*/
        html {
            font-size: calc((100vw - 375px) / 375 + 1px);
        }
    }
    @media screen and (min-width: 414px){
        /*屏幕宽度从414px到1000px,根元素字号为18px-22px*/
        html {
            font-size: calc(18px + 4 * (100vw - 414px ) / 586);
        }
    }
    @media screen and (min-width: 1000px){
        /*屏幕宽度1000px往上,每增加100px则根元素字号增加0.5px*/
        html {
            font-size: calc(22px + 5 * (100vw - 1000px ) / 1000);
        }
    }

该代码引用于《CSS新世界》

4.5 响应式设计

响应式:Responsive Web Design,这种适配方案通常来说一套代码,多端适用。是一种用来为各种分辨率和设备性能优化视觉体验的技术方案。多年前非常流行的Bootstrap就是一套非常好的响应式UI框架。主要通过媒体查询,弹性布局等手段来为从移动端到PC端由小变大的不同分辨率提供可伸缩性的页面布局效果。同样也会出现不同分辨率下呈现功能内容多少不同的现象。但总体会遵循主要内容永远保留的原则。

一般来说,响应式方案是自适应方案的子集。都是致力于适配不同设备,提升用户体验。

image

响应式界面的四个层次

1、同一页面在不同大小和比例上看起来都应该是舒适的;

2、同一页面在不同分辨率上看起来都应该是合理的;

3、同一页面在不同操作方式(如鼠标和触屏)下,体验应该是统一的;

4、同一页面在不同类型的设备(手机、平板、电脑)上,交互方式应该是符合习惯

以下是响应式设计中PC端和移动端设备布局的常见效果示例(PC左,移动右):

能够自动隐藏/部分显示的内容:如在电脑上显示的的大段描述文本,在手机上就只能少量显示或全部隐藏

image

能自动折叠的导航和菜单:展开还是收起,应该根据页面尺寸来判断
image

响应式由于其需要考虑的方面很多,其布局设计上在很大程度上依赖媒体查询。以下是一段媒体查询代码示例:

@media screen and (max-width: 300px) {
    body {
        background-color:lightblue;
    }
}

这段css代码表示如果当前视口宽度小于 300 CSS像素时,body元素则修改背景颜色(background-color)为lightblue

媒体查询支持的关键字和属性还有很多,具体可自行查询。这里特别说明一下max-device-width和max-width属性的区别(max-height和max-device-height同理):

1、max-device-width是真实的设备较短那一边的屏幕CSS像素宽度(固定值不变)。

2、max-width是当前页面视口的CSS像素宽度。

所以当设备进行横竖屏切换时,max-width会变化,而max-device-width不会变化

响应式设计特点:

优点:

1.响应式设计可以向用户提供友好的Web界面,同样的布局,却可以在不同的设备上有不同排版。

2.响应式在开发维护和运营上,相对多个版本成本会降低很多。也无须花大量的时间在网站的维护上

3.方便改动,响应式设计是针对页面的,可以只对必要的页面进行改动,其他页面不受影响。

缺点:

1.为了适配不同的设备,响应式设计需要大量专门为不同设备打造的css及js代码,这导致了文件增大,影响了页面加载速度。

2.在响应式设计中,图片、视频等资源一般是统一加载的,这就导致在低分辨率的机子上,实际加载了大于它的显示要求的图片或视频,导致不必要的流量浪费,影响加载速度;

3.局限性,响应式不适合一些大型的门户网或者电商网站,一般门户网或电商网站一个界面内容较多,对设计样式不好控制,代码过多会影响运行速度。

5. 常见适配问题优化

5.1 1px像素问题

关于移动端经典的1px边框线变粗的问题,其实其真实原因并非网上大多数所说的dpr(即物理像素与CSS像素关系)的原因。dpr只会影响页面的精细程度和高清效果,不会影响像素的尺寸,如果是dpr的原因,那么为什么2px,3px的边框线不会变粗呢?其真正原因我们用一个例子来说明:

UI的750px设计稿中有1px的边框线。当我们采用等比缩放的适配方案(如rem)在375px的移动设备中看的时候,应该是0.5px的边框线。然而移动设备大多数最细只能显示1px的像素,此时比例不对了,就会视觉感官上觉得“变粗”。

总结:1px像素问题的核心在于移动设备的最小可显示的CSS像素,如今最新的IOS版本支持了0.5px的像素。

既然移动端大多设备不支持小于1px 像素的显示,那么如何模拟模拟小于1px的像素呢。网上的方案很多,
这里只提供一种简单易用的(以0.5px为例):

    .setOnePx {
        position: relative;
    }
    .setOnePx::after{
         position: absolute;
         content: '';
         background-color: #e5e5e5;
         display: block;
         width: 100%;
         height: 1px; 
         transform: scale(1, 0.5);
         top: 0;
         left: 0;
     }
    }

5.2 移动端默认样式重置

针对移动端浏览器的用户体验优化,一般会对一些HTML标签的默认样式效果有所改动,以下是一端样式重置的参考示例:

 *,::before,::after{
            box-sizing: border-box;
            -webkit-box-sizing: border-box;
            padding: 0;
            margin: 0;
            /*移动端点击高亮效果的清除*/
            -webkit-tap-highlight-color: transparent;
            tap-highlight-color:transparent;
        }
        body{
            font-size: 14px;
            font-family: "Microsoft Yahei",sans-serif;
            color:#333
        }
        ul,ol{
            list-style: none;
        }
        a{
            text-decoration: none;
            color:#333
        }
        input,textarea{
            /*优化表单元素外观*/
            border: none;
            outline: none;
            appearance: none;
            -webkit-appearance: none;
        }

5.3 图片资源适配

由于需要兼容dpr为2.0以及3.0的设备,常常需要使用2倍图或3倍图资源。但是这样会导致在dpr为1.0的设备也会使用质量较高,文件较大的2倍图或3倍图资源。
当然这样并不可取,会造成大量带宽的浪费。现代浏览器,提供了更好的方式,让我们能够根据设备 dpr 的不同,提供不同尺寸的图片。

1:img元素的srcsetsizes属性:

<div class="illustration">
<img src="illustration-small.png"
srcset="images/illustration-small.png 1x,
               images/illustration-big.png 2x"
style="max-width: 500px"/>
</div>

上面 srcset 里的 1x,2x 表示 像素密度描述符,表示

当屏幕的 dpr = 1 时,使用 images/illustration-small.png 这张图

当屏幕的 dpr = 2 时,使用 images/illustration-big.png 这张图

不符合上述任一条件的,则默认使用src属性指向的图片资源

srcset属性单独使用只适用设备dpr的适配,只适合显示区域一样大小的图像。如果希望不同尺寸的屏幕,显示不同大小的图像,srcset属性就不够用了,必须搭配sizes属性来说设置不同设备下的图像显示大小。

<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     sizes="(max-width: 440px) 100vw,
            (max-width: 900px) 33vw,
            254px"
     src="foo-1280.jpg">

本例中srcest属性的单位为w的数值表示图像的原始图片显示大小

sizes属性的值是一个逗号分隔的字符串,除了最后一部分,前面每个部分都是一个放在括号里面的媒体查询表达式,后面是一个空格,再加上图像的显示宽度。

同时有了srcset和sizes属性后,浏览器根据当前设备的宽度,从sizes属性获得图像的显示宽度,然后从srcset属性找出最接近该宽度的图像,进行加载。

假定当前设备的屏幕宽度是480px CSS像素,那么上面代码表示,浏览器从sizes属性查询得到,图片的显示宽度是33vw(即33%),等于160px。srcset属性里面,正好有宽度等于160px的图片,于是加载foo-160.jpg。254px则是当前设备不符合size的任一条件时的默认图片显示大小

sizes属性必须与srcset属性搭配使用。单独使用sizes属性是无效的。

2:picture元素和source元素

img元素分别使用srcset和size属性时,解决了像素密度和屏幕大小的适配,但是如果要同时适配不同像素密度、不同大小的屏幕,应该怎么办呢?

这时,就要用到picture标签。它是一个容器标签,内部使用source和img,指定不同情况下加载的图像

<picture>
  <source srcset="homepage-person@desktop.png,
                  homepage-person@desktop-2x.png 2x"       
          media="(min-width: 990px)">
  <source srcset="homepage-person@tablet.png,
                  homepage-person@tablet-2x.png 2x" 
          media="(min-width: 750px)">
  <img srcset="homepage-person@mobile.png,
               homepage-person@mobile-2x.png 2x" 
       alt="Shopify Merchant, Corrine Anestopoulos">
</picture>

上面代码中,picture标签内部有两个source标签和一个img标签。

source标签的media属性给出媒体查询表达式,srcset属性就是img标签的srcset属性,给出加载的图像文件。sizes属性这里也可以用。

浏览器按照source标签出现的顺序,依次判断当前设备是否满足media属性的媒体查询表达式,如果满足就加载srcset属性指定的图片文件,并且不再执行后面的source标签和img标签。

img标签是默认情况下加载的图像,用来满足上面所有source都不匹配的情况。

picture标签还可以用来选择不同格式的图像。比如,如果当前浏览器支持 Webp 格式,就加载这种格式的图像,否则加载 PNG 图像。

<picture>
  <source type="image/svg+xml" srcset="logo.xml">
  <source type="image/webp" srcset="logo.webp"> 
  <img src="logo.png" alt="ACME Corp">
</picture>

上面代码中,标签的type属性给出图像的 MIME 类型,srcset是对应的图像 URL。

浏览器按照source标签出现的顺序,依次检查是否支持type属性指定的图像格式,如果支持就加载图像,并且不再检查后面的source标签了。上面例子中,图像加载优先顺序依次为 svg 格式、webp 格式和 png 格式。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值