https://www.sdk.cn/news/3275?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
本文转自互联网技术联盟(ITA1024)技术分享实录,微信公众号:ita1024k
杜瑶
去哪儿网
前端开发总监
互联网技术联盟
ITA1024讲师团成员
正文如下
在正式分享之前,先做个简要的自我介绍。我叫杜瑶,来自去哪儿网,在去哪儿网担任前端总监,目前是去哪儿网移动前端负责人。加入去哪儿网之前在雅虎,华为,360等公司折腾过。(江湖大家都亲切的称呼瑶姐)
我的一些网络足迹:
- CSS参考手册 css.doyoe.com
- CSS探索之旅 blog.doyoe.com
- Web前端实验室 demo.doyoe.com
- Github: doyoe
- Weibo: doyoe
1内容概要
今天分享的内容是UI框架Yo
:包括在去哪儿网的应用及框架本身的特性。
Yo
目前已覆盖了去哪儿网70多个项目,是纯Touch和Hybrid开发的UI框架首选。大幅度的提升了开发效率及风格一致化的统一。
主要分为以下几个部分:
- Yo简介
- Yo的设计思路
- Yo的特性
- Yo的未来展望
2Yo简介
Yo是什么?
Yo是一款基于Sass开发的CSS框架,用于快速构建移动项目UI
- Github: https://github.com/doyoe/Yo
- 文档:http://doyoe.github.io/Yo/doc/
- 示例:http://doyoe.github.io/Yo/demo/
3Yo设计思路
Mobile First
Yo
的设计是以Mobile
为基准标的的,来看一个预览图:
接下来会讲为什么我采取了这种策略。
Why Mobile First
- 公司战略转移
- 生涩的新战场需要有力的框架抹平平台切换所带来的适应过程
- PC端已有成熟的解决方案,无需推倒重来
- 专注于某一具体的领域更能变得专业
说到公司战略的转移,我会说一组大概的数据:
去哪儿网在2009年开始移动平台的布局,应该算是国内在线旅行公司涉足该领域最早的几家之一。在这期间,陆续发布了多款细分业务的客户端。到2012年,仅去哪儿旅行客户端这一个应用的独立用户就突破了2000万。
尤其是近2,3年,我们经历过一次大规模的从PC端向移动端过渡的时期,整个公司的酒店及度假类产品在移动端的订单比例高达85%以上;机票来源于移动端的订单量也远超50%。
基于这些订单数据和运营方向,公司战略性的向移动平台投入大量资源,PC端现在基本上只做一定的维护及必备功能的补全需求。
这就意味着我们之前大量奋战在PC端的前端开发需要转战到移动平台上来,前端舞台开始整体转变。
但这同时伴随而来的是,大部分前端开发对移动平台这个新舞台还是比较陌生的。举个例子:高分屏适配,安卓碎片化处理,手机性能问题等等,都是之前很少触及的东西。
Mobile First的好处
- 可以减少对历史问题的考虑,比如不用考虑IE;
- 保证交互方式的单一性,不用同时考虑PC上的交互行为;
- 更及时的应用上新技术;
- 代码更轻量;
iOS 默认风格
为了取得更佳的用户体验及UI展示,Yo
天然的贴近iOS
风格,如下图的典型iOS风格效果:
Why iOS
- 巨量的iOS用户(超过50%)
- 安卓碎片化过重,不易挑选标的
- iOS的交互及展现具备普适性
我们经过统计,去哪儿的移动在线用户iOS
使用者占比超过50%
,接近六成。这是Yo
的默认风格会靠近iOS
的原因之一。
用过安卓的童鞋,都非常清楚,安卓的碎片化非常严重,不说自身每个大版本之间的差异非常大,就国内各种深度定制的也是一个巨大的问题,所以在安卓上比较难挑选一个合适的标的。
这个选择倒是和现在市面上多数的UI框架类似。
Pure CSS
Yo
是一个纯净CSS框架。之所以不像普遍的UI框架那样将js组件之类的杂合进来,更多的是由于定位上的差异。我更希望Yo只专注在UI展现上,而不是其它。
这能让Yo变成更职能清晰,甚至你可以把它应用在任何移动项目上,它只是一件多彩的外衣而已。
当然,在公司内部,我们有一套依赖于Yo而开发的移动组件库。
分层设计
Yo
使用了分层设计策略来保证代码的层次和逻辑关系清晰。
来看一张层级简图:
Yo
将不同的功能拆解成结构清晰的类别分散到不同的层去进行处理。
其中lib是Yo的核心代码实现,usage是业务代码的舞台。
分层设计的意义
- 清晰的依赖
- 高度解耦
- 高度复用
- 高可移植性
- 结束混乱的文件引用
层级示意图:
单位
需要注意的是Yo使用2种单位来处理UI细节
rem + px
- 边框厚度使用 px 单位
- 字体,大小等除边框厚度之外的定义都使用 rem
4Yo的特性
封装了丰富的常规问题解决方案
Yo
将很多常规的应用场景方案封装了起来,大部分时候只需要一行代码就能实现某个具体的功能。
下面会简要列举几个例子:
形状方法
比如我要画一个圆,我只需要这样就行:
.demo {
// 一行代码画个圆
@include circle(2rem);
}
circle
接受2个参数:一个是$size
,用来指定正方形的边长;一个是$radius
,用来指定圆角半径,默认值是50%
,所以默认只需要传入$size
就可以画出来一个圆,当然,如果你只是想让这个正方形有个圆角,可以传入$radius
,比如值是.1rem
。
由于Yo
支持顺序参数和关键字参数2种方式,所以如果想使用关键字参数,上述代码可以改成:
.demo {
// 一行代码画个圆
@include circle(
$size: 2rem
);
}
我更推荐大家使用关键字参数这种方式,这样就不用关系它们之间的顺序;或者当这个方法发生了变更,增加或者移除了某个参数,会让顺序发生变化。
上述的代码编译后,我们就能得到如下图的一个圆:
当然,还有一些其他的形状方法,这里就不再列举,感兴趣的同学,后续可以去看看文档。
文本方法
对于文本溢出显示省略号的需求,以前在PC端常常会碰到,当然,在移动端也是不可避免的,比如下图这样:
这样的效果,使用Yo
,也只需要一行代码即可实现:
.item {
// 超长文本溢出显示省略号
@include ellipsis;
}
如果你想限定容器的显示宽度,可以给ellipsis
方法传入$width
参数:
.item {
// 约束宽度的超长文本溢出显示省略号
@include ellipsis(
$width: 3rem
);
}
我们能得到下图的效果:
更有意思的是,ellipsis
方法不仅可以处理单行文本,还提供了处理多行文本的能力:
.item {
// 指定多行文本溢出显示省略号
@include ellipsis(
$line-clamp: 2
);
}
只需要指定$line-clamp
参数即可,意思是指定具体需要截断的行数,当超过指定行数之后,会在被截断的那行尾加上省略号。
同样的,其他的文本方法这里就不介绍了。
1像素边框处理方法
说完文本处理,大家可能还对Yo是如何处理1像素边框的话题感兴趣,接下来,会详细说一下。
Yo专门封装了一个border方法,用来处理1像素边框的问题;
该方法使用伪元素::after来处理边框;通过媒体查询,为拥有不同设备像素比的屏幕自动适配成1px;
为了最贴近原生API的设计,border方法接受和CSS border属性一样的厚度,颜色和样式3个参数,不同的是新增了对圆角的处理的参数;
比如我现在需要给一个矩形添加1像素边框,只需要这样:
.demo {
@include border(
$border-width: 1px,
$border-color: red,
$border-style: solid
);
}
其中,$border-width的默认值就是1px(回忆我们之前说的,Yo约束使用2种单位,px就用在了这里),所以其实可以省略;包括$border-style的默认值是solid,也可以省略,所以可以写成:
.demo {
@include border(
$border-color: red
);
}
效果如下图:
假设你只需要某个方位上的边线,那么只需要定义$border-width
参数即可,和CSS border-width属性相同:
.demo {
@include border(
$border-width: 0 0 1px
);
}
结果如下图:
border
方法为什么设计了$radius
参数?
我们说过border
方法其实是使用了::after
来做的,如果只是直接在父元素上设置圆角,那么::after边框的4个角将会被截断,所以border
方法的的圆角参数,其实既设置了父元素的圆角,同时也设置了::after的圆角。
来看看对比效果,一个是未使用border
方法的圆角参数,一个直接使用border
方法$radius
:
硬写的:
.demo {
@include border(
$border-width: 0 0 1px
);
border-radius: .2rem;
}
使用参数的:
.demo {
@include border(
$border-width: 0 0 1px,
$radius: .2rem
);
}
从图中可以看出,假设不提供该参数,很大概率上会造成一些问题,我们可能会忘记需要多处同时设置圆角,更复杂的是,::after的圆角大小其实不是一个固定值,在不同的dpr是不同的。所以如果需要达到和使用参数的效果,还得手写非常多的媒体查询适配代码。
题外话:以前还怎么做过
border
方法是在2.0版本才开始加入的新特性。
在这之前,其实还是用过一种更简易的方式来实现1像素边框的问题:即写一段js,用来获取屏幕的dpr(devicePixelRatio),将该值动态的添加到root节点上;此时CSS通过媒体查询匹配到不同的dpr,在不同的dpr情况下给root节点定义不同的font-size,然后根据dpr对viewport进行对应的缩放。
该方案的好处是,业务开发只需要引入这段js即可,不需要修改原有代码;而存在的问题是Android4.3及以下并不支持viewport缩放(initial-scale除1之外的设置);当然还有一个比较严重的问题是,该方案影响响应式设计的实施。
这里只列举以上几个Yo
的特性方法,大家可以查看文档上对更多方法的描述。
统一的变量管理
Yo对于变量的处理也是非常有意思的。我们将所有的变量收敛统一管理,通过Map进行分类来组织。这样做的好处是:
- 分类清晰;
- 减少全局变量污染;
- 维护方便;
- 为配置层提供支持;
如下图所示:
独立的配置层设计
像大多数允许高度自定义的程序一样,Yo可以让开发者在业务代码中根据自己的需求,修改变量定义的初始值。
Yo在lib中通过base和variables这2个文件将所有的变量约束在不同的分类Map中;同时在usage下,有2个用户配置文件extra和config来进行一一对应;
所有base和variables中的定义,都可以在extra和config进行配置,达到更改初始值的目的。
所以,开发者可以在extra和config中按照自己的需求进行配置,比如,因为用户对象不同,可能对浏览器的要求不同,所以可能需要对厂商前缀进行配置,可以在config文件中这么做:
处理厂商前缀
只需要在config中配置$setting Map就行,如下个图,需要-webkit-和-moz-两种厂商的情况:
如果只需要-webkit,移除-moz-即可
假设不想使用厂商前缀,直接将is-vendor-prefix由true改成false就行
灵活配置iconfont
这差不多就是拷贝一个URL的瞬间过程。
开发者可以决定是否使用iconfont,也可以换用不同的字体文件,只需要对上述$ico map进行配置即可。
由于Yo针对的仅仅是移动平台,所以我们只保留woff和ttf2种字体。
你可以在任何需要使用iconfont图标的地方,加上.yo-ico类即可,然后把图标对应的编码写上即可。当然,你也可以在伪元素里去定义这些特定的图标class,然后直接使用,根据实际情况自行选择吧。
响应式方案
Yo只是希望提供响应式的能力,并不打算把stop-points写死,这样的话,业务开发可以随意定义。
所有的响应式断点都定义在$media-types Map中,同时我们构建了一个responsive方法来与之配合,stop-points可以根据具体的需求,自行修改配置,甚至是新增新的stop-point。
上述代码编译结果如下:
丰富的元件
除了上述这些特性之外,Yo还提供了30多种元件。比较有意思的是,Yo将所有所有自提供的有形代码片段称之为元件,这有点类似flash中的元件。
强大的扩展能力
Yo有非常多的相较于其它UI框架的独特设计,包括它的扩展能力。
Yo基本上不会预设(内置)多种形态的某个元件,比如说:它不会预设多种大小或者颜色的某个元件,只有该元件的default风格,即其基本形态,如果业务中有其它形态的需求,都可以通过扩展来实现,这将大大的减少的冗余和无效的代码。
举个例子:
某个项目中,需要5个按钮,这5个按钮可能只是大小和颜色有差异,但它们不会同时出现在一个页面。
你会用什么样的方式来处理呢?
通常可能是这样做:将这5个按钮定义放在一起,比如都在一个btn的文件里;当某个页面需要用到btn时,直接引入这个文件;比如大家较为熟悉的Bootstrap就是采用这种实现。我截了段Bootstrap对按钮是现在的代码如下图:
可以看到的是Bootstrap将btn实现独立抽离出来了,这类似Yo
的分层概念。不同的是Bootstrap自身做了预设,它默认提供了6种名称固定的按钮,对于其它元件的处理,Bootstrap也是这样。
这种做法的优点在于按钮风格可以通过变量修改;但问题更大的是:
- 不够灵活,按钮数量及形式被固定,对于复杂的项目场景难以应付
- 冗余,所有按钮都会被编译,无法完全做到按需加载(假如有个页面需要用其中的1个按钮,就得引入这个btn文件,但其余5个按钮在这个页面都是冗余的)
Yo是怎样来处理这种问题的
在这点上,Yo与其它框架都有非常大的不同,我将用yo-badge元件来解释Yo是怎么做的,先来看看这个元件的基本形态:
图中红框区域是yo-badge的基本形态,这算是App中经常会使用到的元件了,常用于消息提醒之类的。
然而在Yo里,它可以有任意多种形态的变种,比如:
我们为所有的元件都提供了一个与元件名同名的扩展方法,比如,我想实现上图中的灰色badge,可以通过yo-badge()方法来进行扩展。
扩展:
@include yo-badge(
$name: normal,
$border-color: gray,
$bgcolor: gray
);
所有的同名元件扩展方法,都接受$name参数,用以指定新扩展的元件名,这个名字通过连接线-紧跟在元件名之后,如:yo-badge-normal。
扩展之后如何应用?
<span class="yo-badge yo-badge-normal">9</span>
$name之外的参数,大家可以通过文档查阅。Yo对参数的设计原则遵循的是,只对那些扩展几率高的提供接口,比如:color, border-color, bgcolor, radius等等。
Yo通过元件扩展的方式来解决这种问题。非常好的控制了代码冗余及灵活度,包括清晰的依赖链路,其实都有体现。
现在你可以在需要使用到灰色badge的页面中,通过上述的方法来扩展,至于红色,绿色,黄色的那些,似乎都和你无关了。同时,假设这个灰色的badge是通用的,会在多个页面出现,你可以在将它扩展在某个单独的文件里,然后供需要的页面来引用。
超扩展
我们说了Yo遵循的参数设计原则是只对扩展几率高的提供接口。然后在实际的业务中,这往往可能还不够,你可能还想拥有更为丰富的参数,进行更为深度的自定义扩展。
是的,Yo考虑了你的这种需求,并且设计了能够完全满足这种需求的解决方案。
对于所有的元件同名扩展方法,都拥有超扩展的能力,这是非常酷的一个特性。仍然拿上面那个扩展灰色badge的例子来讲述,假设yo-badge()方法并没有提供扩展margin、font-weight之类的参数,而你的需求要求改变它们,我相信,你会爱上超扩展的:
@include yo-badge(
$name: normal,
$border-color: gray,
$bgcolor: gray
) {
margin: .1rem;
font-weight: bold;
}
直接在方法之后加上大括号,然后就可以像写原生CSS一样任性的书写了。
是的,所有的元件都有与之同名的扩展和超扩展方法,是不是很酷。
动画
Yo
设计了60多种动画,基本上覆盖了业务对常规动画的需求。这些动画目前大约分成8大类:
fade、elastic、flip、roll、speed、rotate、zoom、other
可能大家对Animate
这个热度较高的动画库比较熟悉,这样的话那就更好,Yo
的动画类型比这个还丰富了一些。
Yo给我们带来了什么?
- 更低的开发成本
- 更Cool、更高效的开发模式
- 统一的代码风格
- 样式工程化
我们粗放的统计过,使用Yo
来开发,大约能提升30-50%
的效率,并且大幅降低了出错几率,甚至让我们的JS开发工程师也能愉快的开发页面了。
写在最后
如上述所说,Yo是一个迥异于现在流行框架的。所以,实际上我们并不计划对外提供打包好的 yo.min.css 来供使用,而是推荐直接在 Yo 框架体系中下进行开发。这样你将能体会到上述所说的众多功能和方法为开发所带来的便利,并感受到它的魅力。
更多的特性,离你很近,你只需要用它来写一个简单的应用,胜我千言万语。
开始你的Yo旅程吧。
Thank You
Q&A
问:对google material怎么看?它有可能解决安卓碎片化问题吗?yo有没有计划支持material风格?
杜瑶:其实我不太知道material这个东西,但Yo暂时还不会考虑。因为Yo的设计理念是覆盖大部分,为大部分用户的覆盖做更多的事。后续这个东西覆盖度上来了的话,可以考虑。
问:多行文字省略号怎么用css实现的?
杜瑶:对,这个其实就是-webkit-的一个私有属性实现。
问:相比较js,html和css的发展空间是什么样子的?
杜瑶:这个问题,可能会涉及到大家对职业的规划,所以我会慎重回答,大家请仅做参考。其实,就我本身而言,我并不会去特别强调说哪个最NB,然后就去做哪个。就像我一直和童鞋们说,其实我并不希望大家去研究火箭回收的技术,因为,那对我们来讲,并没有什么用。我更希望大家研究的是如何可以让业务开发更有效率和质量,所以不论是js,css,html或者其他的什么,只要最终是可以有价值的,我都会让大家去做。
问:现在有很多css新特性,如何在移动端使用的时候进行取舍?主要还是兼容问题。
杜瑶:不用一位的追求新特性,要追求的是如何优雅的把问题解决,假设新特性更靠谱,那么就想办法降级或者渐进增强。
问:想问下关于yo的设计思路都参考哪些主流的框架呢,除了bootstrap之外,这个框架大约用了多久成型,多少人维护呢?
杜瑶:其实并没有参考市面上主流的框架,所以才会有很多很有意思的设计。但是有很多启迪是来源于这些流行框架的,我把它们没有解决的痛点,作为了核心要点来设计。
问:可以自定义更细分的宽度来处理响应式吗,而不是yo提供的那五种?
杜瑶:可以,Yo的设计理念就是,不约束用户,只提供能力,所以,只需要在config新增你需要的stop-point就行。
问:在业务诸多的情况下,并且原来就有一套规范或者说规则存在的时候,推广新的一套是否存在阻碍?一般会是怎么样的阻碍,你又如何推广的?是否依赖其他JS框架库,如果依赖是否会导致对方框架库需要重构?
杜瑶:推行新的东西,一定会有障碍,不论是来自于业务上的,还算是来自于领导或者自身的。所以,你索要推行的东西,不能抱着让别人做小白鼠的心理去做,一定要是自己先做过了小白鼠。Yo并没有依赖其他的js框架,但是在去哪儿内部,有一套基于Yo开发的移动组件库。
问:is-vendor-prefix是否增加厂商前缀,是在决定某个项目确定什么使用浏览器的情况下,才能确定出来?,有些项目实际上并不知道最终被那些厂商的浏览器所使用。
杜瑶:这个,其实还是比较好确定,因为Yo基本上是面向mobile和高级浏览器的,所以你假设有疑虑,尽可以把-webkit,-moz-都写上,不过,通常情况下,你的用户群体,你还是知道的,毕竟有用户调研之类的。
问:yo放手给业务定制的地方很多,看上去感觉是个脚手架,提供了很多完善的支持,不过最近组件化浪潮来袭,个人觉得约束性越强可维护越高,开发人员做出业务定制样式重新开发就不需要在意任何细节。以后yo是否会走bootstrap强约束路线?
杜瑶:其实,我所说的不限定,更多指的是不限定用户的扩展,但是其实包括书写和样式的工程化,其实都有很高的约束了,举个例子,在yo里面,所有的元件或者方法,连接线都是“-”,在你使用同名方法扩展后,生成的新元件,默认就也是-了。
问:你们的字体大小是如何处理的?前面你提到根据dpr来设置,那不同的dpr是根据什么来设置,会不会出现不同尺寸大小的兼容性问题
杜瑶:这个其实可以使用Yo提供的响应式来去做,因为Yo其实定义了这些高分屏的断点,但其实,默认的情况下,Yo并没有处理,因为,我们觉得在不同的手机上,字号一致,其实也没太大问题,可以看看我的客户端,都是这样的。
问:提高业务开发效率,是专门团队维护基础组件库,业务线拼装快,还是提供这种规范让开发人员学习并且自己拓展?人的能力有很大区别,就算用了规范代码差异也很大,所以让业务团队只做流水线拼装,样式从已有的选择,感觉也是维护性非常好,业务线代码会很统一,这个瑶姐怎么看?
杜瑶:嗯,其实是的,就像我之前说的,Yo提供了很多方法和元件,基本上大家只需要拼积木就行,如果发现自己的业务和默认的元件不一致,通过元件同名方法进行扩展,但其实都是传参,开发人员甚至都不用写具体的CSS代码,所以基本上可维护性是很好的,并且很统一。我们现在的情形是,使用了Yo之后,基本上介入成本都下降了,因为大家的代码都非常接近。
问:同名扩展函数的超扩展能力是怎么利用sass实现的?
杜瑶:具体可以看一下Yo的源码,主要是利用sass本身的@content特性。
问:一个框架功能越强大,扩展性越好,往往意味着学习成本也越高,yo的学习成本在我看来不能算低,需要非常熟悉sass,掌握二十多个原件的扩展方法估计也不是非常简单的,yo后续发展方向是什么?
杜瑶:Sass只是一个工具,我相信大家都有轻松掌握一个工具的能力。至于说丰富的元件学习成本高,其实还好,因为基本上所有的同名扩展方法的API都差不多,比如:假设是改变前景色,那么都是 $color。
问:yo会支持元件的分开打包吗?小项目其实用不到所有的原件…
杜瑶:只有你用到的文件,才会被编译打包。所以基本上只有你需要的代码,才会被打包进去。
转载请注明:有爱前端 » 去哪儿网前端开发总监杜瑶:高可定制化的UI框架Yo