一个位图像素是栅格图像(如:png, jpg, gif等)最小的数据单元。每一个位图像素都包含着一些自身的显示信息(如:显示位置,颜色值,透明度等)
pt: point ,点,是一个标准的长度单位,1pt=1/72英寸.
px: pixel,像素,屏幕上显示的最小单位。
一个物理像素是显示器(手机屏幕)上最小的物理显示单元
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: CSS像素)
css像素是由视口缩放比和设计稿的像素决定的。
设备像素比 = 物理像素 / 设备独立像素(在某一方向上,x方向或者y方向)
缩放比:scale = 1/dpr
iOS下,对于2和3的屏,正常按dpr实际值处理,其余的用1倍方案。
- 在 dpr = 1 的设备上设置:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
如 Galaxy S5 中,设置前获取屏宽 window.innerWidth
为 360
,设置后还是 360
。
- 在 dpr = 2 的设备上:
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no" />
如 iPhone6 中,设置前获取屏宽 window.innerWidth
为 375
,设置后是 750
(与物理像素匹配)。
- 在 dpr = 3 的设备上:
<meta name="viewport" content="width=device-width, initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no" />
$ scale = point / pixel $
高倍图:@1x,@2x,@3x
早期的iPhone3GS的屏幕分辨率是320*480(PPI=163),iOS绘制图形(CGPoint/CGSize/CGRect)均以point为单位(measured in points):
1 point = 1 pixel(Point Per Inch=Pixel Per Inch=PPI)
后来在iPhone4中,同样大小(3.5 inch)的屏幕采用了Retina显示技术,横、纵向方向像素密度都被放大到2倍,像素分辨率提高到(320x2)x(480x2)= 960x640(PPI=326), 显像分辨率提升至iPhone3GS的4倍(1个Point被渲染成1个2x2的像素矩阵)。
但是对于开发者来说,iOS绘制图形的API依然沿袭point(pt,注意区分印刷行业的“磅”)为单位。在同样的逻辑坐标系下(320x480):
1 point = scale*pixel(在iPhone4~6中,缩放因子scale=2;在iPhone6+中,缩放因子scale=3)。
可以理解为:
**scale=**绝对长度比*(*****point/pixel)=**单位长度内的数量比*(***pixel/point)
UIScreen.h中定义了该属性:
// The natural scale factor associated with the screen.(read-only)
@property(nonatomic,readonly) CGFloat scale NS_AVAILABLE_IOS(4_0);
--------------------------------------------------------------------------------
This value reflects the scale factor needed to convert from the default logical coordinate space into the device coordinate space of this screen.
The default logical coordinate space is measured using points. For standard-resolution displays, the scale factor is 1.0 and one point equals one pixel. For Retina displays, the scale factor is 2.0 and one point is represented by four pixels.
--------------------------------------------------------------------------------
为了自动适应分辨率,系统会根据设备实际分辨率,自动给UIScreen.scale赋值,该属性对开发者只读。
iOS8新增了nativeScale属性:
// Native scale factor of the physical screen
@property(nonatomic,readonly) CGFloat nativeScale NS_AVAILABLE_IOS(8_0);
以下是iPhone6+下的输出,初步看来nativeScale与scale没有太大区别:
--------------------------------------------------------------------------------
(lldb)p (CGFloat)[[UIScreen mainScreen] scale] (CGFloat) $1 = 3 (lldb) p(CGFloat)[[UIScreen mainScreen] nativeScale] (CGFloat) $2 = 3
--------------------------------------------------------------------------------
在同样的逻辑分辨率下,可以通过scale参数识别是iPhone3GS还是iPhone4(s)。以下基于nativeScale参数,定义了探测机型是否为iPhone6+的宏:
--------------------------------------------------------------------------------
// not UIUserInterfaceIdiomPad #define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) // detect iPhone6 Plus based on its native scale #define IS_IPHONE_6PLUS (IS_IPHONE && [[UIScreenmainScreen] nativeScale] == 3.0f)
--------------------------------------------------------------------------------
那么,同样的分辨率和scale,如何区分机型iPhone4与4s、iPhone5与5s呢?通过[[UIDevice currentDevice] model]只能判别iPhone、iPad、iPod大类,要判断iPhone具体机型型号,则需要通过sysctlbyname("hw.machine")获取详细的设备参数信息予以甄别。
我们通常所说的iPhone5屏幕尺寸为4英寸、iPhone6屏幕尺寸为4.7英寸,指的是显示屏对角线的长度(diagonal)。
PPI(Pixel Per Inch by diagonal):表示沿着对角线,每英寸所拥有的像素(Pixel)数目。表示了清晰度。
PPI数值越高,代表显示屏能够以越高的密度显示图像,即通常所说的分辨率越高、颗粒感越弱。
rem:html根字号大小
$ 设计稿的宽/设计稿px = 屏幕宽/屏幕px $
<meta name="viewport" content="initial-scale=1,width=device-width,user-scalable=0,maximum-scale=1" />
- 采用scale = 1.0写死viewport
- 采用媒体查询来确定html根元素的font-size值,即rem值
- rem + 百分比布局
媒体查询的css代码如下:
//网易彩票的响应式布局是采用媒体查询来改变rem值实现的
//媒体查询css
#media-query{
@media screen and (min-width: 240px) {
html,body,button,input,select,textarea {
font-size:9px!important;
}
}
@media screen and (min-width: 320px) {
html,body,button,input,select,textarea {
font-size:12px!important;
}
}
@media screen and (min-width: 374px) {
html,body,button,input,select,textarea {
font-size:14px!important;
}
}
@media screen and (min-width: 400px) {
html,body,button,input,select,textarea {
font-size:15px!important;
}
}
// 省略
}
- 采用scale = 1.0写死viewport
- 不采用rem,body的font-size=14px写死
- px + flexbox布局
- 通过js处理获取手机dpr参数,然后动态生成viewpoint
- 获取手机物理像素宽度,分成10份,每一份的宽度即是rem的尺寸。
- 根据设计稿的尺寸(px)分三种情况进行处理,采用px + rem布局
相关的脚本如下:
$(document).ready(function(){
var dpr, rem, scale;
var docEl = document.documentElement;
var fontEl = document.createElement('style');
var metaEl = document.querySelector('meta[name="viewport"]');
var view1 = document.querySelector('#view-1');
if(window.screen.width < 540){
dpr = window.devicePixelRatio || 1;
scale = 1 / dpr;
rem = docEl.clientWidth * dpr / 10;
}else{
dpr = 1;
scale =1;
rem = 54;
}
//貌似最新的淘宝网站又去掉了,只是限制了主体内容的宽度
// 设置viewport,进行缩放,达到高清效果
metaEl.setAttribute('content', 'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ',user-scalable=no');
// 设置整体div的宽高
view1.setAttribute('style', 'width:'+ docEl.clientWidth+'px; height:'+ docEl.clientHeight+'px');
// 设置data-dpr属性,留作的css hack之用
docEl.setAttribute('data-dpr', dpr);
// 动态写入样式
docEl.firstElementChild.appendChild(fontEl);
fontEl.innerHTML = 'html{font-size:' + rem + 'px!important;}';
$('body').attr('style', 'font-size:' + dpr * 12 +'px');
// 给js调用的,某一dpr下rem和px之间的转换函数
window.rem2px = function(v) {
v = parseFloat(v);
return v * rem;
};
window.px2rem = function(v) {
v = parseFloat(v);
return v / rem;
};
window.dpr = dpr;
window.rem = rem;
})
从以上的分析我们不难看出:
- 网易彩票的方案上手快,开发效率高,兼容性好,但是不够灵活和精细;
- 天猫的设计思路比较简单,flexbox非常灵活,但是flexbox的兼容性方面需要好好处理,不够精细;
- 淘宝的方案几乎解决了移动端遇到的所有问题,堪称完美的解决方案,但是开发效率低、成本比较高。
iOS : masnory 第三方框架自动布局,iOS常用布局方案
Android:AndroidSwipeLayout,flexbox-layout ,awesome-Android-layout