移动web必会技能--屏幕适配(物理像素CSS像素)

屏幕适配,一直是做为一个前端开发始终逃不掉的问题,这个话题能够追溯到最开始的PC端浏览器的不一样分辨率,再到移动端不一样的屏幕尺寸,一直伴随着前端工程师的平常的页面开发工做。所谓屏幕适配,能够理解为一个网页元素或者网页布局,在不一样尺寸,分辨率等场景下,如何呈现最佳的效果。 从最先的PC端屏幕来讲,大部分的屏幕适配采起的是:javascript

  • 页面框架最外层元素宽度固定,而且居中,高度随内容自适应,比较常见的是宽度为960px~1080px。
  • 页面内部的元素大多数使用盒子模型构建,采用固定宽高,当内容超出时,会出现滚动条。
  • 对于一些须要根据屏幕不一样而展现不一样大小的元素,能够给元素设置百分比的单位。

随着HTML5和CSS3的到来,逐渐出现了弹性布局(flex布局),媒体查询Media Query,和响应式页面概念,这些特性均可以应用在PC端以及移动端屏幕适配解决方案中。除了这些以外,还有rem和vw方案更加有针对性的解决移动web页面的适配问题。css

Viewport视窗

在HTML代码的<head>标签中,都有一行设置的代码,以下:html

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
复制代码

这行代码的做用就是设置浏览器的视窗大小,具体的含义咱们后面在介绍,在讲解视窗以前,咱们首先须要了解一下什么是物理像素和CSS像素。前端

物理像素和CSS像素

像素,也就是px,实际是pixel的缩写,它是图像显示的基本单元,每一个像素能够有色彩数值和位置,每一个图像是由若干个像素组成,好比对一幅标有1024×768像素的图像,就代表这幅图像的长边有1024个像素,宽边有768个像素,共有1024×768=786432个像素组成。可是从概念上来讲,像素既不是一个肯定的物理量,也不是一个点或者小方块,而是一个抽象概念。因此像素所表明的具体含义要从其处于的上下文环境来具体分析。物理像素和CSS像素就是不一样的上下文。java

  • 物理像素:设备屏幕实际拥有的像素点,主要和渲染硬件相关。好比iPhone6的屏幕在宽边有750个像素点,长边有1334个像素点,因此iPhone6总共有750*1334个物理像素。
  • CSS像素:也叫逻辑像素,是软件程序系统中使用的像素,每种程序能够有本身的逻辑像素,在web前端页面就是对应的CSS像素,逻辑像素在最终渲染到屏幕上时由相关系统转换为物理像素。
  • 设备像素比:一个设备的物理像素与逻辑像素之比。能够在JavaScript中使用window.devicePixelRatio获取到。

其实对于早期PC端web页面来讲,在的CSS里写个1px,屏幕就给你渲染成1个实际的像素点,此时的设备像素比是1,这时物理像素和CSS像素是同样的。可是对于一些高清屏,例如苹果的retina屏幕,这种屏幕使用2个或者3个物理像素来渲染1个CSS像素,因此这些屏幕的显示效果要清晰不少。例以下图a表明物理像素,b表明CSS像素,它们之间的关系如图下图所示。 web

图片描述
能够想象一下,一个传统的PC端web页面,若是想要彻底放在手机端使用浏览(能够想象成把PC端显示器替换成手机屏幕),必定是放不下的,而这时就须要对页面进行缩放,那么对页面进行放大和缩小,其实就是改变像素比,例以下图,用4个CSS像素和4个物理像素来模拟放大和缩小。
图片描述
在页面处于正常状态时,4个物理像素的区域须要4个CSS像素恰好展现完,当页面缩小时,本来4个物理像素须要大于4个CSS像素才能显示完这片区域,而当页面放大时,本来4个物理像素须要小于4个CSS像素就能够显示完,或者说是4个CSS像素可以放下更多于4个物理像素的位置。这就实现了页面的放大和缩小,而对于HTML而言,控制放大和缩小的就是视窗Viewport。

