手机淘宝的flexible设计与实现
发布在像winter一样冷2015年8月7日view:100171HTML5CSScss3移动开发
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

看到小黑的文章 关于webapp中的文字单位的一些捣腾 感觉很赞。尤其是,他提到了手机淘宝的meta,所以觉得要讲讲我们这方面的一些实践。

手机淘宝从2014年中开始,全面推行flexible设计。什么叫flexible呢?其实flexible就是responsive的低端形态和基础。对我们来说,最直观的感受就是,在超宽屏幕上,网页显示不会两边留白。以前pc时代大家经常讲的流体布局,其实就是一种flexible design。只不过,流体的表述角度是实现,flexible的表述角度是结果,为了跟高大上的responsive保持一致,我们这里使用了flexible这个说法。

讨论方案之前,需要先了解三个关键概念:

  • 单位英寸像素数(Pixel Per Inch,PPI):现实世界的一英寸内像素数,决定了屏幕的显示质量
  • 设备像素比率(Device Pixel Ratio,DPR):物理像素与逻辑像素(px)的对应关系
  • 分辨率(Resolution):屏幕区域的宽高所占像素数

当我们决定不同屏幕的字体和尺寸的单位时,屏幕的这几个参数非常重要。

场景1——Resolution适配

一张banner图片,当你面对不同的屏幕时你希望它的行为是怎样的?

在这个场景中,我们主要需要面对的是分辨率适配问题,考虑到多数网页都是纵向滚动的,在不同的屏幕尺寸下,banner的行为应该是总是铺满屏幕宽度以及总是保持宽高比

最自然的思路是使用百分比宽度,但是假如使用百分比宽度,即width:100%,我们又有两种思路来实现固定宽高比:一是利用img标签的特性,只设宽度等图片加载完,这种方法会导致大量的重排,并且非固定高度会导致懒加载等功能难以实现,所以果断放弃;二是使用before伪元素的margin撑开高度,这种方法是比较干净的纯css实现,但是不具备任何复用性而且要求特定html结构,所以也只好放弃了。

于是,剩下最合适的办法是使用其它相对单位,本来最合适的单位是vw,它的含义是视口宽度,但是这个单位存在严重的兼容问题,所以也只好放弃。

最后我们只好配合js来做,硬算也是一条路,但是同样不具备任何可复用性,最终我们选择了rem,我们用js给html设置一个跟屏幕宽度成正比的font-size,然后把元素宽高都用rem作为单位。

这是我们目前的线上方案了,它是一个近乎Hack的用法,已知的问题包括:

  • 某些Android机型会丢掉rem小数部分
  • 占用了rem单位
  • 不是纯css方案

场景2——PPI适配

一段文字,当你面对不同的屏幕时你希望它的行为是怎样的?

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文字尺寸是相同的,也就是说,我们不希望文字在Retina屏尺寸变小,此外,我们在大屏手机上,希望看到更多文字,以及,现在绝大多数的字体文件,是自带一些点阵尺寸的,通常是16px和24px,所以我们不希望出现13px、15px这样的奇葩尺寸

这样的特征决定了,场景1中的rem方案,不适合用到段落文字上。所以段落文字应该使用px作为单位,考虑到Retina,我们利用media query来指定不同的字体,考虑到dpr判定的兼容性,我们用宽度替换来代替:

.a {
    font-size:12px
}
@media (min-width: 401px){
    .a {
        font-size:24px
    }
}

另一种场景,一些标题性文字,希望随着屏幕宽而增大的,我们可以仍然使用rem作为单位。超过35px(个人直观感受)的文字,已经不用太考虑点阵信息了,靠字体的矢量信息也能渲染的很好。

场景3——DPR匹配

一个区块,设计稿上有1像素边框,当你面对不同的屏幕时你希望它的行为是怎样的?

这个场景,需求很简单,设计师希望在任何屏幕上这条线都是1物理像素

好吧,当然这个问题的答案不是写1px那么简单。在retina屏下面,如果你写了这样的meta

<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

你将永远无法写出1px宽度的东西,除此之外,inline的SVG等元素,也会按照逻辑像素来渲染,整个页面的清晰度会打折。

所以,手机淘宝用JS来动态写meta标签,代码类似这样:

var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

结语

总的来说,手机淘宝的flexible方案是综合运用rem和px两种单位+js设置scale和html字体。

这些JS的内容,可以在我们开源的库ml中找到:

https://github.com/amfe/lib.flexible

