作者毕业后一直在做前端工作,现在90%的项目都是和移动端打交道的,所以当“移动H5”这两个字的时候写在简历上,肯定会问到自适应方案和高清方案“自适应”指的是一套UI(比如750*1334),在多终端下显示效果几乎一样;而“高清”指的是由于DPR增强导致的各种精度适配,本文讲的是笔者理解的自适应方案和高清方案。先说结论吧。自适应方案rem适配思路选择一个尺寸作为设计开发基准定义一套适配规则,自动适配剩余尺寸并赋予特殊适配效果设计效果是历史产物,主流不支持CSS窗口单元浏览器。原理是根据窗口宽度动态调整根元素html的font-size值。设置总宽度为100份,每一份称为一个单位x。同时将1rem的单位设置为10x。缺点需要加载js脚本,根据设备的窗口宽度计算,影响性能。影响力:自2015年诞生以来,在H5适配领域占有一定比例相关技术库:flexible、px2remvw适配思路(如上)原理利用了css窗口的特性,总宽度为100vw,每个part是1vw的单位,1rem的单位设置为10vw缺点因为是按照view的宽度计算的,所以不适用于平板和pc影响:2018年发布的解决方案,目前H5适配了主流相关技术库:postcss-px-to-viewportpx+calc+clamp适配思路根据CSS新特性解决:css变量、calc()函数、clamp()、@container函数实现特性rem的致命缺陷和vwlayouts:像素完美度的损失,一旦屏幕低于或高于某个阈值,通常会出现布局移动或文本内容溢出在大厂使用它(浏览器支持率clamp功能暂时不高),具体可以看大魔的这篇文章:如何打造一个完美缩放的UI界面缺点因为方案比较先进,目前还没有看到大厂用的高清方案。1像素问题DPR下图片高清方案的不同解决方案综上所述,自适应方案是解决各个终端的适配问题,高清方案是解决Retina屏的细节问题。在讲移动端适配方案之前写在前面了。技术概念Deviceindependentpixel(DIP)===CSSpixel===logicalpixel,在Chrome中可以直接看到375*667当看到deviceindependentpixel的时候,别慌,是CSS像素,它的长宽是在Chrome中找的,可以这样记,“deviceindependentpixels”,字数长,文字是CSS像素,也是理论上给定的索引,也叫logicalpixelsphysicalpixelsphysicalpixels可以理解为手机厂商在销售手机时标榜的分辨率,即物理像素=分辨率,表示垂直和水平方向的像素个数,即设备屏幕水平方向有1920个像素点,垂直方向有1080个像素点。像素(假设屏幕分辨率为1920*1080),即屏幕分辨率代表物理像素,出厂时固定,单位为pt,1pt=0.376mm物理像素,也称为设备像素,这意味着设备像素===物理像素。可以这样记住,设备在物理世界中可以测量的长度DPR(DevicePixelRatio),什么是设备像素比(DPR)?DPR=devicepixel/deviceindependentpixel,通常与视网膜屏(Retinascreen)相关以iPhone7为例,iPhone7的DPR=iPhone7物理像素/iPhone7deviceindependentpixel=2width1334/667=2height750/375=2iPhone7的DPR为2,也就是我们常说的视网膜屏,这是一个营销术语。正是因为技术的进步,一个CSS像素被插入到更多的物理像素中。还有哪些营销术语:农夫山泉的大天然搬运工和元气森林的“氪”是笔者记忆中的样子:CSS像素(deviceindependentpixels)就像一个容器。以前是一个一个插入的,所以DPR为1。后来随着技术的发展,一个容器可以塞入更多的真实像素(物理像素)DPR=devicepixels/deviceindependentpixelsDPR=physicalpixels(real)/CSSpixels(virtual)在retina屏幕中,以DPR=2为例,把4(2x2)个物理像素作为一个CSS像素,让屏幕看起来更清晰(精致),但是尺寸元素(CSS像素)本身不会改变。随着硬件的发展,iPhone13Pro等手机的DPR已经是3,未来DPR突破4不是问题。话又说回来,如果DPR是2或3会有什么问题?我们以CSS为最小单位编写代码,并以CSS为最小单位显示在屏幕上。也就是说,当DPR为2时,我们不能模拟1个单位的物理像素(如果浏览器支持使用0.5px的CSS,是可以模拟的,但是如果DPR为3,就使用0.333px?);又因为手机的deviceindependentpixel(CSSpixel)是固定的,在使用传统静态布局(fixedpx)时,会出现样式错位iPhone5/SE:320*568DPR:2iPhone6/7/8:375*667DPR:2iPhone6/7/8Plus:414*736DPR:3iPhoneX:375*812DPR:3所以我们要适配每个终端的CSS像素和1像素问题和高清问题不同DPR下的图片。随着技术的发展,前端摆脱了对IE的兼容,同时陷入各大手机品牌的兼容沼泽自适应方案Rem布局-全球第二简介:rem是相对于计算的根元素html的font-size与rem关联的是em:当em作为font-size单位时,表示父元素的字体大小,当em作为其他属性的单位时,表示自己的字体大小。当rem作用于非根元素时,相对于根元素的字体大小,当rem作用于根元素的字体时,相对于其初始字体大小,本质是按比例缩放,通过模拟vw的特性JavaScript。假设将屏幕宽度平均分为100份,每份的宽度用x表示,x=screenWidth/100,如果以x为单位,则x前面的数值代表该部分的百分比screenwidthp{width:50x}/*屏幕宽度的50%*/如果我们想让页面元素随屏幕宽度按比例变化,我们就需要上面的x,这个x是vw,但是vw用在了上大规模浏览器支持后。在此之前,js+rem可以模拟这种效果。前面说过,当rem作用于非根元素时,相对于根元素的字体大小,所以我们设置根元素单位后,非根元素使用rem作为相对单位html{font-size:16px}p{width:2rem}/*32px*/html{font-size:32px}p{width:2rem}/*64px*/问题来了,我们需要获取一个动态的根元素font-size,并改变大小每个元素。有意思的是,我们两个项目目前的做法是通过媒体查询设置根元素,将元素分为四级,默认为16px。作者对这种做法表示不理解。原开发者说我们这一套跑了6年了,UI适配也没人说。这里有个问题,是不是真的像他说的那样很好适配UI,“媒体查询根元素+rem”也能适配吗?完美吗?作者后面也会在demo中展示这种做法,但是根元素的font-size是怎么变化的呢?它不能总是16px。在中大屏还好,但是小屏字体太大,所以它的size也要动态取。如何让它动态化,上面说了让根元素的font-size等于屏幕宽度的1/100html{font-size:width/100};如何设置html的字体大小等于屏幕宽度的100三分之一呢?可以通过js设置,一般需要在页面domready、resize和screenrotation中设置document.documentElement.style.fontSize=document.documentElement.clientWidth/100+'px';灵活的源码如上面思路中写的设置1%宽度后,在写css的时候,需要使用css处理器如scss/less来编译处理css。假设给定的设计图是750*1334,一个元素的宽度是200px。根据公式:width:200/750*100=26.67rem在sass中需要设置设计图的宽度进行转换:@use'sass:math';$宽度:750px;@functionpx2rem($px){@return#{math.div($px,$width)*100}rem;}将上面的div{width:26.667rem}编译成不同尺寸后,其宽度随模型尺寸不同而变化宽度为iPhone5/SE320*568170*170iPhone6/7/8375*667200*200iPhone6/7/8Plus414*736220.797*220.797iPhoneX375*812200*200。演示是介绍灵活的库,其字体大小根元素是屏幕的1/10)rem布局(灵活)demo优点:rem兼容性能低至ios4.1,android2.1缺点:比例缩放(可以说是优点也可以理解为缺点,用于不同的场景)用户选择大屏有几个出发点,有些人想要更大的字体,更大的图片,有些人想要更多的内容,而不想要更大的图标字体大小不能使用rem(一般使用mediaquery来控制font-size大小)在PC端浏览,一般设置一个最大宽度varclientWidth=document.documentElement.clientWidth;clientWidth=clientWidth<780?客户端宽度:780;文档.文档元素。style.fontSize=clientWidth/100+'px';正文{边距:自动;width:100rem;}用户禁止js怎么办?添加noscribe标签提示用户为HTML添加默认字体大小相关技术方案:flexible(amfe-flexibleorlib-flexible)+postcss-pxtoremViewportlayout-VW不是我生的,适配永夜vw是基于Viewport窗口的长度单位,这里的视口(Viewport)指的是浏览器可视化区域,而这个可见区域的大小是window.innerWidth/window.innerHeight根据CSSValuesandUnitsModuleLevel4:vw等于初始包含块(html元素)宽度的1%,即就是,1vw等于window.innerWidth的值的1%1vh等于window.innerHeight值的1%看图就明白在讲rem布局的时候,我曾经举过x的例子,x就是vw/*remscheme*/html{font-size:width/100}div{width:26.67rem}/*vwscheme*/div{width:26.67vw}vw也可以结合remscheme,不需要js计算html字体大小html{font-size:1vw}div{width:26.67rem}效果如下:vw适配是CSS原生支持的,大部分手机s目前支持兼容,不需要加载js,不会有js带来的性能问题。vw确实不错,但是也有一些问题。可以很好的解决1px边框在高清屏上的显示问题。需要自己处理。由于vw的解法是完全按比例缩放的,所以在PC端会被打断(和rem一样)。相关技术方案:postcss-px-to-viewportVW布局demopx适配——一幂降十不会使用rem/vw,移动端布局也可以使用传统的响应式布局,需要设计规范使用css变量适配(篇幅原因就不详细介绍了,直接看代码)使用场景:新闻,内容类网站,不适合rem,因为大屏用户想看更多内容,比如网易新闻,知乎,taptapPX+CSS变量演示媒体查询-我有座位吗?上面说了,我们公司原来的H5端是用mediaquery的方式适配的。我试过复现,只能说区别还不错。看得出来mediaquery想干这个,不过我还是心有余而力不足。动力不足,用rem、vw、px等。该方法可以实现非标准尺寸(375667设计稿)下header的高度为165.59px,由于媒体大屏,rootfont-size设置为17px,而header的高度header变成159.38px(179.375rem)如下图GIF注:所以只用mediaquery还是不行。媒体查询布局演示的各种改编的比较。vw和rem自适应的本质是比例缩放。直接写成px。具体哪个好就看你自己了REMlayoutVWlayoutPX+css支持可变布局容器的最小宽度。不支持容器的最大宽度。不支持容器的最大宽度。支持高清设备的1px边框。支持容器的固定纵横比。1.无需导入js2。自然支持,写法跟VW一样缺点1.需要导入js设置html2的font-size。字号不能用rem3.PC端浏览会破图,一般需要设置最大宽度1.PC端会破外观2.不支持老手机。除了VW,还有一个方案是匹配vw和rem。随窗口变化设置根元素大小的vw单位,动态改变每个元素的大小来限制根元素的字体大小。最大值和最小值,结合body加上最大宽度和最小宽度//rem单位转换:75px只是为了方便计算,750px-75px,640-64px,1080px-108px等等$vm_fontsize:75;//iPhone6size根元素大小的基值@functionrem($px){@return($px/$vm_fontsize)*1rem;}//根元素大小使用vw单位$vm_design:750;html{font-大小:($vm_fontsize/($vm_design/2))*100vw;//同时通过MediaQueries限制根元素的最大值和最小值@mediascreenand(max-width:320px){font-size:64px;}@media屏幕和(最小宽度:540像素){字体大小:108像素;}}//body也增加最大和最小宽度限制为了避免默认的100%宽度的块元素跟随body太大或太小body{max-width:540px;min-width:320px;}高清解1像素问题1像素是指在Retina屏幕上显示1个单位的物理像素很好理解CSS像素(deviceindependentpixels)是我们人为指定的。当DPR为1时,1个像素(指我们写的CSS像素)等于1个物理像素;但是当DPR为3时,1个像素就是3个物理像素DPR=1,此时1个物理像素等于1个CSS像素DPR=2,此时1个物理像素等于0.5个CSS像素border-width:1px,其中1px其实是1个CSS像素宽度,等于2个物理像素,设计师其实想要的是border-width:0.5pxDPR=3,此时1个物理像素等于0.33个CSS像素设计师要的是border-width:0.33px解决办法是用0.5px有限制,iOS8及以上,苹果系统支持,但在iOS8和Android以下(部分低端设备),0.5px会显示为0px,因为1个CSS像素代表2(DPR为2),3(DPR就是3)物理像素,而设备不知道0.5px的写法,就画1px,然后想办法把宽度减半,实现background-image:linear-gradient(totop,,,,)使用scaling实现transform:scaleY(0.333)使用图片实现base64使用SVG实现嵌入背景urlborder-image低端机支持不好以上都是通过CSS媒体查询实现@mediaonlyscreenand(-webkit-min-device-pixel-ratio:2),onlyscreenand(min-device-pixel-ratio:2){}@mediaonlyscreenand(-webkit-min-device-pixel-ratio:3),onlyscreenand(min-device-pixel-ratio:3){}图片适配和优化图片通常占据网页下载资源的绝大部分,优化图片通常可以最小化从网站下载的字节数并提高网站性能。有一些通用的优化手段:为不同的DPR屏幕提供最合适的图像尺寸。看了很多各大厂商适配分析的文章,比如:各大厂商如何适配移动端?各大厂商对rem适配有用,也有用vm适配,vm+rem结合,纯px的场景,比如新闻和社区,里面有很多可读的内容:px+flex+percentage,比如携程、知乎、TapTap都有很多种可视化组件。移动端依赖性强的页面:vw+rem比如电商,论坛总结rem方案,引入amfe-flexible库设计:设计的图片为750*1334,设计好裁剪后上传到蓝湖,写px根据大小。开发:使用rem方案引入amfe-flexible库安装pxtorem工具如px2rem配置px2rem在项目中写入px,输出为rem适用于任何场景使用vw方案安装pxtovw工具如px2vw在项目中配置px2vw中间写px,vw适用于任何场景,用px方案随便写什么,但是因为设计方案,按钮的大小是固定的,图标的大小是标准的,TabBar的高度也是硬编码的。当一切都有了标准之后,写页面就方便了。比如左侧固定为100*50,右侧flex布局左侧固定为100*50,右侧为calc(100%-100px)(使用CSS3中的calc计算)。兼容性问题Q:为什么大部分H5手机UI库单元都使用px?这不会是一个合适的问题吗?其实我们写完px之后,如果项目使用rem写业务,我们可以通过引入px2rem(已经六年没有维护了)来转换。在有赞vant库中,它对浏览器适配的介绍是:ViewportlayoutVant默认使用px作为样式单位。如果需要使用viewport单位(vw,vh,vmin,vmax),推荐使用postcss-px-to-Viewportconversionpostcss-px-to-viewport是一个将px单位转换为vw/的PostCSS插件vhunitsremlayout如果需要使用rem单位进行适配,推荐以下两个工具:postcss-pxtorem是一个PostCSS插件,用于将px单位转换为rem单位lib-flexible用于设置rem基准值demo合集:在线demo参考资料前端基础知识概览——移动端屏幕、图片、字体、布局的兼容性与适配Rem布局原理分析,再说说Retina下1px的解决方案,以及然后说说移动端页面的适配如何在vue项目中使用vw实现移动端适配
