资讯专栏INFORMATION COLUMN

使用 REM 进行布局和适配.

Moxmi / 2744人阅读

摘要:最终统筹一下我们要做的事情让变成和屏幕分辨率一致的宽度根据设备宽度和来指明根元素的值这些操作之后你就可以实现最终的代码了

首先从屏幕开始说起.

屏幕是由一个一个显示单元组成的.
1 每一个显示单元都是物理世界真实存在的;
2 把一个显示单元的大小称为一个"物理像素";
3 通常我们所说的 "分辨率", 就是指一块屏幕显示单元的个数, 比如
750*1334, 表示这块屏幕由 750*1334 个显示单元组成

映射规则

像素是计算机系统里面的单位, 通常情况下, 我们让一个像素对应一个显示单元. 所以有时候, 我们说屏幕高 667px, 实际上就是说, 屏幕的的高有 667个显示单元的高度之和.

随着技术的进步, 显示单元可以做的越来越小, 比如以前是 10mm*10mm 的一个显示单元, 现在我们可以做到 5mm*5mm 一个显示单元.
为什么追求显示单元的小? 因为越小图像越精细.

但是: 显示单元的变小, 意味着屏幕的分辨率变大。

这里就牵涉到了一些事情:

假设屏幕的大小不变, 但是分辨率从 A, 变成 2A (也就是显示单元缩小了一半)
并且: 一个像素对应一个显示单元, 这个规则始终不变

此时, 你原来宽度为 100px 的一个元素, 在这个 2A 屏幕上渲染出来, 你会明显的发现:
在视觉上: 这个 100px 明显比之前小了, 和之前的 50px 的时候一样大小.

那怎么办啊, 这样显示肯定是不可以的, 所以我们要对这个情况做处理:

1 我们规定, 大小为 n*n 的显示单元, 是标准的显示单元, 标准意味着它合乎我们长久的判断: 100px 在物理世界大概有多大.

2 我们要知道当前屏幕的显示单元, 和标准显示单元之间的大小比例,比如说当前屏幕的显示单元的大小是标准的一半还是 三分之一.

通过 devicePixelRatio 属性来获

我们可以认为:
devicePixelRatio 标记是: 标准显示单元/当前设备的显示单元

建立在上面的基础上面, 你就可以动态的调整元素的大小, 比如说某个元素 x 的宽度是 100px;

在 devicePixelRatio = 1 的设备上面宽度是 100px
在 devicePixelRatio = 2 的设备上面宽度就要是 200px;

ok, 那么我们来搞.
根据不同的 devicePixelRatio 来调整元素的样式.

var box = document.querySelector(".box");

var height = parseInt(getComputedStyle(box).height);
var width = parseInt(getComputedStyle(box).width);

box.style.height = height * parseInt(window.devicePixelRatio) + "px";
box.style.width = width * parseInt(window.devicePixelRatio) + "px";

这仅仅是一个元素的两个属性, 1000个元素, 每个元素 5 个属性, 就可以让你哭掉了.
所以这种处理方式肯定是不可以的.

然后我们发现了 rem 单位.
它的简单解释:

当你给某个元素A 设置了 height:2rem 的时候
它会找到根节点(html) 的 font-size 值, 比如是 16px
然后拿 16 * 2 = 32px
作为元素A 的最终 height.

这个就可以利用了
1 让元素使用 rem 作单位
2 然后控制根元素的 font-size 值, 在不同的 devicePixelRatio 下面的时候, 呈现不同的值
比如你可以设置:

devicePixelRatio = 1, font-size(root) = 100px;
devicePixelRatio = 2, font-size(root) = 200px;

元素在这个时候, 就会自动响应大小的变化.

好, 开始搞:

var fontSize = 100 * parseInt(window.devicePixelRatio) + "px";
document.documentElement.style.fontSize = fontSize;

嗯, 结果还是不错的, 在不同的分辨率下面, 我们也能实现页面相同了.

实际上, 上面的讨论, 已经解决了我们的问题:
在相同物理尺寸下的设备, 如何在分辨率不同的情况下, 让一个 100px 的元素, 它对应的物理世界的
大小, 始终相同?

现在更近一步, 上面的讨论, 固定了一个变量: 屏幕尺寸, 现在放开这个变量, 固定屏幕的分辨率这个变量.
这个问题就变成适配问题了:

场景描述:
比如你的一个页面本来是以 375宽度为基础做出来的, 那么在设备的宽度变成 320px 的时候,
你的页面就会出现问题: 挤压, 变形, 错乱, 或者超出隐藏, 超出滚动等等操作.

怎么办啊?
希望的是在 320 也能正常显示: 让页面上的所有元素都缩小一些, 也就ok了. 比如一个元素
在 375 设备上面显示这么大, 在 320 上面显示成这么大不就行了.

那么如何缩小?
rem;
你想下, 只要在屏幕的宽度变小的时候, 让根元素的 font-size 跟着变小, 那么所有使用 rem 作为单位的
元素, 是不是也跟着变小, 目标就达成了.

那么怎么让 font-size(root) 随着屏幕的宽度变小而变小啊.

选一对基准值, 比如: 375px/100px; 表示屏幕宽度为 375的时候, font-size(root) 为 100;

每次计算一下就好, 比如发现屏幕的当前宽度为 320, 那么算不出来此时的 font-size(root) 吗??
算出来不会设置根元素的 font-size 吗?

好吧, 上面说的暂时都不要试, 先提一个事情.
所有的上面的讨论, 实际上都建立在:

当你屏幕的分辨率是 100100 的时候, 你就拥有一份 100100 大小的容器, 用来呈现你的网页.
比如说, 你的 iPhone7 的分辨率是 6671334, 那么你就拥有一份 6671334 大小的容器来放你的网页

可惜并不是这样的.

从 iPhone 发布前夕说起:

开发人员发现, 原本为 pc 开发的网页
在 iPhone 上面显示不全, 这部分可以通过滚动条来解决.
但是使用 百分比布局的页面就坑爹了, 原本在 pc 端浏览器上拥有
的 20% 在 iPhone 上面就一点点了, 布局完全乱了, 坑啊.
为了解决这个问题, 开发人员提出了一个的新的玩意: "layout viewport"

我该怎么解释这个玩意呢.

    ==============  // 这个是你的百分比页面所基于的宽度

    ===             // 这个是你屏幕的宽度

这样一来, 页面肯定会错乱. 所以提出的 layout viewport 把模型变成这样:

    ==============  // 这个是你的百分比页面所基于的宽度

    =============   // layout viewport 的宽度

    ===             // 这个是你屏幕的宽度

你的页面会被放到 layout viewport 这个容器上面, 然后再将 layout viewport 缩小到
和屏幕宽度一样的大小.
并且允许用户放大页面,通过滚动条滑动来浏览器全部页面.

在最初的时候, 这种方式的确解决了 pc 端页面在手机上浏览的问题, 但是随着移动端的兴起,
大量的针对移动端的页面被制作出来, 也就是模型变成这样:

    ===   // 针对移动端做的页面

    ============   // layout viewport 

    ===   // 屏幕的宽度

这样很明显就出现问题了: 你的页面先放到 layout viewport 上面, 然后又缩小到和屏幕宽度一致
最终显示出来的, 就是你的页面明显被缩小了.

所以我们要解决这个问题, 要把 layout viewport 的大小, 变成和屏幕的宽度一致.
这里假设屏幕的显示单元始终是标准的显示单元大小。

怎么让 layout viewport 变成和屏幕的宽度一致呢?
通过 meta name="viewport" 标签.

解释一下:
meta name="viewport" 有一个 content 属性, 它里面有几个值, 可以用来对 layout viewport
做处理. content 有如下几个字段:

initial-scale: 这个值会影响最终 layout viewport 的宽度, 计算公式应该是这样:

屏幕的分辨率/(devicePixelRatio*initial-scale) = 最终的 layout viewport 的宽度. 

屏幕的分辨率我们可以拿到, devicePixelRatio 也可以拿到.
比如 iPhone7, 屏幕分辨率是 750*1334, devicePixelRatio=2, 当你设置 initial-scale=1 的时候
layout viewport 的最终宽度就是 375;

这里有一个点, 我说一下;
我们可以让 layout viewport 的宽度是任意值, 通过对 initial-scale 的设置.
那我们要设置它为多少呢?

可以设置成 375, 这个宽度, 是以标准显示单元为单位算出来的宽度
也可以设置成 750, 这样的话, 你的 1px 就完整对应这个设备的 1 个显示单元.

我们选择后者, 因为这个牵涉到 1px border 的实现.
如果设置成这个, 那么你的 initial-scale 始终只要设置成 1/devicePixelRatio 即可,
因为 devicePixelRatio * 1/devicePixelRatio = 1;

还有其他的两个相关属性:
maximum-scale: 最大能放大多少
minimum-scale: 最小能放大多少

希望不能缩放, 因为我们的页面不需要缩放就能正常显示, 缩放了反而显示不正确。

最终统筹一下:
我们要做的事情
1 让 layout viewport 变成和屏幕分辨率一致的宽度
2 根据设备宽度和 devicePixelRatio 来指明根元素的 font-size 值

这些操作之后, 你就可以实现最终的代码了.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84209.html

相关文章

  • rem, vw, 还是...? 各凭本事的移动端适配方案

    摘要:另一种就是不缩放,对等问题单独引入处理方案。彩蛋部分相信大多数同学也是有想法在实际开发中把融入到现有的移动端适配方案中的。 前言 2018年最后的法定假期都已经结束了,我相信大部分正在进行或曾经进行过移动端页面开发的同学都或多或少的了解过使用rem进行移动端页面适配的方案以及使用vw的方案,(没了解过的同学可以参见大漠老师的这两篇文章 使用Flexible实现手淘H5页面的终端适配和再...

    wangbinke 评论0 收藏0
  • rem, vw, 还是...? 各凭本事的移动端适配方案

    摘要:另一种就是不缩放,对等问题单独引入处理方案。彩蛋部分相信大多数同学也是有想法在实际开发中把融入到现有的移动端适配方案中的。 前言 2018年最后的法定假期都已经结束了,我相信大部分正在进行或曾经进行过移动端页面开发的同学都或多或少的了解过使用rem进行移动端页面适配的方案以及使用vw的方案,(没了解过的同学可以参见大漠老师的这两篇文章 使用Flexible实现手淘H5页面的终端适配和再...

    tianren124 评论0 收藏0
  • 我对移动端适配的了解

    摘要:随着移动端的发展,在手机上看电脑端的页面已成为非常普及现象。方案一固定高度,使其宽度自适应这也是我接触移动端适配第一次使用的方案。 不知不觉做前端已经两年了,从PC端,移动端,微信小程序一路走来到今天刚刚开放注册的快应用(手机厂商对抗小程序的新技能,所以在注册时用的是qq邮箱的话要去垃圾箱里才能找到注册邮件),对于前端圈日新月异的磅礴发展对于大前端发展是喜闻乐见的,这次的快应用的手机厂...

    import. 评论0 收藏0
  • 我对移动端适配的了解

    摘要:随着移动端的发展,在手机上看电脑端的页面已成为非常普及现象。方案一固定高度,使其宽度自适应这也是我接触移动端适配第一次使用的方案。 不知不觉做前端已经两年了,从PC端,移动端,微信小程序一路走来到今天刚刚开放注册的快应用(手机厂商对抗小程序的新技能,所以在注册时用的是qq邮箱的话要去垃圾箱里才能找到注册邮件),对于前端圈日新月异的磅礴发展对于大前端发展是喜闻乐见的,这次的快应用的手机厂...

    snowLu 评论0 收藏0
  • 我对移动端适配的了解

    摘要:随着移动端的发展,在手机上看电脑端的页面已成为非常普及现象。方案一固定高度,使其宽度自适应这也是我接触移动端适配第一次使用的方案。 不知不觉做前端已经两年了,从PC端,移动端,微信小程序一路走来到今天刚刚开放注册的快应用(手机厂商对抗小程序的新技能,所以在注册时用的是qq邮箱的话要去垃圾箱里才能找到注册邮件),对于前端圈日新月异的磅礴发展对于大前端发展是喜闻乐见的,这次的快应用的手机厂...

    XGBCCC 评论0 收藏0

发表评论

0条评论

Moxmi

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<