评论
发表评论
1个月前
添加了一枚【评注】:这个还是犀利的
1个月前
赞了此文章!
1个月前
赞了此文章!
2个月前
添加了一枚【评注】:123
2个月前

123

3个月前

1

6个月前
添加了一枚【评注】:点点
6个月前
添加了一枚【评注】:HTML
6个月前
添加了一枚【评注】:web
6个月前
添加了一枚【评注】:而已
7个月前
添加了一枚【评注】:真,爱心
7个月前
添加了一枚【评注】:....
7个月前
赞了此文章!
7个月前
赞了此文章!
8个月前
赞了此文章!
11个月前
赞了此文章!
1年前
赞了此文章!
1年前
赞了此文章!
1年前
添加了一枚【评注】:爱心
1年前
添加了一枚【评注】:这个功能有趣
1年前
添加了一枚【评注】:5
1年前
添加了一枚【评注】:4
1年前
添加了一枚【评注】:3
1年前
添加了一枚【评注】:2
1年前
添加了一枚【评注】:1
1年前
添加了一枚【评注】:这个 挺有意思的
1年前
赞了此文章!
1年前

hhshshhs

1年前
赞了此文章!
1年前
添加了一枚【评注】:嘿嘿
1年前
添加了一枚【评注】:hahah
1年前
添加了一枚【评注】:xxx
1年前
添加了一枚【评注】:被挡住了吧! 哈哈哈
1年前
赞了此文章!
1年前
添加了一枚【评注】:a
1年前
添加了一枚【评注】:x
1年前
添加了一枚【评注】:x
1年前
添加了一枚【评注】:x
1年前
添加了一枚【评注】:x
1年前
添加了一枚【评注】:x
1年前
赞了此文章!
1年前
添加了一枚【评注】:32
1年前
添加了一枚【评注】:12
1年前
添加了一枚【评注】:1
1年前
添加了一枚【评注】:1
1年前
添加了一枚【评注】:1
1年前

某宝确实厉害,某某宝也厉害,前端大牛真厉害。

1年前

某宝确实厉害,某某宝也厉害,前端大牛真厉害。

1年前
添加了一枚【评注】:rem确实比较方便,以前在项目里面已经体验到了!
2年前
添加了一枚【评注】:可以做一个
2年前
添加了一枚【评注】:lalala
2年前
添加了一枚【评注】:lalala
2年前
添加了一枚【评注】:lalala
2年前
添加了一枚【评注】:lalala
2年前
添加了一枚【评注】:丑啊
2年前
添加了一枚【评注】:122
2年前
添加了一枚【评注】:什么鬼?
2年前
添加了一枚【评注】:2
2年前

@Dadait 默认应该隐藏掉,别默认显示了。(┬_┬)

2年前

PO主,能把页面上的评注点去掉吗?有没有考虑过密集恐惧症的阴影面积呀。

2年前
添加了一枚【评注】:再往上都怎么弄得啊
2年前
赞了此文章!
2年前

我在app项目中用这个的时候 在安卓安卓 review里面出现不兼容,请问有解决方法吗 ? ios效果非常好

2年前
添加了一枚【评注】:笑而不语
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
添加了一枚【评注】:必须赞。。。。。。。。
2年前
赞了此文章!
2年前
添加了一枚【评注】:123
2年前
添加了一枚【评注】:12
2年前
添加了一枚【评注】:212
2年前
添加了一枚【评注】:1
2年前
添加了一枚【评注】:1
2年前

add

2年前
添加了一枚【评注】:egress
2年前
添加了一枚【评注】:好屌的批注
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前

公司的广东省高

2年前

什么时候学会

2年前
赞了此文章!
2年前
添加了一枚【评注】:就比你搞!!!咋地?
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
添加了一枚【评注】:1
2年前
添加了一枚【评注】:不错
2年前
添加了一枚【评注】:还可以用padding-top:x%来撑开父级高度,只需要img和父级相互定位好即可。算是最简单的解决方法。
2年前

犀利!!

2年前
添加了一枚【评注】:刚才弄太高了,点不开了。。
2年前
添加了一枚【评注】:呵呵
2年前
添加了一枚【评注】:123
2年前
添加了一枚【评注】:123
2年前
添加了一枚【评注】:叼
2年前

哎呀我去

2年前
添加了一枚【评注】:这点是干啥的呀
WRITTEN BY
寒冬winter
ali-mfe-hire@list.alibaba-inc.com 阿里无线前端求简历
TA的新浪微博
PUBLISHED IN

我的收藏