查看原文
其他

干货 | 响应式设计在携程火车票的应用

永利 携程技术 2022-06-07

作者简介

 

永利,携程开发经理,专注于Web领域的探索。


一、什么是响应式设计?


可能很多人脑海中已经出现了这样一个动画,当浏览器中页面尺寸不断变化时,内容也在随之变化。简单说,响应式网站设计是一种允许设计和代码响应设备屏幕大小的方法。


二、响应式设计的优势有哪些?


1) 节省人力物力

一套代码两端使用,节省开发、设计、测试、产品、运营资源。

2) 两个端使用同一个url:

  • 利于seo,可以集中精力和资源做一个url的seo,提升搜索引擎的排名。以Google来说,网址不同但内容相同的情况下,虽不会将该网站列为恶意连结,但仍会影响评价。


  • 不需要设置302跳转。如果是非响应式的站点,当移动端浏览器访问桌面站点的url,或者当桌面浏览器访问移动端站点的url时,需要设置正确的302跳转,而这将大大影响用户体验。


三、在携程火车票的应用


响应式设计的概念已经出来蛮长时间,但在国内一直处于不愠不火的状态。当然这与响应式设计并非完美不无关系,在我们的实践当中,也确实遇到了一些问题。

1)业务代码中充斥着大量的媒体查询代码,两个端样式的分开书写不利于阅读和维护。如下:


css// h5.box { font-size: 14px; }// pc@media only screen and (min-width: 760px) { .box { font-size: 18px; }}

假如遇到层级嵌套很深,这种写法可读性更差。

解决方案:

响应式不仅可以根据屏幕尺寸做,一些简单的场合,还可以根据设备代理(UA)做。

由于项目中绝大部分模块的样式代码即使移动端和桌面端有所不同,也只需要书写两种即可,不必特意针对不同尺寸的屏幕分别书写样式代码。据此可以试着来优化代码。

html<html class="isMobile ? 'h5' : 'pc'"></html>

less.box { font-size: 14px; .pc & { font-size: 18px; }}

首先,我们在html中预设了h5或者pc的class,之后在样式中分别根据h5,pc环境书写样式。默认是h5的样式,pc如果有所不同直接覆盖样式即可。这样就把移动端和桌面端的样式写在了一起,样式中减少了大量的媒体查询的代码,并且.pc、.h5的名字不比媒体查询的代码更容易看懂吗?

当然isMobile可以通过屏幕尺寸甚至可以通过UA来实现。使用屏幕尺寸实现的好处就是当用户屏幕在尺寸变化时可以实时响应,不过这个好处不大。用UA实现的好处是服务端也能拿到UA,做ssr时在服务端就能确定渲染哪个平台组件,能够有效的减少size。

这边的less代码用到了一个小技巧,假设没有 & 符号,那么.pc的类会从.box的子元素中去寻找,由于在less中 & 代表的是父元素,也就是.box类,.pc & 就会逃逸出.box的作用范围。.pc会从.box的祖先元素中去寻找,在scss中可以使用@at-root实现相同的效果。

2)size的增加

桌面端和移动端的屏幕大小和操作方式的差异决定了两者的设计一定存在着根本性的区别。为了保证两个端都有较好的用户体验,某些组件(如城市选择器,日期选择器)不得不分别引入。这是导致尺寸增加最重要的因素。要解决这个问题需要根据模块展示的位置做不同处理。

模块在非首屏上展示,这种场景解决比较简单,两个端分别动态引入不同的组件即可。如今的react和vue都已经支持动态引入组件的方式。

棘手的是模块在首屏展示,要如何区分引入呢?如果还是按照动态引入组件的方式,那势必是需要在模块展示区域中有一个加载中的状态,影响体验。两个都导入又会增加包size,假如是ssr的项目,倒是可以在服务端通过UA来区分引入两个端的组件,只不过打包后的js依旧会比较大,降低执行性能。怎么才能两全其美呢?

我们的解决方案是分别定义pc和h5两个page级别的组件,分别引入各自端需要的模块。服务端识别UA去加载正确的page。这个组件要做到尽量的轻量,业务逻辑都交给内部的组件去处理。这样就解决了首屏模块区分引入的问题,只是会多一点代码的维护量。

由于我们用的是携程公司内部的nfes ssr 框架,nfes是这样去定义一个路由的:

javascript{ reg: '/xxx', pageName: 'xxx.html',}

基于此,我们向框架组提出了pageName能够支持传入一个方法,支持根据ua来区分。如下:

javascript{ reg: '/xxx', pageName(req) { return /mobile/i.test(req.headers['user-agent']) ? 'xxxh5.html' : 'xxxpc.html' },}

如果你的项目没有用到前端路由,那么事情到这里就结束了。但是我们做的是一个ssr项目,在前端无刷新路由跳转时,前端需要判断UA,去渲染正确的page组件。这种方式并不适合无刷新跳转,前端拿不到req。一开始我们有考虑过是否可以把req这个对象中必要的字段序列化到html中,比如说headers,这样就能保证前端也能完全有这套配置。但是考虑到这种做法太魔法,不太好理解,最终针对性的出了解决方法。

javascript{ reg: '/xxx', h5PageName: 'xxxh5.html', onlinePageName: 'xxxpc.html',}

具体的实现交由前端或者后端跳转时统一实现即可。如果有些页面确实不适合做响应式,但是又想路径一致,也可以用这种方式解决。

3)图片的引入

对于一些小icon时尽量采用iconfont的形式去替代,幸运的是公司有专业的设计师能做到。其他的情况就用image标签的srcset属性或者用background-image的 image-set方法去引入不同的倍图。记得做好兼容处理即可。


四、适合场景


只要两个端想做的事情相似,偏浏览并且交互不是特别复杂的绝大部分web应用,都非常适合用响应式的方案。有些人可能会担心尺寸增加,会导致加载和执行性能的降低,其实完全没必要,毕竟现在的移动网络和浏览器的执行效率跟五六年前相比已经好太多了。

目前在trip中铁项目中的订单详情页和订单完成页,用了响应式设计来开发,其他页面也在陆续跟进中。这种方式对开发人员最直观的感受就是除了样式上需要根据情况适配一下桌面和移动端,js代码是几乎完全一致的,开发效率得到了明显提升,再也不想回去之前的开发方式了。


【推荐阅读】




 “携程技术”公众号

  分享,交流,成长



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存