重拾 CSS 的樂趣(上)

CSS魔法發表於2015-09-06

前言

我在第二屆 CSS Conf(2015 中國 CSS 開發者大會)上的演講廣受好評,很多網友向我索取現場視訊。條件所限,這個演講並沒有留下視訊存檔。因此,本文嘗試在靜態幻燈片的基礎上,以文字的方式還原現場講解,儘可能為不能去現場的朋友呈現最完整的體驗。

我在每幅圖片之間補充了講解文字。你不用分辨每段文字是配合上圖還是下圖的,只管順序閱讀即可。

重拾 CSS 的樂趣 - 幻燈片封面

大家看到封面的畫風,應該可以看出我今天走的不是技術路線,而是娛樂路線。如果說前面幾位講師的分享是燒腦的懸疑推理大片,我這個環節就是輕鬆愉快的爆米花電影了,大家可以放鬆一下。

CSS魔法 #百姓網#

接下來,接照慣例,需要介紹一下 “這個人”。有兩個標籤可以描述這個人。

首先,他來自百姓網(此處省略百姓網的誘人之處一百字)。歡迎各位小夥伴到百姓網來看一看,我們一起來玩些好玩的。

第二個標籤是這個:

#把 CSS 寫進名字的男人#

大家可能會說,“把 CSS 寫進自己的名字”,聽起來這麼拽,那你上一屆 CSS Conf 怎麼沒來?

CSS Conf

上一屆 CSS Conf 我確實沒有來。我給自己找的理由是北京太遠了,我就不去了。但實際上我自己很清楚,真正的原因是,我並不知道自己應該在這樣的大會上分享什麼。

第二屆 CSS Conf 就在上海,我沒有任何理由不來,但我仍然需要面對這個問題——我要為現場的觀眾分享些什麼呢?

其實,最近這幾年,在 CSS 領域出現了很多好東西:

Sass、Stylus、Less、PostCSS 等 logo

當我聽說它們、瞭解它們、使用它們的時候,我的心情是這樣的——

插畫:小男孩在遊樂場

右邊的這個小男孩就是我。我的心情是激動、新奇、興奮。

那麼,我會在 CSS Conf 上分享它們嗎?一番思索之後,我的答案是——“不”。

有幾個原因:首先,我相信肯定會有其它同學會分享它們;此外,它們不是 CSS,它們並不能解決我們在 CSS 上遇到的問題。

灰化的各個 logo

更重要的是,它們其實跟我沒什麼關係,它們是別人寫的優秀的工具,而我只是在享受別人的發明所帶來的便利。就好像我在遊樂場 high 了一天之後,我還是我,還是要回到自己平凡的生活。

那我應該分享些什麼?我嘗試在記憶的長河中逆流而上,找尋 CSS 最初帶給我的欣喜和感動。

插畫:小男孩蹲在地上玩積木

我發現,有一件事情,即使在今天,仍然可以實實在在地帶給我樂趣——那就是用 CSS 的各種神奇的特性,實現各種神奇的效果。有些效果甚至令人驚歎——“這怎麼可能是用 CSS 實現的?!”

CSS魔法個人主頁截圖 - CSS 謎題 1

在 我的個人主頁 上,收錄了一些 CSS 謎題。所謂 “謎題”,就是需要費一番腦筋才能實現的效果。每一道題都有我自己的解答和評述。

CSS魔法個人主頁截圖 - CSS 謎題 2

在這些謎題中,收穫最多讚歎的,應該是這個案例——弧形排列的可摺疊二級導航。

弧形排列的可摺疊二級導航

這是 2009 年的時候,一位網友在論壇裡求助,說他們公司的設計師想要實現這樣一個效果。大家看到背景是一個弧形的造型,所有導航選單需要順著這個背景圖案以弧形排列。

弧形排列的可摺疊二級導航 - 紅框標註

而且,有些選單是可以展開的(上圖中加紅框的部分)。當我點選第一個可展開選單時,效果是這樣的:

弧形排列的可摺疊二級導航 - 導航展開演示 1

點選第二和第三個,展開效果是這樣的:

弧形排列的可摺疊二級導航 - 導航展開演示 2

……和這樣的:

弧形排列的可摺疊二級導航 - 導航展開演示 3

所有選單項都需要順滑地貼合這個弧形背景自然展開。

論壇裡的網友紛紛表示,這樣的效果應該用 Flash 來實現才對,用 CSS 怎麼可能做到?!

我動了一番腦筋,最終把這個效果做了出來。當然,在這個例子裡,我用到了一些 JS,用來監聽點選事件、切換元素 class;除此以外所有的元素佈局和定位都是由 CSS 來完成的,也就是說,你可以任意地改變選單項的數量和內容。