视窗

在了解了物理像素和CSS像素的概念以后,而后就须要引入下一个概念,移动设备中的视窗,视窗就是浏览器显示页面内容的屏幕区域,有3种不一样的类别,主要分为:前端工程化

  • 物理视窗(Visual Viewport):表示物理屏幕的可视区域,屏幕显示器的物理像素,也就是长宽边上有多少个像素点。一样尺寸的屏幕,像素点越多,像素密度越大,它的硬件像素会更多。能够理解成物理视窗的大小就是屏幕的大小。
  • 布局视窗(Layout Viewport):是由浏览器厂商提出的一种虚拟的布局视窗,用来解决页面在手机上显示的问题。这种视窗能够经过<meta>标签设置viewport来修改。每一个浏览器默认都会有一个设置,例如iOS,Android这些机型设置布局视窗宽度为980px,因此PC上的网页基本能在手机上呈现,只不过元素看上去很小,通常能够经过手指动双击缩放网页。
  • 理想视窗(Ideal Viewport):理想中的视口。这个概念最先由苹果提出,其余浏览器厂商陆续跟进,目的是解决在布局视窗下页面元素太小的问题,显示在理想视口中的页面具备最理想的宽度,用户无需进行缩放。因此理想视窗就至关于把布局视窗修改为一个理想的大小,这个大小和物理视窗基本相等。

以下图,能够表示物理视窗和布局视窗的关系,底部的网页大小至关于布局视窗,而半透明灰色区域表示物理视窗大小,看起来就像一个手机屏幕大小。 浏览器

图片描述
因此若是想要在物理视窗里面彻底展现布局视窗里的内容,确定要将页面缩小。那么缩小到多少合适呢,就须要有理想视窗,以下图所示。
图片描述

设置Viewport

对于移动端web页面,能够采用<meta>标签对视窗的大小,缩放等进行配置,也就是以前提到的在<head>标签内设置的<meta>的代码以下:bash

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
复制代码

其中,能够配置的属性含义以下:前端工程师

  • width:该属性被用来控制视窗的宽度,能够将width设置为320这样确切的像素数,也能够设为device-width这样的关键字,表示设备的实际宽度,通常为了自适应布局,广泛的作法是将width设置为device-width。
  • height:该属性被用来控制视窗的高度,能够将height设置为640这样确切的像素数,也能够设为device-height这样的关键字,表示设备的实际高度,通常不会设置视窗的高度,这样内容超出的话采用滚动方式浏览。
  • initial-scale:该属性用于指定页面的初始缩放比例,能够配置0.0~10的数字,initial-scale=1表示不进行缩放,视窗恰好等于理想视窗,当大于1时表示将视窗进行放大,小于1时表示缩小。这里只表示初始视窗缩放值,用户也能够本身进行缩放,例如双指拖动手势缩放或者双击手势放大。
  • maximum-scale:该属性表示用户可以手动放大的最大比例,能够配置0.0~10的数字。
  • minimum-scale:该属性相似maximum-scale,用来指定页面缩小的最小比例。一般状况下,不会定义该属性的值,页面过小将难以浏览。
  • user-scalable:该属性表示是否容许用户手动进行缩放,可配置no或者yes。当配置成no时,用户将不能经过手势操做的方式对页面进行缩放。

在使用<meta>标签设置viewport时有几点须要注意,首先viewport只对移动端浏览器有效,对PC端浏览器是无效的,其次对于移动端浏览器,某些属性也并非彻底支持,例如对于iOS的Safari浏览器,从10.0版本开始将不在支持user-scalable=no,因此即便设置了user-scalable=no,用户依然能够对页面进行手势操做来缩放。若是依然须要禁用,能够参考以下代码:

