H5页面适配及微信默认字号问题的最佳实践

H5页面适配及微信默认字号问题的最佳实践

Write By CS逍遥剑仙

我的主页: csxiaoyao.com

GitHub: github.com/csxiaoyaojianxian

Email: sunjianfeng@csxiaoyao.com QQ: 1724338257

1. css 中的单位

1.1 基于像素 px

最常用的 绝对单位,按精确像素计算

1.2 基于字号 em / rem

  • em相对单位,基准为父节点字体大小,若自身定义了 font-size 则按自身计算,不推荐使用
  • rem相对单位,css3新加,按照根节点 <html> 的字号作为基准,下方提供的设置根节点 62.5% 的方案并不推荐,具体实践见第二节的介绍
/* 根节点字体大小设置为 62.5%,即 10px 可以方便计算,否则将以浏览器默认字号 16px 为基准 */
/* 10 ÷ 16 × 100% = 62.5% */
/* 但 chrome 最小的字体大小为 12px,因此浏览器中的字体均 >= 1.2rem */
html { font-size: 62.5%; }
body { font-size: 1.4rem; } /* 1.4 × 10px = 14px */

1.3 基于视窗 vw / vh / vmin / vmax

  • vw / vh 即 viewpoint width / height,按照 视窗 的宽高的百分比进行计算,和 css 中的 % 按照父元素的宽高作为计算基准的方式不同
  • vmin / vmax 取视窗宽高二者中较小 / 大值的百分比进行计算
/* 元素始终在屏幕上可见 */
.box {
    width: 100vmin;
    height: 100vmin;
}
/* 元素始终铺满整屏 */
.box {
    width: 100vmax;
    height: 100vmax;
}

1.4 其他 % / vm / pc / pt / ch / ex ...

  • % 百分比,一般相对于父元素,但对于 position: absolute; 的元素是相对于已定位的父元素,对于 position: fixed; 的元素是相对于可视窗口,并且当父元素没有指定高度时,子元素设置百分比没有效果,高度直接为子元素的实际高度
  • vm css3 新单位,相对于视窗宽高较小的那个的百分比,兼容性较差

下面的单位几乎用不到:

  • in
  • cm 厘米
  • mm 毫米
  • pt point,约1/72寸
  • pc pica,大约6pt,1/6寸
  • ch ...
  • ex ...

...

2. 使用 rem 进行移动端页面适配

移动端适配最简单的是通过js动态计算 viewport 的缩放值,但过于粗暴,会导致页面图片文字失真模糊。目前,移动端页面一般使用 remvw / vh 开发会较为方便,下面以 rem 为例:

为了方便计算,约定:100px = 1rem,若设计师给到一张宽度为 750px 的设计稿,那么可以设置 html 的字体大小为 设备宽度 / 设计稿宽度 * 100 个px像素,以 iPhone 6/7/8 的宽度 375px 为例,则 html 字体的大小为 50px,即在宽度为 375 px 的设备上,1rem = 50px。对于开发人员,一个宽度为 50px 的 div,就可以很轻松的通过除以 100,计算出对应的 rem 为 0.5rem,不需要再根据各种机型进行适配,0.5rem 换算到 iPhone 6/7/8 为 25px,而放到 750px 宽的设备上对应的是 50px。

总体来说,使用 rem 进行适配需要以下四步:

  • 先根据设计稿尺寸使用 px 完成页面
  • 设置 meta,控制视口宽度,按 1:1 比例渲染页面
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1">
  • 动态设置 html 的 font-size
var clientWidth = document.documentElement.clientWidth
document.documentElement.style.fontSize = 100 * clientWidth / 750 + 'px'

建议设置监听,在页面尺寸变化时仍能正常展示

if (!document.addEventListener || !window.addEventListener) return
document.addEventListener('DOMContentLoaded', setScale, false)
window.addEventListener('orientationchange' in win ? 'orientationchange' : 'resize', setScale, false)
window.addEventListener('load', setScale, false)
  • 将页面各元素的 px 值除以 100 转换为 rem

3. 横版页面的 rem 适配

上面第二部分通过动态设置 html 的 font-size 已经实现了页面随设计稿比例缩放,这种方式是页面宽度 100% 撑满设备宽度的,但是很多情况下,我们更希望部分横版页面能够高度撑满设备高度,而左右部分留白,此时有两种方式可以实现:

  • html 的 font-size 依据页面高度进行设置,假设横版设计稿高度为 375px
var clientHeight = document.documentElement.clientHeight
document.documentElement.style.fontSize = 100 * clientHeight / 375 + 'px'
  • 限制横版页面的最大宽度,假设最大宽度为 670px 时,左右留白适配合适
