背景介绍

目前,随着移动设备的普及和4G网络的普及,web在移动端的占比已经远远超过PC端,各种H5页面推广页面,H5小游戏热度火爆。以前简单的使用px单位(没有弹性)的时代已经无法满足各位设计师和用户了。如何100%还原UI设计师的设计图,一直困扰着前端工程师。

css单位

学习首先我们简单了解下css目前都支持哪些单位:

  • px: 设置固定的布局或者元素大小,缺点是没有弹性
  • em: 参考父元素的font-size,em会继承父级元素的字体大小,em的值并不是固定的
  • rem: 相对根元素html的font-size
  • %: 相对父元素,对于position: absolute;的元素是相对于已定位的父元素,对于position: fixed;的元素是相对于ViewPort(可视窗口)
  • vw: view width的简写, 是指可视窗口的宽度,浏览器宽度1200px, 1 vw = 1200px/100 = 12 px
  • vh: view height的简写,是指可视窗口的高度,浏览器高度900px, 1 vh = 900px/100 = 9 px
  • vm: 相对于视口的宽度或高度中较小的那个, 其中最小的那个被均分为100单位的vm,浏览器高度900px,宽度1200px,取最小的浏览器高度,1 vm = 900px/100 = 9 px
  • in: 寸
  • cm: 厘米
  • mm: 毫米
  • pt: point, 大约1/72寸
  • pc: pica, 大约6pt, 1/6寸

具有弹性布局能力的单位:

  • em,%: 相对于父元素
  • rem: 相对于html
  • vw, vh, vm: 相对于可视窗口

从上可以看出,要做页面整体弹窗缩放的话,使用rem, vm, vw, vh更适合,因为任何内容都可以找到同一个基准。

HTML viewport基础

概念

viewport 是用户网页的可视区域。

手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。

用法

<meta name="viewport" content="width=device-width, initial-scale=1.0">

属性说明

  • width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
  • height:和 width 相对应,指定高度。
  • initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例,默认值1。
  • maximum-scale:允许用户缩放到的最大比例。
  • minimum-scale:允许用户缩放到的最小比例。
  • user-scalable:用户是否可以手动缩放。

弹性布局方案

通过以上可以看出,使用弹性布局的css单位配合设置html viewport元信息,就可以实现整体页面的弹性布局(包含字体大小)。

先弄明白几个概念:

设备分辨率:一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值;
设备屏幕宽度:设备显示器的实际宽度;
DPR:设备上物理像素和设备独立像素(device-independent pixels (dips))的比例,DPR = 设备分辨率/设备屏幕宽度;
300ppi:每英寸300个像素点

思路

根据以上的概念,那么,我们知道

window.devicePixelRatio = document.body.clientWidth / window.screen.width;

如果屏幕分辨率宽是1080px,屏幕宽度为360px,那么DPR=1080/360=3。

如果现在UI设计图也是1080px,那么前端工程师不想丢失任何细节的使用代码如何还原呢?

可以设置屏幕宽度为1080px, 设置viewport属性initial-scale = 1/3;

这样360px的屏幕就可以容纳1080px宽的内容了。

但是每个手机的分辨率都不一样,那么如何来设置这个这个initial-scale呢?我们可以通过以下方式:

var scale = 1 / window.devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'user-scalable=no,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale);

将user-scalable设置为no, 不允许缩放,有缩放需要的,可以不设置

之后如何设置某一个区块的宽,高,或者字体大小呢?

我们还需要设置html标签,字体的大小,我习惯于使用设计图的宽/20来获取元素的rem数值。比如

  • UI设计图文字大小30px, 那么我习惯使用 font-size: 1.5rem;
  • UI设计图图片宽100px, 我习惯使用 width: 5rem;

那么我会设置html的font-size为 deviceWidht / (UI设计图宽/20);

var base = 720 / 20; // 720为UI设计稿的宽
var fontSize = deviceWidth / base;
document.documentElement.style.fontSize = fontSize + 'px';

结合以上,完整代码为:

<script type="text/javascript">
var scale = 1 / window.devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'user-scalable=no,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale);
window.onresize = function (base) {
  var deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth;
  var screenWidth = window.screen.width;
  if (deviceWidth / screenWidth != window.devicePixelRatio) {
    document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
    deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth;
  }
  var fontSize = deviceWidth / base;
  document.documentElement.style.fontSize = fontSize + 'px';
};
window.onresize(720);
</script>

以上代码我放在<head>里面,在html标签渲染前就开始设置。

一开始就根据DPR设置initial-scale,之后在onresize里面设置html字体大小。

大家会注意到onresize里面有这样一段代码:

var deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth;
var screenWidth = window.screen.width;
if (deviceWidth / screenWidth != window.devicePixelRatio) {
  document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
  deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth;
}

这一段代码是为了兼容一部分旧款机器,这些机器无法正常的获取到DPR值,那么我们就只能设置屏幕页面内容宽度为设备宽度。

有疑问,欢迎联系博主讨论。

适用于移动设备弹性布局的js脚本(rem单位)的更多相关文章

  1. 【前端开发】移动端适配方案js,rem单位转换,640设计稿20px=1rem

    ! function() { var style = document.createElement("STYLE"), docEl = document.documentEleme ...

  2. web app 自适应方案总结 关键字 弹性布局之rem

    关于rem,主要参考文档 1.腾讯ISUX (http://isux.tencent.com/web-app-rem.html) 2.http://www.w3cplus.com/css3/defin ...

  3. web app 自适应方案总结 弹性布局之rem

    关于rem,主要参考文档 1.腾讯ISUX (http://isux.tencent.com/web-app-rem.html) 2.http://www.w3cplus.com/css3/defin ...

  4. web app 自适应 弹性布局之rem

    关于rem,主要参考文档 1.腾讯ISUX (http://isux.tencent.com/web-app-rem.html) 2.http://www.w3cplus.com/css3/defin ...

  5. Flex弹性布局在移动设备上的应用

    引文 首先,我们有表格布局.当不考虑语义并且利用一些适当的嵌套和其他技巧,我们可以用table建立具有一定功能的布局. 然后是现在大多数人都在使用的浮动布局.我们可以使用任何我们想用的元素,但浮动并不 ...

  6. 30行js让你的rem弹性布局适配所有分辨率(含竖屏适配)(转载)

    用rem来实现移动端的弹性布局是个好主意!用法如下: CSS @media only screen and (max-width: 320px), only screen and (max-devic ...

  7. 30行js让你的rem弹性布局适配所有分辨率(含竖屏适配)

    用rem来实现移动端的弹性布局是个好主意!用法如下: CSS @media only screen and (max-width: 320px), only screen and (max-devic ...

  8. 基于淘宝弹性布局方案lib-flexible的问题研究

    上篇文章<淘宝弹性布局方案lib-flexible实践>结合一个简单的实例,说明了lib-flexible的基本用法,但是lib-flexible的这种适配方式在适配的时候会修改viewp ...

  9. 百度在PWA中阐述的弹性布局-[CSS]

    原文链接 响应式布局 自从进入移动互联网时代,响应式布局这个词经常出现在 Web 设计和开发领域,它让 Web 页面在不同尺寸的设备上都具有良好的浏览体验. 开始之前 在讲解响应式布局之前,需要先了解 ...

随机推荐

  1. maven 包下载地址

    <groupId>cn.com.bmsoft.smartcity</groupId><artifactId>base</artifactId><p ...

  2. C# autocomplete

    前台代码 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runa ...

  3. 校园管家(Android开发团队项目)NABCD

    N(Need)需求: 现如今数据越来越零碎化,繁杂化,身为在校大学生的我们也因此对于时间的利用率也相应减少,为了时间的充分利用,减少在冗杂的信息中耽误的时间,充分利用大学资源,因此我们打算做一个专门发 ...

  4. 653. Two Sum IV - Input is a BST-easy

    我不懂有没有收藏之类的功能,收藏别人的解法. tql,不懂为什么直接比较set里的值,不是两个数sum么 有一些答案都用到了iterator迭代器 http://www.cplusplus.com/r ...

  5. 20164301 Exp2 后门原理与实践

    Exp2 后门原理与实践 1.实验内容  (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, 任务计划启动 (3)使用MSF meterprete ...

  6. What You Can Learn from Actifio Logs

    The Actifio services generate many logs, some of which are useful for troubleshooting. This section ...

  7. Noname

    版本: LayaAir IDE 2.0.1beta laya.core.js ___Laya ColorUtils LayaGLQuickRunner DrawTextureCmd Point Col ...

  8. Vue.js 父子组件之间通信的方式

    Vue 父子组件之间的同学有一下几种方式: 1. props 2. $emit -- 组件封装用的比较多 3. .sync -- 语法糖 4. $attrs 和 $listeners -- 组件封装用 ...

  9. 1、编写一个简单Makefile模板

    一.Makefile简介 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译, ...

  10. Element UI toggleRowExpansion用法

    背景: 官方说明文档没有具体代码示例 一.官方文档 方法名: toggleRowExpansion 说明: 用于可展开表格,切换某一行的展开状态,如果使用了第二个参数,则是设置这一行展开与否(expa ...