window.onload = function () {
  document.addEventListener('touchstart',  function(event) {
    // 当两个手指操做
    if (event.touches.length > 1) {
       // 组织浏览器默认事件
       event.preventDefault();
    }
  });
  
  var lastTouchEnd = 0;
  document.addEventListener('touchend', function(event) {
    var now = (new Date()).getTime();
    // 判断是不是双击操做,即两次点击间隔小于300ms
    if (now - lastTouchEnd <= 300) {
     // 组织浏览器默认事件
      event.preventDefault();
    }
    lastTouchEnd = now;
  }, false);
}
复制代码

经过手势来进行缩放是属于浏览器的默认功能,上面代码的原理就是利用event.preventDefault()方法,来禁用浏览器的默认事件,这样就不能触发这个默认的缩放功能。具体逻辑能够将代码运行以后看一下效果。 Viewport视窗的相关知识点是了解移动web适配的基础,经过动态的设置viewport能够实现不一样屏幕下的页面适配,例如对设备像素比不为1的机型进行缩放,强制让物理像素和CSS像素相等,代码以下:

(function(){
    var scale = 1/window.devicePixelRatio;
    var meta = document.createElement("meta");
    meta.name = "viewport";
    meta.content = "width=device-width,initial-scale="+scale+",minimum-scale="+scale+",maximum-scale="+scale;
    document.head.appendChild(meta);
})();
复制代码

这种方法有时候不许确,好比devicePixelRatio不为整数的时候,会出现除不尽的状况,那缩放的倍数就会出现很长的小数,再去算物理像素的时候就会有偏差,因此如今大部分移动web页面采用更加完善的rem或者vw加flex的方案来进行适配。

Rem适配

Rem适配方案是当下流行而且兼容性最好的移动端适配解决方案,它支持大部分的移动端系统和机型,Rem其实是一个字体单位,即rem(font size of the root element)是指相对于根元素的字体大小的单位,简单的说它就是一个相对单位。看到rem你们必定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很类似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。 因此Rem适配方案的适配原理就是:将咱们以前写px的单位换成rem单位,而后根据屏幕大小动态设置根元素<html>的font-size大小,那么只要跟元素的font-size改变,对应的元素的大小就会改变,从而达到在不一样屏幕下的适配的目的。

动态设置根元素font-size

使用浏览器浏览网页时,网页中的字体大小由根元素<html>来决定,而<html>的字体大小由浏览器自己决定,在不修改浏览器默认字体状况下是16px,即默认状况下1rem = 16px,可是若是采用Rem的适配方案就须要动态设置<html>的font-size。通常状况下是根据屏幕的宽度来动态设置,即采用屏幕宽度来识别不一样的机型,以达到对不一样机型的适配,具体有两种方案来设置,第一种是采用媒体查询(Media Query),代码以下:

@media screen and (min-width:461px){
    html{
        font-size:18px;
    }
}
@media screen and (max-width:460px) and (min-width:401px){
    html{
       font-size:22px;
    }
}

@media screen and (max-width:400px){
    html{
        font-size:30px;
    }
}
复制代码

上面代码中,使用screen媒体特性,来定义了3组屏幕宽度区间,当小于400px,大于401px且小于460px,大于461px,当屏幕宽度位于不一样的区间时,则会应用上对应的<html>的font-size。 另一种则是使用Javascript动态设置<html>的font-size,代码以下:

// 获取屏幕视窗宽度
let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;// 获取宽度最好有个兼容的方案,避免某些状况下第一种获取不到能够选择第二种
//获取html
let htmlDom = document.getElementsByTagName('html')[0];
htmlDom.style.fontSize = htmlWidth / 10 + 'px';   //求出font-size
复制代码

上面代码中,获得屏幕宽度后,通常要除以一个系数,这里使用的系数是10,这样获得的font-size值更加灵活,适配性更强,因此实际应用当中,大多数采用的JavaScript来动态设置。若是想要实时监听屏幕大小的变化动态修改font-size,能够引入resize事件,代码以下:

window.addEventListener('resize',function(){
    /*上面设置font-size的代码*/
})
复制代码

