vivo 悟空活动中台-基于行为预设的动态布局方案

简介: 本文以“满屏”场景下的页面布局思考为切入点,以微组件为元素单元,提供了一种新的布局方案设计思路——基于行为预设的动态布局方案,并详细的分享了设计目的及具体实现方案,对技术基础要求不高,是一篇男女老少皆宜的“技术甜点”。

本文首发于 vivo互联网技术 微信公众号 
链接: https://mp.weixin.qq.com/s/CwLAV2j7Uxam01m1p7cXxg
作者:悟空中台研发团队

【悟空活动中台】系列往期精彩文章:

一、写在前面

作为前端工程师,页面布局是基本功。面对悟空中台的海量的活动需求,仅仅有几招常规的布局套路显然是难以招架的,悟空开发者团队从个性化需求中提炼特定场景下的共性特点,设计了多个“创意布局”方案。

本文以“满屏”场景下的页面布局思考为切入点,以微组件为元素单元,提供了一种新的布局方案设计思路——基于行为预设的动态布局方案,并详细的分享了设计目的及具体实现方案,对技术基础要求不高,是一篇男女老少皆宜的“技术甜点”。

二、灵感缘起

灵感往往并不是凭空产生的,而是与问题的出现形成因果关系,解决方案也鲜有一蹴而就,大多有一个不断完善的演进过程,我们都执着于发现问题,分析问题,解决问题的轮回。

1、问题是什么

1.1、客户端茫茫多,而设计稿只有一个

这是移动端H5页面进行布局时面临的核心问题之一。

随着移动端生态的日益繁荣,设备屏幕宽高比从3:4、9:16 到  9:19、9:21,分辨率从480p、720p到1080p甚至2k,显然设计师同学不可能针对每种场景都进行对应的创作,所以一般只就约定的标准尺寸(如常见的1080 * 1920 )输出一张设计稿。

而前端开发同学在实施样式布局时,就需要能根据设计师的一张设计稿,作出适配各种不同屏幕尺寸、分辨率的效果。

1.2、避免重复劳作

如果你面对的是2个设备,可能你只需要写两套样式去适配;

如果你面对的是20个设备,可能累一点也能搞得定;

如果你面对的是200个、2000个设备呢?仅仅是体力劳动已经完全不能解决问题,我们需要有更高效的办法——制定一套规则,遵循该规则的页面能够在运行时自己去适配所在设备。

2、普适性方案

为了实现页面运行时的样式自适应,我们从一开始的静态布局、流式布局、到响应式布局、弹性布局,目前大家普遍采取的方案是使用rem单位的弹性布局,即基于设备像素比(Device Pixel Ratio,简称DPR)计算并设置不同设备中的根字体大小,元素尺寸采取 rem 单位的方案,具体实现此处就不再赘述。

2.1、优势

面对不同大小、比例和素质的屏幕,只需要写一套样式,就能够做到对设计稿视觉效果的精准还原;跨屏适配的逻辑代码可以完全直接复用,配合现有的px转rem插件,几乎没有额外工作量开销。

2.2、不足

以上方案虽然有着诸多优势,但是有时面对特定场景也会存在适配效果不够理想的问题。

2.2.1、满屏场景

在单页或者滑屏H5场景下,对任何设备,页面内容“恰好”占满视口。打个比方:页面内容就像是一个“万能螺丝钉”,不管任何规格的螺帽(视口),它都能做到“严丝合缝”的填充。

上图展示了不同规格视口中,页面内容总能恰好占满视口,没有溢出也没有留白;前文所述的普适性方案在满屏场景下就存在一些问题。

2.2.2、元素溢出和页面留白

由于基于DPR和rem的方案特点是动态适配且对设计稿的精确还原,所以当遇到实际可视区域与设计稿比例不一致的情况,就会出现纵向适配问题:

  • 视口比设计稿“长”时,页面纵向无法填充一屏,出现底部留白

  • 视口比设计稿“短”时,就会出现页面纵向内容无法一屏显示的问题,即元素溢出

