多屏适配方案

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

流行多屏适配种类

  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, 還是...? 各憑本事的移動端適配方案

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容