计算rem数值

设置完font-size以后,就能够直接利用rem单位来给咱们的div或者其余元素设置宽高等等的属性了,这里就有一个问题,咱们通常拿到的UI稿都会提供标注,这些标注通常会标识出某个元素例如按钮,图片具体大小数值,单位是px,而且整个UI稿都会基于一个具体的移动设备,例如iPhone6s等,能够参考下图所示。

图片描述
那么,咱们如何根据视觉稿上的px单位值转换成对应的rem单位值呢?这里举一个例子,一个按钮在视觉搞上标注的大小是:宽200px,高400px,那么咱们根据这个来进行以下计算:

  • 以iPhone6s视觉搞来讲,屏幕是375*667单位是px。
  • 根据上面JavaScript方法设置的<html>的font-size获得是37.5px,这里37.5px称作rem的基准值,下面的计算会用。
  • 根据1rem=37.5px,获得200px=5.3rem,400px=10.6rem。

根据上面的方法,咱们就能够给按钮元素设置rem单位了,代码以下:

.button {
   width: 5.3rem;
   height: 10.6rem;
font-size:0.53rem;
background-color: red;
}
复制代码

咱们给一个元素采用了rem单位来设置了宽高,那么这个元素在不一样机型中显示时,因为设置的根元素<html>的font-size大小不同,那么rem所实际渲染出来的大小也就不同,能够比较一下分别在Chrome开发者工具中的Device Mode中采用iPhone6s和iPhone6P运行的效果区别,如图下图所示。

图片描述
如上图所示,对于同一个按钮,在不一样的机型上表现出的大小是不同的,这就是rem带来的适配效果。 固然,采用rem适配,必须针对rem基准值来将px转换成对应的rem值,这个计算是很繁琐的一件事情,可是这个工做能够交给Sass[ Sass(英文全称:Syntactically Awesome Stylesheets)是一个最初由Hampton Catlin设计并由Natalie Weizenbaum开发的一个CSS预处理器,采用类CSS语法并在最后解析成CSS的脚本语言。]来帮助咱们完成,例如能够在Sass代码中定义一个公式,代码以下:

@function px2rem($px){
    $rem: 37.5;
    @return ($px/$rem) + rem;// $px表示变量,+号表示拼接,rem为字符串至关于'rem'
}
.button {
   width: px2rem(200);
   height: px2rem(400);
   font-size: px2rem(20);
   background-color: red;
}
复制代码

固然,上面的代码已经不是一个标准的CSS代码了,而是一个Sass语言的CSS代码,不过没有学过Sass也没有关系,咱们只会用到Sass的不多一部分知识点。 上面代码中,定义了一个方法,方法名为px2rem,这个方法接收一个参数就是将要转换的px值,而后根据rem基准值来计算。当在给元素设置宽高时,调用这个方法即px2rem(200),将须要转换的px值做为参数传递进去,这样通过编译后,最终获得的就是rem单位的值了即width: px2rem(200)转换成了width:5.3rem。 总结下来,使用Rem适配方案主要有如下几点须要注意:

  • 首先须要有一段JavaScript脚原本动态设置根元素<html>的font-size,这段脚本通常放置在<head>标签里面,让font-size更早的设置,可让适配更早的生效。
  • 一旦页面使用了Rem适配,那么除特殊状况除外(例如雪碧图定位background-position时),页面中凡是用到px为单位的元素都应该改成rem单位,这样才能作到总体适配。
  • 对于宽度比高度大不少的机型例如横屏下的iPad以及一些手写笔记本,是不适合采用Rem方案的,由于宽度较大会致使<html>的font-size设置不许确。另外就是一些小说网站,屏幕越小的移动设备若是用了rem单位就会致使文字就越小,就会致使看文章的时候特别费眼。

vw适配

