[譯] 再談 CSS 中的代碼味道

duduwenku 7年前發布 | 15K 次閱讀 CSS 前端技術

談 CSS 中的代碼味道

回到 2012 年,我寫了一篇關于潛在 CSS 反模式的文章 CSS中的代碼味道 。回看那篇文章,盡管四年過去了,我依然認同里面的全部內容,但是我有一些新的東西加到列表中。再次說明,這些內容并不一定總是壞的東西,因此把它們稱為代碼味道:在你的使用案例中它們也許可以很好的被接受,但是它們仍然讓人覺得有一點奇怪。

在我們開始前,讓我們回想一下什么是代碼味道,摘自 維基百科 (emphasis mine):

代碼味道,也被稱作代碼異味,在計算機編程領域,指程序源代碼中的任何 有可能預示著更深層次問題 的征兆。按照 Martin Fowler 所說的,「代碼味道是一種表面跡象,通常對應著系統中的深層次問題」。另外一種看待代碼味道方式是關于準則和質量:「代碼味道是代碼中某種特定的結構表明了 違反了基本的設計準則 并且對設計質量產生負面影響」,代碼味道通常不是 bug —— 它們不是技術性的錯誤 并且不會當時就對程序的功能產生阻礙。相反的, 它們預示著可能拖慢開發的設計缺陷 或者增大未來出現 bug 或者故障的風險。代碼異味是導致技術債的因素的指示器。Robert C. Martin 將一系列代碼味道稱作軟件技藝的「價值體系」。

因此, 它們并不總是技術上的錯誤, (不過)它們可作為一個不錯的檢驗方法。

<h2>@extend</h2>

希望我可以把這第一條講得細致又簡潔:我早就被告知 @extend 的副作用和陷阱,我也會積極地認為它是代碼味道。它也并不絕對的不好,雖然通常是的。對它應該持懷疑態度。

<p>@extend 的問題是多方面的,可以概括如下:</p>
  • 它對性能的影響事實上比 mixins 更嚴重。Gzip 偏愛重復性的內容,所以具有更高重復性 CSS 文件 (如 mixins) 取得更高的壓縮量。

  • 它是貪婪的。Sass 的 @extend 將會 @extend 它找到的每個 class 的實例,返回給我們一個相當長的選擇器鏈 看起來像這樣 。

  • 它移動你的代碼庫的順序。在 CSS 中原始的順序至關重要,所以應該總是避免在你的項目中移動選擇器的位置。

  • 它使文件晦澀難懂。 @extend 在你的 Sass 中隱藏了很多復雜的東西,你需要逐步的拆開,然而在你審閱文件的過程中,這個復雜的 class 方法將所有的信息置于焦點。

擴展閱讀:

為類使用連接字符串

另外一個 Sass 讓人惱火的地方就是在你的類上使用 & 連接字符串,例如:

.foo {
  color: red;

&-bar { font-weight: bold; }

}</code></pre>

編譯成:

.foo {
  color: red;
}

.foo-bar { font-weight: bold; }</code></pre>

