原始碼分析:如何定製Semantic-UI

MasterOfPuppets發表於2018-05-30

SemanticUI簡介

我來現在就職的這家公司之前,只使用過Bootstrap,並不知道SemanticUI。後來接手了現在的專案之後才知道有這麼個框架。相比於盛行的Bootstrap,SemanticUI有它的值得使用的地方。

  • SemanticUI 像它的名字一樣。更加語義化。
  • 預設的樣式比Bootstrap好看很多,更加鮮明活潑。個人感覺。
  • 類名比Bootstrap短。並且更加離散。巢狀層級也少很多。

但是它有一個很讓人頭疼的缺點,就是對開發者的種種不友好。

  • 文件不夠詳細,很多模組的使用方法都是寥寥數語,或者放的地方很深。需要依靠你自己的程式設計經驗去猜。
  • 模組定製並不像Bootstrap那樣可以直接勾選自己需要的模組然後打包。在SemanticUI中,你必須在npm安裝過程中選擇要安裝哪些模組。
  • yarn不友好。如上一條,npm中可以在過程中選擇安裝哪些模組。但是SemanticUI的安裝指令碼不被yarn所識別。必須yarn add semantic-ui --ignore-scripts才可以。新增了ignore-scriptes選項自然也就喪失了定製化的功能。由於我現在用的框架是RoR,預設使用的前端管理工具就是yarn,所以感覺很難受。

以上只是隨便說了說SemanticUI與Bootstrap的區別,並不全面。因為這不是本文主要內容。

定製SemanticUI

有時候我們希望全域性地定製SemanticUI。比如SemanticUI的預設字型大小為14px。而我們的專案預設大小為12px。在我接手專案的時候,諸如此類與框架提供樣式相悖的樣式都是直接在一個init.scss檔案中進行覆蓋來重置。感覺很醜,也會造成程式碼的冗餘。

但是由於剛接手時並不瞭解SemanticUI,而且我身為一個前端程式設計師入職時居然直接讓我上手開發Rails應用,手忙腳亂的我全身心都在學Rails根本沒時間考慮這個問題。並且,在SemanticUI 官網中不能很容易地找到定製的方法(其實是有的,但是東一塊西一塊很難系統地貫穿起來)。所以我也就照著原來的樣子做了這個專案一年。

init.scss中有些樣式難以找到原來定義的地方,覆蓋非常困難。chrome-dev-tool看穿了才會在一個六七行的選擇器後面找到這個樣式的定義,然後加一下權重進行覆蓋 —— 就是再寫一個六七行甚至七八行的選擇器。不想再說了,痛苦。

最近老闆發話了,要做前端的大改版。我終於有機會也有時間進行大重構了。過程可能會跟撕痂一樣痛苦,但結果一定會跟撕完了一樣爽

如何入手

我是在SemanticUI的Github的src資料夾中看到了這個README.md才知道怎麼做的。

裡面講了一些如何重置SemanticUI預設樣式,構建適合自己專案的SemanticUI的方法。我一眼就看到了底下的一些關鍵詞resetfont size。驚呆了,原來在這。於是細細地讀了起來。

這篇README講了什麼呢?

  1. 如何構建SemanticUI。直接gulp install
  2. 可以監控檔案實時構建。gulp watch
  3. 配置檔案的位置。
  4. 工作流。使用構建工具構建你專屬的SemanticUI並在專案中直接使用構建完成的定製包。
  5. 主題化。
  6. 定製化。

我們要做的是定製自己的主題,自己的UI規範(字型大小,字型顏色,行高,一級二級三級主題色等等...)。所以我們可以先從5和6入手。

主題與樣式的層級關係

主題的定義檔案有一定的層級關係:

  1. SemanticUI的預設主題。就是什麼也不設定一路回車然後直接構建直接使用的主題。
  2. SemanticUI提供的可選的預置的主題包。比如amazon主題或者material主題。
  3. 元件自有的主題。比如全域性主題色是#f5f5f5,但是primary按鈕元件自己的主題色是藍色,則以藍色為準。
  4. 你自己定製的主題。

某個元素應用的主題,是以上面四條倒序查詢的。你自己定製的主題優先,沒定製則尋找可選主題。如果沒進行任何設定,則使用預設主題。

目錄結構

以上的主題都是在哪裡定義的呢?我們如何修改它?文中提到了目錄結構。

  • src/definitions 資料夾中定義了每個元件使用的jscss
  • src/themes 中存放了SemanticUI提供的所有可用的主題。在我們構建時可以選擇一個來使用。預設主題也在這裡面。
  • src/site 你的專有主題。

原始碼驗證

我們先開啟src/semantic.less檔案。在檔案的最頂部有這樣的語句:

& { @import "definitions/globals/reset"; }
複製程式碼

