zoukankan      html  css  js  c++  java
  • 设备像素比+图片高清显示+移动适配

    一、设备像素比 dpr (devicePixelRatio)
     
    首先进行概念的一些解释:
     
    1、物理像素(又称硬件像素)(physical pixel)
    一个物理像素是显示器上最小的物理显示单元,每一个像素都有自己的颜色值和亮度。
    同一个设备,它的物理像素是固定的,即一个设备的分辨率是固定的。
    //计算公式:
    //物理像素 = 逻辑像素 × 设备像素比
     
    2、逻辑像素 dpi (又称css像素、设备独立像素)(density-independent pixel)
    逻辑像素是指css样式中使用的逻辑像素,也可以说是设备的宽高。
    iphone4之前的手机逻辑像素数和逻辑像素数是相等的,但是由于视网膜设备(Retina屏)的出现,逻辑像素与物理像素之间有了不同的倍数对等关系。
    //获取方法
    document.documentElement.clientWidth  //iphone6 => 320
    document.documentElement.clientHeight  //iphone6 => 667
     
    3、设备像素比 dpr (devicePixelRatio)
    设备像素比 = 物理像素 / 逻辑像素
    //js获取方法
    window.devicePixelRadio  //iphone6 =>2
    注意点:
    (1)在fireFox及ie中不支持window.devicePixelRatio
    (2)在同一设备不同浏览器中,window.devicePixelRatio值可能不同,这是由于不同的浏览器中css像素数不同
     
    4、像素密度 ppi (pixels per inch)
    每英寸中显示的像素数,通常使用ppi来作为像素密度的单位;计算公式: 对角线像素个数 / 屏幕尺寸         
    对角线像素个数计算:(物理像素长² + 物理像素宽²)开根
     
     
     
    不同手机物理像素、逻辑像素及像素比:
    手机名称
    像素分辨率(px)
    倍率
    逻辑分辨率(pt)
    物理尺寸(英寸)
    屏幕密度(ppi)
    DPI
    i6 plus
    1242*2208
    @3x
    414*736
    5.5
    401
    154
    I6
    750*1334
    @2x
    375*667
    4.7
    330
    163
    I5s
    640*1136
    @2x
    320*568
    4
    330
    163
    I5
    640*1136
    @2x
    320*568
    4
    330
    163
    I4
    640*960
    @2x
    320*480
    3.5
    330
    163
    I3GS
    320*480
    @1x
    320*480
    3.5
    163
     
    android
    240*320
    @0.75
    320*420
    120
       
    android
    320*480
    @1x
    320*480
    160
       
    android
    480*800
    @1.5x
    360*500
    240
       
    android
    640*960
    @2x
    320*480
    320
       
    android
    540*960
    @1.5x
    360*640
    360
       
    android
    720*1280
    @2x
    360*640
    360
       
    android
    1080*1920
    @3x
    360*640
    360
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    综合以上几个概念,以Iphone6举例说明:设备宽高(即逻辑像素)为:375×667 ,dpr为2,物理像素为 750×1334
    //css样式
    1px;
    height:1px;
    相同尺寸下,普通屏幕 VS Retina 屏,css像素所呈现的物理尺寸(大小)是一致的,不同的是一个css像素所对应的物理像素的个数不一致:
    普通屏幕:css像素:物理像素 = 1:1
    retina屏: css像素:物理像素 = 1:4
    即4个物理像素显示一个css像素;
     
    二、图片高清显示
    首先了解一下图片的显示规则:
    位图像素:一个位图像素是栅格图像最小的数据单元。每个位图像素都包含自身的显示信息,如色值,透明度等
    理论上,当位图像素对应物理像素时,图片才能清晰展示。
    例如:img标签,css像素为200*300,普通屏幕下对应物理像素为200*300,retina屏幕对应物理像素为400*600:
        (1)当在retina屏中,使用200*300@1x图片时,由于每个单位的位图像素不可分割,只能就近取色,从而导致retina屏图片模糊;使用两倍图片@2x,如200*300的img标签,使用400*600的图片,这样retina屏幕下,物理像素:位图像素 = 1:1,图片清晰
        (2)如果在普通屏下使用@2x图片,一个物理像素对应4个位图像素,它的取色需要一定的算法,显示结果就只有原图像素总数的4分之一(这个过程叫downsampling),图片虽然不会模糊,但是会少一些锐利度或者色差;同样会造成资源浪费
    最好的解决方案:不同的dpr下,使用不同尺寸的图片。
    (1)可以通过媒体查询或者js进行控制,拼接不同的url
    (2)img标签,设置srcset属性
    //srcrest以最合适的src去匹配不同屏幕(高分屏低分屏如Retina;大屏小屏)
    // 2x、3x 表示目标屏幕的像素密度
    <img src="source.jpg" srcset="source_2x.jpg 2x, source_3x.jpg 3x">
    //400w、600w表示目标浏览器的宽度的限度,如浏览器宽度550w时,匹配600w的src
    <img src="source.jpg" width="100%" srcset="source_400.jpg 400w, source_600.jpg 600w, source_1280.jpg 1280w">
     
    二、移动端适配之rem
    适配前提:
    <meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width">
     
    设配原理:使用rem单位进行移动端布局适配,原理是针对不同手机屏幕尺寸和dpr动态的改变根节点html的font-size大小
     
    1、js方法实现
     
    (1)引入flexible.js,改变根元素font-size
     
    ;(function(win, lib) {
    var doc = win.document;
    var docEl = doc.documentElement;
    var metaEl = doc.querySelector('meta[name="viewport"]');
    var flexibleEl = doc.querySelector('meta[name="flexible"]');
    var dpr = 0;
    var scale = 0;
    var tid;
    var flexible = lib.flexible || (lib.flexible = {});
     
    if (metaEl) {
    console.warn('将根据已有的meta标签来设置缩放比例');
    var match = metaEl.getAttribute('content').match(/initial-scale=([d.]+)/);
    if (match) {
    scale = parseFloat(match[1]);
    dpr = parseInt(1 / scale);
    }
    } else if (flexibleEl) {
    var content = flexibleEl.getAttribute('content');
    if (content) {
    var initialDpr = content.match(/initial-dpr=([d.]+)/);
    var maximumDpr = content.match(/maximum-dpr=([d.]+)/);
    if (initialDpr) {
    dpr = parseFloat(initialDpr[1]);
    scale = parseFloat((1 / dpr).toFixed(2));
    }
    if (maximumDpr) {
    dpr = parseFloat(maximumDpr[1]);
    scale = parseFloat((1 / dpr).toFixed(2));
    }
    }
    }
     
    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;
    }
     
    docEl.setAttribute('data-dpr', dpr);
    window.dpr = dpr;
     
    if (!metaEl) {
    metaEl = doc.createElement('meta');
    metaEl.setAttribute('name', 'viewport');
    metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
    if (docEl.firstElementChild) {
    docEl.firstElementChild.appendChild(metaEl);
    } else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    doc.write(wrap.innerHTML);
    }
    }
     
    function refreshRem(){
    var width = docEl.getBoundingClientRect().width;
    if (width / dpr > 540) {
    width = 540 * dpr;
    }
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
    }
     
    win.addEventListener('resize', function() {
    clearTimeout(tid);
    tid = setTimeout(refreshRem, 300);
    }, false);
    win.addEventListener('pageshow', function(e) {
    if (e.persisted) {
    clearTimeout(tid);
    tid = setTimeout(refreshRem, 300);
    }
    }, false);
     
    // if (doc.readyState === 'complete') {
    // doc.body.style.fontSize = 12 * dpr + 'px';
    // } else {
    // doc.addEventListener('DOMContentLoaded', function(e) {
    // doc.body.style.fontSize = 12 * dpr + 'px';
    // }, false);
    // }
     
     
    refreshRem();
     
    flexible.dpr = win.dpr = dpr;
    flexible.refreshRem = refreshRem;
    flexible.rem2px = function(d) {
    var val = parseFloat(d) * this.rem;
    if (typeof d === 'string' && d.match(/rem$/)) {
    val += 'px';
    }
    return val;
    }
    flexible.px2rem = function(d) {
    var val = parseFloat(d) / this.rem;
    if (typeof d === 'string' && d.match(/px$/)) {
    val += 'rem';
    }
    return val;
    }
     
    })(window, window['lib'] || (window['lib'] = {}));
     
     
    (2)css使用rem为单位
    css代码中如何还原视觉稿尺寸:视觉稿一般均为二倍视觉稿,例如:以iphone6(设备尺寸375*667)做设计标准,高清设计稿为750 * 1334,html的font-size会被设置为 75px
    方法一:利用sass/less @mixin计算
    @mixin px2rem($attr,$value){
        $attr:($value / 75) * 1rem
    }
     
    p{  //设计稿 300* 300 的元素
        @include px2rem(width,300);
        @include px2rem(height,300) ;
    }
     
    方法二:打包工具 postcss-px2rem 
    css代码中按照设计稿尺寸编写,css文件利用打包工具,打包为rem单位
    //gulpfile.babel.js
    //具体使用方法请参考官网
    px2rem({
    remUnit:75  //设计稿尺寸/10
    }),
    注意:
    使用rem为单位,1px边框转化为rem后,在andriod等版本手机,由于实际计算边框宽度不足1px,所以,边框不显示;
    解决方法:(1)增加边框宽度,经实测2.5px边框,ios和andriod手机效果兼容性更好
                     (2)在sass文件中,在不需要转化rem的地方,添加注释 /*no*/
    .testDiv{
        border:1px solid red;/*no*/
        height:100px;
        line-height:100px;
        font-size:75px;
    }
     
    2、css媒体查询实现
    html{
        font-size:32px;
    }
    @media (min-device-width:320px){
        html{
            font-size:32px;
        }
    }
    @media (min-device-width:375px){
        html{
            font-size:37.5px;
        }
    }
    @media (min-device-width:414px){
        html{
            font-size:41.4px;
        }
    }
     
    缺点:根据设备宽度媒体查询设置根元素font-size,不够准确,只能设置某一范围,赋予相同字号
     
     
     
     
     
     
     版权声明:本文为博主原创文章,未经博主允许不得转载。 http://www.cnblogs.com/zuozuo-blog/
     
     
    参考文章:https://www.cnblogs.com/jingwhale/p/5741567.html
                    https://blog.csdn.net/a0405221/article/details/78913714
     
     
     
     
  • 相关阅读:
    【Java】《Java程序设计基础教程》第三章学习
    【Python】编程小白的第一本python(最基本的魔法函数)
    【Python】编程小白的第一本python(基础中的基础)
    bootstrap中的col-xs-*,col-sm-*,col-md-* 关系
    java基础面试题总结
    人生中第一次面试(阿里一面)
    阿里云服务器ip:端口号无法访问
    redis基本指令
    linux基本指令
    centos安装redis
  • 原文地址:https://www.cnblogs.com/zuozuo-blog/p/8986543.html
Copyright © 2011-2022 走看看