h5 适配方案

vite+vue3的h5适配方案

  1. 安装lib-flexible和postcss-px2rem

npm i lib-flexible -D

pnpm install postcss-px2rem -D

  1. 在main.ts文件中引入lib-flexible
  2. 在vite.config.js配置文件中配置postcss-px2rem
js 复制代码
import px2rem from 'postcss-px2rem'

css: {
    postcss: {
      plugins: [
        px2rem({
          remUnit: 37.5 // 1rem === 37.5px
        })
      ]
    }
  }

postcss-px2rem介绍

This is a postcss plugin of px2rem.

postcss

是一个用javascript工具和插件转换css代码的工具。

lib-flexible计算根结点html的fontSize的源码

js 复制代码
;(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);
    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; // 将布局视口分成10等分
    docEl.style.fontSize = rem + "px"; //将根节点html上的fontSize设置为布局视口的10分之一
    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);
    }

基础知识

像素

  • 设备的逻辑像素(屏幕分辨率)
  • 设备的物理像素
  • 设备像素比 = 设备的物理像素宽度 / 设备的逻辑像素宽度, 通过window.devicePixelRatio获取

视口

  • 可视视口(visual viewport):视觉视口是屏幕上实际可见的内容

  • 布局视口(layout viewport):布局视图覆盖页面上的所有元素

    一般移动设备的浏览器都默认设置了一个布局视口,用于解决早期的PC端页面在手机上显示的问题。IOS、Android基本都是将这个视口分辨率设置为980px,所以PC上的网页大多能在手机上呈现。

  • 理想视口(ideal viewport) 移动端默认按照980px的宽度布局; 如果所有的网页都按照980px在移动端布局,那么最终页面都会被缩放显示。 事实上这种方式不利于我们进行移动开发局部,我们希望的是设置100px,那么显示的就是100px; 如何做到这一点呢,通过设置理想视口(ideal viewport)。

移动web包含两个视口,即布局视口和视觉视口。布局视口覆盖页面上的所有元素,视觉视口是屏幕上实际可见的内容。当用户捏缩页面时,视觉视口会缩小,但布局视口不变。屏幕键盘(OSK)等用户界面功能可以缩小视觉视口,而不会影响布局视口。 参考:blog.csdn.net/m0_51636525...

  • window.screen.width:返回的是屏幕宽度
  • window.innerWidth :返回窗口的布局视口宽度
  • window.visualViewport.width:返回窗口的可视视口宽度
  • document.documentElement.clientWidthdocument.documentElement.getBoundingClientRect().width:获取的是布局视口宽度

viewport元标签

  • viewport的width设置的是布局视口的宽度。
  • 移动设备,大部分设备的默认布局视口宽度是980px
  • width=device-width 设置布局视口和可视视口大小相同
  • viewport的initial-scale属性:设置页面首次加载时显示的缩放倍数。

案例展示

  • 案例1: 下图是未设置viewport元标签时的默认展示: 此时,布局视口的宽度默认为980px,缩放比例是0.37。所以,默认情况下会缩小页面,展示布局视口下的所有内容。当内部元素div的宽度大于布局视口的宽度, 此时的多余的div部分没有展示。

  • 案例2: 以下是设置viewport的width=device-width和initial-scale=1.0对应的展示图:

js 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div style="width: 1000px;background-color: red;overflow:auto;">浏览器默认fontSize大小</div>

rem

rem(font size of the root elememt)是CSS3新增的一个相对单位,是指相对于根元素的字体大小的单位。

uniapp计算根结点html的fontSize的圆满

node_modules/@dcloudio/uni-h5/dist/uni-h5.es.js

js 复制代码
function getWindowWidth$1() {
  const screenFix = /^Apple/.test(navigator.vendor) && typeof window.orientation === "number";
  const landscape = screenFix && Math.abs(window.orientation) === 90;
  var screenWidth = screenFix ? Math[landscape ? "max" : "min"](screen.width, screen.height) : screen.width;
  var windowWidth = Math.min(
    window.innerWidth,
    document.documentElement.clientWidth,
    screenWidth
  ) || screenWidth;
  return windowWidth;
}


function useRem() {
  const config = __uniConfig.globalStyle || {};
  const maxWidth2 = checkValue$1(config.rpxCalcMaxDeviceWidth, 960);
  const baseWidth2 = checkValue$1(config.rpxCalcBaseDeviceWidth, 375);
  function updateRem() {
    let width = getWindowWidth$1();
    width = width <= maxWidth2 ? width : baseWidth2;
    document.documentElement.style.fontSize = width / 23.4375 + "px";
  }
  updateRem();
  document.addEventListener("DOMContentLoaded", updateRem);
  window.addEventListener("load", updateRem);
  window.addEventListener("resize", updateRem);
}

代码中 23.4375 是从 iphone6 的屏宽除以默认字号计算得来:375 / 16。也就是说以 iphone6 的屏幕宽度,可以放下 23.4375 个默认文字。

相关推荐
twins352043 分钟前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky1 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
安冬的码畜日常1 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
l1x1n02 小时前
No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史
前端·http·html
昨天;明天。今天。2 小时前
案例-任务清单
前端·javascript·css
zqx_73 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己3 小时前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称4 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色4 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript