H5 - rem自适应方案

  H5 - rem自适应方案

  对于H5应用来说,为了更通用地满足各机型屏幕的自适应布局要求,我们目前采用rem布局方案。

  rem

  rem是相对于根元素(html)字体大小的单位,它只是一种相对单位。不同于另一个相对单位em,em是相对于父元素的字体大小,而rem则相对于根元素(html),与父元素的字体大小无关。

  等比例适配所有屏幕

  不论传统的px绝对像素布局,还是流式布局、固定宽度和响应式做法,都有其缺陷,并不能完全做到自适应所有屏幕。

  但是,rem方案可以比较容易地做到等比例适配所有屏幕,保证各屏幕的显示效果与原始设计稿一致。

  我们看看rem是如何工作的。

  举个例子:

  html{

  font-size: 20px;

  }

  .btn {

  width: 6rem;

  height: 3rem;

  line-height: 3rem;

  font-size: 1.2rem;

  display: inline-block;

  background: #06c;

  color: #fff;

  border-radius: .5rem;

  text-decoration: none;

  text-align: center;

  }

  如果我们把html的font-size改改,再看看效果。

  html{

  font-size: 40px;

  }

  可以看到,按钮的 width 、 height 、 font-size 和 border-radius 都被放大了一倍,我们只需要改变 html 的 font-size ,就能改变按钮在页面上的显示大小,而不必再去重设按钮的样式规则。

  按钮的大小 = 按钮的rem * html.font-size

  于是,利用这个特性,我们可以这样实现等比例适配所有屏幕。

  基准屏幕宽度

  以设计稿宽度作为最理想的基准屏幕宽度,假设设计稿宽度是 750px ,那么基准屏幕宽度就是 750px ,宽度大于 750px 的屏幕,等同于等比例放大了页面,小于 750px 的屏幕,等同于等比例缩小了页面。

  把设计稿750px十等分一下,每等分= 75px ,我们可以把这个 75px 当做 1个rem单位 ,那么 750px 宽度就等于是 10rem 。

  设置html的 font-size: 75px ,即 1rem ,也就是 rem的基准px=75px 。

  设计稿上的元素尺寸换算公式: 原始px值 / rem基准px ;例如 240px * 120px 的元素,其实就是 3.2rem * 1.6rem 。

  适配任意屏幕

  我们可以通过js来取得当前机型屏幕的宽度值,然后10等分得出当前屏幕1个rem应该代表的绝对像素值,再将这个 rem基准px 动态设置到 html.font-size ,核心代码如下:

  var docEl = document.documentElement;

  var width = docEl.getBoundingClientRect().width;

  var rem = width / 10;

  docEl.style.fontSize = rem + 'px';

  我们还可以通过less预处理工具,编写一个绝对px转rem的函数,自动转换px值,省却我们手动计算rem的麻烦,核心代码如下:

  @design-width: 750px; // 设计稿宽度

  @rem: @design-width / 10; // 10等分得到的rem基准px

  .px2rem(@attr; @px) when (ispixel(@px)) {

  @{attr}: unit(@px / @rem, rem);

  }

  // 处理非px值

  .px2rem(@attr; @px) when (default()) {

  @{attr}: @px;

  }

  .px2rem(@attr; @px1; @px2) when (ispixel(@px1)) and (ispixel(@px2)) {

  @{attr}: unit(@px1 / @rem, rem) unit(@px2 / @rem, rem);

  }

  .px2rem(@attr; @px1; @px2) when (ispixel(@px1)) and not (ispixel(@px2)) {

  @{attr}: unit(@px1 / @rem, rem) @px2;

  }

  .px2rem(@attr; @px1; @px2) when not (ispixel(@px1)) and (ispixel(@px2)) {

  @{attr}: @px1 unit(@px2 / @rem, rem);

  }

  //

  处理非px值

  .px2rem(@attr; @px1; @px2) when (default()) {

  @{attr}: @px1 @px2;

  }

  然后用法如:

  .px2rem(width; 240px);

  .px2rem(padding; 10px; 20px);

  对于Retina高清屏幕的处理

  对于2倍和3倍的高清屏幕,分别做2倍和3倍处理。

  处理方法是:重设viewport,将viewport缩小指定倍数。

  核心代码如:

  var dpr = 1;

  var scale = 1;

  // 仅ios考虑2/3倍方案,其他设备下,仍旧使用1倍的方案

  if (/i(Phone|Pod|Pad)/.test(navigator.userAgent)) {

  var ratio = win.devicePixelRatio;

  dpr = ratio >= 3 ? 3 : (ratio >= 2 ? 2 : 1);

  } else {

  dpr = 1;

  }

  scale = 1 / dpr;

  docEl.setAttribute('data-dpr', dpr);

  metaEl.setAttribute('content', 'initial-scale=' + scale + ', width=device-width, maximum-scale=' + scale + ', user-scalable=no');

  字号不用rem

  字号大小不推荐用rem作为单位,因此,字号仍旧使用px作为单位,并配合 data-dpr 自定义属性来在普通屏和2/3倍高清屏设置不同的 font-size 。

  高清屏的 font-size =设计稿的font-size,普通屏是设计稿font-size的一半。

  处理方式是:设定 body 的 font-size ,此后页面上所有元素的字号大小都是相对于body的 font-size ,而不是html的 font-size 。

  核心代码如:

  var fontBase = 16; // 普通屏基准字号:16px,高清屏基准字号:16px * 2、16px * 3

  if (doc.readyState === 'complete') {

  document.body.style.fontSize = fontBase * dpr + 'px';

  } else {

  document.addEventListener('DOMContentLoaded', function(e) {

  document.body.style.fontSize = fontBase * dpr + 'px';

  }, false);

  }

  // 默认普通屏,设计稿字号的一半

  h3 {

  font-size: 18px;

  }

  // 高清屏:设计稿的字号

  [data-dpr="2"] h3 {

  font-size: 36px;

  }

  [data-dpr="3"] h3 {

  font-size: 54px;

  }

  文本字号应该用rem吗? 显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。 如此一来, rem并不适合用到段落文本上。所以在整个案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

  关于css图片

  css图片只需要按设计稿输出的高清图即可,编写样式的时候, width 和 height 分别取图片真实宽和高的一半,再折算成rem单位,然后设定 background-size: contain 。

  .icon {

  width: .px2rem(image-width / 2);

  height: .px2rem(image-height / 2);

  background-image: url(image);

  background-size: contain;

  }

  关于img标签图片

  如果img标签加载的图片可以知道其宽高的话,那么也可以按照上一节的方法来设定图片的高清显示。

  如果不能预知图片大小,则需要通过js动态计算,将计算得出的宽高按上一节的方法动态设到 style 上。

  动态计算rem的函数是: FS.px2rem(px) 。

  完整代码

  

  

  

  

  

  

  


请使用浏览器的分享功能分享到微信等