• 移动端适配rem/vw,vh原理(详细)


    参考 https://juejin.cn/post/6981800084686143518

    了解像素相关知识:
    移动端适配
    掌握web开发基础系列--物理像素、逻辑像素、css像素
    为什么给750px的设计图

    其实我一直很想写一些关于适配方面的文章,因为很多东西只有实践才能对这个知识点更加的了解,而不是查几篇文章就行了~

    我希望能够解答这些问题:

    1.什么是物理像素,和逻辑像素,DPR
    2.为什么我们的设计师给的尺寸都是750px
    3.rem适配原理以及对应的插件
    4.vw,vh适配原理以及对应的插件

    1.什么是物理像素,和逻辑像素,DPR

    物理像素(physical pixel, 也叫做设备像素):显示器上的像素,机器生产出来时就已经确定了。
    逻辑像素(density-independent pixel也叫做css像素/设备独立像素):用于控制元素样式的样式单位像素,CSS像素从来都只是一个相对值。

    物理像素(physical pixel): 设备屏幕实际拥有的像素点,屏幕的基本单元,是有实体的。比如iPhone 6的屏幕在宽度方向有750个像素点,高度方向有1334个像素点,所有iPhone 6 总共有750*1334个像素点。

    逻辑像素/独立像素(density-independent pixel): 我们平时描述一张图片宽高时一般用 200px * 100px,这里的px也是逻辑像素。

    我们应该知道iphone6的宽度是375px,这里指的是逻辑像素,那就说明1px的css像素里面包含了2个物理像素点,如果你不怕瞎的话,可以将眼睛靠近电脑屏幕,发现屏幕的界面都是根据红、绿、蓝三个颜色组成

    以前的的屏幕是假设是375px的物理像素,对应的是375个物理像素点,其实在很久以前,CSS里写个1px,屏幕就给你渲染成1个实际的像素点,DPR=1,多么简单自然~ 后来苹果公司为其产品mac、iPhone以及iPad的屏幕配置了Retina高清屏,也就是说这种屏幕拥有的物理像素点数比非高清屏多4倍甚至更多。如果还按照DPR=1进行展示,那么同一张图片在高清屏上面显示的区域面积会是非高清屏的1/4,这样的话由于图片在屏幕上的展示面积大大缩小,也会导致出现“看不清”的问题。

    在1px对应多个物理像素点主要是为了更加高清,也就是越多,对于我们肉眼能看到红、绿、蓝三个色的难度越大. 所以当你使用750px的设计图的时候,对应的图应该是xx2@png

    设备像素比(Device Pixel Ratio,DPR)

    DPR = 物理像素/逻辑像素

    2.rem 适配

    2.1 CSS3 长度单位 rem

    image.png

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      我是根元素html的大小
      <div class="two">我是两倍</div>
      <div class="three">我是三倍</div>
      
      <style> html{ 
          font-size:12px;
        }
        .two { 
          font-size:2rem;
          height: 5rem;
           5rem;
          background-color: red;
        }
        .three{
          font-size:3rem;
          height: 10rem;
           10rem;
          background-color: yellow;
        } </style>
    </head>
    </html>
    复制代码
    

    image.png

    比如上面这个例子,虽然我只设置了font-size:12px;,并没有去设置width是多少,但是rem就是看html的font-size的值为固定值,在这个基础上去乘以对应的倍数,其实我这块我以前老是转不过弯,为啥这么多属性就只设置一个font-size的默认值就行,主要还是看rem初始的定义,也许这个属性不是font-size,也许是test等等,他规定什么属性就是什么属性,我是这么理解的,但是font-size的默认值和最小值值得注意

    font-size:2rem; => font-size:2*12px;

    那么,思考一下,这个html的font-size的值我到底设置多少呢?是不是应该根据视觉宽度来设定

    2.2 浏览器默认字体大小

    浏览器默认最小字体12px, 意思就是我设置一个字体为2px,这个2px,是不会起作用的,会显示城最小的字体12px 默认的字体大小是16px,意思就是假设我不会html做任何设置,对其他的样式class设置2rem,那么显示出来的样式应该是32px(16px * 2)

    如何获取google浏览器的默认font-size

    var div=document.getElementsByTagName('html')[0]
    const res = window.getComputedStyle(div).fontSize // 16px
    console.log(res, 1111)
    复制代码
    

    image.png

    1625394225(1).png

    2.3 rem适配

    假设我们的UI图给的尺寸是375px的逻辑像素

     .two { 
          font-size:2rem; 
          height: 5rem;
           5rem;
          background-color: red;
        }
        .three{
          font-size:3rem;
          height: 10rem;
           10rem;
          background-color: yellow;
        }
    复制代码
    
    获取原始值,html的默认font-size为16,意思就是在iphone6下面
    375px的UI设计图之下,量出来的应该为:
    2rem = 32px 5rem = 80px 3rem = 48px 10rem = 160px
    750px的UI设计图,量出来的应该为:
    2rem = 64px 5rem = 160px 3rem = 96px 10rem = 320px
    复制代码
    
    适配代码分析

    innerWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏)
    innerHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏)

    //原理:
    // 获取屏幕的宽度,然后将屏幕分为多少份(设计稿宽度那么多份)
    const boxInnerWidth = window.innerWidth
    // 假设设计稿为375px
    const UIwidth = 375
    // 每份分成多少px
    const everyPiece = boxInnerWidth/UIwidth 
    // 将html的font-size设置为比例值
    document.documentElement.style.fontSize = `${everyPiece * 100}px`
    
    复制代码
    

    改成以下也可以:

    (function () {
       function changeRootFont() {
          var UIwidth = 750, rem2px = 100;
          document.documentElement.style.fontsize = 
         ((window.innerWidth / UIwidth) * rem2px) + 'px';
       }
       changeRootFont();
       window.addEventListener('resize', changeRootFont,false);
    })();
    复制代码
    

    按道理来说,document.documentElement.style.fontSize = ${everyPiece}px就行了呀, 为什么要*100,假设我们在iphone6手机里,那么const everyPiece = boxInnerWidth/UIwidth的everyPiece会等于1px,html的font-size设置为1是不会生效的,所以我们需要将font-size扩大到12倍以上,但是你想这里我扩大了,等我写rem倍数的时候,是不是要除以这个对应的扩大倍数,所以为了好除,我们直接写100,也就是我们量出来的ui里面的px数往右边移动两个小数点就好了

    .two { 
      font-size:0.32rem; 
      height: 0.8rem;
       0.8rem;
      background-color: red;
    }
    .three{
      font-size:0.48rem;
      height: 1.6rem;
       1.6rem;
      background-color: yellow;
    }
    复制代码
    

    3.vw,vh适配

    image.png

    100vw = 一个视口的宽度
    1vw = 1%视口的宽度
    100vh = 一个视口的高度
    1vh= 1%视口的高度
    复制代码
    
     <div class="test">
       哈哈哈哈
      </div>
    复制代码
    
    .test {
       calc(100vw * (300 / 375));
      height: 100px;
      background-color: red;
      color: white;
      font-size: calc(100vw * (24 / 375)) ;
    }
    复制代码
    

    假设你在项目中,可以使用sass

    @function px2vw($px) {
      @return $px * 100vw / 375; // 375的设计图
    }
    
    .test {
       px2vw(300);
      height: px2vw(100);
      background-color: red;
      color: white;
      font-size: px2vw(24);
    }
    复制代码
    

    原理: 因为vw是将屏幕分成100份,1vw表示其中的一份,100vw表示的是横向满屏,那么假设我的设计图是375px,目前量的宽是24px,那么 24/375表示是我占屏幕总宽度的24/375,这时候你又知道 屏幕总宽度为100vw, 那么动态的宽度为24/375*100vw,而24的尺寸不一,所以封装一个方法来调用

    VW,rem的优缺点:

    rem:

    1.因为是根据html根元素来做其他元素的rem处理的,所以script的代码应该在定义其他元素css之前,必须写在header里面,在触发resize的时候还要再获取window.innerWidth
    2.如果是设置的${everyPiece * 100}px这里的比例值不是100,px转成rem会很难算

    vw:

    1.vw单位兼容性比rem稍差,ios8、安卓4.4及以上才完全支持
    2.假设上面这样使用一个方法,写法上看起来我觉得有点怪怪的,没有rem那么直接

    所以有了结合版本:(大佬说他就是用的这个,没有任何问题)
    html{
      font-size:calc(100vw/375*100)
    }
    .test {
       3rem ;
      height: 1rem;
      background-color: red;
      color: white;
      font-size: 0.24rem
    }
    复制代码
    

    4.插件推荐(VUE.JS)

    rem (fexible.js,2年前的项目用过)

    参考:
    fexible的使用
    vue项目中使用lib-flexible解决移动端适配的问题

    vw (postcss-px-to-viewport,目前在用)

    参考(大家可以找个简单的文章看看哈,其实就是个插件):
    如何在Vue项目中使用vw实现移动端适配

    5.为什么设计师出750px的设计图

    参考:
    为什么设计稿是750px

    看了很多的文章,大概的意思就是设计图是按照物理像素给的图,这块我也没有说彻底弄懂,哭

    6.如果有手机端和pc端如何进行适配
    const isMobile = function () {
      const userAgentInfo = navigator.userAgent
      let mobileAgents = [
        'Android',
        'iPhone',
        'SymbianOS',
        'Windows Phone',
        'iPad',
        'iPod',
      ]
      return mobileAgents.some(i => userAgentInfo.includes(i))
    }
    复制代码
    

    设置全局的isMobileFunc是否为手机端的判断,路由指向同一个页面,这个页面引入pc端的代码,以及mobile的代码,根据isMobile判断显示哪个子组件

    适配: var UIwidth = isMobile ? 750 : pcUIWidth, rem2px = 100;

    (function () {
       function changeRootFont() {
          var UIwidth = isMobile ? 750 : pcUIWidth, rem2px = 100;
          document.documentElement.style.fontsize = 
         ((window.innerWidth / UIwidth) * rem2px) + 'px';
       }
       changeRootFont();
       window.addEventListener('resize', changeRootFont,false);
    })();
    复制代码
    

    BTY,关于rem,vw适配更多的优缺点,欢迎评论,后续会将fexible.js和postcss-px-to-viewport的插件使用贴出来

    -_-奥利给

  • 相关阅读:
    单元测试的必要性
    【C++ STL】Queue
    【C++ STL】Stack
    【C++ STL】容器的选择
    【C++ STL】Map和Multimap
    [Effective JavaScript 笔记]第19条:熟练掌握高阶函数
    [Effective JavaScript 笔记]第18条:理解函数调用、方法调用及构造函数调用之间的不同
    node实现rar格式压缩
    [Effective JavaScript 笔记]第2章:变量作用域--个人总结
    [Effective JavaScript 笔记]第17条:间接调用eval函数优于直接调用
  • 原文地址:https://www.cnblogs.com/kuangke/p/16880674.html
Copyright © 2020-2023  润新知