前方依旧高能 ^_^ , 本文主要解决以下问题:
然后给出主观的最佳实践。
赶时间戳这里传送门
比较无聊干燥的文章,看前请喝水。
研究样本
ml.js
一个月前去了css开发者大会,听到了手淘的自适应方案,想起之前一直就想了解ml.js到底干了什么事。回来仔细研究了一下,抱着好奇心一并看了同样类型的网站的方案,深入学习一下。
研究结论
手淘
获取手机dpr( window.devicePixelRatio
),动态生成viewport。
换取手机宽度,分成10份,每一份的宽度即是rem的尺寸。
根据设计稿尺寸( px
)通过计算,转换成 rem
去布局。
ps
:海外淘宝并没有这样做,而是scale1.0并且图片 大概
都是2倍图。
天猫
采用 scale=1.0
写死viewport。
flex布局,笃定认为布局尺寸是375 ( iPhone6
)
rem 确定非flex的元素
手机携程
采用 scale=1.0
写死viewport
px + 百分比布局
实现之前
提及实现之前,先简单过一些概念。
完美视口
完美视口
的概念已经街知巷闻了,如果不知道可以先戳这里。
在这几篇文章里,还会学会 设备像素
, css像素
等概念,大神讲的很透彻,这里就不献丑了。
ppk 谈 viewport其1 ppk 谈 viewport其2 ppk 谈 viewport其3
这里给出 完美视口
<meta name="viewport" content="initial-scale=1.0,width=device-width,user-scalable=0,maximum-scale=1.0"/>
在移动端,低端无定制的需求,都可以用这个 完美视口
完成。然而看到这篇文章的你,显然完美视口还不能满足。
dpr
dpr是 devicePixelRatio
的简写,也就是 屏幕分辩比
。
历史原因,由于苹果retina的产生,使得清晰度提升,主要是因为`设备像素`提升了一倍,因此可以用更多像素去绘画更清晰的图像。#我乱说的#
坊间对于dpr更通俗的说法叫
scale
scale是 屏幕拉伸比
。也就是视口上的 initial-scale
, maximum-sacle
等属性。
scale 和 dpr的关系是倒数。
直观感受
这是我对dpr的直观感受
同样去展示 1 x 1
像素的点,虽然在屏幕上看到的大小是一样,但背后表现它的像素数量是不同。
这也意味着,在一样大小的面积内,更多 物理像素
的屏幕上展现色彩的能力越强。
但这不是我要关注的点,我们关注的是。
1. 是否需要根据倍屏去切换scale达到伸缩的目的
2. 切换scale的成本和回报
下面根据几个实验来回答这两个问题。
自适应问题
实验1 - 传说中的1px
大多数给出要动态切换scale的理由有以下两个。
1. 1px并不是 [ 真实的1px ] , 2. 为了充分利用屏幕的分辨率,使用符合屏幕的图片。
这一条和设计稿密切想关,要讨论它不能抛开设计稿不谈。
这里先补一下 切图课
,如果自己要做1x , 2x, 3x 的设计稿。如何去实现?
尺寸!!!
大多数情况下,设计师产出各种尺寸的稿子(事实上一般只是2倍稿子),都是先画出大尺寸的稿子,再去缩小尺寸,最后导出。 这样会带来问题:
如果设计师在2倍稿子里画了一条 1px
的线,这时候假如我们要在scale=1.0里呈现的话,就会变成 0.5px
,如下图。
而很大一部分手机是无法画出0.5px的,因此这里一般有一个hack
transform:scaleX(0.5)或transform:scaleY(0.5)
但是有人提出了, 既然可以改变viewport的scale达到合理利用不同倍屏的优势,为什么不这么写呢。
<meta name="viewport" content="initial-scale=2.0,width=device-width/>
等等,为了设计稿的尺寸我们如此大费周章?
事实上,即使2x设计稿避免了1px。3x设计稿也可能出现2px。
而且这里如果写死scale可能造成部分地方和稿子出入较大,无法还原设计稿,界面的显示会打折扣。
解决这个问题的关键在于: 交流
如果你的设计师是个要求严格,而且产品界面把控非常严格的话,应该动态去实现viewport或使用scale的hack去改变。
如果部分区域实在没有必要 [ 过度优化 ]
, scale=1.0 实在是非常低成本还原的方案,未尝不可。
对于这一点,争议较多,因为如果要做到对应倍图的话,意味着图片都需要做三份。成本太高了。
这里通常有两种做法
图片服务
例如在100x100的图片容器中。
1倍图 http:// img.xxx.com/abc.jpg_100x100 2倍图 http:// img.xxx.com/abc.jpg_200x200 3倍图 http:// img.xxx.com/abc.jpg_300x300
定死尺寸
放弃1屏手机
,全部启用2倍图,由于流量会消耗比较大(低端机),因此 滚动加载
等优化手段就会显得比较重要了。
实验1 - scale对倍图重要吗
这里看一下不同scale下图片的差异。
测试样本:160x160凯尔特人队标logo(一不小心暴露了绿色的血液)
测试容器:160x160 img标签
测试环境: intial-scale分别为 1.0
/ 0.5
/ 0.3333
图片尺寸: 1x
(160x160) 2x
(320x320) 3x
(480x480)
测试结论: 不同scale
下使用 不同图片
差异非常大。
但是这里需要验证,是否 不同scale
对 同一图片
差异起到绝对作用。
肉眼观看 基本无区别
,除了用取色器去获取,会发现有 色差
和部分像素被分割(下面会说到),之外,用不同scale显示同一图片基本没有什么区别。
实验2 - DownSampling
由于上一个实验最后的图片,使用同一scale下,不同倍数的图片,存在色差,这里验证一下。
测试方案
测试图片:
图片尺寸:
400x300 , 300x225 , 200x150 , 100x75
测试环境:
scale = 1.0
测试容器:
100x75的 /
由于之前知道了DownSampling概念的存在,这里只是好奇心驱动试验一下。(对自适应其实没有卵用)
DownSampling是说大图放入比图片尺寸小的容器中的时候,出现像素分割成就近色的情况。
测试结果:
注:6plus貌似和其他机型不同。
触发情况:
不同颜色像素接触的地方,会出现DownSampling。
rem
对于rem要说的不多,看这张图。对于用到px的元素,使用rem统一去管理是很灵活的!
字体
无论是采用动态生成viewport或者写死scale,字体都需要适配大屏。之前提出的rem方案被证实在不同手机上显示不一致,这里还是回归成了px。
px最好用双数
两种方案(这里不考虑媒体查询,因为Android碎..,嗯,不说了...)
JS动态计算 (常见做法)
根据不同屏幕宽度计算不同字号大小。 1. 定基准值,设计稿是750宽度(2倍屏),字体的大小是24px. 2. 计算指定宽度的字体大小。
var fontSize = width / 750 * 24 ;
根据dpr设定 (比较好的做法)
ps : 一般时初始化时设置为/
的attribute,
window.document.documentElement.setAttribute('dpr',window.devicePixelRatio)
然后css这样写
[dpr=1] { font-size=16px; } [dpr=2] { font-size=32px; }
布局
权衡之下,我觉得flex真的灵活方便太多,因此这里给出一个布局demo。大致如下图。(画的比较粗糙..)
(左稿右还原)
基本涵盖:
为什么 flex
能够做到 百分比
做不到的自适应。
比如我们也去学天猫,笃定认为宽度就是 375
(iPhone6尺寸),那么两个元素flex分别为200和175。
无需计算百分比,在不同的界面上就会自动计算,而且以该浏览器可以识别的最小单位实现,比自己计算的百分比要精准。
demo传送门
结论
写死 initial-scale=1.0
对于实现 1px问题
, 问题比较大。 与设计师沟通协商
才是最好的解决问题的方法。
写死 initial-scale=1.0
对于不同图片的显示, 采用不同倍图的话,会有一定压缩,但在可接受范围内。(当然,动态生成scale能够完美呈现...)
布局
如果采用 动态生成viewport
方案,就用到rem来还原设计稿(还有rem-px的计算)。成本在 效率
上。
如果采用 写死initial-scale=1.0
方案,就用flex布局,主要成本在 flex兼容性
上,但是实现非常灵活简单。
后记
viewport的scale
的重要性远比我想象的要低很多,我原本以为这就是自适应。
但是后来发现,其实自适应还是回到了远古时代的 百分比%
,只是现在有更聪明更灵活的方式 flex
,未来应该有两个方向去自适应。
一个是拥抱vw,vh。(手淘的ml.js十等分宽度, 1rem=10vw
)
一个是更好的使用flex
现在使用后者已经有很多的库可以解决兼容性了,如参考资源最后的一个flex库。
调研的网站并不多,但是百分比仍然是很多人的首选。
参考资源
手淘ml库
手机淘宝
天猫首页
移动端高清、多平适配方案
rem对webapp带来的影响
flex方案 适配到IE10+
微信扫描查看或分享