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 个默认文字。

相关推荐
hackeroink4 分钟前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者2 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-2 小时前
验证码机制
前端·后端
燃先生._.3 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖4 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235244 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240255 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar5 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人6 小时前
前端知识补充—CSS
前端·css