var maxWidth = 670
var calWidth = Math.min(document.documentElement.clientWidth, maxWidth)
document.documentElement.style.fontSize = 100 * calWidth / 750 + 'px'

4. 解决微信等第三方App的默认字号问题

微信等 App 内可以设置默认字号,若用户修改了默认文字大小,会给上述的适配造成困扰,解决方法是先获取 App 的原始缩放比例,再在此基础上计算 font-size,实现如下:

// 创建1rem宽度的不可见元素,用于计算原始缩放比例
var scaleDom = (function () {
  var scaleDom = document.createElement('div')
  scaleDom.style.cssText = 'width:1rem;height:0;overflow:hidden;position:absolute;z-index:-2;visibility:hidden;'
  document.body.appendChild(scaleDom)
  return scaleDom
})()

// 计算使用过fontSize缩放(如微信)下的原始缩放比例
function getOriginScale () {
  var htmlFontSize = Number(String(document.querySelector('html').style.fontSize || 16).replace('px', ''))
  var instanceWidth = Number(String(window.getComputedStyle ? window.getComputedStyle(scaleDom).width : scaleDom.offsetWidth).replace('px', ''))
  var scale = (htmlFontSize && instanceWidth) ? htmlFontSize / instanceWidth : 1
  return scale
}

// 设置 html 用于处理 rem 的 font-size
function setScale () {
  var scale = getOriginScale()
  var clientWidth = document.documentElement.clientWidth
  if (!clientWidth) return
  window.uimakerScale = clientWidth / designWidth * scale
  document.documentElement.style.fontSize = 100 * window.uimakerScale + 'px'
}

5. 最佳实践

针对上述的适配方案,本文提供一套已在 html 自助化系统的生产环境中使用的适配代码作为最佳实践。

首先是 html 代码中需要配置视窗参数:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  ...
</head>
<body data-page-type="{{jsonData.pageType}}" data-design-width="{{jsonData.width}}" data-max-width="{{jsonData.maxWidth}}">
  ...
</body>
</html>

在初始化代码中执行下面的自执行函数,即可完成适配。

;(function (doc, win) {
  // 页面数据
  var pageType = parseInt(doc.body.getAttribute('data-page-type')) || 0 // 页面方向 0竖1横
  var designWidth = parseInt(doc.body.getAttribute('data-design-width')) || 750 // 设计宽度
  var maxWidth = parseInt(doc.body.getAttribute('data-max-width')) || designWidth // 最大页面适配宽度

  // 创建1rem宽度的不可见元素,用于计算原始缩放比例
  var scaleDom = (function () {
    var scaleDom = doc.createElement('div')
    scaleDom.style.cssText = 'width:1rem;height:0;overflow:hidden;position:absolute;z-index:-2;visibility:hidden;'
    doc.body.appendChild(scaleDom)
    return scaleDom
  })()

  // 计算使用过fontSize缩放(如微信)下的原始缩放比例
  function getOriginScale () {
    var htmlFontSize = Number(String(doc.querySelector('html').style.fontSize || 16).replace('px', ''))
    var instanceWidth = Number(String(win.getComputedStyle ? win.getComputedStyle(scaleDom).width : scaleDom.offsetWidth).replace('px', ''))
    var scale = (htmlFontSize && instanceWidth) ? htmlFontSize / instanceWidth : 1
    return scale
  }

  // 设置 html 用于处理 rem 的 font-size 和 页面二次缩放
  function setScale () {
    var scale = getOriginScale()
    var clientWidth = doc.documentElement.clientWidth
    var clientHeight = doc.documentElement.clientHeight
    if (!clientWidth || !clientHeight) return
    var calWidth = maxWidth > 0 ? Math.min(clientWidth, maxWidth) : clientWidth
    win.uimakerScale = calWidth / designWidth * scale
    doc.documentElement.style.fontSize = 100 * win.uimakerScale + 'px'
  }

  setScale()
  setTimeout(() => { setScale() }, 300)

  if (!doc.addEventListener || !win.addEventListener) return
  doc.addEventListener('DOMContentLoaded', setScale, false)
  win.addEventListener('orientationchange' in win ? 'orientationchange' : 'resize', setScale, false)
  win.addEventListener('load', setScale, false)
})(document, window)

6. 总结

移动端的适配已是老生常谈,市面上也有不少成熟的第三方库,但或多或少需要进行额外的配置,本文的方案是结合本人在一个自助化生成网页的项目的生产环境的实践中总结得出,若有更好的方案和建议欢迎和我交流。

sign

原文地址:https://cloud.tencent.com/developer/article/1809067

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340