喬布斯在《遺失的訪談》中說過「每個人都應該學習編程,因為它教會你如何思考」。
前言
在上一家公司,由于 UI 妹子離職和招聘問題荤牍,不得以兼任了 UI 視覺工作。雖然之前的產(chǎn)品/交互工作和 UI 有很多交集庆冕、自己的個人項目中也會有一些 UI 設計康吵,但卻不曾獨自去設計一個完整產(chǎn)品的 UI。這一回访递,算是從「動口」到「動手」了晦嵌,好在是 B 端產(chǎn)品,對視覺美觀性要求沒那么高拷姿,相對而言統(tǒng)一性更為重要惭载。
之前作為 UI 上游環(huán)節(jié)時,我總是會給 UI 提意見跌前,要求盡量統(tǒng)一棕兼、要求考慮實現(xiàn)成本……現(xiàn)在自己做 UI 后陡舅,才發(fā)現(xiàn)滿足自己的要求挺困難的抵乓。雖然最終并沒有達到我自己滿意的程度,但這段實戰(zhàn)經(jīng)歷,確實使我對 UI 設計的統(tǒng)一性有了一些更深入的理解灾炭,尤其是將「視覺設計的感性思維」和「程序實現(xiàn)的邏輯思維」融合后茎芋,有了一個全新的視角。
我的這些理解蜈出,對于很多前端工程師來說田弥,可能屬于「常識」;但對于沒有前端經(jīng)驗的產(chǎn)品/交互/UI 設計師而言铡原,我相信是有一定幫助的偷厦。如果我自己能早幾年想明白,至少前幾個項目在 UI 的統(tǒng)一性上可以提升不少燕刻。
P.S. 本文出現(xiàn)的代碼都是 CSS 樣式代碼只泼、沒有任何復雜的邏輯。沒有代碼基礎的同學卵洗,請不要抗拒请唱,當成英文來讀就行。
如何繪制一個界面过蹂?
從設計視角來看
-
在各類設計工具(如 Sketch)中十绑,是圖層的組合
從工程視角來看
無論從哪個角度本橙,界面都是通過各種元素之間的各種組合、疊加脆诉,拼接而成勋功。
如何使繪制出的界面統(tǒng)一?
既然界面是由各種元素拼出來的库说,那要達到整體界面統(tǒng)一狂鞋,這些構成元素自然需要先統(tǒng)一。統(tǒng)一的方式潜的,就包括建立一套「控件庫」(或者說 Symbol骚揍、模板、Library啰挪、UI Kit……有許多不同的稱呼)信不,總之就是預定義一些「元素」及「元素組」,通過對有限的「元素」及「元素組」做統(tǒng)一亡呵,使得最終組合而成的界面也能在某種程度上實現(xiàn)統(tǒng)一抽活。
如果你從事過 UI 相關工作,一定或多或少了解過諸如此類的「控件庫」锰什、或是 Atomic Design 之類的設計思想下硕。
如何設計一套統(tǒng)一的「控件庫」丁逝?
前面的都是概念,這才是實際要做的事情梭姓。為了省篇幅霜幼,我僅以「按鈕」為例,講述一下我對于「統(tǒng)一控件」的理解誉尖。
階段一
這其實是我剛接觸 CSS 時的理解罪既,現(xiàn)在只是回顧一下最初那種淺顯的想法。
雖然這種理解非常淺顯铡恕,但不少軟件連這一步都沒做到琢感。
最初我以為,統(tǒng)一是:
所有的中號按鈕探熔,高度都是 24px
所有的藍色按鈕猩谊,色值都是 #0000FF
……
總之,只要最終看效果上去統(tǒng)一就行祭刚,沒有考慮其背后的實現(xiàn)牌捷,沒有「控件庫」的概念。
寫成代碼涡驮,可能會是這樣:
- 假設有 99 個按鈕暗甥,每個按鈕都有自己的樣式,只是這 99 種樣式被強行設成了相同捉捅。
.button-1 {
height: 24px;
background-color: #0000FF;}
.button-2 {
height: 24px;
background-color: #0000FF;}
...
.button-99 {
height: 24px;
background-color: #0000FF;}
階段二
這是我自己動手做 UI 之前的想法撤防,要求 UI 設計師預先規(guī)劃好所有可能會出現(xiàn)按鈕(3 種尺寸、每種尺寸又有 3 種不同顏色棒口,共計 9 種按鈕)寄月。
這時候,我以為統(tǒng)一是:
預先枚舉出所有可能用到的標準控件无牵,加入控件庫漾肮。
程序實現(xiàn)時,統(tǒng)一使用控件庫中的標準控件茎毁。
……
雖然有了「控件庫」的概念克懊,但實現(xiàn)手段是非常粗暴的「枚舉法」
寫成代碼,可能會是這樣:
- 假設有 99 個按鈕七蜘,所有按鈕都是只從這 9 種預設樣式中選一種
.button-normal-small {
height: 20px;
background-color: #FFFFFF;}
.button-normal-middle{
height: 24px;
background-color: #FFFFFF;}
.button-normal-large {
height: 32px;
background-color: #FFFFFF;}
.button-blue-small {
height: 20px;
background-color: #0000FF;}
.button-blue-middle{
height: 24px;
background-color: #0000FF;}
.button-blue-large {
height: 32px;
background-color: #0000FF;}
.button-red-small {
height: 20px;
background-color: #FF0000;}
.button-red-middle{
height: 24px;
background-color: #FF0000;}
.button-red-large {
height: 32px;
background-color: #FF0000;}
階段三
這時谭溉,我需要自己去制作控件庫了。作為一個懶人橡卤、我可不想枚舉出所有的按鈕扮念。所謂懶惰使人進步,我?guī)е鴨栴}去看了一下各大網(wǎng)站的網(wǎng)頁代碼碧库。很容易就能發(fā)現(xiàn)了規(guī)律柜与,人家是用多個 css 類疊加出來的巧勤。
對嘛!設計的時候是 3 種尺寸旅挤、3 種顏色踢关,也就是分「尺寸」和「顏色」這 2 個維度伞鲫,那實現(xiàn)的時候也應該是用維度疊加粘茄,而不是枚舉。
原來需要畫 3 × 3 = 9 個按鈕秕脓,現(xiàn)在只需要畫 3 +3 = 6 個了柒瓣!
這時候,我以為統(tǒng)一是:
將一個控件抽象成「特定維度的疊加組合」
實現(xiàn)時吠架,通過限定這些維度來實現(xiàn)統(tǒng)一
寫成代碼芙贫,可能會是這樣:
- 分別設「color、size」這 2 個維度的樣式傍药,使用按鈕時磺平,用這 2 個維度的疊加效果。
.button.color-normal {
background-color: #FFFFFF;}
.button.color-blue {
background-color: #0000FF;}
.button.color-red {
background-color: #FF0000;}
.button.size-small{
height: 20px;}
.button.size-middle{
height: 24px;}
.button.size-large{
height: 32px;}
階段四
其實對于「設計指南」而言拐辽,通常就是只到「階段三」的層次拣挪。強如 Google 的 Material Design,雖然標注很細致俱诸,但依然是屬于「階段三」這個層次菠劝。
基于 Material Design 的這種標注,你可以嘗試解釋一下這 2 個問題:
- 為什么按鈕的高度是 36dp睁搭?
- 為什么這個按鈕的最小寬度(min-width)是 64dp赶诊?
怎么樣?這些具體的 dp 值是怎么得到的园骆,能解釋清楚嗎舔痪?至少我做不到。
之前作為 UI 的上游環(huán)節(jié)锌唾,我沒有深入去思考辙喂、停留在了這些表面的標注上。現(xiàn)在真正自己去設計一套控件庫時鸠珠,才發(fā)現(xiàn)巍耗,如果只看這些表面的細節(jié),再詳細都不夠渐排,還應當更進一步去思考得到這些結果的「推導過程」炬太,否則只是在依葫蘆畫瓢、不是真正的理解驯耻。
回想到曾經(jīng)看過的一個印象深刻的觀點「優(yōu)秀的設計亲族,每一個像素都是有據(jù)可循的」
那么炒考,什么叫做「有據(jù)可循」?
- 按我個人的理解霎迫,就是可以用準確的邏輯規(guī)則表述斋枢、而不是憑感覺
(其實感覺也是一種基于經(jīng)驗的規(guī)則,又名「神經(jīng)網(wǎng)絡算法」知给,只是我們自己無法理解瓤帚、表述)
什么又是準確的邏輯規(guī)則?
- 代碼I(偽代碼也行)
順著「用準確的代碼解釋每一個像素」這個思路戈次,我又重新審視了一遍控件庫。聯(lián)想到之前做網(wǎng)站時掃過一眼的 scss(用變量定義 css 的一種語言)筒扒,終于領悟到了「階段四」:
控件的每一個屬性都應該是有推導過程的「相對值」怯邪,而不是一個憑感覺直接得到具體結果的「絕對值」。
寫成代碼花墩,可能會是這樣:
- 所有「色值」悬秉、「像素值」都用「變量」表示。當然了冰蘑,這不是真實的例子和泌,只是為了做簡單的示例
(關于「變量」的詳細說明,請看下一節(jié) Variables)
.button.color-normal {
background-color: $color-normal;}
.button.color-blue {
background-color: $color-blue;}
.button.color-red {
background-color: $color-red;}
.button.size-small{
height: $small;}
.button.size-middle{
height: $middle;}
.button.size-large{
height: $large;}
Variables(變量)
Variables懂缕,僅指 CSS 樣式層面的變量允跑。(這里我參考了 Blueprint 的命名,用了 Variables 一詞搪柑,在其他很多設計系統(tǒng)(Design System)中聋丝,也都有類似概念。比如在 Saleforce Lightning 中工碾,它被稱之為 Tokens弱睦。)
等等,之前不是說「設計指南只到階段三的層次」么渊额?怎么突然很多設計系統(tǒng)中又有類似概念了况木?
還是因為代碼。
- 在成熟的 Design System 中旬迹,除了設計指南部分火惊,通常還有完整的開源代碼
- 只是我之前看這些 Design System 時,未曾想到去看源代碼部分
以我們自己的按鈕舉例奔垦,一層層拆解它的「變量」吧屹耐。(為了簡化,暫不考慮按鈕的 hover椿猎、down惶岭、disable寿弱、loading 等狀態(tài))。
先來看一下絕對值
這是我參照 Material Design 做的標注(單位都是 px)
對著這個按鈕按灶,再來看一下這 2 個問題:
- 為什么按鈕的高度是 24px症革?
- 為什么這個按鈕的最小寬度(min-width)是 54px?
回答這 2 個問題之前鸯旁,還需要先進一步拆解一下「按鈕」
按鈕是什么噪矛?
- 在 Sketch 中,是「背景」上疊加「文字」
- 在 HTML&CSS 中羡亩,是「背景容器」內塞入「文字」摩疑。
既然是要「用準確的代碼解釋每一個像素」危融,我們得用代碼的邏輯來看畏铆。CSS 盒模型 了解一下?
盒模型簡單的說就是:
按鈕的尺寸 = 容器外邊距(margin) + 容器邊框(border) + 容器內邊距(padding) + 內部文字的尺寸
我們這個按鈕對應的實際盒模型如下:
拆解問題一
參照上圖的盒模型吉殃,可以先開始回答第一個問題
- 為什么按鈕的高度是 24px辞居?
解:
因為
- 外邊距為 0;
- 邊框為 1px蛋勺,但有上下兩條邊瓦灶,因此還要 ×2;
- 垂直方向的內邊距為 2px,同樣有上下兩個邊距抱完,也要 ×2;
- 文字高度為 18px;
所以贼陶,將上述值相加即可得到
- 0 + (1px * 2) + (2px * 2) + 18px = 24px
繼續(xù)追問……
文字的高度為什么是 18px?
解:
因為
- 使用了標準字號 12px
- 文字行高是字號的 1.5 倍巧娱,這點應該屬于 UI 設計的常識吧碉怔?
所以,可以得到
- 12px * 1.5 = 18px
將標準字號命名為 $font-size-m禁添,其對應的標準行高即為
- $line-height-m = $font-size-m * 1.5
繼續(xù)追問……
為什么 border 是 1px撮胧? 垂直 padding 又是 2px?
解:
這 2 個問題老翘,如果只看按鈕本身芹啥,確實很難再解釋為什么了
但它們也不是一個孤立存在的絕對值,背后也是有特定含義的變量1px 的 border铺峭,可以稱之為「細邊框」墓怀,即 $border-width-thin: 1px;
所有需要「細邊框」的地方都用 $border-width-thin
類似的,2px 的 padding卫键,可以稱之為「超小間距」傀履,即 $spacing-xs: 2px;
所有需要「超小間距」的情況都用 $spacing-xs
最終用「代碼公式」來回答這問題,就是
24px = ($border-width-thin * 2) + ($spacing-xs * 2) + $line-height-m
拆解問題二
再來看一下問題二
為什么這個按鈕的最小寬度(min-width)是 54px永罚?
解題思路和「問題一」類似啤呼,這里只解釋一下關鍵點:
因為我是按照最少 3 個漢字的寬度來設計的最小尺寸
- 之前提到過卧秘,標準字號命名為 $font-size-m,是 12px
- 換算一下官扣,12px * 3 = 36px
另外水平方向的 padding 設了 8px翅敌,再加上兩邊各 1px 的邊框
- 36px + 8px * 2 + 1px * 2 = 54px
所以,最終用「代碼公式」來回答這問題惕蹄,就是
- 54px = $font-size-m * 3 + ($spacing-xs * 2) + ($border-width-thin * 2)
「尺寸」總結
回顧一下幾個涉及「尺寸」的屬性蚯涮,及其對應的變量值,在代碼中如下:
(還有 border-radius 也是尺寸相關的屬性卖陵,只是不影響寬/高計算遭顶,因此未曾提及。)
min-width: $font-size-m * 3; //最小寬度
padding: $spacing-xs $spacing-m; //內邊距(前者為垂直方向泪蔫、后者為水平方向)
font-size: $font-size-m; //字號
line-height: $line-height-m; //行高
border-width: $border-width-thin; //邊框粗細
至于 $spacing-xs棒旗、$spacing-m、$font-size-m撩荣、等等铣揉,這些「變量」的值具體應該設多少,這里暫不深入餐曹。本文的主要還想表達「所有值都用有據(jù)可循的變量表示」這種思路逛拱,至于每一個變量的具體值設定,那是另一個龐大的話題了台猴。
以下鏈接是我自己的設定方式朽合,如有興趣可供參考
https://github.com/UXplayer/GS_Guideline/blob/master/_sass/variables.scss
回到「階段四」的例子
還記得之前「階段四」的示例代碼嗎?是類似這樣不真實的饱狂、極其簡單的例子
.button.size-small{
height: $small;}
如果按照我們實際用的按鈕來看曹步,按鈕「尺寸」維度應該如下:
- 對于不同尺寸的按鈕,其「最小寬度嗡官、內邊距箭窜、字號、行高」都一同變化
.size-small{
min-width: $font-size-s * 3;
padding: 0 $spacing-s;
font-size: $font-size-s;
line-height: $line-height-s;
}
.size-normal{
min-width: $font-size-m * 3;
padding: $spacing-xs $spacing-m;
font-size: $font-size-m;
line-height: $line-height-m;
}
.size-large{
min-width: $font-size-l * 3;
padding: $spacing-s $spacing-l;
font-size: $font-size-l;
line-height: $line-height-l;
}
顏色
對于「顏色」維度衍腥,就是背景色磺樱、文字色、邊框色婆咸,這些包含色值的屬性竹捉。
在顏色的使用上,UI 設計師通常都還是會預定義好色板的尚骄。即便沒有用精確的代碼來解釋块差,如果有用 Sketch 的 Symbol,也已足夠保證統(tǒng)一性。此外憨闰,顏色在代碼實現(xiàn)上状蜗,通常也還是會枚舉出色板中的顏色作為「變量」,除非你是做開源庫鹉动,需要有一些色板的生成算法轧坎,否則不會尺寸那樣包含各種計算規(guī)則。
因此「顏色」部分就不再贅述了泽示,思路和「尺寸」部分是一樣的缸血,甚至更簡單一些。
總結
啰里啰嗦地寫了那么多械筛,其實主旨還是那一點:
控件的每一個屬性都應該是有推導過程的「相對值」捎泻,而不是一個憑感覺直接得到具體結果的「絕對值」。
一個完整的控件庫埋哟,要比按鈕復雜的多笆豁,但萬變不離其宗,無非是「推導過程」更長一些罷了定欧。
像程序學習渔呵,用工程思維怒竿、邏輯思維去重新審視你自以為熟悉的 UI 設計砍鸠,也許還會發(fā)現(xiàn)更多的新大陸。
最后
我們的項目是用 QT 開發(fā)的 PC 端產(chǎn)品耕驰,我在給開發(fā)提需求的同時爷辱,用 HTML&CSS 寫了一部分控件,可以點此查看 在線演示項目 (做了一些調整朦肘,和實際項目并不完全相同)
該演示項目的源代碼可以在 GitHub 查看饭弓。因為我這個只是簡單的 Demo 演示,比起大型開源項目的源碼媒抠,讀起來應該容易不少弟断。
我為什么要自己用代碼寫一遍?
首先趴生,批量調整樣式時阀趴,代碼比 Sketch 快得多;
其次苍匆,便于和開發(fā)溝通(給開發(fā)直接看代碼刘急,要比用自然語言解釋規(guī)則輕松多了)