vivo 悟空活動中臺-基於行爲預設的動態佈局方案

本文首發於 vivo互聯網技術 微信公衆號
連接: https://mp.weixin.qq.com/s/CwLAV2j7Uxam01m1p7cXxg
做者:悟空中臺研發團隊html

【悟空活動中臺】系列往期精彩文章:前端

1、寫在前面

做爲前端工程師,頁面佈局是基本功。面對悟空中臺的海量的活動需求,僅僅有幾招常規的佈局套路顯然是難以招架的,悟空開發者團隊從個性化需求中提煉特定場景下的共性特色,設計了多個「創意佈局」方案。前端工程師

本文以「滿屏」場景下的頁面佈局思考爲切入點,以微組件爲元素單元,提供了一種新的佈局方案設計思路——基於行爲預設的動態佈局方案,並詳細的分享了設計目的及具體實現方案,對技術基礎要求不高,是一篇男女老幼皆宜的「技術甜點」。佈局

2、靈感緣起

靈感每每並非憑空產生的,而是與問題的出現造成因果關係,解決方案也鮮有一蹴而就,大多有一個不斷完善的演進過程,咱們都執着於發現問題,分析問題,解決問題的輪迴。字體

一、問題是什麼

1.一、客戶端茫茫多,而設計稿只有一個

這是移動端H5頁面進行佈局時面臨的核心問題之一。優化

隨着移動端生態的日益繁榮,設備屏幕寬高比從 3:四、9:16 到 9:1九、9:21 ,分辨率從 480p 、720p 到 1080p 甚至 2k ,顯然設計師同窗不可能針對每種場景都進行對應的創做,因此通常只就約定的標準尺寸(如常見的 1080 * 1920 )輸出一張設計稿。ui

而前端開發同窗在實施樣式佈局時,就須要能根據設計師的一張設計稿,做出適配各類不一樣屏幕尺寸、分辨率的效果。

1.二、避免重複勞做

若是你面對的是 2 個設備,可能你只須要寫兩套樣式去適配;

若是你面對的是 20 個設備,可能累一點也能搞得定;

若是你面對的是 200 個、 2000 個設備呢?僅僅是體力勞動已經徹底不能解決問題,咱們須要有更高效的辦法——制定一套規則,遵循該規則的頁面可以在運行時本身去適配所在設備。

二、普適性方案

爲了實現頁面運行時的樣式自適應,咱們從一開始的靜態佈局、流式佈局、到響應式佈局、彈性佈局,目前你們廣泛採起的方案是使用rem單位的彈性佈局,即基於設備像素比( Device Pixel Ratio,簡稱 DPR )計算並設置不一樣設備中的根字體大小,元素尺寸採起 rem 單位的方案,具體實現此處就再也不贅述。

2.一、優點

面對不一樣大小、比例和素質的屏幕,只須要寫一套樣式,就可以作到對設計稿視覺效果的精準還原;跨屏適配的邏輯代碼能夠徹底直接複用,配合現有的 px 轉 rem 插件,幾乎沒有額外工做量開銷。

2.二、不足

以上方案雖然有着諸多優點,可是有時面對特定場景也會存在適配效果不夠理想的問題。

2.2.一、滿屏場景

在單頁或者滑屏H5場景下,對任何設備,頁面內容「剛好」佔滿視口。打個比方:頁面內容就像是一個「萬能螺絲釘」,無論任何規格的螺帽(視口),它都能作到「嚴絲合縫」的填充。

上圖展現了不一樣規格視口中,頁面內容總能剛好佔滿視口,沒有溢出也沒有留白;前文所述的普適性方案在滿屏場景下就存在一些問題。

2.2.二、元素溢出和頁面留白

因爲基於 DPR 和 rem 的方案特色是動態適配且對設計稿的精確還原,因此當遇到實際可視區域與設計稿比例不一致的狀況,就會出現縱向適配問題:

  • 視口比設計稿「長」時,頁面縱向沒法填充一屏,出現底部留白

  • 視口比設計稿「短」時,就會出現頁面縱向內容沒法一屏顯示的問題,即元素溢出

2.三、初步優化方案

爲了解決縱向適配問題,咱們將頁面內容分爲背景圖和內部元素兩部分,並針對性的進行屬性調整,初步能夠解決問題。

2.3.一、背景適配

對於背景元素,通常有兩種方案:

  • 拉伸填充

    令背景直接在橫向、縱向進行平鋪;缺點是會令背景圖片因爲拉伸/收縮而產生形變,比例失衡。

