react工程搭建系列之---移动端适配与antd-mobile高清适配方案

news/2025/4/22 2:21:09

一、逻辑像素(css像素)与物理像素(设备像素)

机型逻辑像素物理像素Scale Factor
iphone 3GS320 x 480320 x 4801x
iphone 4320 x 480640 x 9602x
iphone 4S320 x 480640 x 9602x
iphone 5320 x 568640 x 11362x
iphone 5C320 x 568640 x 11362x
iphone 5S320 x 568640 x 11362x
iphone 5SE320 x 568640 x 11362x
iphone 6375 x 667750 x 11342x
iphone 6P414 x 7361080 x 19202.6x
iphone 6S375 x 667750 x 11342x
iphone 6SP414 x 7361080 x 19202.6x
iphone 7375 x 667750 x 11342x
iphone 7P414 x 7361080 x 19202.6x
  • 设备像素:设备硬件的物理像素
  • 逻辑像素:软件所支持的像素
  • dpr(Device Pixel Ratio: Number of device pixels per CSS Pixel): 设备像素比
    也叫dppx 就是一个css像素控制几个物理像素,物理分辨率/逻辑分辨率(css分辨率)= dpr
  • iphone 3GS,可以看到一个逻辑像素是由一个物理像素构成,随着技术发展出现了Retina屏使得设备分辨率提高一倍,一个逻辑像素可以由 (640/320)* (960/480) = 4个物理像素构成,这样屏幕看起来更清晰

图片描述

二、三种viewport

1.the visual viewport

the visual viewport是在屏幕上显示页面的一部分,用户可以滚动以更改他看到的页面部分,或者缩放以更改可视视口的大小
图片描述

the visual viewport的大小等于window.innerWidth/Height

2.the layout viewport

css布局尤其是百分比宽是相对于the layout viewport来计算的,the layout viewport比the visual viewport宽的多。
浏览器会控制layout viewport尺寸使其在完全缩小的情况下覆盖整个屏幕,这时the visual viewport=the layout viewport
图片描述

因此,the layout viewport的宽度和高度等于在最大缩小模式下可以在屏幕上显示的任何宽度和高度。当用户放大这些尺寸时保持不变
图片描述

the layout viewport的大小等于document.documentElement.clientWidth/Height

3. the ideal viewport

它为每个设备上的web页面提供了一个理想尺寸,每个设备的理想尺寸都会不同。在非Retina屏的时代,the ideal viewport等于物理像素数,但这不是必须的。具有高物理像素密度的新型设备任然保留了原有的ideal viewport,因为它非常适合设备。
4S以上版本包含4S,iPhone理想的视口是320x480,无论它是否有视网膜屏幕。那是因为320x480是这些iPhone上web页面的理想尺寸。

关于ideal viewport有两点很关键:

  1. the layout viewport可以被设置成the ideal viewport,使用meta标签的The width=device-width 和initial-scale=1指令实现
  2. 所有的scale指令是相对于the ideal viewport而言,不管the layout viewport拥有多大的宽度,因此maximum-scale=3 意味着web页面可以放大到the ideal viewport的300%

三、meta viewport

1.meta viewport标签

meta viewport标签包含有关视口(viewports)和缩放(zooming)的浏览器指令。特别是,它允许Web开发人员设置layout viewport的宽度,这个宽度直接影响到width:20%这样的css声明的计算

meta viewport标签具有以下语法:

<meta name="viewport" content="name=value,name=value">

2.指令

viewport mata标签的每一对name/value都是一条指令。总共有6条指令:

  1. width: 用来设置layout viewport的宽度。
  2. initial-scale: 用来设置页面的初始缩放值以及layout viewport的宽度。
  3. minimum-scale: 用来设置允许的最小缩放值(例如,用户可以缩小至什么程度)。
  4. maximum-scale: 用来设置允许的最大缩放值(例如,用户可以放大至什么程度)。
  5. height: 期望用于设置layout viewport的高度。但一直没被支持。
  6. user-scalable: 当设置为no时,则禁止用户进行缩放。

3.device-width值

width指令有一个特殊的值:device-width。它能将layout viewport的宽度设置成ideal viewport宽度。 理论上同样有一个类似的device-height值,但实际上这个值并不起作用。

四、缩放对viewport的影响

1.缩放

缩放是棘手的。理论上讲很简单:确定用户可以放大或缩小的缩放系数(zoom factor)。这里存在两个问题:

  1. 我们不能够直接读取缩放系数,而是需要读取visual viewport的宽度,它与缩放系数成反比关系。缩放系数越大,visual viewport的宽度越小。因此,最小缩放系数决定了最大visual viewport宽度,反之亦然。
  2. 事实证明,无论layout viewport的当前大小是什么,所有缩放因子都相对于ideal viewport

因此关于缩放这个名字的问题,缩放实际上是比例,而viewport meta的指令称之为initial-scale、minimum-scale、maximum-scale。其它浏览器为了保持和针对iPhone适配的网站兼容也只好被迫实现了这些指令。
这三个指令期望一个缩放因子,例如2意味着“缩放到ideal viewport宽度的200%”

2.公式