2.3、初步优化方案

为了解决纵向适配问题,我们将页面内容分为背景图和内部元素两部分,并针对性的进行属性调整,初步可以解决问题。

2.3.1、背景适配

对于背景元素,一般有两种方案:

  • 拉伸填充

    
    令背景直接在横向、纵向进行平铺;缺点是会令背景图片由于拉伸/收缩而产生形变,比例失衡。
    
    
background-size: 100% 100%;
  • 裁切溢出

    
    在保持背景图比例不变的前提下,使其大小能够完全cover窗口大小,并将多余的横向/纵向部分裁掉。
    
    
background-size: cover;
background-position: center;

2.3.2、内部元素定位方式

对于页面元素,我们采用固定定位(fixed),令其相对于窗口的各个边位置固定。

下图展示了分别相对于视口顶部左边、顶部右边、底部左边和底部右边固定定位的元素:

2.4、“精进”的优化

2.4.1、初步优化方案的问题

这种布局方案可以做到无论是横向还是纵向,页面内容所占空间始终与视口区域相同,初步满足了“满屏”的需求,但是仍然存在不足

  • 不够灵活

    
    固定定位的问题在于元素始终是以自己的某条边相对于视口的对应边框进行定位(如:只能是元素顶部相对于窗口顶部位置固定,而不能实现元素底部相对于窗口顶部位置固定的需求)
    
  • 空间竞争

    
    由于所有元素根据屏幕实际宽度进行**等比缩放**,故对屏幕“剩余空间”的利用是静态的,即当屏幕宽高比变化时,所有元素总是 同时 “占据”或者“让出”特定比例的空间,尤其是在空间紧凑的情况下,可能存在非重点内容元素(点缀作用)与重点内容元素“空间竞争”的问题。
    
    

下图反映了固定定位在可视区域变小的情景下,元素对“剩余”空间的挤占:

2.4.2、预设方案进行灵活适配

为了进一步提升满屏场景布局的效果,悟空中台团队基于DPR & rem布局方案,借鉴了元素相对窗口固定定位的思想,提出并实现了基于行为预设的动态布局方案。

三、预设规则

即通过在用户配置页面的时候提供页面背景图和内部元素的属性、定位行为预设,实现产出页面对不同视口的良好适配。

1、背景图尺寸预设

1.1、多种方案灵活可选

提供多种背景图填充方式,供用户灵活选择:

  • 默认——不对background-size进行设置

  • 拉伸填充——横纵平铺

  • 包含——contain

  • 覆盖——cover

  • 重复平铺——repeat

2、内部元素行为预设

提供配置选项,可以对元素的缩放行为作出灵活的配置以满足实际需求。

2.1、缩放行为预设

缩放行为预设主要解决不同视口下页面元素间的空间竞争问题。

2.1.1、元素分类

将元素分类为 主要元素 和 次要元素

  • 主要元素

    
    页面中需要突出的重点内容,在视口尺寸发生变化引起的空间竞争中,处于优势地位;
    
  • 次要元素

    
    页面中相对不重点的内容,在视口尺寸发生变化引起的空间竞争中,处于劣势地位;
    
    

2.1.2、基准视口与实际视口

基准视口即与设计稿比例相同的视口,即如果设计稿比例是 9:16 ,则基准视口就是比例为 9:16 的视口;其他比例的视口我们称之为 非基准视口。

实际视口即页面运行时的视口,根据不同比例,可能是基准视口,也可能是非基准视口。

2.1.3、实际视口中的元素缩放行为

当实际视口短于基准视口,主要元素大小与基准视口保持不变,次要元素按视口比例缩小;

当实际视口长于基准视口,主要元素按视口比例放大,次要元素大小与基准视口保持不变。

经过以上缩放行为预设,可以灵活定义不同元素在实际视口中的缩放行为,解决元素因视口变化出现的空间竞争问题。

2.1.4、元素类型别名

为了使运营同学更容易理解主要元素和次要元素的预期行为,我们称放大元素为主要元素的别名,缩小元素为次要元素的别名,其余称为默认元素。

2.2、定位方式预设

定位方式预设为了提升元素定位的灵活性,使得元素内部的定位基准可以根据实际需要任意选取。

2.2.1、锚点

元素内部选取一个定位中心,作为锚点,将来元素的定位都是基于锚点进行计算。

锚点的设置可以让元素的定位更加灵活:如果将元素的锚点设置为其底边的中点,那么令锚点吸附视口顶部即可实现元素底部相对视口顶部距离固定,这是常规固定定位无法实现的。

2.2.2、吸附性

对于一个元素,可以预设其锚点吸附于视口的顶部/底部,左边/右边,具体规则如下:

  1. 元素在水平方向或垂直方向上,不能同时吸附对应的两条边;比如不能令一个元素同时吸附视口顶部和视口底部;但是可以另其同时吸附视口顶部和视口左边。

  2. 元素若预设吸附了视口某一条边,则在任意规格的视口中,元素锚点相对于该条边的距离相同(以rem为单位)。

  3. 若元素在水平或垂直方向上,并不吸附于任意一条边,则令其相对于该方向上的两条边的距离比例固定;比如若元素同时不吸附于视口左边和右边,则元素相对于视口左边和右边的距离之比固定,值为在页面设计器中,配置页面时该元素距离视口左边和右边的距离之比。

四、预设规则的实现

本部分介绍了预设规则的具体实现,重点在于体现设计思路,示例代码均为伪代码。

1、基准视口与实际视口

1.1、基准视口宽高

描述基准视口的宽度与高度,我们设基准宽度用baseW表示,其值为10.8 rem(对应设计稿1080px),同理基准高度baseH的值设置为21.6 rem。

1.2、实际视口宽高

描述实际视口宽度与高度,我们设实际宽度和高度分别为realWrealH,且由于使用基于DPR和rem的方案,容易得出realW = baseW = 10.8rem;

这样一来,实际视口与基准视口的差别就在于realHbaseH的不同。

1.3、实际视口高度计算

根据realW / realH = window.innerWidth / window.innerHeight,将realW = 10.8 rem代入即可求得实际视口的 CSS 高度:

realW = 10.8
realH = (realW * window.innerHeight) / window.innerWidht

1.4、视口高度比

实际视口与基准视口的比例,设其为windowHeightRatio,则

// 计算视口高度比
windowHeightRatio = realH / baseH

2、元素缩放行为预设的实现

2.1、缩放类型

使用scaleType描述元素缩放类型,其可选值有三个——zoomIn(放大)、zoomOut(缩小)和standard(不进行缩放)。

2.2、缩放比 scale

使用scale描述元素在实际视口与标准视口下的缩放比,设元素在基准视口下的宽高为widthheight,则元素在实际视口下的宽高分别为baseW scale和baseH scale。

2.3、缩放行为目标

对于 scaleType 为zoomIn的元素,当实际视口高于基准视口时,元素缩放比为视口高度比,元素表现为放大;当实际视口不高于 基准视口时,元素缩放比为 1,元素大小保持不变。即

  • 当windowHeightRatio > 1(实际视口大于基准视口)时,元素sacle = windowHeightRatio

  • 当windowHeightRatio <= 1(实际视口小于基准视口)时,元素sacle = 1

对于 scaleType 为zoomOut的元素,当实际视口低于基准视口时,元素缩放比为视口高度比(realH / baseH),元素表现为缩小;当实际视口不低于基准视口时,元素缩放比为 1,元素大小保持不变。即

  • 当windowHeightRatio > 1(实际视口大于基准视口)时,元素sacle = 1

  • 当windowHeightRatio < 1(实际视口大于基准视口)时,元素sacle = windowHeightRatio

