当前位置: 首页 > news >正文

用户体验与响应式字体二三事|rem单位与flexible.js、rpx单位与css媒体查询

响应式页面已经趋近成熟。在视觉和前端眼中,需要着重考虑的只有一点:当可视区域变化时,是在一行中展示更多/更少的内容?还是让字体随之变化而保证在不同屏幕中展示内容不变(除非一些极端情况)?

可以明确的是,上面的问题并不针对“字体”。字体一定是跟随“页面”响应式逻辑!
最明显的例子是:大部分PC页面一定是选择前者,因为页面整体必须跟随可视区域变化;而在H5中,由于各种情况影响,很多时候会选择后者。

所以,这又引出了“布局”。比如下面的情况,在很小屏下应该如何布局?
微店-秒杀商家侧

简单来说,我认为一个“好的布局”应该是:以视觉为主、交互次之。平铺文字以自适应换行为主、按钮文字和固定小空间文字以 js 介入更改视觉大小为主。极小屏下以按钮、icon、图片为主,文字仅起辅助作用(大屏相反,以文字为主、图片次之、按钮再次、icon、多层级结构为辅)。优先考虑多层级结构、单文档流次之。
这其中稍有复杂,后面另作文章,这里先不探究。

而我们今天的主题便是H5端字体变化~

说起H5响应式,不能不提曾经“惊为天人”的flexible.js库。其实网上分析的文章很多,笔者曾经也针对某个具体场景实现过更简洁的代码段。简单来说,它的作用就是帮我们计算出1rem 等于多少px

// 首先是一个立即执行函数,执行时传入的参数是window和document
(function flexible (window, document) {
  var docEl = document.documentElement  // 返回文档的root元素
  var dpr = window.devicePixelRatio || 1 // 获取设备的dpr,即当前设置下物理像素与虚拟像素的比值

  // adjust body font size 设置默认字体大小,默认的字体大小继承自body
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px'
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();

  // set 1rem = viewWidth / 10
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  // reset rem unit on page resize
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })

  // detect 0.5px supports  检测是否支持0.5像素,解决1px在高清屏多像素问题,需要css的配合。
  if (dpr >= 2) {
    var fakeBody = document.createElement('body')
    var testElement = document.createElement('div')
    testElement.style.border = '.5px solid transparent'
    fakeBody.appendChild(testElement)
    docEl.appendChild(fakeBody)
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines')
    }
    docEl.removeChild(fakeBody)
  }
}(window, document))

可以看到,其核心就是1rem = 屏幕宽度的1/10,其余大量代码都是为此服务。

我们把视觉稿分成10等份,视觉稿 A = W/10,我们把设备可视区域也就是我们的各种移动端设备的这个画布也分成10份,并赋值给根元素的fontSize,我们都知道rem是根据根元素字体大小计算的,所以我们的1rem也就是设备可视区域/10,现在视觉稿上有一块区域宽B,B占了 B/A 份,相应地在设备可视区域上也要占 B/A 份。那它等比放到设备可视区域的宽度就是 B/A rem
这就是flexible.js能实现设备兼容的原理。

题外话,因为我们写代码的时候必须要用px单位,我们在项目中可能用过 px2rem插件。拿 vue 项目来说:

px2rem: {
    open: true, // 如果要开启,需要设置为 true
    loader: 'px2rem-loader', // 开发者在当前目录需要自行安装 px2rem-loader: npm i px2rem-loader
    options: {
        remUnit: 75
    }
},

remUnit:75
这里为啥是75呢,这是因为我们的视觉稿宽度一般是以二倍iPhone6 750px 为基准的,十分之一就是75px

更多关于上面内容可以查阅笔者之前的一篇文章:移动Web开发适配绝招rem

经过这么长时间,flexible库已经慢慢无法适应更多可能的现代页面了。正巧css的快速发展让前端在媒体查询 @media 上看到了更多可能!

关于媒体查询助力页面响应式的文章也有很多,这里我结合我司sheer库中的rpx单位加深一下印象:

rpx 单位,简而言之就是以 rpx 代替 px 做单位,打包编译时会处理为 px 或 rem 等可以被浏览器识别的单位。
我司的 rpx 单位其实和微信小程序的 rpx 以及上面的 flexible 库大体上看原理差不多 —— 先依据可视宽度转换,再根据根元素值重新赋值让浏览器解析。它支持文首提到的两种响应式方式,而且不仅作用于文字。

重点在于,为了兼容老项目,也得益于我司的 sheer 库并不只是一个js文件,我们用 css 做了关于根节点大小的响应式处理

@media screen and (width:360px){html{font-size:48px}}
@media screen and (width:375px){html{font-size:50px}}
@media screen and (width:414px){html{font-size:55.2px}}
@media screen and (width:480px){html{font-size:64px}}
@media screen and (width:540px){html{font-size:72px}}
@media screen and (min-width:750px){html{font-size:100px}}

@media 的用处可不止于此:
秒杀设置端

很显然,之前的开发中并没有考虑到极小屏下的场景 —— 在字体允许的、不影响体验的大小下宽度并不足以支持和大屏一样的内容。这也是前端目前常见的一个问题。
这个时候,我们最好是将其移到 input 下方或是“嵌入” input 中。虽然这种场景目前很少,但谁知道后续的折叠屏又有什么新花样呢?(图为Galaxy Fold机型)

在我看来,@media 的用处和精髓也就在此:它是一个“范围属性”。如果针对一个个单独的点做处理,过多的 media 反而会使效率大打折扣,所以我更建议选取“某些阶段”的临界点做处理。

相关文章:

  • 408 | 【2009年】计算机统考真题 自用回顾知识点整理
  • MyMusic 重点实现
  • 云计算敏捷团队的 10 个最佳实践工具
  • 阿里面试官终于把多年总结的Java八股文PDF版分享出来了,帮我金九银十拿下4个offer
  • java毕业设计超市管理系统Mybatis+系统+数据库+调试部署
  • 计算机网络 第 1 章 计算机网络概述
  • 如何转换图片格式?教你三招一键轻松转换图片格式
  • 【从小白到大白04】Linux基本权限
  • Unity_飞机大战_防止单例随场景销毁和跨场景两个物体脚本问题_自动加载物体挂载脚本的两种方式
  • taro 兼容支付宝小程序和微信小程序<七>-- 上传图片及图片转base64
  • 【附源码】计算机毕业设计SSM汽车交易平台
  • 购买域名-腾讯云
  • 【Linux练习生】Linux多线程
  • JavavEE中网络编程Socket套接字Ⅱ(TCP)
  • Intel汇编-函数使用堆栈传递数据
  • python3.6+scrapy+mysql 爬虫实战
  • 【翻译】babel对TC39装饰器草案的实现
  • DOM的那些事
  • ES2017异步函数现已正式可用
  • flask接收请求并推入栈
  • IP路由与转发
  • Java方法详解
  • JDK 6和JDK 7中的substring()方法
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • mockjs让前端开发独立于后端
  • Sequelize 中文文档 v4 - Getting started - 入门
  • Tornado学习笔记(1)
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 前端工程化(Gulp、Webpack)-webpack
  • 如何合理的规划jvm性能调优
  • 如何解决微信端直接跳WAP端
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 算法-插入排序
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • $.ajax中的eval及dataType
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (八)Flask之app.route装饰器函数的参数
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (六)Hibernate的二级缓存
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (转)负载均衡,回话保持,cookie
  • (转)四层和七层负载均衡的区别
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET 8.0 中有哪些新的变化?
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .net 中viewstate的原理和使用
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)