多屏适配方案

本文提供几种常用的多屏适配方案,由于不同公司和产品,适配需求不同,这里没法一一概况完全,仅供参考。

流行多屏适配种类

  1. PC 和移动端各自为一套独立的页面

    PC 固定宽度(设置最小宽度),移动端自适应(flexible)
    参考示例:https://www.ifanr.com

  2. PC 和移动端共用一套

    响应式和自适应结合
    参考示例:https://www.ifanr.com/api/ifanr-special/vivo-nex

  3. 移动端为主,PC 放置介绍页或者二维码

    参考示例:https://www.ifanr.com/api/ifanr-special/apple-2018-autumn

多屏适配方案五花八门,不同公司有不同的适配要求,对于开发者而言,需要在开发前明确产品需求,再选择相应的适配方案。

移动端自适应方案

前面提到了几种多屏适配的方案,这里重点讲讲移动端自适应的方案

1. init-scale 方案

scale = 1 / dpr;
metaEl.setAttribute('content',  'initial-scale=' + scale + ', maximum-scale=' +  scale + ', minimum-scale=' + scale + ', user-scalable=no');

自动拉伸,好处是简单,只需要根据设计稿的尺寸开发即可,不需要考虑单位转换,坏处是完全放弃 px 单位,没法再进行细粒度的调整,在大屏幕上,仅仅是进行放大操作,而不是展示更多内容,丧失大屏幕的优势。

在 ipad pro 下等比放大
在 ipad pro 下展示更多内容

2. rem 方案

关于 rem 这里就不多介绍了,不过要理解 rem 的定义,即 1rem 等于根字体的大小。这也是后面说把设计稿的基准字体大小设为 100 方便计算的原因。
使用 rem 做自适应的原理,即根据设计稿尺寸和实际的屏幕尺寸,等比例地缩放设计稿上的元素的尺寸。

两个公式:

/*
 * 等比公式
 * clientWidth 为通过 documentElement.clientWidth 获取的当前屏幕宽度
 * designWidth 为设计稿宽度(通常为 750)
 * designFontSize 为自定义的设计稿的基准字体大小,为方便计算,设为 100
 * 通过该公式求出 clientFontSize,即动态设置的根字体大小
 */
clientWidth / designWidth = clientFontSize / designFontSize

/*
 * px 转 rem 公式
 * pxValue 为设计稿中元素的尺寸
 * designFontSize 在前面已定义的 100 (可设为任何数,不过两边要保持一致) 
 * remValue 即为我们实际设置的 rem 大小
 * 该转换一般是在 sass 等 css 编译语言中进行
 */
remValue = pxValue / designFontSize

示例代码如下:

javascript:

const designWidth = 750
const designFontSize = 100

function getFontSize() {
   const clientWidth = document.documentElement.clientWidth
   const fontSize = clientWidth * designFontSize / baseClientWidth
   return fontSize
}

function adjustFontSize() {
   const htmlEle = document.getElementsByTagName('html')[0]
   let fontSize = this.getFontSize()
   htmlEle.style.fontSize = fontSize + 'px'

   window.onresize = () => {
      fontSize = this.getFontSize()
      htmlEle.style.fontSize = fontSize + 'px'
   }
}

sass:

$designFontSize = 100
@function r ($size) {
   @return $size / $designFontSize + rem;
}

补充:rem + init-scale 解决 1px 问题

左边为高清屏下的 1px ,右边为缩小了一倍的 1px

在 2dpr 屏上,css border 的 1px 实际上是 2px,如果设计师要求 border 的宽度为普通屏幕上的 1px,则此时需要将 border 设置为 0.5 px,然而大部分浏览器不允许 css 的值为小数点,因此我们可以通过 init-scale 的缩小功能,将 1px border 缩小为 0.5 px,从而解决 1px 问题

scale = 1 / dpr;
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
fontSize = clientWidth * 100 * dpr / baseClientWidth;

其它解决 1px 问题的方案:before after 伪类 + transform 的 scale 属性

3. vw 方案

rem 其实是 vw 的 hack 实现,因为在 rem 方案诞生时,vw 的兼容性还不够理想。
使用 vw 边不再需要 js 动态设置根字体的大小了,直接使用 sass 等语言,将 px 转为 vw 即可:

@function vw($px) {
  @return ($px / 375) * 100vw;
}

补充:提供最大和最小宽度限制需求
使用上面的 rem 或则 vw 做自适应,在移动端的适配效果还是很不错的,但是如果用户在 PC 上打开了链接,而你又没有专门的 PC 页面的话,那么,适配效果就会很糟糕,示例效果如下:

移动端下适配很好的页面,在 PC 上的适配效果

虽然元素仍然是等比放大,但是在 PC 上放大有点吓人了,因此我们有时有必要限制一个最大的宽度,大于这个宽度,页面边不再放大了。如下为限制了最大宽度的 h5,在 PC 上的效果:

在 PC 上限制最大宽度

给出 rem 和 vw 宽度限制的代码示例:

  1. rem
const designFontSize = 100
const clientWidth = document.documentElement.clientWidth

if (clientWidth > 540) {
   fontSize = (540 * designFontSize) / designDocsWidth
}

if (clientWidth < 320) {
   fontSize = (minWidth * designFontSize) / designDocsWidth
}
  1. vw
html {
  font-size: 16px;
}

@media screen and (min-width: 320px) {
  html {
    font-size: calc(16px + 4 * (100vw - 320px) / 220);
  }
}

@media screen and (min-width: 540px) {
  html {
    font-size: 20px;
  }
}
@function r($size){
  @return ($size / 16) + rem; // 16px for 375.
}

计算公式:

font-size: calc([minimum size] + ([maximum size] - [minimum size]) * ((100vw - [minimum viewport width]) / ([maximum viewport width] - [minimum viewport width])));

在整理这篇文章之前,我一直对多屏适配心生畏惧,即使已经做了一年多的前端工程师,完成了几个产品和 H5 页面的开发,但一说起多屏适配,还是很头疼,没法很清晰地解答如何做好多屏适配。在我完成这篇文章后,我觉得我的思路清晰了很多,这并不是我已经找到了银弹 —— 我觉得根本没有一套解决所有适配需求的银弹,而是我认识到,多屏适配的方案是在太多了,我并没有必要全部去了解,全部去实验,我觉得我只要掌握了原理,掌握几套常用的解决方案即可,剩下的再根据产品需求,去完善,找出最佳的解决方案。这样一想,适配问题不再那么可怕了。

参考资料

使用Flexible實現手淘H5頁面的終端適配

再聊移動端頁面的適配

Fluid Typography

rem, vw, 還是...? 各憑本事的移動端適配方案

你可能感兴趣的:(多屏适配方案)