对于scaleType为standard的元素,表现行为是始终与设计稿尺寸保持一致,故

  • 对于任何windowHeightRatio,始终有 sacle = 1

// 根据元素缩放类型确定元素的实际缩放比
switch (scaleType) {
  case 'zoomIn':
    scale = windowHeightRatio >= 1 ? windowHeightRatio : 1
    break
  case 'zoomOut':
    scale = windowHeightRatio >= 1 ? 1 : windowHeightRatio
    break
  default:
    scale = 1
}

至此,我们已经完成了对元素缩放类型的定义及缩放比的计算,接下来我们要定义并实现的另一个预设特性——定位特性。

3、元素定位方式预设的实现

3.1、锚点

锚点的设置并不固定,可以灵活根据实际需求的效果进行设置;为便于理解,本例将其设置为元素实际宽高的中心点

3.2、吸附性

不同视口内,页面元素的锚点相对于视口的某一个的位置是定值,称该元素吸附于该条边,视吸附的边的不同,可以分为吸顶吸底靠左靠右

对于某个元素,若其在水平或竖直方向并不吸附于某一条边,而是相对于顶部到底部或左边到右边的距离是固定比例,则称其为按比例居中

3.3、元素定位

我们以视口左上角作为定位坐标系的原点( 0, 0 ),将元素的吸附性使用元素锚点相对于定位原点的距离进行描述。

令元素与基准视口顶部及左边的距离为baseTop和baseLeft;

元素与实际视口顶部及左边的距离为realTop和realLeft。

3.3.1 特元素与可视区域顶部距离 realTop 的计算

(1)吸顶元素

吸顶元素的特性是元素锚点与视口顶部距离固定,即

  • 不同视口中,元素的高度的一半元素顶部到到屏幕顶部的距离的是不变的。

根据特性有如下换算关系:

height / 2 + baseTop = height * scale / 2 + realTop

由realH = baseH * scale得到

realTop = height / 2 + baseTop - (height * scale) / 2

(2) 吸底元素

特性是元素锚点与视口底部的距离固定,即

  • 不同视口中,元素的高度的一半元素底部到到屏幕底部的距离的是不变的。

故应有如下换算关系:

baseH - ( baseTop + height / 2 ) = realH - ( realTop + height * scale / 2 )

求得

realTop = realH - baseH + (baseTop + height / 2) - (height * scale) / 2

(3)按比例居中元素

特性是元素锚点距视口顶部和底部的距离成固定比例,即

  • 不同视口中,元素高度的一半加上元素顶部到屏幕顶部的距离的和的值,与元素高度的一半加上元素底部到屏幕底部的距离的和的值,这两个值相等

故应有如下换算关系:

( height / 2 + baseTops ) / baseH = ( height * scale / 2 + realTop ) / realH

求得

realTop = (realH / baseH) * (height / 2 + baseTops) - (height * scale) / 2

3.3.2、元素与可视区域左边框距离 realLeft 的计算

(1)靠左元素

对于靠左元素,特点是锚点距离视口左边框的距离固定,即

  • 不同视口中,元素元素宽度的一半与元素左边到屏幕左边的距离是固定的。

故应有如下换算关系:

baseLeft + width / 2 = realLeft + width * scale / 2

求得

realLeft = baseLeft + width / 2 - (width * scale) / 2

(2)靠右元素

计算过程同上文,可以得到

realLeft = realW - baseW + ( baseLeft + width / 2 ) - width * scale / 2

(3)按比例居中元素

根据元素锚点到屏幕左右边框距离相等,可以得到

realLeft = (realW / baseW) * (baseLeft + width / 2) - (width * scale) / 2

由于我们基于rem和DPR的布局方案的一个“准则”是视口宽度总是10.8rem,即realW实际和baseW在数值上相等,所以上述结果可以简化为:、

