html5 分层屏幕适配的方法


Posted in HTML / CSS onMarch 16, 2018

设计大大,这次真的是 "按设计稿来" 了,因为现在,任何机子都是设计稿标准机! 开发同学,这下你就直接读设计稿标注就好了啦!

屏幕适配

屏幕适配应当指内容 适配区 和 屏幕区 间的适配关系。

单屏适配有 contain、cover 或 fill,多屏常见是 依宽 。

contain 和 cover 还需要 定位 来处理留白和超出的内容。

而同一个 H5 里不同内容往往用不同适配方式,即 分层。

html5 分层屏幕适配的方法

html5 分层屏幕适配的方法

优选CSS

  1. 页面加载后 js 往往需要延时至少 70ms 才能获取正确的 webview 宽高
  2. css 往往最先执行,且 cssom 的解析往往和 dom 在最开始并行构建
  3. js 会等待 dom 和 cssom 处理完后才能执行,而 css 只需等待 dom
  4. 相比 js 在切换横竖屏时要切换 2 次进程来重绘,css 无需切换

对于屏幕适配这类表现问题,能用 css 实现就应该用 css 实现。

整层适配

为确保各层元素同步缩放,不走样,每层的 适配区 应当等于设计稿大小。

直接的实现就是构造和 适配区 一样尺寸的 容器, 整层适配。

容器 内可以有若干个相同适配方式的 元素。

svg 实现为例:

<!doctype html>
<html>
<body>
<style>
.layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
</style>
<!-- fill -->
<svg class="layer" viewBox="0 0 1080 1920" preserveAspectRatio="none"> <!-- 容器 -->
  <rect x="0" y="0" width="1080" height="1920" fill="rgba(96,96,96,.08)"/>  <!-- 元素 -->
</svg>
<!-- contain 居中 -->
<svg class="layer" viewBox="0 0 1080 1920" preserveAspectRatio="xMidYMid meet"> <!-- 容器 -->
  <rect x="0" y="233" width="1080" height="1407" fill="#1565C0"/>  <!-- 元素 -->
</svg>
<!-- contain 居底 -->
<svg class="layer" viewBox="0 0 1080 1920" preserveAspectRatio="xMidYMax meet"> <!-- 容器 -->
  <rect x="444" y="1779" width="191" height="39" fill="#1565C0"/>  <!-- 元素 -->
</svg>
</body>
</html>

实际效果:

html5 分层屏幕适配的方法

整层适配 实现简单,开发时直接读取设计稿值,可以满足大部分静态页面需求。

但在 h5 动画多的时候,就得考虑动画流畅,页面性能了。

用可替换元素如 <img> <object> <svg> 等做 容器,以及用背景图做 元素 的,

在应用 css 动画时有性能缺陷:

  1. 对 容器 内 元素 应用 css 动画会造成频繁重排和重绘,导致卡顿。
  2. 将和 适配区 尺寸相同的 容器 提升为合成层时所占内存过大,有多少层内存就翻多少倍。

为这些实现方案提升性能就要针对 容器 动画,并减小 容器 的尺寸,最好是和一层里所有 元素 的最小总面积相等,做到 精简适配

精简适配

html5 分层屏幕适配的方法

公式

推导过程见 H5 分层屏幕适配公式推导

设计稿
  宽 v
  高 g
  
适配前元素
  横坐标 x
  纵坐标 y
  宽 w
  高 h

适配后容器
  横坐标 x3 = x*u/v
  纵坐标 y3 = y*f/g

适配后元素
  横坐标 x4 = m*u + (x - m*v)/w*w1 = m*v/w*w3 + (x - m*v)/w*w1
  纵坐标 y4 = n*f + (y - n*g)/h*h1 = n*g/h*h3 + (y - n*g)/h*h1
  宽 w3 = (w/v)*u
  高 h3 = (h/g)*f
  当 contain 方式适配时
    缩放值 s = Math.min(f/g, u/v)
    横向左留白占总留白 o = (m*v - x)/w
    纵向上留白占总留白 p =  (n*g - y)/h
  当 cover 方式适配时
    缩放值 s = Math.max(f/g, u/v)
    横向左超出占总超出 o = (x - m*v)/w
    纵向上超出占总超出 p =  (y - n*g)/h

适配区
  垂直居顶时 m = 0
  垂直居中时 m = .5
  垂直居底时 m = 1 
  水平居左时 n = 0
  水平居中时 n = .5
  水平居右时 n = 1 

相比整层适配内存优化 (w3*h3)/(v1*g1) >= w*h/(v*g)

