关于一些基本概念如设备像素,css像素,参考
- 移动端适配方案(上)
- CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport
像素
上图的pt和px互换才正确,reader @2x 指设备像素比
meta里面设置width=device-width,这个device-width就是设备独立像素。
在chrome里 看到的375*667是设备独立像素
设计师给的是640px宽的设计稿是根据设备像素(device pixel,物理像素)为单位制作的设计稿;而前端工程师参照相关的设备像素比来进行换算,比如根据iPhone5出稿的设计稿的中有一个width:100px,height:200px的按钮,那么前端工程师在编码web页面时应该写width:50px,height:100px。他们之间的换算比例是根据设备像素比来计算的。
当,iphone5的css像素是320X568,当
,css像素变成640X1136(如下图),这是因为当scale=1,1个css像素对应2个物理像素,而iphone5的物理像素是640X1136,当scale=0.5,1个css像素对应1个物理像素,css像素必须变成640X1136才能刚好完全对应所有物理像素,需要注意的是当scale=1,你用css写div height:50px;在开发者工具inspect div,确实高50px,变成scale=0.5,在开发者工具看div的height还是50px
动态rem
rem这个单位代表根元素的 font-size 大小,例如 元素的font-size为16px,则1rem=16px
手机有很多不同分辨率,如下图,如果用响应式,要做3套css,如果只想做1套css适应不同手机,方法是用百分比布局或整体缩放
百分比布局:
缺点是高度不能确定,不能实现例如宽高2:1,例如.child {height:20%} 是没用的
整体缩放:
在解决这个问题上vw是最好的,因为vw和设备宽度有关,1vw=视口宽度的 1/100,但兼容性差
另外的方法就是动态rem,动态rem的简单实现:https://jsbin.com/zoxizor/1/edit?html,css,output
- 在 SCSS 里使用 PX2REM :
在 scss 文件里添加
@function px( $px ){
@return $px/$designWidth*10 + rem;
}
$designWidth : 640; // 640 是设计稿的宽度,
.child{
width: px(320); //5rem
height: px(160);
margin: px(40) px(40);
border: 1px solid red;
float: left;
font-size: 1.2em;
}
即可实现 px 自动变 rem
移动端1px问题
以 dpr=2 为例:
你拿到一张标准的基于 iphone6 的设计稿(750px)
你看到它设计的一个 border宽度是 1px
那么border的其实是 border: 0.5px solid #000;
但问题是在iOS 7 和之前版本,OS X Mavericks 及以前版本,还有 Android 设备上浏览器可能不认识0.5px的边框,将会把它解释成0px,没有边框。所以网上有很多其他的实现1px边框的方法
而所谓的1px变粗请看 javascript - 1px边框在移动端变粗问题产生的原理 , 移动端高清、多屏适配方案
设计稿上有1像素边框,当你面对不同的屏幕时你希望它的行为是怎样的?设计师希望在不同dpr的屏幕上这条线都是1物理像素。
下面flexible.js的部分代码可以实现,
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
if (!metaEl) {
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
当直接写,且dpr=2,border:1px,渲染出来是2px物理像素
当,此时页面被缩小50%,border:1px渲染出来是1px物理像素
flexible.js
为了解决1px边框问题,flexible.js根据dpr对页面缩放
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
if (!metaEl) {
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
}
导致字体font-size也要做相应调整:
.a{
font-size:12px;
}
[data-dpr="2"] .a{
font-size: 24px;
}
[data-dpr="3"] .a{
font-size: 36px;
}
设计师原本的要求是这样的:任何手机屏幕上字体大小都要统一
dpr=2,根据源码, scale=0.5,所以1个css像素对应1个物理像素,font-size=24px,对应24个物理像素,而dpr=1时font-size=12px,对应12个物理像素,根据下图,dpr=1的普通屏的1个物理像素宽,物理尺寸上等于dpr=2的retina屏的2个物理像素宽,所以任何手机屏幕上字体的物理尺寸大小一样
- 其他
用chrome的开发者工具的手机模式查看页面可发现,在手机屏幕单击鼠标可以触发oumousedown/oumousedown/oumousedown事件,但移动鼠标不能触发oumousemove,在移动端对应的事件是ontouchstart,ontouchmove,ontouchend
if(document.body.ontouchstart !== undefined){}
// 在pc上document.body.ontouchstart是undefined,表明不支持该事件,而在触屏设备上是null,支持该事件
var x = event.touches[0].clientX //touch点的x坐标
// 因为手机支持多点触控,所以关于touch的信息都放在一个数组里,touches[0]表示一点触控,tounch[1]表示另外一点触控
而在pc上用 var x = event.clientX 获取鼠标点击的x坐标
手机上没有hover事件,resize事件
原生js没有监听在手机上用手指滑动的事件,一种方法就是记录第一次和第二次touch点的位置,如果第二次touch点在第一次touch点的左边,表明用户向左滑
更多资料:
- 淘宝flexiblejs用rem,为什么还要缩放viewport? - 知乎
- 如何在Vue项目中使用vw实现移动端适配
- 移动端适配方案(下)
- 再聊移动端页面的适配
- 使用Flexible实现手淘H5页面的终端适配