物理像素
iphone 6 的宽度有750个物理像素
逻辑像素
也叫设备的独立像素,css像素也是逻辑像素的一种
逻辑像素比(dpr)
物理像素➗逻辑像素,iphone6 的dpr=2
常见问题
- 图片模糊
- 1px问题
1.图片模糊
一个图片大小200px * 200px(逻辑像素) 在dpr为1的屏幕下显示正常,在dpr为2的情况下那么在200px * 200px(逻辑像素)下物理像素是400px * 400px(物理像素)
本来一个物理像素点就好了现在变成了(2*2)个,那么问题来了,其他的物理像素点会去找相近的颜色去填充,所以就变的模糊了
2.1px问题
这个问题很有意思,真的给我上了一课以后看文章,真的要多看一些在做出选择为什么呢?
网上很多人的说法:因为dpr>1所以导致边框线变粗,我就很奇怪1px变粗,那为什么没有2px问题,3px问题,4px问题...,为什么2px,3px,4px不会变粗,然道他们的dpr不是>1吗?明显他们就说错了,但是哇,就很夸张很多人写的都是因为dpr的原因?
我认为:其实就是在一个750px的设计图上的边框为1px那么按照比例在iphone6->375px逻辑像素下<-下显示的的边框按比例是0.5px其实就是这样而已,其实有些公司会把这个1px在移动端变成.5px(阿里巴巴,JD)都是变了的,但是也有没有变的,为什么呢?应为其实边框本来就是不支持百分比的所以其实我认为按照css规范其实设计图1px那么不管在什么屏幕下应该都是1px,而不是去缩放边框(阅文的官网,google)我看的就是1px还是1px,其实这个和UI说的算的咯
国内知名互联网企业移动端H5尺寸适配方案
1.很多年前淘宝的lib-flexible移动端配置方案
原理:通过dpr,去动态生成缩放视口,从而逻辑像素等于物理像素,那么在动态生成html下的字体大小就可以控制rem了,比如在750的设计稿下,一个div为75px,那么我们可以1rem,
缩放视图
var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
根据不同移动设备动态计算font-size
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
但是这个已经被淘汰了,由于viewport
单位得到众多浏览器的兼容,lib-flexible
这个过渡方案已经可以放弃使用,
<meta name="viewport" content="width=device-width, initial-scale=1.0">
作用:
- 以ip6为例子,在逻辑像素比为2的情况下可以看到750px,但是通过设置width=device-width,让视图可视宽度,变成设备的逻辑像素为350px
注意:
- initial-scale=1.0 和 width=device-width的效果是一样的一起写的作用是处理不同浏览器的兼容问题
- 设置完成后,那么我们就要防止就是图片大小过低导致不清晰的问题了
JD
/* JD的移动端刷屏 */
html {
font-size: 20px;
font-size: 5.33333vw
/* 3.75px * 5.33333 ~ 20px */
}
@media screen and (max-width:320px) {
html {
font-size: 17.06667px
}
}
@media screen and (min-width:540px) {
html {
font-size: 28.8px
}
}
其实这个就很有意思,不会根据屏幕大小改变一点就去变一点,而是在一个范围,然后再弹性布局
百度
html {
font-size: 100px
}
@media screen and (max-width: 360px) {
html {
font-size:90px;
line-height: 90px
}
}
body {
font-size: 16px;
}
阅文
html {
font-size: 16px;
}
@media screen and (min-width: 375px) {
html {
/* iPhone6的375px尺寸作为16px基准,414px正好18px大小, 600 20px */
font-size: calc(100% + 2 * (100vw - 375px) / 39);
font-size: calc(16px + 2 * (100vw - 375px) / 39);
}
}
@media screen and (min-width: 414px) {
html {
/* 414px-1000px每100像素宽字体增加1px(18px-22px) */
font-size: calc(112.5% + 4 * (100vw - 414px) / 586);
font-size: calc(18px + 4 * (100vw - 414px) / 586);
}
}
@media screen and (min-width: 600px) {
html {
/* 600px-1000px每100像素宽字体增加1px(20px-24px) */
font-size: calc(125% + 4 * (100vw - 600px) / 400);
font-size: calc(20px + 4 * (100vw - 600px) / 400);
}
}
@media screen and (min-width: 1000px) {
html {
/* 1000px往后是每100像素0.5px增加 */
font-size: calc(137.5% + 6 * (100vw - 1000px) / 1000);
font-size: calc(22px + 6 * (100vw - 1000px) / 1000);
}
}
网易
(1)以iphone6作为参照,iphone6的宽度是375px,dpr为2,所以对于上面显示的375px的图,我们需要的图片大小是750px,所以我们拿到的psd设计图的宽度必须是750px。为了方便书写rem,我们希望psd设计图上750px对应的rem是7.5rem。而设计图上面750px在iphone6上面的实际大小是375px,所以我们需要设置iphone6的font-size=375/7.5px=50px。更一般地,由于移动端的font-size的默认值是16px,所以我们更倾向于用一个百分比来设置font-size:font-size=50/16=312.5%。(注意:用px和百分比没有本质上的不同。这里也可以不除以16直接乘50,同百分比后续也是要乘以16px的)
(2)在其它屏幕上进行缩放,为了解决这个问题,我们用js来读取屏幕的宽度,然后利用这个宽度来进行缩放,代码如下:
var initScreen=function(){
$("html").css("font-size", document.documentElement.clientWidth / 375 * 312.5 + "%");
}
最后,我们需要解决横屏问题和用户手动缩放问题,他们本质上都是改变屏幕宽度的问题,所以我们监听resize事件或者onorientationchange事件,当发生的时候,重新调用initScreen方法。代码如下:
$(window).on('onorientationchange' in window ? 'orientationchange' : 'resize', function () {
setTimeout(initScreen, 200);
});
注意:上面的代码并不是原生js,要引入zepto库!也可以用原生js实现,不过要考虑兼容性问题,我就不贴出代码了。
注意:我这种适配方案中,1rem的实际大小是50px,而不是100px。所以0.12rem的字体,在设计稿上面是12px,但是在手机上的实际大小是6px
另外,为了增加代码的健壮性,在js加载不成功的时候也能进行适配,建议在css加上媒体查询:
@media screen and (max-width: 320px) {
html {
font-size:42.667px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 321px) and (max-width:360px) {
html {
font-size:48px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 361px) and (max-width:375px) {
html {
font-size:50px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 376px) and (max-width:393px) {
html {
font-size:52.4px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 394px) and (max-width:412px) {
html {
font-size:54.93px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 413px) and (max-width:414px) {
html {
font-size:55.2px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 415px) and (max-width:480px) {
html {
font-size:64px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 481px) and (max-width:540px) {
html {
font-size:72px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 541px) and (max-width:640px) {
html {
font-size:85.33px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 641px) and (max-width:720px) {
html {
font-size:96px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 721px) and (max-width:768px) {
html {
font-size:102.4px;
font-size: 13.33333vw
}
}
@media screen and (min-width: 769px) {
html {
font-size:102.4px;
font-size: 13.33333vw
}
}
目前淘宝
解读
1.开始函数先来匿名函数
2.找到HTML文档对象,因为后面要给他定义fontSize的值;
3.找到dpr的值,如果大于等于2,就给这个设备设置0.5px的边框
4.除以3.75的解释:如果设计图为750那么就是除以7.5为什么是7.5 ? 因为我们以100px为1rem那么750的设计图为7.5rem,那么我们要求出不同设备的rem的值就是用n.clientWidth/7.5就是rem的值
5.函数i给html定义fontSize的值
6.最后if()中的条件:
6-1:判断 是否存在document.body 再设置html标签的font-size的值
6-2:设置html标签的font-size的值,
6-3:设置监听横屏事件,和判断是否是缓存
6-4:最后判断drp的值:是否设置.5px的边框
7.if{}中的代码是判断是否支持.5px,支持添加属性hairlines
// 解读
// e = window ; t = document
// n === document.documentElement 是一个会返回文档对象(document)的根元素的只读属性(如HTML文档的 <html> 元素
// d === window.devicePixelRatio 返回当前显示设备的dpr
// 这里 / 3.75 的解释
// 设计图以iPhone6的分辨率为标准(750x1334)
// 把上面代码中的3.75改为7.5(如果设计图以375x667为标准则不用改)
// 前端写CSS时把设计图的单位统一以除以100,然后使用rem单位。
!function (e, t) {
var n = t.documentElement // document.documentElement
, d = e.devicePixelRatio || 1; // dpr
function i() {
var e = n.clientWidth / 3.75;
n.style.fontSize = e + "px"
}
// 判断 是否存在document.body 再设置html标签的font-size的值,监听横屏事件,和判断是否是缓存,和判断drp的值
if (function e() {
t.body ? t.body.style.fontSize = "16px" : t.addEventListener("DOMContentLoaded", e)
}(),
i(),
e.addEventListener("resize", i), // 当屏幕变成横屏的时候触发事件
// onpageshow 事件类似于 onload 事件,onload 事件在页面第一次加载时触发, onpageshow 事件在每次加载页面时触发,即 onload 事件在页面从浏览器缓存中读取时不触发
e.addEventListener("pageshow", function (e) {
// e.persisted : 返回boolead类型 是否是来自缓存数据,如果是那么也会触发i()
e.persisted && i()
}),
// 当 drp 大于等于2的时候
2 <= d) {
// 以下代码是再处理.5xp的兼容问题
// createElement//创建元素节点
var o = t.createElement("body")
, a = t.createElement("div");
a.style.border = ".5px solid transparent",
// appendChild//让他成为这个文档现有节点的一个子节点
o.appendChild(a),
n.appendChild(o),
// offsetHeight 元素再垂直方向上的时间 offsetHeight=height+padding+border
// 判断是否支持.5px支持,添加属性
// classList.add 添加属性
1 === a.offsetHeight && n.classList.add("hairlines"),
// removeChild() //方法可从子节点列表中删除某个节点
n.removeChild(o)
}
}(window, document)
解决1px问题
代码来自JD移动端页面
处理情况:分界线
li:after{
content: "";
height: 0;
display: block;
border-bottom: 1px solid #ddd;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
.li:after{
-webkit-transform: scaleY(.5);
// 设置源点的位置
// transform的缩放是像源点逼近
-webkit-transform-origin: 50% 100%;
}
}
处理情况:边框
li:after{
content: "";
display: block;
border: 1px solid #ddd;
/* 穿透,click点击这个无效 */
pointer-events: none;
/* 设置全局大小 */
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
.li:after{
// 先缩小一半,大小和边框
-webkit-transform: scale(.5);
-webkit-transform-origin: 0 0;
/* 覆盖上面的样式,将大小面积放大一倍 ,这样只有边框缩小*/
bottom: -100%;
right: -100%;
}
}