前端学习之——h5适配
记得第一次写移动端页面时,本以为就按着效果图就好了,没想到出了很多问题,后来看了网上的一些文章,就试着用媒体查询去各种写样式,但是,总的感觉就是太累,太浪费时间,主要最后出来的效果还不太理想,所以,这种“凭眼神”的方式写页面不是长久之计,决定彻底总结一次,把在各处学到的,自己领悟到的全部清晰罗列,理清思路,这样以后就会越来越专业啦。。。
ps:这是一篇很绕很绕的博客。。
首先,还是要先认识移动端和浏览器端有什么不同?
我们只需要了解:
1、在pc端,css布局窗口尺寸=pc窗口的尺寸,只要效果图设计得好,就按照效果图来就可以了。
需要考虑的是各个浏览器以及浏览器不同版本的兼容。
2、在移动端,由于手机屏幕很窄,如果也让css布局窗口尺寸=手机屏幕窗口尺寸,则在pc端设计的网页,在手机端看起来会很丑。
所以,在移动端,css布局窗口尺寸比手机屏幕尺寸大得多。这样一来,也能避免pc端网页在手机端不会被压扁。
(比如:你写的pc端页面用手机打开来看,会出现横向滚动条,需要左右滑动才能看到整个网页。)
但是,如果手机端的页面如果都要左右滑动看的话,并不理想,手机端更适合窄的页面,所以,出现了一个概念——理想视口。
理想视口定义了不同移动端设备的理想css布局尺寸。
那理想在哪?举个例子:iPhone6的理想视口尺寸为375*667 。
也就是如果css布局 超出 这个尺寸,你就需要滑动才能看到完整页面,但这不是用户所需要的效果!!
在代码中head标签内加上下面的语句,可以将布局尺寸设为理想尺寸:
<meta name="viewport" content="width=device-width"/>
device-width就是理想视口宽度。
解决设备像素比带来的问题
有了理想视口概念之后,设计师会设计针对移动端的效果图,我们也不用左右滑动来看完整页面了。
但是,问题又出现了:设备的物理像素个数 和 理想视口的像素个数 不总是一致的。
因为现在手机大部分都是视网膜屏幕,简单来说,视网膜屏幕就是在相同尺寸的屏幕上压缩更多的像素个数。
这就出现了新的概念——设备像素比。
设备像素比(DPR)=设备物理像素个数 / 理想视口像素个数
比如,早期的iPhone的设备物理像素是320px,理想视口也是320px,所以设备像素比为1。
而iPhone5的设备物理像素是640px,理想视口是320px,所以设备像素比为2。
当然,以上的计算都是基于页面没有 缩放 的情况下 ,缩放是一个改变css像素的过程。所以当你用手指缩放页面的时候就是在增加或减少css像素。
也就是,如果想要让理想视口尺寸在css样式的控制之内,还得控制它的缩放。
在head标签中写下面的代码,可以设置初始缩放和最大缩放都为1,且不允许用户对页面进行缩放:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
>设备像素比,会带来什么问题?
因为设计稿一般是按照设备物理像素尺寸设计的,而且大部分都是按照iPhone6的尺寸:750px。
但是css布局是依据理想视口尺寸。
所以当设备像素比不为1的时候,依据设计稿尺寸写代码就会出错。
就拿iPhone6举个例子:
如果依据750px的尺寸设计了效果图,里面有个宽为375px的盒子,在效果图中它占了一半,但是如果css也写了375px,由于iPhone6的设备像素比为2,即它的理想视口尺寸为375px,所以此时展现出来的效果是占满全屏的。
如下图所示:
可能你会说:那将效果图的尺寸除以2,那不就可以了吗?
重要的是:设计师只会提供一个效果图给我们(一般是iPhone6的),而且并不是所有手机的设备像素比都是2,设备物理像素和理想视口尺寸都各有不同,所以即使将iPhone6的效果图正确展现,也不适配别的手机。
>解决设备像素比带来的问题:
在一开始的时候,我们在meta标签中用width=device-width,将css布局尺寸设置成为了理想布局尺寸,对于iPhone6来说,就相当于将布局尺寸设置成了375px。
那么,怎样让设计图上375px的尺寸,在css中也写375px,还能在iPhone6上显示375px的物理像素尺寸呢?
此时,我们就想到了之前提到的缩放,meta标签中initial-scale=1.0, maximum-scale=1.0可以设置缩放比例。
那么,在iPhone6的例子中,如果把缩放比例设置为设备像素比的倒数,即0.5,这样,不就可以直接按照设计图来写代码,还能正确显示了。
实验一下:
成功了!!
接着,我们又想了:有没有一种方法可以自动知道每种设备的设备像素比呢?答案是:有的。
window.devicePixelRatio可以得到设备像素比。所以只要在js中将meta标签里的缩放比例动态设置为window.devicePixelRatio的倒数就可以了。
如下:
var scale = 1 / window.devicePixelRatio; $("[name='viewport']").attr('content', 'width=device-width,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
这样,不仅可以直接根据设计图尺寸写代码,而且还能在不同的机型上看到同样大小的尺寸。
实验一下:
这样真的完美了吗?
折腾半天,终于完美了!??
从上面的图,我们也看到了:确实是不同尺寸手机上都展现了同一个尺寸的红色长方形盒子,但这真的是我们想要的吗?
我们更希望看到的应该是:同一个盒子在不同尺寸的手机上所占比例都是一样的,那样才完美!
用rem解决比例问题:
rem和em:(对比一下~)
rem是相对于html标签字体大小的相对尺寸单位。例如:html的font-size=12px; 则1rem=12px。
em是相对于父元素标签字体大小的相对尺寸单位。例如:<div style="font-size:12px;"><span class="font-size:2em;"></span></div>; 则span标签中字体大小就为24px。
那怎样用rem解决比例问题呢?
试想:如果页面中的尺寸单位都用rem代替,也就是不再以px为单位。然后html的字体大小如果可以设置一个动态生成的值(每个机型不同)。
这样,比例问题不就解决了吗?
索性,我们就将html的字体大小设为设备像素大小的 1 / 10(iPhone6上就是75px),此刻1rem就相当于75px,5rem就相当于375px。
【在实际写样式的时候就需要用设计图尺寸375除以75,得到5,以rem为单位,即5rem】
也就是:
$('html').css('font-size', document.documentElement.clientWidth / 10 + 'px');
来看最后的效果:
我们通俗理解一下上面这种方法:
就相当于将不同机型尺寸都等分为10份,而那个红盒子在里面都占5份,所以用这种方法可以让盒子在不同机型中所占比例相同。
麻烦在于:就拿iPhone6的设计图来说,html的字体大小算出来是75px,所以每次将效果图上量到的尺寸转化为rem为单位都要除以75,这样会花费很多计算的时间。
都分析到这份上了,那就应该把更好的方法也总结出来:
如果是计算麻烦,那我们就从后往前推:怎样计算比较简单,或者说不用计算器,口算也行呢?
上面的除数是75,比较困难,你就想:如果是100,那就不困难了!
那怎样可以让除数为100呢?(iphone6为设计图尺寸情况下)
那就让设计图所对应的 1rem=100,就可以了
(ps:必须迁就设计图,因为我们是要照着设计图写代码的,对吧?)
即:(750/100) * 各个设备不同的1rem = 各个设备布局尺寸
》》》也就是把所有尺寸手机都等分为7.5份,每一份是多少是动态计算的,由此来保证在每个机型中尺寸所占比例相同!!
还有很重要的一点是:document.documentElement.clientWidth得到的是css布局宽度(理想视口),那在改进方法中,还需要知道设备像素比,然后再控制缩放比吗?
其实,此刻我们只需要知道 等分成几份 的时候计算较方便而已,不是吗?
所以缩放比也不用动态设置了,就按原来1:1就可以了。
改进方法的总代码为:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> * { margin: 0; padding: 0; } </style> </head> <body> <div style="width:3.75rem; height:1rem;background:red;"></div> </body> <script src="js/jquery.js"></script> <script> $('html').css('font-size', document.documentElement.clientWidth / 7.5 + 'px'); console.log(document.documentElement.clientWidth / 7.5); </script> </html>
之前的代码为:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content=""> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> * { margin: 0; padding: 0; } </style> </head> <body> <div style="width:5rem; height:1.333333rem;background:red;"></div> </body> <script src="js/jquery.js"></script> <script> var scale = 1 / window.devicePixelRatio; $("[name='viewport']").attr('content', 'width=device-width,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); $('html').css('font-size', document.documentElement.clientWidth / 10 + 'px'); </script> </html>
所以,改进之后,计算方便了(此处讲的是基于iPhone6效果图的情况)。
那字号也要全部用rem控制吗?
单独把字号拿出来说的原因是:对文字来说,在页面中所占比例不是最重要的,字儿看得清才最重要。
此刻咱们就借鉴一下大公司是怎么做的吧!
淘宝、网易等都是用媒体查询的方式来控制字体大小:
@media screen and (max-width: 321px) { body { font-size:16px } } @media screen and (min-width: 321px) and (max-width:400px) { body { font-size:17px } } @media screen and (min-width: 400px) { body { font-size:19px } }
可以由上面的代码总结出:
1、将尺寸分为三个区间:321px以下,321px~400px,400px以上;
2、第一个区间与第二个区间之间字体大小相差1px,第二个区间与第三个区间之间相差2px;
3、具体每个区间字体设为多少像素,要看效果图。
举例:如果使用iPhone6的效果图,且效果图中字体大小为20px。
由于iPhone6尺寸为375px,在321px~400px区间,所以媒体查询应该写为:
@media screen and (max-width: 321px) {
body {
font-size:19px
}
}
@media screen and (min-width: 321px) and (max-width:400px) {
body {
font-size:20px
}
}
@media screen and (min-width: 400px) {
body {
font-size:22px
}
}
终于总结完了,这下脑子清晰多了,再也不用“凭眼神”了。