<img> 实现示例
当设 max-width 为 w/v,max-height 为 h/g 时对应 contain 适配。
当设 min-width 为 w/v,min-height 为 h/g 时对应 cover 适配。
当设 width 为 w/v,height 为 h/g 时表示 fill 适配。
contain 适配时,如果图片原始尺寸小于 max-width 和 max-height 时,用 zoom: 10 放大或者直接修改图片原始尺寸。
cover 适配时,如果图片原始尺寸大于 min-width 和 min-height 时,用 zoom: .1 缩小或者直接修改图片原始尺寸。
因 top left 中百分比是相对屏幕宽 u 和高 f 的,对应 m*u 和 n*f
因 transform 中百分比是相对适配后元素宽 w1 和高 h1 的,对应 (m*v + x)/w*w1 和 (n*f + y)/h*h1

<!doctype html>
<html>
<body>
<style>
img {
  /* min-width 和 min-height 构成了虚拟的容器 */
  min-width: 50.37037037037037%; /* w3 = (w/v)*u 其中 w = 544,v = 1080 */
  min-height: 7.395833333333333%; /* h3 = (h/g)*f 其中 h = 142,g = 1920 */
  zoom: .1;
  /* x4 = m*u + (x - m*v)/w*w1 */
  /* y4 = n*f + (y - n*g)/h*h1 */
  position: absolute;
  left: 50%; /* m*u 其中 m = .5*/
  top: 50%; /* n*f 其中 n = .5 */
  transform:
    translateX(-48.34558823529412%) /* (x - m*v)/w*w1 其中 x = 277,m = .5,v = 1080,w = 544 */
    translateY(378.8732394366197%); /* (y - n*g)/h*h1 其中 y = 1498,n = .5,g = 1920,h = 142 */
}
</style>
<img src="http://ui.qzone.com/544x142"/> <!-- 元素 -->
</body>
</html>