visual viewport width = ideal viewport width / zoom factor
zoom factor = ideal viewport width / visual viewport width

3.理解

我们先来梳理一下:

  • 我们平时开发的css是基于layout viewport来计算
  • 在完全缩小的情况下layout viewport=visual viewport
  • 使用meta viewport的width指令设置layout viewport的宽,当width=device-width 和initial-scale=1时,layout viewport=ideal viewport。以iphone4S为例,ideal width是320,此时layout viewport也是320,初始缩放系数是1也就是没有缩放
  • 当用户进行缩放的时候layout viewport是不会变的,visual viewport与缩放系数成反比

我的理解:

这里以手机拍照为例,用手机后置摄像头拍摄电脑上的一个网页,调整手机与电脑之间的距离使得整个页面刚好拍进手机里,但是网页变小了,这时layout viewport=visual viewport,这种情况就叫做完全缩小
缩放系数,如果我想让网页变大,调近手机与电脑之间的距离,这时网页变大了,但是网页看不全了也就是可视区域变小了;同理我想让网页变小,那么调远手机与电脑之间的距离,这时网页变小了,但是网页能看到的东西多了,也就是可视区域变大了

五、移动端适配方案

1.目前行业内流行几种适配方法

  • JS根据屏幕动态计算 使用js判断页面宽度算出页面应有的font-size
  • 媒体查询 使用媒体查询 来兼容不同尺寸屏幕 设置不同尺寸下的rem大小
  • flex布局 CSS3中提出的新布局方案 移动端的兼容性较好

使用rem作为移动端尺寸单位替代px,那么1rem=?px
目前1rem有三种方案:

  1. 1rem=16px
    这个是默认的大小
  2. 1rem= 75px
    这个是手淘团队在flexible方案中在iphone6中的显示结果
    flexible方案核心就是根据屏幕的dpr和尺寸 动态算出当前页的rem大小 动态的修改meta标签
    该方案目前也被应用在手淘首页中
  3. 1rem=100px
    这个是阿里旗下的蚂蚁金服在Ant-mobile中的方案
    ant-mobile也有自己高清解决方案 其核心跟flexible类似
    现应用于ant-mobile中

如果项目中使用的是1rem=16px,又集成了antd-mobile,那么就会导致antd-mobile中的组件特别小,这就面临着方案转换的问题,如果我们在项目的样式中以rem作为单位,现在是16px转100px,如果以后用75px那么所有的样式文件中rem就都需要进行转换工程量很大。所以,样式文件中我们还使用px作为单位,然后使用插件将px转成rem,这样就算有方案转换,我们也只需要修改插件中的配置和一些脚本文件

图片描述

六、高清适配方案

1.在public/index.html中删除meta viewport标签,然后用下列代码动态生成meta viewport标签

'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[\S\s]+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`;
};
flex(100, 1);

代码理解:以iphone6为准,dpr=2,scale=1/2,fontSize=100;由之前介绍的viewport可以知道,scale=1/2那么visual viewport=2*ideal viewport

2.修改package.json

"theme": {"hd": "2px","brand-primary": "red","color-text-base": "#333"},

3.修改config-overrides.js在webpack配置中使用 postcss-pxtorem 把 px 转成 rem 单位

安装react-app-rewire-postcss

npm install react-app-rewire-postcss --save-dev

配置postcss,完整代码如下:

const { injectBabelPlugin, getLoader } = require('react-app-rewired');
const rewirePostcss = require('react-app-rewire-postcss');
const pxtorem = require('postcss-pxtorem');
const autoprefixer = require('autoprefixer');
const theme = require('./package.json').theme;
const fileLoaderMatcher = function (rule) {return rule.loader && rule.loader.indexOf(`file-loader`) != -1;
}
module.exports = function override(config, env) {// do stuff with the webpack config...config = injectBabelPlugin(['import', {libraryName: 'antd-mobile',// style: 'css',style: true, // use less for customized theme}], config);console.log(config.module.rules[2].oneOf);// sassconfig.module.rules[2].oneOf.unshift({test: /\.scss$/,use: [require.resolve('style-loader'),require.resolve('css-loader'),require.resolve('sass-loader'),{loader: require.resolve('postcss-loader'),options: {// Necessary for external CSS imports to work// https://github.com/facebookincubator/create-react-app/issues/2677ident: 'postcss',plugins: () => [require('postcss-flexbugs-fixes'),autoprefixer({browsers: ['>1%','last 4 versions','Firefox ESR','not ie < 9', // React doesn't support IE8 anyway],flexbox: 'no-2009',})],},}]});//lessconfig.module.rules[2].oneOf.unshift({test: /\.less$/,use: [require.resolve('style-loader'),require.resolve('css-loader'),{loader: require.resolve('postcss-loader'),options: {// Necessary for external CSS imports to work// https://github.com/facebookincubator/create-react-app/issues/2677ident: 'postcss',plugins: () => [require('postcss-flexbugs-fixes'),autoprefixer({browsers: ['>1%','last 4 versions','Firefox ESR','not ie < 9', // React doesn't support IE8 anyway],flexbox: 'no-2009',}),],},},{loader: require.resolve('less-loader'),options: {// theme vars, also can use theme.js instead of this.modifyVars: theme,},},]});config = rewirePostcss(config,{plugins: () => [require('postcss-flexbugs-fixes'),require('postcss-preset-env')({autoprefixer: {flexbox: 'no-2009',},stage: 3,}),pxtorem({rootValue: 100,    //以100px为准,不同方案修改这里propWhiteList: [],})],});// file-loader excludelet l = getLoader(config.module.rules, fileLoaderMatcher);l.exclude.push(/\.scss$/);l.exclude.push(/\.less$/);return config;
};