background-size: 100% 100%;複製代碼
  • 裁切溢出

    在保持背景圖比例不變的前提下,使其大小可以徹底cover窗口大小,並將多餘的橫向/縱向部分裁掉。

background-size: cover;
background-position: center;複製代碼

2.3.二、內部元素定位方式

對於頁面元素,咱們採用固定定位( fixed ),令其相對於窗口的各個邊位置固定。

下圖展現了分別相對於視口頂部左邊、頂部右邊、底部左邊和底部右邊固定定位的元素:

2.四、「精進」的優化

2.4.一、初步優化方案的問題

這種佈局方案能夠作到不管是橫向仍是縱向,頁面內容所佔空間始終與視口區域相同,初步知足了「滿屏」的需求,可是仍然存在不足

  • 不夠靈活

    固定定位的問題在於元素始終是以本身的某條邊相對於視口的對應邊框進行定位(如:只能是元素頂部相對於窗口頂部位置固定,而不能實現元素底部相對於窗口頂部位置固定的需求)

  • 空間競爭

    因爲全部元素根據屏幕實際寬度進行 等比縮放 ,故對屏幕「剩餘空間」的利用是靜態的,即當屏幕寬高比變化時,全部元素老是 同時 「佔據」或者「讓出」特定比例的空間,尤爲是在空間緊湊的狀況下,可能存在非重點內容元素(點綴做用)與重點內容元素「空間競爭」的問題。

下圖反映了固定定位在可視區域變小的情景下,元素對「剩餘」空間的擠佔:

2.4.二、預設方案進行靈活適配

爲了進一步提高滿屏場景佈局的效果,悟空中臺團隊基於 DPR & rem 佈局方案,借鑑了元素相對窗口固定定位的思想,提出並實現了基於行爲預設的動態佈局方案。

3、預設規則

即經過在用戶配置頁面的時候提供頁面背景圖和內部元素的屬性、定位行爲預設,實現產出頁面對不一樣視口的良好適配。

一、背景圖尺寸預設

1.一、多種方案靈活可選

提供多種背景圖填充方式,供用戶靈活選擇:

  • 默認——不對 background-size 進行設置

  • 拉伸填充——橫縱平鋪

  • 包含—— contain

  • 覆蓋—— cover

  • 重複平鋪—— repeat


二、內部元素行爲預設

提供配置選項,能夠對元素的縮放行爲做出靈活的配置以知足實際需求。

2.一、縮放行爲預設

縮放行爲預設主要解決不一樣視口下頁面元素間的空間競爭問題。

2.1.一、元素分類

將元素分類爲 主要元素 和 次要元素

  • 主要元素

    頁面中須要突出的重點內容,在視口尺寸發生變化引發的空間競爭中,處於優點地位;

  • 次要元素

    頁面中相對不重點的內容,在視口尺寸發生變化引發的空間競爭中,處於劣勢地位;

2.1.二、基準視口與實際視口

基準視口 即與設計稿比例相同的視口,即若是設計稿比例是 9:16 ,則基準視口就是比例爲 9:16 的視口;其餘比例的視口咱們稱之爲 非基準視口。

實際視口即頁面運行時的視口,根據不一樣比例,多是基準視口,也多是非基準視口。

2.1.三、實際視口中的元素縮放行爲

當實際視口短於基準視口,主要元素大小與基準視口保持不變,次要元素按視口比例縮小;

當實際視口長於基準視口,主要元素按視口比例放大,次要元素大小與基準視口保持不變。

通過以上縮放行爲預設,能夠靈活定義不一樣元素在實際視口中的縮放行爲,解決元素因視口變化出現的空間競爭問題。

2.1.四、元素類型別名

爲了使運營同窗更容易理解主要元素和次要元素的預期行爲,咱們稱放大元素爲主要元素的別名,縮小元素爲次要元素的別名,其他稱爲默認元素。

2.二、定位方式預設

定位方式預設爲了提高元素定位的靈活性,使得元素內部的定位基準能夠根據實際須要任意選取。

2.2.一、錨點

元素內部選取一個定位中心,做爲錨點,未來元素的定位都是基於錨點進行計算。

錨點的設置可讓元素的定位更加靈活:若是將元素的錨點設置爲其底邊的中點,那麼令錨點吸附視口頂部便可實現元素底部相對視口頂部距離固定,這是常規固定定位沒法實現的。

2.2.二、吸附性

