揭祕GitHub CSS技術細節

伯小樂發表於2014-08-25

伯樂線上注:這篇文章翻譯自Bootstrap作者之一:Mark的博文。Mark目前在GitHub工作,他在這篇文章中分享了GitHub在CSS方面使用的相關技術。如果你對CSS感興趣,但還不熟悉它,推薦看看這篇文章《快速學習和實踐CSS/CSS3的線上教程》。另外,Mark在文章中提到了很多工具和技術概念,並直接連結到官網。在譯文中,我修改了部分連結,指向了中文介紹頁面(含官網地址),方便大家快速地瞭解。這篇文章涉及到很多方面,如果你發現翻譯不恰當的地方,請在評論中指正。謝謝!

以下是譯文正文

對其他產品的開發細節,我一直都非常感興趣,尤其是他們的樣式指南和使用CSS的方式。所謂己所欲施於人,於是我決定分享一些關於GitHub CSS方面的東西。

GitHub CSS 概覽

  • 前處理器選擇了SCSS
  • 遠超過100多個的獨立樣式原始檔,這些原始檔編譯後再發布到生產環境。
  • 為了規避IE<10的樣式規則限制(詳見補充1),編譯後的CSS分割成2個樣式檔案。
  • 兩個樣式檔案總共的大小在90KB左右。
  • 沒有用到特別的“CSS 架構”。
  • 使用px(畫素)作為單位,同時有些地方也用到了些 em。
  • 使用 Normalize.css 和 我們自定義的CSS重置樣式。

前處理器

前面已經提到了,GitHub使用SCSS作為前處理器。早在我加入GitHub之前就選擇了它,儘管Boostrap目前使用的是LESS,我對SCSS也覺得Ok(譯註:本文的作者Mark Otto是Bootstrap的作者之一)。我們的SCSS使用了Rails asset pipeline編譯,同時也用上了Sprockets來檢查包含檔案的依賴關係。(譯註:如果你對Bootstrap感興趣,這裡關聯推薦一門免費的線上課程《玩轉Bootstrap》)

那麼LESSStylus,或者其他的前處理器呢?我並不認為LESS之前在GitHub作為前處理器的一個備選,但我確實不好去評價這個。目前來看,我們可能也不會去切換,畢竟沒有什麼顯而易見的益處。

為什麼要用前處理器?我們內部的框架包含了一系列相關的變數(例如:font stacks, brand colors)和 混合(mixins),可以讓你更簡單、更快捷地編寫程式碼。

因為Autoprefixer基本上讓我們現有的mixins全部都失效,我們目前還沒有使用Autoprefixer,但真應該用起來。希望我們能儘快用上它。

我們目前也沒有使用Source Maps,但很快會有所改變。(注:Source Maps很酷,它可以提供將編譯和壓縮的樣式檔案對映到原始檔原始位置)

除此之外,我們使用SCSS提供的工具非常有限,包括:顏色變數, mixins, 顏色函式, 數學函式 和 巢狀。我們確實不需要class的迭代, 設定全域性配置項 和 其他的部分。

模式(原文是Architecture,這裡翻譯成模式更貼切)

常用的CSS模式包括BEMOOCSS。我們偏向於OOCSS,但我們沒有整體的去研究。我們傾向於採用基本的方式來編寫CSS程式碼:(譯註:剛開始聽到CSS架構時,有點疑惑。CSS怎麼也有架構?看過BEM和OOCSS後,才清楚CSS架構其實是編寫CSS程式碼的一種模式。)

  • 在選擇器(selectors)中,把優先使用類(classes)
  • 避免沒有必要的巢狀
  • 在class name中使用單破折號
  • 儘可能保持簡短,避免困惑

我以後會在其他文章中寫更多關於我推薦的CSS模式。這篇文章中,上面這幾點概括了GitHub團隊編寫CSS的規範,雖不完美,但基本意思都到了。

CSS檢測 (Linting)

我們是幾周前才開始檢測我們的SCSS (SCSS-lint)。即使我們有了足夠通用的慣例,每個人的樣式和格式都多少有些獨特。現在,每個持續整合(CI)構建包括基本的SCSS檢測,出現一下情況就會報錯:

  • 在你的CSS有一個class,但在 app/views/ 模板中沒有用到。
  • 相同的selector(選擇器)使用了多次(它們應該合併到一起)。
  • 違反了常規的格式化規則(巢狀限制,rulesets之間的換行,:s後面缺少空格,等)

總而言之,上面這幾個規則讓我們的程式碼保持整潔。

兩個包(Two bundles)

GitHub.com 有2個CSS包, githubgithub2。幾年前,這個拆分是為了解決IE 4095 個選擇器限制的問題,針對的是 IE9及IE9以下的版本。目前,GitHub要求訪問的IE瀏覽器是IE 9和IE 9+版本,所以,這個拆分仍然必須保留。

在GitHub的這兩個CSS檔案中,目前有7000左右的選擇器。下面我們對比一下其他網站或框架有多少個選擇器。

  • Bootstrap v3.2.0 :~1900
  • Twitter:~8900
  • NY Times: ~2100
  • SoundCloud: ~1100

這些資料是藉助cssstats獲取到的。這是一個很棒的小工具!

通過Sprockets include

