移动端适配基础概念和适配方案
物理像素与设备独立像素:
概念:
分辨率指的是物理像素,物理像素即设计图的像素以及css中的像素。
设备独立像素:实际的视窗口大小。
设备像素比:
每款设备的devicePixelRatio都是已知,并且不变的,目前高清屏,普遍都是2,不过还有更高的,比如2.5, 3 等,魅族note的手机devicePixelRatio就是3。
devicePixelRatio*scale(scale为viewport里设置的值)=屏幕物理像素(与css相对应)/设备独立像素(逻辑像素)。
devicePixelRatio是window对象的一个属性,它被大多数的webkit浏览器所支持。当devicePixelRatio值等于1时(也就是最小值),那么它普通显示屏,当devicePixelRatio值大于1(通常是1.5、2.0),那么它就是高清显示屏。
高清屏(Retina)和普通屏区别:
相同区域的物理像素点数,高清屏是普通屏的几倍。
retina是高清屏,普通屏幕的1个CSS像素点对应4个高清屏幕的像素点,1个分成4个,不够分的情况下,颜色会取近似值。所以在普通屏幕正常显示的图片,在高清屏上会变的模糊。
兼容高清屏:裁切图是2倍图(以高清屏的要求去裁切),在css中使用的时候会使用css设置的尺寸为裁切图的一半。因为在高清屏中使用普通图片的时候,同样的css尺寸,图片被放大了。
设备宽度320像素,当使用<meta name="viewport" content="width=device-width">,视窗的布局宽度会被设置为屏幕的宽度,即320px。页面会很自然的覆盖在屏幕上。
对于iphone4s来说,当屏幕纵向显示的时候,屏幕的物理像素是640像素,而视区宽度不是640像素而是320像素。屏幕的物理像素为640像素,独立像素还是320像素,window.devicePixelRatio=2。
适配普通屏和高清屏的方案
根据不同的设备像素比来加载不同的图片:
- 针对普通显示屏(devicePixelRatio = 1.0、1.3),加载一张1倍的图片
- 针对高清显示屏(devicePixelRatio >= 1.5、2.0、3.0),加载一张2倍大的图片
(1)使用css 的media queries来加载不同图片(意味要切两套图片1倍图和2倍图):
示例的demo如下:
.css{/* 普通显示屏(设备像素比例小于等于1.3)使用1倍的图 */
background-image: url(img_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:1.5){
.css{/* 高清显示屏(设备像素比例大于等于1.5)使用2倍图 */
background-image: url(img_2x.png);
}
}
CSS Media Queries的优点
- 只有对应的目标元素才会下载图片资源
- 跨浏览器兼容
- 像素可以精确控制
CSS Media Queries的缺点
- 单调无味的实现过程,特别是大型项目中
- 只能通过HTML元素的背景图片来实现,无任何语义化可言
(2)JavaScript的解决方案
使用js对"window.devicePixelRatio"进行判断,然后根据对应的值给Retina屏幕选择图像。
$(document).ready(function(){
if (window.devicePixelRatio > 1) {
var lowresImages = $('img');
images.each(function(i) {
var lowres = $(this).attr('src');
var highres = lowres.replace(".", "@2x.");
$(this).attr('src', highres);
});
}
});
Javascript查询的优点
- 易于实施
- 非Retina屏幕不用下载过大的资源
- 像素精确控制
Javascript查询的缺点
- Retina屏幕下必须下载标准和高精密度的两个资源
- Retina屏幕下图像交互可见
- 浏览器兼容性不强
(3)使用SVG矢量图像
SVG矢量图的优点
- 一个资源适合所有设备
- 易于维护
- 面向未来的:可伸缩向量图形
SVG矢量图的缺点
- 没有像素那样有精度
- 由于文件大小,不适合复杂的图形
- 不支持IE7-8和早期的安卓版本
em与rem的区别:
推文:
http://caibaojian.com/rem-vs-em.html
rem 取决于 html 元素的字体大小。
em相对于使用em单位的元素的字体大小,像素值是em值乘以使用em单位的元素的字体大小。父元素的字体大小可以影响 em 值,但这种情况的发生,纯粹是因为继承。 当 em 单位设置在 html 元素上时,它将转换为em值乘以浏览器字体大小的设置。
html——div——padding——1.5em
f-s:16px——16px——16*1.5=24px
html——div——div——padding
f-s:16px——1.25em(20px)——20px——20*1.5=30px
由于存在着这些隐患,所以必须知道如何正确管理使用 em 单位。
默认情况下浏览器通常有字体大小 16px,但这可以被用户更改为从 9px 到 72px的任何值。
正确使用rem和em的场景:
使用 rem 单位的主要目的应该是确保无论用户如何设置自己的浏览器,我们的布局都能调整到合适大小。
//如果您确实需要更改 html 元素的字体大小,那么就使用em,rem单位,这样根元素的值还会是用户浏览器字体大小的乘积。
em 单位的主要目的应该是允许保持在一个特定的设计元素范围内的可扩展性。
当使用 em 单位,他们使用的元素的字体大小应设置对rem单位,以保留的可扩展性,但避免继承混淆。一般使用 rem 单位的字体大小,em 单位只在特殊的情况下使用。
通常不使用 em 单位控制字体大小。
不要使用 em 或 rem :
布局中的列宽通常应该是 %,因此他们可以流畅适应无法预知大小的视区。然而单一列一般仍然应使用 rem 值来设置最大宽度。
偶尔会遇到真的需要使用显式的固定的值,以防止缩放的元素。
布局:
flex布局详细实例:
https://www.cnblogs.com/lynnmn/p/6262941.html
适配方案
流式布局:
宽度使用百分比,高度固定。大屏幕下,会被横向拉伸变形,设计起来也有局限性,有兼容性,大量百分比也不好计算。
固定宽度:
固定宽度,超出部分留白,大屏幕手机下看起来页面会特别小,操作的按钮也很小
响应式:
工作大,维护性难,一般都是中小型的门户或者博客类站点会采用响应式的方法从web page到web app直接一步到位,因为这样反而可以节约成本,不用再专门为自己的网站做一个web app的版本。
设置viewport进行缩放:
例如以320宽度为基准,进行缩放,最大缩放为320*1.3 = 416,基本缩放到416都就可以兼容iphone6 plus的屏幕了,这个方法简单粗暴,又高效。不过有反应缩放会导致有些页面元素会糊的情况。·
<meta name="viewport" content="width=320,maximum-scale=1.3,user-scalable=no">
使用flexbox
https://www.cnblogs.com/lynnmn/p/6262941.html
rem等比例适配所有屏幕:
· 根据不同的屏幕算出html的font-size,而页面内的大小单位都用rem来写,利用rem单位相对根元素的font-size来做计算,从而实现了自适应。
设计图尺寸与适应尺寸之间的换算:
推文:
http://caibaojian.com/mobile-responsive-example.html
方案一:
scale设置为1,整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小(实际的视窗口大小),比如设计稿横向分辨率为640px,为了计算方便,取一个100px的font-size为参照,那么body元素的宽度就可以设置为width: 6.4rem,于是html的font-size=deviceWidth / 6.4。这个deviceWidth就是viewport设置中的那个deviceWidth。
这个deviceWidth通过document.documentElement.clientWidth就能取到了,所以当页面的dom ready后,做的第一件事情就是:·
document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
注意两点:
视口要如下设置:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
相关知识点:[S3-E415]常用meta整理
当deviceWidth大于设计稿的横向分辨率时,html的font-size始终等于横向分辨率/body元素宽:
因为当deviceWidth大于640时,则物理分辨率大于1280(这就看设备的devicePixelRatio这个值了),应该去访问pc网站了。
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
方案二:
当scale根据devicePixelRatio动态设置,每款设备的devicePixelRatio都是已知,并且不变的,目前高清屏,普遍都是2,不过还有更高的,比如2.5, 3 等。
1、动态设置scale:
var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
deviceWidth=物理分辨率/(devicePixelRatio * scale)——》deviceWidth=物理分辨率=document.documentElement.clientWidth(和方案一一样)
2、font-size = deviceWidth / 100:——》font-size
3、当横向分辨率达到某个临界点,deviceWidth就等于某个值
总结:方案二肯定的用计算器。。但是使用css处理器的话就好办了:
但是上面两种方法的font-size都是使用媒体查询做的,使用js能适配所有。
更改html的font-size,一种是使用js(能适配所有尺寸)—— flexible.js。
一种使用媒体查询(适配部分设备,一般在做web app都会先统计网站有哪些主流的屏幕设备,然后去针对那些设备去做media query设置也可以实现适配)