background 实现示例

  1. background-size 值为 contain 时对应 contain 适配。
  2. background-size 值为 cover 时对应 cover 适配。
  3. background-size 值为 100% 100% 时对应 `fill 适配。
  4. background-position 百分比和 o p 意义相同
<!doctype html>
<html>
<body>
<style>
div {
  position: absolute;
  width: 50.37037037037037%; /* w3 = w/v*u 其中 w = 544,v = 1080 */
  height: 7.395833333333333%; /* h3 = h/g*f 其中 h = 142,g = 1920 */
  background: url(http://ui.qzone.com/544x142) no-repeat; /* 背景图做元素 */
  background-size: cover;
  left: 25.64814814814815%; /* x3 = x/v*u 其中 x = 277, v = 1080 */
  top: 78.02083333333333%; /* y3 = y/g*f 其中 y = 1498, g = 1920 */
  background-position-x: -48.34558823529412%; /* o = (x - m*v)/w 其中 m = .5 , v = 1080,x = 277,w = 544*/
  background-position-y: 378.8732394366197%; /* p = (y - n*g)/h 其中 n = .5 , g = 1920,y = 1498,h = 142*/
}
</style>
<div></div> <!-- 容器 -->
</body>
</html>

<svg> 实现示例

  1. preserveAspectRatiomeetOrSlicemeet 时对应 contain 适配。
  2. preserveAspectRatiomeetOrSliceslice 时对应 cover 适配。
  3. preserveAspectRatio 值为 none 时对应 fill 适配。
  4. 这里 preserveAspectRatiomeetOrSlice 相对的是容器,不是 适配区 这里用 transform 来定位,而 preserveAspectRatiomeetOrSlice 固定为 xMinYMin
<!doctype html>
<html>
<body>
<style>
svg {
  position: absolute;
  width: 50.37037037037037%;
  height: 7.395833333333333%;
  /* x4 = m*v/w*w3 + (x - m*v)/w*w1 */
  /* y4 = n*g/h*h3 + (y - n*g)/h*h1 */
  top: 0;
  left: 0;
  transform:
    translateX(99.26470588235294%) /* m*v/w*w3 其中 m = .5,v = 1080,w = 544 */
    translateY(676.056338028169%); /* n*g/h*h3 其中 n = .5,g = 1920,h = 142 */
    overflow: visible;
}
svg image {
  transform:
    translateX(-48.34558823529412%) /* (x - m*v)/w*w1 其中 x = 277,m = .5,v = 1080,w = 544 */
    translateY(378.8732394366197%); /* (y - n*g)/h*h1 其中 y = 1498,n = .5,g = 1920,h = 142 */
}
</style>
<svg viewBox="0 0 544 142" preserveAspectRatio="xMinYMin meet"> <!-- 容器 -->
  <image width="544" height="142" xlink:href="http://ui.qzone.com/544x142"/> <!-- 元素 -->
</svg>
</body>
</html>

辅助工具

手动计算百分比及写 css 很麻烦,可以借助 sass 等工具来辅助简化。
设计稿宽 vg 一般是页面级常量。
只需读取设计稿里每个 元素 的横坐标 x 、纵坐标 y 、宽 w 和 高 h,然后工具生成 css 即可。
这下妈妈再也不用担心我还原问题、屏幕适配问题了。

文字处理

文字固定或单行不固定,svgtext 标签可以处理

文字固定或单行不固定还可以将文字转为图片

文字多行不固定,可以借助 svgforeignObject 嵌入普通 div

方案对比

屏幕适配方案非常多,选哪种方式实现 整层适配 或 精简适配,下面是对比

方案 缩放 定位 文字缩放 兼容
padding-top 百分比 只能依宽
viewport 支持情况复杂
object-fit 移动端 android 4.4.4+
svg preserveRatio 移动端 android 3.0+
(max/min)-(width/height) 固定文字
background-size 文字转图片

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
发现两个有趣的CSS3动画效果
Aug 14 HTML / CSS
利用CSS3的特性改变文本选中时的颜色
Sep 11 HTML / CSS
CSS3的first-child选择器实战攻略
Apr 28 HTML / CSS
CSS的background属性及CSS3的背景图片设置总结
Jun 13 HTML / CSS
css3 中translate和transition的使用方法
Mar 26 HTML / CSS
基于ccs3的timeline时间线实现方法
Apr 30 HTML / CSS
纯CSS3实现运行时钟的示例代码
Jan 25 HTML / CSS
基于HTML5的WebSocket的实例代码
Aug 15 HTML / CSS
使用HTML5做个画图板的方法介绍
May 03 HTML / CSS
html5教程实现Photoshop渐变色效果
Dec 04 HTML / CSS
HTML5响应式(自适应)网页设计的实现
Nov 17 HTML / CSS
如何查看浏览器对html5的支持情况
Dec 15 HTML / CSS
canvas实现图片马赛克的示例代码
Mar 26 #HTML / CSS
HTML5 拖拽批量上传文件的示例代码
Mar 28 #HTML / CSS
利用html5 canvas动态画饼状图的示例代码
Apr 02 #HTML / CSS
简单聊聊H5的pushState与replaceState的用法
Apr 03 #HTML / CSS
如何使用localstorage代替cookie实现跨域共享数据问题
Apr 18 #HTML / CSS
Html5 localStorage入门教程
Apr 26 #HTML / CSS
在HTML5 canvas里用卷积核进行图像处理的方法
May 02 #HTML / CSS
You might like
php at(@)符号的用法简介
2009/07/11 PHP
php使用qr生成二维码的示例分享
2014/01/20 PHP
使用php测试硬盘写入速度示例
2014/01/27 PHP
php中实现可以返回多个值的函数实例
2015/03/21 PHP
PDO::getAvailableDrivers讲解
2019/01/28 PHP
Nodejs学习笔记之入门篇
2015/04/16 NodeJs
jQuery替换textarea中换行的方法
2015/06/10 Javascript
node+experss实现爬取电影天堂爬虫
2016/11/20 Javascript
jQuery无缝轮播图代码
2016/12/22 Javascript
node.js操作mongodb简单示例分享
2017/05/25 Javascript
vue中多个倒计时实现代码实例
2019/03/27 Javascript
vue读取本地的excel文件并显示在网页上方法示例
2019/05/29 Javascript
浅谈laytpl 模板空值显示null的解决方法及简单的js表达式
2019/09/19 Javascript
vue.js实现图书管理功能
2019/09/24 Javascript
一分钟学会JavaScript中的try-catch
2020/12/14 Javascript
[02:34]DOTA2亚洲邀请赛 BG战队出场宣传片
2015/03/09 DOTA
[00:36]DOTA2风云人物相约完美“圣”典 12月17日不见不散
2016/11/30 DOTA
python获取当前日期和时间的方法
2015/04/30 Python
python查询sqlite数据表的方法
2015/05/08 Python
Python使用pyh生成HTML文档的方法示例
2018/03/10 Python
Python实现对文件进行单词划分并去重排序操作示例
2018/07/10 Python
Python 元组拆包示例(Tuple Unpacking)
2019/12/24 Python
python 偷懒技巧——使用 keyboard 录制键盘事件
2020/09/21 Python
突袭HTML5之Javascript API扩展3—本地存储全新体验
2013/01/31 HTML / CSS
谈一谈HTML5本地存储技术
2016/03/02 HTML / CSS
印度网上购物首选目的地:Flipkart
2016/08/01 全球购物
美国最大的高尔夫发球时间预订网站:TeeOff.com
2018/03/28 全球购物
玉兰油美国官网:OLAY美国
2018/10/25 全球购物
Rhone官方网站:男士运动服装、健身服装和高级运动服
2019/05/01 全球购物
医学专业毕业生推荐信
2013/11/14 职场文书
办公设备采购方案
2014/03/16 职场文书
毕业生就业推荐表自我评价
2015/03/02 职场文书
2016年春季运动会加油稿
2015/07/22 职场文书
教学反思怎么写
2016/02/24 职场文书
win10安装配置nginx的过程
2021/03/31 Servers
Java使用HttpClient实现文件下载
2022/08/14 Java/Android