realLeft = ( baseLeft + width / 2 ) - width * scale / 2

至此,我们已经完成了对元素预设规则——元素缩放特性和元素定位特性的实现,接下来需要使用这两种特性对元素的综合样式进行描述。

4、元素最终样式

4.1、定位方案的选择

4.1.1、简单场景

对于单一的“满屏”需求,如一个单独的满屏页面,我们只需要对其中的元素使用固定定位(fixed)方案结合前面几个步骤求得的scale,realTop和realLeft求得样式即可,举个栗子:

style = `
  top: ${realTop}rem;
  left: ${realLeft}rem;
  width: ${width}rem;
  height: ${height}rem;
  transform: scale(${scale});
`

4.1.2、较为复杂的场景

如果我们的页面需要由一连串的“满屏”页面组成,并且可以进行“满屏”页面的切换,实现类似幻灯片一样的效果,则实际上每个“满屏”的页面其实是我们最终页面的一个具备“满屏”特性的“容器”,容器内部的元素在进行布局时,需要相对于容器进行绝对定位(absolute)。

4.1.3 使用锚点进行样式表达

而且既然我们已经有了元素锚点的概念,使用元素锚点的偏移量进行定位是更合乎情理的,锚点即是CSS中的transform-origin属性,即transform-origin : center,假设元素均处于默认起始位置 (top = left = 0),我们使用transform属性对元素的偏移位置进行设置:

锚点竖直方向原位置:baseAnchorY = height / 2

锚点竖直方向目标位置:realAnchorY = realTop + height * scale / 2

根据以上可以求得:

锚点竖直方向的偏移量:offsetVertical = realAnchorY - baseAnchorY = realTop + height * scale / 2 - height / 2

同理求得锚点水平方向的偏移量:offsetHorizontal = realAnchorX - baseAnchorX

最终获得元素样式为:

style = `
  top: 0px;
  left: 0px; 
  width: ${width}rem;
  height: ${height}rem;
  transform-origin: center; // 锚点设置
  transform: translateX(${offsetVertical}rem) translateY(${offsetHorizontal}rem) scale(${style.scale});
`

五、预设方案在生产中的应用

1、集成形式

目前基于行为预设的动态布局方案已经作为悟空活动中台上单页满屏场景的默认布局配置方案,用户可以通过简单的两步操作,便可调选中元素的吸附和缩放特性进行预设:

 

2、产出实例

悟空平台已经产出许多应用了的线上专题,比如经典的vivo 浏览器年终策划 | 2018 大事鉴

六、写在最后

基于行为预设的动态布局方案一定程度上实现了根据视口尺寸对元素定位和大小的动态设置,达到了“恰到好处的突出重点”的效果。根据业务现实情况,预设方案也可以有多种不同的灵活实现,比如元素的响应式缩放、吸附特征以及锚点位置的设置可以根据需求动态调整。

如果本文能够对你的布局设计带来一点点微小灵感的话,那真是深感荣幸。感谢阅读。