vw其实也是一个CSS单位,相似的还有vh,vmin,vmax共四个单位,这些单位伴随着CSS3的出现就已经有了,可是当时移动web的浪潮已经来临,而且Rem出现的要早一些,因此不少开发人员对此并不熟悉。 和Rem适配方案相比,vw适配方案不须要使用JavaScript脚原本提早设置font-size,vw适配方案彻底基于CSS自身,这也是相对于Rem适配方案的优点所在,而且对于横竖屏切换较为频繁的页面时能够采用vmin单位,更加灵活。咱们先来了解一下vw,vh,vmin,vmax这几个单位,含义以下:

  • vw : 1vw 等于视口宽度的1%。
  • vh : 1vh 等于视口高度的1%。
  • vmin : 选取vw和vh中最小的那个,1vmin等于视口宽度的1%和视口高度的1%中最小的值。
  • vmax : 选取vw和vh中最大的那个,1vmax等于视口宽度的1%和视口高度的1%中最大的值。

从上面的解释能够看出,vw和vh这些单位也并非一个固定的值,而是根据视口宽度或者高度而变。那么什么是视口呢?还记得以前讲解的viewport吗,经过标签:

<meta name="viewport" content="width=device-width">
复制代码

设置的这个宽度就是视口宽度,而且能够经过JavaScript中的document.documentElement.clientWidth或者document.body.clientWidth获取到这个值,这里就和前面讲解Rem适配方案时获取屏幕宽度时的用法是同样的。 有些同窗会遇到例如window.innerWidth或者window.screen.width来获取屏幕或者视口的宽度,这种方法获取到的通常是设备的物理宽度,例如真实的分辨率或者物理像素值,这个和视口宽度不必定相等,当<meta>标签设置viewport时,若是width=!device-width时,这种状况下就是不相等的,因此各位在使用时仍是须要注意一下。

计算vw数值

对于vw适配方案,也是须要计算vw值的,同理咱们仍是以iPhone6的UI稿为例子,例如一个按钮在视觉搞上标注的大小是宽200px,高400px,那么咱们根据这个来作以下计算:

  • 以iPhone6s视觉搞来讲,屏幕是375*667单位是px。
  • 根据1vw等于视口宽度的1%,即1vw等于3.75px,获得200px=53vw,400px=106vw(这里取整)。

根据上面的方法,咱们就能够给按钮元素设置vw单位了,代码以下:

.button {
   width: 53vw;
   height: 106vw;
   background-color: red;
}
复制代码

和计算rem值同理,也能够利用Sass来声明一个方法,作px到vw的转换,代码以下:

@function px2vw($px) {
    $vw: 3.75;
    @return ($px/$vw)+vw;// $px表示变量,+号表示拼接,vw为字符串至关于'vw'
}
.button {
   width: px2vw(53);
   height: px2vw(106);
   background-color: red;
}
复制代码

不管是转换成rem值仍是vw值,在后续的实战项目中,均可以经过另外一种方式来更加方便的转换。例如能够经过构建的方式,在代码中只须要写px值,经过配置一些插件和工具,最终生成的项目中就是转换好的代码,这就是前端工程化带来的便利。

Rem适配和vw适配兼容性

从上面的对两种相关的适配方案讲解,能够知道vw适配方案要优于Rem适配方案的,可是没有Rem流行就在于vw的兼容性问题,咱们从caniuse[ caniuse是一个当下流行的前端技术兼容性查询网站,地址是:www.caniuse.com/]网站中查询到兼容性以下。

图片描述
图片描述
Rem适配方案在主流浏览器中总体支持性98.93%,而vw适配方案在主流浏览器中总体支持性94.44%,而且对于Android4.4以前的机型来讲vw不支持是硬伤,毕竟这部分机型的市场占有率仍是有一部分的。因此各位在选取适配方案时,要根据本身业务的场景来选择合适的方案,避免出现兼容性问题。

更多关于移动web相关的内容,欢迎关注课程: 《从0到1 实战朋友圈移动Web App开发》 《移动Web App开发之实战美团外卖》

相关文章
相关标签/搜索