大家可以試試,在 2009 年,要相容 IE6,應該怎麼做?

今天由於時間關係,我們不會講解這個案例。我會跟大家聊一些跟 CSS 有關的趣事。我今天的分享分為兩個部分:

幻燈片大綱:一件趣事、一件樂事

第一部分會介紹一件 CSS 能做的有趣的事情;第二部分是我最近遇到的一件值得高興的事情。

首先,這件趣事就是用 CSS 畫圖示。

CSS 圖示

請問現場有哪些同學嘗試過?(僅前三排就有多人舉手。)好的,試過的同學接下來一定會找到很多共鳴。

有同學可能會問:

為什麼要用 CSS 畫圖示?

我這裡不想找一些技術上的原因,單從感性的角度來回答這個問題。

為什麼要用 CSS 畫圖示? - 好玩!

它太好玩了!只有你試過,你才知道它有多好玩。

有一句話,大家可能聽過,是說 JS 的:

“所有可以用 JS 寫的專案,最終一定會用 JS 重寫一遍”

我這裡借用這個句型,說一個 CSS 的版本:

“所有可以用 CSS 畫出來的圖形,最終一定會用 CSS 再畫一遍”

不信?我們來看一些例子:

機器貓

在 CSS3 剛開始火起來的時候,大家肯定見過這張圖——用 CSS3 畫的機器貓。

iPhone 3GS

用純 CSS 畫的 iPhone。

小黃人

用 CSS 畫的小黃人。

很多公司的 logo 也是很有特點的,也被網友用 CSS 畫了出來,比如 Opera 的 logo:

Opera logo

最神奇的是下面這個:

IE8 logo

(笑聲。)

居然還有網友用 CSS3 畫了一個 IE8 的圖示。不過,諷刺的是,IE8 自己完全沒有能力正常渲染這個圖示。(笑聲。)

這件事情這麼好玩,我自己當然也是做過的。

CMUI demo 頁面截圖

我寫過一個移動端的 Web UI 框架叫 CMUI,在最初的版本中,圖示的解決方案 就是用純 CSS 來實現的。

我們來看一下用 CSS 畫圖示會用到哪些基本原理。

黑色矩形

怎樣用 CSS 來畫一個矩形?這沒有任何難度,因為任何一個塊元素本身就是矩形。

改變它的寬高,把它拉長,就可以得到一條線:

黑色水平線

那怎樣得到一個三角形?

黑色三角形

在早期的 CSS 中,沒有任何特性是跟斜線直接相關的。但你要相信勞動人民的智慧是無窮的。很快 CSS 開發者們就發現了關於邊框的一個祕密。

黑色方框

這是一個加了邊框的塊元素。當我們把四個方向上的邊框設定為不同的顏色時,效果會變成這樣:

四邊為彩色邊框的矩形

我們會發現,在不同邊框顏色的交界處,出現了一道斜邊。接下來,我們逐漸減小這個元素的寬高至零,同時增加各條邊框的厚度,最終會變成這個樣子:

四個彩色三角形拼合的矩形

我們會得到四個頭對頭的三角形!

接下來,我們用透明色把不需要的三條邊框隱去,就可以得到一個三角形:

綠色三角形

通過改變這個元素各條邊框的厚度,就可以改變這個三角形各條邊的角度。我們可以得到銳角三角形:

綠色三角形 - 頂角為銳角

……或者直角三角形等等。

綠色三角形 - 某個角為直角

以上是在 CSS2 時代用 CSS 畫圖示時我們可以做的。CSS3 為 CSS 增加了更加強大的能力,我們看來一個例子:

方框、圓角框、圓形

CSS3 增加了圓角屬性,給一個矩形設定圓角,可以得到一個圓角矩形;逐漸增加圓角半徑到一定的程度,我們就可以得到一個圓形。

線段、圓頭線段、斜 45° 的圓頭線段

圓角除了對邊框有效,還可以對實色矩形生效。比如這條短線,我們可以把它設定為圓頭的樣式;CSS3 還增加了旋轉這樣的變形屬性,我們可以把它扭轉一定的角度。

把這兩個圖形組合起來,我們就可以得到……

放大鏡圖示

一個放大鏡的圖示。

根據這個思路,常見的圖形都可以拆解開來,化整為零,用 CSS 畫出來。比如下面這個:

加號

……這個:

房子

……和這個:

卡通小人半身像

下面這個圖示稍稍有些複雜:

iOS 6 的動作圖示

你可能會想,它居然也可以用 CSS 畫出來?

我們先從簡單的開始。三角形我們已經介紹過了,所以先把它隱去:

iOS 6 的動作圖示 - 隱去三角形