将src/App.css改成scss格式并修改App.js如下:

/*src/App.scss*/
.App {text-align: center;.App-Button{width: 750px;height: 88px;}
}
/*src/App.js*/
import React, { Component } from 'react';
import './App.scss';
import {Button} from 'antd-mobile';class App extends Component {render() {return (<div className="App"><Button type='primary' className='App-Button'>{document.documentElement.clientWidth}</Button></div>);}
}export default App;

最终运行结果如下图:

图片描述

可以看到px已经被转换成rem了,layout viewport = 750px

项目地址:https://github.com/SuRuiGit/m...


https://dhexx.cn/news/show-2257079.html

相关文章

【甘道夫】Ubuntu14 server + Hadoop2.2.0环境下Sqoop1.99.3部署记录

第一步。下载、解压、配置环境变量&#xff1a;官网下载sqoop1.99.3http://mirrors.cnnic.cn/apache/sqoop/1.99.3/将sqoop解压到目标文件夹&#xff0c;我的是/home/fulong/Sqoop/sqoop-1.99.3-bin-hadoop200配置环境变量&#xff1a;export SQOOP_HOME/home/fulong/Sqoop/sqo…

MySQL中 replace 函数应用

2019独角兽企业重金招聘Python工程师标准>>> 将以下字段中的【忻州】替换为【洛阳】 Sql语句如下 UPDATE sys_organization SET org_name REPLACE(org_name,忻州,洛阳); 执行结果如下 转载于:https://my.oschina.net/u/3866531/blog/2251560

python网络爬虫如何学_2018年,小白如何学习Python网络爬虫?

原标题&#xff1a;2018年,小白如何学习Python网络爬虫&#xff1f;人生苦短&#xff0c;我用PythonPython网络爬虫上手很快&#xff0c;能够尽早入门&#xff0c;可是想精通确实是需求些时间&#xff0c;需求达到爬虫工程师的级别更是需求煞费苦心了&#xff0c;接下来共享的学…

[转] 使用gc objgraph 优化python内存

转自https://www.cnblogs.com/xybaby/p/7491656.html 使用gc、objgraph干掉python内存泄露与循环引用&#xff01; 目录 一分钟版本python内存管理 引用计数垃圾回收gc module内存泄露 objgraph查找内存泄露循环引用 定位循环引用消灭循环引用总结references正文 Python使用引用…

迭代器和生成器补充

初步铺垫&#xff1a; for i in [1,2,3,4]: passl [1,2,3,4]l2 iter(l) print(l2.__next__()) print(l2.__next__)print(range(100)) #range(100) 就是一个生成器&#xff0c;为了节省内存&#xff0c;值不会直接输出 print(range(0,100)) #两种range取值方法&#xff1a; pr…

数组扩容 java_Java数组扩容问题

模拟扩容&#xff0c;由于不能使用方法&#xff0c;有些局限&#xff0c;可以运行看看。根据录入提示进行测试&#xff1a;package developer.test;/*** 默认创建一个长度为10的string数组&#xff0c;用户可以循环手动添加数据&#xff0c;当添加数据超过数组长度时&#xff0…

单位阶跃函数(Heaviside/unit step function)—— 化简分段函数

注意&#xff0c;单位阶跃函数一种不连续函数。 1. 常见定义 最经典的定义来自于 Ramp function&#xff08;斜坡函数&#xff0c;max{x,0}&#xff09;的微分形式&#xff1b; H(x)ddxmax{x,0}2. 化简分段函数 如对于指数分布的概率密度函数&#xff1a; f(x;λ){λe−λx0x≥…

第一周作业-三级菜单

1. 运行程序输出第一级菜单2. 选择一级菜单某项&#xff0c;输出二级菜单&#xff0c;同理输出三级菜单 3. 菜单数据保存在文件中 4. 让用户选择是否要退出 5. 有返回上一级菜单的功能 1 #coding:utf-82 #Author:Mr Zhi3 file_o open("menu",r,encoding"utf-8&…

bdd java_Java的BDD框架之间有什么区别?

我刚刚完成了比较三个BDD框架的Java。显然我的发现有一个相当短的使用期限。>非常灵活>非常漂亮的报表输出>好的插件框架>记录不良。我不得不读的来源&#xff0c;以计算出来(幸运的是&#xff0c;它非常好的质量)。>装置似乎可能最终紧密耦合到html。>非常浅…

成绩图表JAVA_求大神帮忙看一下这段java代码怎么能让记录学生成绩的表格显示出来啊?...

展开全部你没有给table赋值。代码如下即可package student.UI;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.aw…