GitHub的CSS和JS都是通過Sprockets和require來include。我們通過app/assets/stylesheets目錄下面的不同子目錄,維護著我們的2個CSS 包。
/*
= require primer/basecoat/normalize
= require primer/basecoat/base
= require primer/basecoat/forms
= require primer/basecoat/type
= require primer/basecoat/utility
= require_directory ./shared
= require_directory ./_plugins
= require_directory ./graphs
= require primer-user-content/components/markdown
= require primer-user-content/components/syntax-pygments
= require primer/components/buttons
= require primer/components/navigation
= require primer/components/behavior
= require primer/components/alerts
= require primer/components/tooltips
= require primer/components/counter
= require primer-select-menu
= require octicons

= require_directory .
*/

Primer 是我們內部的一個框架,我們先include了它們,然後匯入了整個目錄的SCSS檔案(順序由Sprockets決定,我相信是按字母先後順序)。通過 require_directory . 來包括我們的樣式表很棒,但也有點糟糕。

樣式的生效順序也很重要。這其實真不應該,但在每個設計系統,都有一些規則和基本的樣式層級關係。使用Sprockets,我們有時會陷入一些怪異的問題。之所以會遇到這種問題,是因為新的檔案在任何時候都可以加入到其中任何一個bundle。取決於它們的檔名,它們將出現在已編譯的CSS檔案的不同的地方。

另外,使用Sprockets意味著你的SCSS檔案不能立即和自動地訪問你全域性的變數和mixins。也就意味著你不得不在那些引用了一個變數或者mixin的檔案頂部,顯示地 @import 它們。

不斷地被這些偶然出現的怪異問題困擾後,我們提交了一個 request,改成顯式地 @import。增加的好處是更加清晰地洞察我們的CSS,更方便地嘗試上述提到的bundles。以此同時,不好的一面是不得不去維護一個列表,但我卻認為這樣增加了對整個系統的掌控。

效能

Bundle大小和選擇器的統計圖

我們內部使用很多圖形來監控網站和API的運作。我們也跟蹤一些有趣的前端狀態資料。比如:這是我們兩個CSS bundles在過去3個月的大小變化。

github-bundles-sizes

類似的統計,這是在我們的blob(file)頁面的選擇器,最近一個月的數量變化。很顯然,我們仍然有很多工作要做,以降低 tag selectors。

github-selector-count

因為我們定期第部署更新的CSS(每天部署幾十次),我們經常把超大CSS檔案上的的快取弄爆掉。我們還沒有怎麼去優化這些檔案的大小或者限制cache busting,但已經開始深入去解決這些問題。

在Twiiter我們曾經有2個bundles,core和more(不知道現在是否還有)。core確保發出第一條tweet所需要的樣式儘可能地少,而其他的樣式則放到more。在GitHub,我們對bundle的劃分有點武斷,

一般來講,selector的效能並非我自己所關注的。我們意識到一些糟糕的實踐方式:巢狀,ID,元素等等。但我們並沒有去過度優化。其中一個例外就是在 diff 頁面。由於在顯示diff時需要擴充套件的描述,我避免類似這樣的屬性選擇器[class^=”octicon”]。如果過多地使用,這些屬性選擇器會導致瀏覽器崩潰。

GitHub的一位同事,Jon Rohan,有一個和GitHub CSS效能有關的演講,非常棒!感興趣的可以從這裡看看。

文件

github-styleguide-buttons

提到文件,我們目前做的還湊合,但已經在做一些改進。我們有一個對外公開訪問的CSS樣式指南,寫CSS的通用規則和一些元件例項都放在那裡。指南用KSS生成。

I還不完善,但可以給大家(這裡應該指的是GitHub的團隊成員)作為參考。尤其是新員工指導方面,想他們展示我們如何把事情做的更高效(就像我2年前加入GitHub一樣)。

Primer

github-primer

我之前提到了Primer,如果大家還不瞭解,我介紹一下:Primer是我們內部的一個框架,用於那些公開或者內部的應用的公共樣式和元件。包括:

  • Normalize
  • 盒子大小,排版,連結等方面的全域性樣式
  • 導航
  • 表單
  • 格子系統
  • Markdown樣式
  • 自定義選擇選單

Primer在GitHub.com, Gist和幾個內部的APP中都用到。一般來講,如果一個樣式能夠(或者應該)在其他的應用中使用,我們會考慮把它加入到Primer。

Primer大部分的元件都放到了我們的樣式指南中(比如:導航條、工具提示條等)。不過,最近我在改進Primer,樣式指南中的很多內容不穩定,但我們會盡快更新,把Primer最新的內容包括進來。

有人問Primer是否能開源,我也希望如此,但是一時半會還無法將Primer開源。

重構

在GitHub,我們的程式碼(包括CSS)都是共享的。和大型的開源專案不同,我們沒有嚴格的版本規則,我們會定期的清除垃圾程式碼。通過以下兩種方式來找到刪減的部分。

手工找到那些看起來類似,但卻用著不同的HTML和CSS的東西,然後合併它們。

通過執行一個指令碼在CSS中查詢一個class,看看它在views在是否已經存在。(最近,我們把這個加入到CI測試中,現在經常會看到它)

重構CSS的實際過程並不獨特。發現並清楚垃圾程式碼,提交一個PR(pull request),通知CSS團隊,儘快釋出。至少說誰刪除程式碼,團隊的任何人都可以。

伯樂線上補充:

1)IE<10樣式規則限制。詳見這裡
對於IE 10 以下版本的IE瀏覽器,樣式表有以下限制

  • 單個樣式檔案最多隻包括 4095個規則
  • 單個樣式檔案最多隻能 @import 31個外部樣式
  • @import 最多巢狀4層

 

相關文章