zoukankan      html  css  js  c++  java
  • 手机端页面自适应解决方案—rem布局

    代码原理

    这是阿里团队的高清方案布局代码,所谓高清方案就是根据设备屏幕的DPR(设备像素比,又称DPPX,比如dpr=2时,表示1个CSS像素由4个物理像素点组成) 动态设置 html 的font-size, 同时根据设备DPR调整页面的缩放值,进而达到高清效果。

    有何优势

    • 引用简单,布局简便
    • 根据设备屏幕的DPR,自动设置最合适的高清缩放。
    • 保证了不同设备下视觉体验的一致性。(老方案是,屏幕越大元素越大;此方案是,屏幕越大,看的越多)
    • 有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素)

    如何使用

    重要的事情说三遍!
    绝不是每个地方都要用rem,rem只适用于固定尺寸!
    绝不是每个地方都要用rem,rem只适用于固定尺寸!
    绝不是每个地方都要用rem,rem只适用于固定尺寸!
    在相当数量的布局情境中(比如底部导航元素平分屏幕宽,大尺寸元素),你必须使用百分比或者flex才能完美布局!
    看过 《手机端页面自适应解决方案—rem布局》的朋友,应该对rem有所了解,这里不再赘述,
    此方案也是默认 1rem = 100px,所以你布局的时候,完全可以按照设计师给你的效果图写各种尺寸啦。
    比如你在效果图上量取的某个按钮元素长 55px, 宽37px ,那你直接可以这样写样式:

    .myBtn {
        0.55rem;
       height: 0.37rem;
    }

    rem布局(进阶版)实践应用


    iPhone5 下页面效果.png

    iPhone 6 Plus 下页面效果.png

    为了让朋友们更清晰感受此方案的巨大优势,下面是源码和Demo

    实践应用源码(请在手机端或者手机模式下浏览效果更佳!)
    示例源码
    在线Demo

    常见问题说明(2017/1/19)

    许多同学对该方案存在不少误解导致使用出现各种问题,这里统一回复下。

    1.问:为啥手机网页效果图宽度是要640或者750的,我非得弄个666的不行咩?

    答:老实说当然可以,不过为了规范,640或者750是相对合适的。
    拿Iphone 5s 举例,它的css像素宽度是320px,由于它的dpr=2,所以它的物理像素宽度为320 × 2 = 640px,这也就是为什么,你在5s上截了一张图,在电脑上打开,它的原始宽度是640px的原因。
    那 iphone 6 的截图宽度呢? 375 × 2 = 750
    那 iphone 6 sp 的截图宽度呢? 414 × 3 = 1242
    以此类推,你现在能明白效果图为什么一般是 640 ,750 甚至是 1242 的原因了么?(真没有歧视安卓机的意思。。。)

    2.问:宽度用rem写的情况下, 在 iphone6 上没问题, 在 iphone5上会有横向滚动条,何解?

    答:假设你的效果图宽度是750,在这个效果图上可能有一个宽度为7rem(高清方案默认 1rem = 100px)的元素。我们知道,高清方案的特点就是几乎完美还原效果图,也就是说,你写了一个宽度为 7rem 的元素,那么在目前主流移动设备上都是7rem。然而,iphone 5 的宽度为640,也就是6.4rem。于是横向滚动条不可避免的出现了。
    怎么办呢? 这是我目前推荐的比较安全的方式:如果元素的宽度超过效果图宽度的一半(效果图宽为640或750),果断使用百分比宽度,或者flex布局。就像把等屏宽的图片宽度设为100%一样。

    3.问:不是 1rem = 100px吗,为什么我的代码写了一个宽度为3rem的元素,在电脑端的谷歌浏览器上宽度只有150px?

    答:先说高清方案代码,再次强调咱们的高清方案代码是根据设备的dpr动态设置html 的 font-size,
    如果dpr=1(如电脑端),则html的font-size为50px,此时 1rem = 50px
    如果dpr=2(如iphone 5 和 6),则html的font-size为100px,此时 1rem = 100px
    如果dpr=3(如iphone 6 sp),则html的font-size为150px,此时 1rem = 150px
    如果dpr为其他值,即便不是整数,如3.4 , 也是一样直接将dpr 乘以 50 。

    再来说说效果图,一般来讲,我们的效果图宽度要么是640,要么是750,无论哪一个,它们对应设备的dpr=2,此时,1 rem = 50 × 2 = 100px。这也就是为什么高清方案默认1rem = 100px。而将1rem默认100px也是好处多多,可以帮你快速换算单位,比如在750宽度下的效果图,某元素宽度为53px,那么css宽度直接设为53/100=0.53rem了。

    然而极少情况下,有设计师将效果图宽定为1242px,因为他手里只有一个iphone 6 sp (dpr = 3),设计完效果图刚好可以在他的iphone 6 sp里查看调整。一切完毕之后,他将这个效果图交给你来切图。由于这个效果图对应设备的dpr=3,也就是1rem = 50 × 3 = 150px。所以如果你量取了一个宽度为90px的元素,它的css宽度应该为 90/150=0.6rem。由于咱们的高清方案默认1rem=100px,为了还原效果图,你需要这样换算。当然,一个技巧就是你可以直接修改咱们的高清方案的默认设置。在代码的最后 你会看到 flex(100, 1) ,将其修改成flex(66.66667, 1)(感谢简友:V旅行指出此处错误! 2017/3/24)就不用那么麻烦的换算了,此时那个90px的直接写成0.9rem就可以了。

    4.问:高清方案在微信上,有时候字体会不受控制变的很大,怎么办?

    答:点我,这是我对该问题的总结

    5.问:我在底部导航用的flex感觉更合适一些,请问这样子混着用可以吗?

    答:咱们的rem适合写固定尺寸。其余的根据需要换成flex或者百分比。源码示例中就有这三种的综合运用。

    6.问:在高清方案下,一个标准的,较为理想的宽度为640的页面效果图应该是怎样的?

    点击浏览:一个标准的640手机页面设计稿参考(没错,在此方案中,你可以完全按照这张设计稿的尺寸写布局了。就是这么简单!)

    7.问:可以提供下这个高清方案的源码吗?
    'use strict';
    
    /**
     * @param {Number} [baseFontSize = 100] - 基础fontSize, 默认100px;
     * @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体;
     */
    const win = window;
    export default win.flex = (baseFontSize, fontscale) => {
      const _baseFontSize = baseFontSize || 100;
      const _fontscale = fontscale || 1;
    
      const doc = win.document;
      const ua = navigator.userAgent;
      const matches = ua.match(/Android[Ss]+AppleWebkit/(d{3})/i);
      const UCversion = ua.match(/U3/((d+|.){5,})/i);
      const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
      const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
      let dpr = win.devicePixelRatio || 1;
      if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
        // 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
        dpr = 1;
      }
      const scale = 1 / dpr;
    
      let metaEl = doc.querySelector('meta[name="viewport"]');
      if (!metaEl) {
        metaEl = doc.createElement('meta');
        metaEl.setAttribute('name', 'viewport');
        doc.head.appendChild(metaEl);
      }
      metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
      doc.documentElement.style.fontSize = `${_baseFontSize / 2 * dpr * _fontscale}px`;
    };
    8.问:我在使用 rem 布局进阶方案的时候遇到了XXX的问题,如何解决?
    • 此方案久经考验,具有普遍适用性,自身出致命问题的情况很少,至少笔者是没遇到过。
    • 绝大多数你遇到的问题,都是由于对rem布局理解不到位导致的。本文对rem布局做了大量的解释说明,配置了若干 demo,你可以把你遇到的问题放到demo里测试。遇到问题时,首先问自己,为什么这明显的错误大家没遇到就我遇到了??
    • 如果你真的经过充分验证,比对,确实是rem布局自身出了问题,那么请私信我,把还原问题场景的 demo 或者文件发给我。谢谢!
  • 相关阅读:
    printcap
    browser-ua
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode70 爬楼梯
  • 原文地址:https://www.cnblogs.com/itrena/p/8359668.html
Copyright © 2011-2022 走看看