這裡匯入了一個reset檔案到當前的semantic.less。我們來看一下reset中都有什麼。首先,reset檔案的頂部定義了兩個變數,一個叫做@type一個叫做@element

@type    : 'global';
@element : 'reset';
複製程式碼

緊接著匯入了主題配置檔案:@import (multiple) '../../theme.config';。在這個配置檔案中我們又看到了如下兩個變數:

/* Global */
@site       : 'default';
@reset      : 'default';

...... ......

/*******************************
            Folders
*******************************/

/* Path to theme packages */
@themesFolder : 'themes';

/* Path to site override folder */
@siteFolder   : 'site/';
複製程式碼

註釋寫的很清楚了,是資料夾路徑變數。分別是主題包路徑和覆蓋檔案的路徑。這兩個路徑在哪裡被用到了呢?繼續看這個檔案,在最底部,引入了一個theme.less檔案。該檔案中有這樣一段程式碼:

/*--------------------
   Site Variables
---------------------*/

/* Default site.variables */
@import "@{themesFolder}/default/globals/site.variables";

/* Packaged site.variables */
@import "@{themesFolder}/@{site}/globals/site.variables";

/* Component's site.variables */
@import (optional) "@{themesFolder}/@{theme}/globals/site.variables";

/* Site theme site.variables */
@import (optional) "@{siteFolder}/globals/site.variables";
複製程式碼

註釋表明是網站變數。裡面用到了上一個檔案theme.config中定義的四個變數。指向了四個路徑引入了四個檔案。到這裡你應該意識到了,我們重置樣式的地方應該就在這些地方。

請注意這四個檔案的順序:

  1. default網站變數。
  2. 可選包網站變數。
  3. 元件自己的變數。
  4. 你自己定製的網站變數。

由於CSS的特性,層級一樣的重複宣告的樣式是後蓋前。所以以上檔案以後面的為準。即,最權威的是你自己定義的樣式。這與之前所說的主題層級的載入優先順序是吻合的。

回顧一下theme.config。這裡定義的變數:

/* Path to theme packages */
@themesFolder : 'themes';

/* Path to site override folder */
@siteFolder   : 'site/';
複製程式碼

我們便知道這四個路徑都指到哪裡了。既然以我們自定義的主題為準,那麼我們直接看@import (optional) "@{siteFolder}/globals/site.variables";也就是site/globals/site.variables。裡面空空如也,只有一句註釋:使用者全域性變數。找到了!我們只要在這裡重置樣式就可以了。

定位到檔案了,該如何書寫呢?面對空空如也的檔案無從下手?通常面對這種情況,最好的做法是看它預設的檔案是怎麼寫的。

開啟src/themes/default/globals/site.variables,看到下面幾個程式碼片段,你就會茅塞頓開:

@fontName          : 'Lato';

......


@emSize   : 14px;

@fontSize : 14px;
......

@primaryColor        : @blue;
@secondaryColor      : @black;

......

複製程式碼

以字型大小為例,如果我們要更改我們全域性的字型大小,以12px為基準。我們回到我們空空的site/globals/site.variables檔案。新增如下程式碼:

@emSize   : 12px;

@fontSize : 12px;

複製程式碼

這樣我們就完成了樣式覆蓋,使用12px作為基準字型大小了。

舉一反三

我們已經會了如何定製全域性的樣式。那麼一些特殊化的定製要如何完成呢?比如,全域性字型大小為12px,但是產品和UI要求了,所有的按鈕內字型都要是14px

其實根據上面的經驗,我們的做法還是一樣的。

首先開啟src/site/elements/button.variables。熟悉的一幕又出現了:只有一句註釋。再開啟src/themes/default/elements/button.variables又看到了令人興奮的片段(別想歪):

/* Button */
@verticalMargin: 0em;
@horizontalMargin: 0.25em;
@backgroundColor: #E0E1E2;
@backgroundImage: none;
@background: @backgroundColor @backgroundImage;
@lineHeight: 1em;
複製程式碼

咋整?回到那個空檔案進行變數覆蓋呀~就這麼簡單。

最後一步

已經對預設的樣式進行覆蓋了,是時候打包我們自己的SemanticUI了!

gulp clean
gulp build
複製程式碼

打包成功後使用時會發現,樣式乖乖的都按規定走了。再也不用寫七八行的選擇器了。爽。再見了init.scss

討論

有的人說了,既然都動了原始碼,幹嘛不直接在src/themes/default/elements/button.variables改了算了。有兩個原因不這麼做:

  1. 不講道理的原因:官方說了你最好在自己的重置檔案裡寫。
  2. 因為你在自己的重置檔案裡寫,知道自己重置了哪些樣式,而直接修改原來的,就啥也不知道了。

學會了這種方式以後,你就可以基於SemanticUI進行“二次開發”,打造適合你的SemanticUI框架。

安利

醜爆手搭部落格瞭解一下:http://qxchenblog.cn

相關文章