顯而易見的好處是簡潔:事實上我們只用寫一次命名空間 foo 確實是很 DRY (Don't repeat yourself)。

一個不那么明顯的缺點是,字符串 foo-bar 現在在源代碼中不存在。搜索代碼庫查找 foo-bar 只會返回 HTML 中的結果(或者是編譯過的 CSS 文件,如果你已經把它納入到你的項目中)。想要在源代碼中定位 .foo-bar 的樣式變得非常困難。

我不僅僅是 CSS 全稱寫法的愛好者:總的來說,相比于重新為元素命名一個類,我更喜歡查找到它原有的類名,所以可查找性對我來說很重要。如果我加入一個項目大量使用 Sass 的字符串連接,追蹤查找通常都會是非常艱難的。

當然你也可以說 sourcemaps 將會幫助我們,或者如果我正在查找 .nav__item 這個類,我可以簡單的打開 nav.scss 這個文件,但是不幸的是這并不總是奏效。獲得更多的信息,可以看我做的關于它的 錄屏 。

Background 簡寫

我最近討論的另外一個主題就是使用 background 簡寫語法。想了解更多細節,請參考 the relevant article ,但是在這里做一個總結如下:

.btn {
  background: #f43059;
}

…當你可能想要表達的意思是:

.btn {
  background-color: #f43059;
}

…這是另一種代碼味道的實踐。當我看到前者被使用的時候,很少是開發者實際上想要的:幾乎任何時候他們真正的意思是后者。后者 僅僅 設置或者改變背景色,而前者將會也重置或者復原背景圖、背景位置、背景鏈接等。

在 CSS 項目中看到這樣的形式立即提醒我,我們終究會因為它遇到問題。

關鍵選擇器多次出現

關鍵選擇器是獲得目標或者是被賦予樣式的選擇器。它通常在左花括號 ( { ) 前面的內容,但也并不總是。在下面的 CSS 中:

.foo {}

nav li .bar {}

.promo a, .promo .btn {}</code></pre>

…關鍵選擇器是:

  • .foo ,
  • .bar ,
  • a ,
  • .btn .

如果我負責一個代碼庫并且 ack for .btn ,我可能看到如下輸出:

.btn {}

.header .btn, .header .btn:hover {}

.sidebar .btn {}

.modal .btn {}

.page aside .btn {}

nav .btn {}</code></pre>

除了很多普遍存在的相當糟糕的 CSS,我在這里想指出的問題是 .btn 被定義了很多次,這告訴我:

  1. 沒有遵循 Single Source of Truth 告訴我按鈕看起來是什么樣的;
  2. 有很多變化 意思是 .btn 類有很多潛在的不同的樣式,所有的這些都是通過 CSS 的可變性造成的。

一看到像這樣的 CSS,我就意識到在按鈕上做任何工作都將會有很大的影響,追蹤按鈕樣式到底來自哪里將會非常困難,并且任何位置的改動都有可能對其他地方造成影響。這就是 CSS 可變性的關鍵性問題之一。

使用 BEM 的命名形式以便創建全新的類名稱以應對這些改變,例如:

.btn {}

.btn--large {}

.btn--primary {}

.btn--ghost {}</code></pre>

每個只有一個關鍵選擇器。

一個類名出現在另一個組件的文件中

在一個和上面相似但是稍微不同的場景里,類名出現在另一個組件的文件中預示著代碼味道。

上一個代碼味道處理同一個關鍵選擇器有多于一個實例的問題,這個代碼味道處理這些選擇器應該放在哪。這個問題來自于 Dave Rupert

如果我們需要給某些因為它們的上下文的不同而加樣式,我們應該把這些額外的樣式加到哪呢?

  1. 要加樣式的對象所在的文件里?
  2. 控制該對象上下文的文件里?

讓我們假設我們有如下 CSS:

.btn {
  [styles]
}

.modal .btn { font-size: 0.75em; }</code></pre>

.modal .btn {} 應該放在哪?

它應該 在 .btn 所在的文件中。

我們應該盡量將我們的樣式基于主題(例如:關鍵選擇器)分組。在這個例子中,主題是 .btn :這才是我們真正關心的。 .modal 只不過是 .btn 的上下文,所以我們根本沒給它添加樣式。為此,我們不應該將 .btn 的樣式移出到另外的文件中。

我們不這樣做簡單的因為它們是并列的:將所有按鈕的上下文放在一處更方便。如果我想得到項目中所有按鈕樣式的概觀,我僅僅需要打開 _components.buttons.scss ,而不是一堆其他的文件。

這樣做使得將所有按鈕的樣式移入另外一個新項目變得更容易,更重要的是這樣做提前讀懂變得容易。我相信你們都對這種感覺相當熟悉,就是文本編輯器中打開十余個文件,而僅僅試圖修改很小的一處樣式。這是我們能夠避免的。

將你的樣式基于主題的分組到文件中:如果是給按鈕的樣式,無論它是什么樣的,我們應該讓它在 _components.buttons.scss 文件中。

一個簡單的經驗法則就是,問問你自己這樣的問題,我是在給 x 添加樣式還是 y?如果答案是 x,那么你的 CSS 應該在 x.css 文件中;如果答案是 y,它應該在 y.css 中。

BEM Mixes

事實上很有趣的,我根本不會這樣寫 CSS —— 我使用 BEM mix —— 但是這是另一個不同問題的答案。不是像下面這樣:

// _components.buttons.scss

.btn { [styles] }

.modal .btn { [styles] }

// _components.modal.scss

.modal { [styles] }</code></pre>

而是像這樣:

// _components.buttons.scss

.btn { [styles] }

// _components.modal.scss

.modal { [styles] }

.modalbtn { [styles] }</code></pre>

第三,新的類名稱將會應用于 HTML 上,像這樣

<div class="modal">
  <button class="btn  modalbtn">Dismiss</button>
</div></code></pre> 
  

這被叫做 BEM mix,我們介紹第三種新的類名稱來指向屬于 modal 的按鈕。這樣避免了它在哪里的問題,它通過避免嵌套,減少了名稱唯一性的問題,同時通過重復 .btn 類避免可變性帶來的問題。完美!

CSS @import

我會說 CSS @import 不僅僅是代碼味道,它的的確確是壞的實踐。它推遲 CSS 文件的加載(性能的決定性因素),比實際的需要加載的更晚,造成嚴重的性能下降。下載具有 @import 的 CSS 文件的(簡化的)工作流程看起來有點像:

  1. 獲取 HTML 文件,這個 HTML 文件中請求 CSS 文件;
  2. 獲取 CSS 文件,這個 CSS 文件請求另外一個 CSS 文件;
  3. 獲取最后一個 CSS 文件;
  4. 開始渲染頁面。

如果我們得到 @import 的內容,將其壓入一個單獨的文件,工作流程看起來將會是這樣:

  1. 獲取 HTML 文件,這個 HTML 文件中請求 CSS 文件;
  2. 獲取 CSS 文件;
  3. 開始渲染頁面。

如果我們不能將所有的 CSS 放入一個文件(例如我們鏈接了谷歌字體),那么我們應該在 HTML 中使用兩個 <link /> 元素,而不是使用 @import 。這可能讓人感覺有點不那么壓縮(但也是更好的方式處理所有 CSS 文件的依賴),它對于性能仍然是比較友好的:

  1. 獲取 HTML 文件,這個 HTML 文件中請求 CSS 文件;
  2. 獲取所有的 CSS 文件;
  3. 開始渲染頁面。

所以我們在這里對我先前那篇關于代碼味道的文章做了幾點添加。這些是我已經看到的并且忍受著的幾點:希望現在你也可以避開他們。

 

來自:https://juejin.im/entry/58c2042cda2f600d8722131b

 

 本文由用戶 duduwenku 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!