對於一個元素,能夠預設其錨點吸附於視口的頂部/底部,左邊/右邊,具體規則以下:

  1. 元素在水平方向或垂直方向上,不能同時吸附對應的兩條邊;好比不能令一個元素同時吸附視口頂部和視口底部;可是能夠另其同時吸附視口頂部和視口左邊。

  2. 元素若預設吸附了視口某一條邊,則在任意規格的視口中,元素錨點相對於該條邊的距離相同(以 rem 爲單位)。

  3. 若元素在水平或垂直方向上,並不吸附於任意一條邊,則令其相對於該方向上的兩條邊的距離比例固定;好比若元素同時不吸附於視口左邊和右邊,則元素相對於視口左邊和右邊的距離之比固定,值爲在頁面設計器中,配置頁面時該元素距離視口左邊和右邊的距離之比。

4、預設規則的實現

本部分介紹了預設規則的具體實現,重點在於體現設計思路,示例代碼均爲僞代碼。

一、基準視口與實際視口

1.一、基準視口寬高

描述基準視口的寬度與高度,咱們設基準寬度用 baseW 表示,其值爲 10.8 rem (對應設計稿 1080px ),同理基準高度 baseH 的值設置爲 21.6 rem 。

1.二、實際視口寬高

描述實際視口寬度與高度,咱們設實際寬度和高度分別爲 realWrealH ,且因爲使用基於 DPR 和 rem 的方案,容易得出 realW = baseW = 10.8rem ;

這樣一來,實際視口與基準視口的差異就在於 realHbaseH 的不一樣。

1.三、實際視口高度計算

根據 realW / realH = window.innerWidth / window.innerHeight ,將 realW = 10.8 rem 代入便可求得實際視口的 CSS 高度:

realW = 10.8
realH = (realW * window.innerHeight) / window.innerWidht複製代碼

1.四、視口高度比

實際視口與基準視口的比例,設其爲 windowHeightRatio ,則

// 計算視口高度比
windowHeightRatio = realH / baseH複製代碼

二、元素縮放行爲預設的實現

2.一、縮放類型

使用 scaleType 描述元素縮放類型,其可選值有三個—— zoomIn(放大)、 zoomOut(縮小)和 standard(不進行縮放)。

2.二、縮放比 scale

使用 scale 描述元素在實際視口與標準視口下的縮放比,設元素在基準視口下的寬高爲 widthheight ,則元素在實際視口下的寬高分別爲 baseW * scale 和 baseH * scale 。

2.三、縮放行爲目標

對於 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.二、吸附性

不一樣視口內,頁面元素的 錨點 相對於視口的某一個的位置是定值,稱該元素 吸附 於該條邊,視吸附的邊的不一樣,能夠分爲 吸頂吸底靠左靠右

對於某個元素,若其在水平或豎直方向並 不吸附 於某一條邊,而是相對於頂部到底部或左邊到右邊的距離是固定比例,則稱其爲 按比例居中


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.二、元素與可視區域左邊框距離 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.一、簡單場景

對於單一的「滿屏」需求,如一個單獨的滿屏頁面,咱們只須要對其中的元素使用 固定定位(fixed)方案結合前面幾個步驟求得的 scale , realTop 和 realLeft 求得樣式便可,舉個栗子:

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

4.1.二、較爲複雜的場景

若是咱們的頁面須要由一連串的「滿屏」頁面組成,而且能夠進行「滿屏」頁面的切換,實現相似幻燈片同樣的效果,則實際上每一個「滿屏」的頁面實際上是咱們最終頁面的一個具有「滿屏」特性的「容器」,容器內部的元素在進行佈局時,須要相對於容器進行絕對定位( 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});
`複製代碼

5、預設方案在生產中的應用

一、集成形式

目前基於行爲預設的動態佈局方案已經做爲 悟空活動中臺 上單頁滿屏場景的默認佈局配置方案,用戶能夠經過簡單的兩步操做,即可調選中元素的吸附和縮放特性進行預設:

二、產出實例

悟空平臺已經產出許多應用了的線上專題,好比經典的vivo 瀏覽器年終策劃 | 2018 大事鑑


6、寫在最後

基於行爲預設的動態佈局方案 必定程度上實現了根據視口尺寸對元素定位和大小的動態設置,達到了「恰到好處的突出重點」的效果。根據業務現實狀況,預設方案也能夠有多種不一樣的靈活實現,好比元素的響應式縮放、吸附特徵以及錨點位置的設置能夠根據需求動態調整。

若是本文可以對你的佈局設計帶來一點點微小靈感的話,那真是深感榮幸。感謝閱讀。

更多內容敬請關注 vivo 互聯網技術 微信公衆號

注:轉載文章請先與微信號:Labs2020 聯繫。

相關文章
相關標籤/搜索