屏幕适配,一直是做为一个前端开发始终逃不掉的问题,这个话题能够追溯到最开始的PC端浏览器的不一样分辨率,再到移动端不一样的屏幕尺寸,一直伴随着前端工程师的平常的页面开发工做。所谓屏幕适配,能够理解为一个网页元素或者网页布局,在不一样尺寸,分辨率等场景下,如何呈现最佳的效果。 从最先的PC端屏幕来讲,大部分的屏幕适配采起的是:javascript
随着HTML5和CSS3的到来,逐渐出现了弹性布局(flex布局),媒体查询Media Query,和响应式页面概念,这些特性均可以应用在PC端以及移动端屏幕适配解决方案中。除了这些以外,还有rem和vw方案更加有针对性的解决移动web页面的适配问题。css
在HTML代码的<head>
标签中,都有一行设置的代码,以下:html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
复制代码
这行代码的做用就是设置浏览器的视窗大小,具体的含义咱们后面在介绍,在讲解视窗以前,咱们首先须要了解一下什么是物理像素和CSS像素。前端
像素,也就是px,实际是pixel的缩写,它是图像显示的基本单元,每一个像素能够有色彩数值和位置,每一个图像是由若干个像素组成,好比对一幅标有1024×768像素的图像,就代表这幅图像的长边有1024个像素,宽边有768个像素,共有1024×768=786432个像素组成。可是从概念上来讲,像素既不是一个肯定的物理量,也不是一个点或者小方块,而是一个抽象概念。因此像素所表明的具体含义要从其处于的上下文环境来具体分析。物理像素和CSS像素就是不一样的上下文。java
window.devicePixelRatio
获取到。其实对于早期PC端web页面来讲,在的CSS里写个1px,屏幕就给你渲染成1个实际的像素点,此时的设备像素比是1,这时物理像素和CSS像素是同样的。可是对于一些高清屏,例如苹果的retina屏幕,这种屏幕使用2个或者3个物理像素来渲染1个CSS像素,因此这些屏幕的显示效果要清晰不少。例以下图a表明物理像素,b表明CSS像素,它们之间的关系如图下图所示。 web
在了解了物理像素和CSS像素的概念以后,而后就须要引入下一个概念,移动设备中的视窗,视窗就是浏览器显示页面内容的屏幕区域,有3种不一样的类别,主要分为:前端工程化
<meta>
标签设置viewport来修改。每一个浏览器默认都会有一个设置,例如iOS,Android这些机型设置布局视窗宽度为980px,因此PC上的网页基本能在手机上呈现,只不过元素看上去很小,通常能够经过手指动双击缩放网页。以下图,能够表示物理视窗和布局视窗的关系,底部的网页大小至关于布局视窗,而半透明灰色区域表示物理视窗大小,看起来就像一个手机屏幕大小。 浏览器
对于移动端web页面,能够采用<meta>
标签对视窗的大小,缩放等进行配置,也就是以前提到的在<head>
标签内设置的<meta>
的代码以下:bash
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=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(font size of the root element)是指相对于根元素的字体大小的单位,简单的说它就是一个相对单位。看到rem你们必定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很类似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。 因此Rem适配方案的适配原理就是:将咱们以前写px的单位换成rem单位,而后根据屏幕大小动态设置根元素<html>
的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的代码*/
})
复制代码
设置完font-size以后,就能够直接利用rem单位来给咱们的div或者其余元素设置宽高等等的属性了,这里就有一个问题,咱们通常拿到的UI稿都会提供标注,这些标注通常会标识出某个元素例如按钮,图片具体大小数值,单位是px,而且整个UI稿都会基于一个具体的移动设备,例如iPhone6s等,能够参考下图所示。
<html>
的font-size获得是37.5px,这里37.5px称作rem的基准值,下面的计算会用。根据上面的方法,咱们就能够给按钮元素设置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运行的效果区别,如图下图所示。
@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适配方案主要有如下几点须要注意:
<html>
的font-size,这段脚本通常放置在<head>
标签里面,让font-size更早的设置,可让适配更早的生效。<html>
的font-size设置不许确。另外就是一些小说网站,屏幕越小的移动设备若是用了rem单位就会致使文字就越小,就会致使看文章的时候特别费眼。vw其实也是一个CSS单位,相似的还有vh,vmin,vmax共四个单位,这些单位伴随着CSS3的出现就已经有了,可是当时移动web的浪潮已经来临,而且Rem出现的要早一些,因此不少开发人员对此并不熟悉。 和Rem适配方案相比,vw适配方案不须要使用JavaScript脚原本提早设置font-size,vw适配方案彻底基于CSS自身,这也是相对于Rem适配方案的优点所在,而且对于横竖屏切换较为频繁的页面时能够采用vmin单位,更加灵活。咱们先来了解一下vw,vh,vmin,vmax这几个单位,含义以下:
从上面的解释能够看出,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值的,同理咱们仍是以iPhone6的UI稿为例子,例如一个按钮在视觉搞上标注的大小是宽200px,高400px,那么咱们根据这个来作以下计算:
根据上面的方法,咱们就能够给按钮元素设置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值,经过配置一些插件和工具,最终生成的项目中就是转换好的代码,这就是前端工程化带来的便利。
从上面的对两种相关的适配方案讲解,能够知道vw适配方案要优于Rem适配方案的,可是没有Rem流行就在于vw的兼容性问题,咱们从caniuse[ caniuse是一个当下流行的前端技术兼容性查询网站,地址是:www.caniuse.com/]网站中查询到兼容性以下。
更多关于移动web相关的内容,欢迎关注课程: 《从0到1 实战朋友圈移动Web App开发》 《移动Web App开发之实战美团外卖》