再來看外層的那個有斜向缺口的矩形框。斜角缺口也需要利用邊框交界處的斜邊來實現,不過這個框無法用一個元素來實現,我們需要分兩步走。完成一邊:

iOS 6 的動作圖示 - 隱去部分外框

……再完成一邊:

iOS 6 的動作圖示 - 隱去外框

最後我們剩下的難題似乎就是這個奇怪的形狀了,好像是個鷹嘴的樣子。

類似鷹嘴的圖形

這個形狀如何實現?給大家五秒鐘的時間考慮一下。

在揭開謎底之前,我們需要了解一下:

關於圓角的兩個真相

這裡有一個塊元素,設定了邊框和圓角,它的兩條邊框會通過一段圓弧連線起來:

邊框和圓角

首先,第一個真相,邊框圓角可以指定兩個半徑值(下圖中的 r1 和 r2):

邊框和圓角 - 標示圓角的半徑

如果這兩個半徑值相等,則連線兩條邊框的圓弧就是一條相標準的 1/4 圓弧。如果不相等(比如我們把 r2減小),會得到這樣的效果:

邊框和橢圓圓角

我們發現連線兩條邊框的圓弧會變成一道 1/4 橢圓弧。這個真相解決了我們在尺度上的問題。接下來,我們需要解決形狀上的問題。

第二個真相,不同方向上的邊框的厚度(下圖中的 w1 和 w4)也是可以不一樣的:

邊框和圓角 - 標示邊框的厚度

如果我們逐漸減小 w4 的值至零,我們會得到這個形狀:

類似鷹嘴的圖形,末端延長

大家應該可以看出,我們需要的形狀已經出現了。最後,我們調整一下這個元素的寬高,只保留我們需要的部分,就可以得到這個鷹嘴的形狀。

類似鷹嘴的圖形

最終,我們就實現了這個乍看起來不可能用 CSS 實現的圖示。

iOS 6 的動作圖示

看到這裡,可能有同學會說:

“奇技淫巧”?

“你這是奇技淫巧啊!”

事實上,我們剛剛介紹的技巧都是標準的 CSS 特性。只有那些對 CSS 的各種特性觀察入微的人,才有可能在非常規的場景之下把這些特性發揮出來,從而完成不可能完成的任務。——這是我對所謂 CSS “奇技淫巧” 的理解。

說到 CSS 圖示這件事,有一個網站不能不提。

one-div.com 網頁截圖

這個網站叫 one-div.com,收錄了這位站長製作的純 CSS 圖示。這個網站最大的特點在於,所有的圖示只用到了一個 <div> 標籤。(驚歎聲。)很有創意,推薦大家觀摩。

用 CSS 畫圖示這麼好玩的事情,肯定不止我和這位站長會想到。我們搜尋 “純 CSS 圖示” 這個關鍵字,可以發現有很多的案例和開源專案。

Google 搜尋結果截圖 1

當然,我們也會聽到反對的聲音。比如這一條:

Google 搜尋結果截圖 2

“用 CSS 畫圖示,這種瘋狂的事情趕快停止吧!”

大家玩得這麼開心,你一本正經地來教育大家,很無趣,對吧?當然,這篇文章的觀點肯定有它的道理,但任何一門技術都是有優點和缺點的,要看使用場景。比如,下面就是一個正面的例子:

fileicon.css 專案主頁截圖

這是一個開源專案,叫 fileicon.css,作者是中國人。

為什麼說它是一個正面的例子呢?因為,作為一個樣式庫,它的介面非常清晰。

程式碼

你只需要使用一個空元素,再加上一些有意義的屬性就可以了。

然後,你就可以得到一個設計精緻的檔案圖示了——它有著優雅的圓角,還有一個可愛的折角效果。

檔案圖示

我很喜歡這個專案。

不過在現有的版本中,它有一個小缺憾——只能把它放在純白的背景上。如果你把它放在其它背景上,會發現它的折角的空缺位置是不透明的:

檔案圖示與透明背景

實際上能做到這一步已經很不容易了。大家可以自己試一下,用一個空標籤把這樣的圖示做出來。

我很喜歡這個專案,於是我花了一點時間,給作者寫了一個 demo。我用了一些 CSS 奇技淫巧,把折角處做成了真正的透明:

檔案圖示與透明背景

同時,我還順手支援了 IE8。

檔案圖示與透明背景

因為 IE8 支援偽元素,我們沒有理由放棄它。只不過 IE8 無法渲染圓角,我們在 IE8 下只有方角效果了。

笑臉

好的,以上就是我的分享的第一部分——CSS 圖示。

(掌聲。)


鳴謝

  • 插畫作者:小妖(百姓網設計師)

相關文章