目录
相关文章
|
3月前
|
安全 区块链
区块链农场游戏系统开发运营版/玩法详情/规则方案/案例设计/项目源码
Developing a blockchain farm game system is an interesting and challenging task. Here is a design solution that can help you get started developing such a system
|
8月前
|
人工智能 算法 大数据
听静渔说,开发者以国赛的方式进场了
开发者关系和培训中心负责人孟晋宇, 做客天津卫视节目,讲述了阿里云在数字化人才培养和技能人才方面为开发者提供的体系化解决方案:我们积累了非常多的数字化实践经验,沉淀了体系化的能力技术,从而转化为体系化的课程,按照升级打怪的模式,通过微认证——ACA——ACP——ACE这样的认证体系,帮助开发者,逐步完成整体技术的认知能力和岗位技能的提升。
27816 8
听静渔说,开发者以国赛的方式进场了
|
10月前
|
区块链
DAPP画室/书画/字画古董拍卖竞拍抢拍商城系统开发(案例设计)/项目逻辑/成熟技术/方案介绍/源码说明
智能合约是DAPP的核心组成部分,它是一种自执行的计算机代码,It can ensure that any transaction is validated and executed.智能合约提供了一种区块链上的可编程机制,通过编写代码,将一系列的条件和操作映射到智能合约中,To achieve management and control of data and transactions on the blockchain.
|
9月前
|
安全
NFT卡牌游戏链游系统开发(开发方案)/详情规则/成熟技术/设计界面/案例项目/源码程序
NFT (Non Homogeneous Token) card chain game refers to a game based on blockchain technology where NFT is used as the card in the game. NFT is a unique and non interchangeable digital asset that can represent various virtual cards, props, or characters in the game.
|
11月前
|
新零售 人工智能 供应链
东郊到家系统开发(规则及玩法)/方案详解/案例设计/成熟技术,东郊到家APP开发源码
 新零售就是企业借助互联网,通过大数据、人工智能等一些手段,对产品的生产、流通以及销售的过程俩进行升级改造,从而可以把线上服务、线下服务以及现代的物流进行深度的融合的新零售模式。
|
12月前
|
边缘计算 编解码 5G
《2022中国云游戏行业认知与观察》——第二章、云游戏应用场景与技术实践——2.1 云端游 & 云手游:定义全新业务模式 提升游戏 ROI——2.1.1 应用案例:《战舰世界》云游戏版,云端海战一触即发!
《2022中国云游戏行业认知与观察》——第二章、云游戏应用场景与技术实践——2.1 云端游 & 云手游:定义全新业务模式 提升游戏 ROI——2.1.1 应用案例:《战舰世界》云游戏版,云端海战一触即发!
165 0
|
12月前
|
Rust 定位技术 区块链
区块链农场养殖类游戏模式玩法及开发源码示例
区块链农场养殖游戏是一个去中心化的虚拟农场游戏,玩家可以在游戏中体验种植、养殖的乐趣。游戏中的农场是一个数字资产,可以用来购买土地、种子、化肥、农药等物品,并通过种植、养殖动物获得收益。
|
12月前
|
SQL 关系型数据库 MySQL
链动2+1系统开发玩法规则 | 链动2+1系统开发成品源码实例
“链动2+1”是一种促进企业和品牌迅速建立起获客团队、拓宽客源渠道、促进销售增长的一种新模式。 这是一种在传统的分销模式基础上的,并且合理合规,主要是为了激发员工的积极性,鼓励顾客带新客户,而顾客除了可以获得折扣外,还可以获得一定的提成和奖金。
|
开发框架 Rust 安全
Stepn跑鞋趣步跑步运动系统开发(开发逻辑)丨Stepn跑鞋链游项目系统开发(详情及玩法)/成熟技术/源码版
在DApp开发中,智能合约是不可或缺的一部分。智能合约通常使用Solidity语言编写,并且运行在以太坊或其他区块链平台上。在智能合约中,开发人员可以编写代码来定义合约的逻辑和执行流程。智能合约的执行是通过区块链网络的节点共识机制来完成的,保证了其不可篡改性和安全性。
|
移动开发 前端开发 IDE
手淘双11最新实践:PopLayer弹层领域研发模式升级
近年来,各大APP内的弹层需求逐渐增多,以手机淘宝为例,日常的弹层上线频率为单端每月50次左右,而在大促期间可以达到240次以上。在手淘内,各类弹层业务都会通过PopLayer中间件的能力进行投放。但业务往往会遇到开发弹层难、慢、稳定性差的种种困难。对比于往年业务研发成本较高的现状,PopLayer在今年提出了【低研发搭投模式】来解决这类问题,形成一套快速搭建+可视化+多端多场景通用的解决方案,在日常与大促期间得到了广泛应用: