組織css代碼

前言

本文主要描述的組織css的問題,文章內容整理自《前端架構設計》的讀書筆記。css

繼承與特性之爭

h2{
}
#sidebar h2{  
background:red;
}
#sidebar .calendar h2{
background:green;
}

複製代碼

上面這樣寫樣式有很大的問題,主要是咱們在樣式書寫時默認的繼承到了以前的樣式,但在特殊化的樣式時,爲了讓本身的樣式生效,又要新寫樣式進行覆蓋。html

因此列舉一下可能的問題是下面的:前端

  • 選擇器的優先級:選擇合適的優先級,查詢效率高,方便其餘人樣式覆蓋的需求
  • 顏色重置:要恢復到原來的顏色,須要進行不斷的重置或者賦值
  • 位置依賴:若是咱們的樣式移到其餘位置,那麼樣式代碼就會失效,由於嚴格依賴dom的結構和順序,不能很好的解耦
  • 多重繼承:最終元素的樣式多是層層嵌套獲得的最終樣式代碼,很是不可複用,當改變主體的樣式時,子元素都會受到影響
  • 深層嵌套:效率很是低

現代化的模塊方案

在以前的章節中,咱們講到了css不一樣的模塊化方案,那麼對於上面描述的問題,其實能夠很簡化的去解決。vue

案例代碼

你根據以上的需求按照模塊的方案和命名,去除各類依賴,最大程度使用class命名方式,減小繼承,更大程度的使用獨立樣式代碼塊,輕鬆解決了以上的問題。webpack

<h2 class="content_title"></h2>
<div class="sidebar">
    <h2 class="content_title--reversed"></h2>
    <div class="calendar">
         <h2 class="calendar_title"></h2>
    </div>
</div>
複製代碼
// 組件文件夾
.content_title{}
// 不用恢復重置樣式
.contitle_title--reverse{}
// 特殊組件的title定義
.calendar_title{
}
複製代碼

單一職責原則

好比咱們在定義標題的時候,可能有兩個模塊都用到了標題。web

<div class="calendar">
 <h2 class="primary-title"></h2>
</div>
<div class="blog">
 <h2 class="primary-title"></h2>
</div>
<style> .primary-title{ } </style>
複製代碼

可能的問題,是咱們須要在日曆或者博客的時候須要去修改這個樣式,因而你的樣式可能變成這樣的。element-ui

.primary-title{
}
.blog .primary-title{}
複製代碼

這樣的問題是會致使選擇器過多,因而咱們按照bem進一步優化。bootstrap

.calendar_header{}
.blog_header{}
複製代碼

這樣維護以後,每一個樣式塊都只負責本身的內容,除了致使代碼的重複以外沒有任何壞處。好處是若是項目嚴格執行單一職責方式,當咱們改動任何代碼的時候,不會擔憂對全局形成的影響。那麼重複的代碼怎麼解決,這個其實webpack的部分和gzip的部分已經能把咱們的代碼進行優化了。api

延伸思考:若是壓縮打包的角度能夠去掉重複代碼的部分,那麼更多角度考慮代碼的可持續、可維護就行了。數組

單同樣式來源

簡單來說,就是你的樣式代碼應該來源於儘量少的組件,最好是維護在一個class中,保證整個樣式代碼是可追溯的,也能夠預想效果的。

案例

<div class="blog">
  <div class="blog-header"></div>
</div>
<div class="calendar">
  <div class="calendar-header"></div>
</div>
複製代碼
/* calendar css*/
.calendar-header{
}
/* blog css*/
.blog-header{
}
.blog .blog-header{}
複製代碼

以blog進行title的限定,主要是限制讓字號小一點,這種的主要問題是當項目積累下來,會有不少樣式代碼散落在各個組件,這樣致使不可追溯。(補充個常識,以父元素爲何進行修飾子元素,這個稱爲樣式上下文)

那麼建議的方式是將散落在各處的代碼徹底控制在一個組件內。

組件修飾符

雖然單一組件的原則讓咱們對組件的樣式代碼封裝的很好,但仍是有一些特殊的需求,那咱們如何設計這方面的代碼呢?經過皮膚或者子模塊來實現,也能夠稱爲組件修飾符。

好比咱們針對日曆的組件,咱們須要追加一個特殊的樣式,能夠這樣實現。

.calendar-header{
}
.calendar--nested .calendar-header{
}
複製代碼

經過這樣的方式,咱們不但能夠實現皮膚的需求,也能夠實現對上下文的解耦,咱們只要關注組件須要什麼樣的特殊樣式,進行組件修飾便可,而不用依賴耦合在父容器裏。

element-ui的css

如下以element的2.4.11版本爲例,根據其api文檔以及源碼的角度爲你們分析element-ui是如何解決這些問題的。

el-button分析

  • el-button文檔地址

  • api設計規範:能夠看到button的暴露的api主要是基於屬性的

    參數 說明 類型 可選值 默認值
    size 尺寸 string medium / small / mini
    type 類型 string primary / success / warning / danger / info / text
    plain 是否樸素按鈕 boolean false
    round 是否圓角按鈕 boolean false
    circle 是否圓形按鈕 boolean false
    loading 是否加載中狀態 boolean false
    disabled 是否禁用狀態 boolean false
    icon 圖標類名 string
    autofocus 是否默認聚焦 boolean false
    native-type 原生 type 屬性 string button / submit / reset button
  • class的設計,雖然組件的設計是基於屬性的,但實際不一樣的屬性最終都是表現爲class的。那麼基於這樣的角度去設計樣式是element-ui的獨創或者是vue組件的創新麼?其實早在bootstrap裏就是這樣設計的。

    class 說明
    el-button-group 按鈕組的樣式,做爲外部容器,不對el-button產生任何樣式代碼,但對其內含有的el-button會產生垂直居中的效果,還有向右的間距,.el-button-group .el-button--primary:first-child{}
    el-button el-button--default 基本樣式,修飾符,生效規則el-button--default也是直接定義其樣式規則,不依賴於el-button
    el-button el-button--medium el-button--medium 修飾符中直接定義好尺寸的所有代碼
    el-button el-button--default is-circle 基本樣式,smacss狀態樣式 ,其中is-circle包含這個原型的所有樣式,其生效的條件是與el-button同時生效,is-disabled同理
    icon="el-icon-edit" 帶icon的部分不在button裏作特殊樣式,其樣式屬於基本樣式,可是dom結構是經過組件進行添加的,那麼其圖標的字號來源於哪裏呢?來源於el-button的基本樣式14px,因此這部分進行了解耦,不用單獨設置
  • 組件內如何根據屬性進行返回對應的class.

class="el-button"
// 能夠看到其根據傳入的各個type屬性分別將class追加到class數組之中
:class="[type ? 'el-button--' + type : '',buttonSize ? 'el-button--' + buttonSize : '',{'is-disabled': buttonDisabled,'is-loading': loading,'is-plain': plain,'is-round': round,'is-circle': circle}]"
//根據爲loading 顯示出固定的loading圖標
<i class="el-icon-loading" v-if="loading"></i>
// 根據傳入的icon以及沒有loading顯示出對應type的icon
<i :class="icon" v-if="icon && !loading"></i>
複製代碼

輕度定製的element

常常有場景咱們須要引入element-ui以後須要對其ui進行皮膚化的開發樣式,雖然element-ui有暴露其對應的組件樣式,咱們也能夠進行對應的詳細的源碼的fork並開發,但在大多數中小公司其實不用小題大作。咱們只須要根據本身的狀況,針對同樣的樣式進行全局樣式覆蓋便可。那麼,咱們項目中針對按鈕的皮膚化改變會是這樣的。

// 定義variables.scss的主題變量
// 主題色相關變量
$color-thin:rgba(60,191,196,0.1);
$color:rgba(60,191,196,1);

// customer-element.scss  主要定義已使用餓了麼組件樣式的修改
@import  './variables';
// 一個按鈕樣式的全局覆蓋
.el-button--primary{
&:hover,&:focus{
background:$color;
border-color:$color;
}
background:$color;
border-color:$color;
}
複製代碼

bootstrap的css

咱們一樣也是分析bootstrap裏的樣式使用,基本也是使用class拼盤理論的。

<div class="btn-group" role="group" aria-label="...">
  <button type="button" class="btn btn-default">Left</button>
  <button type="button" class="btn btn-default">Middle</button>
  <button type="button" class="btn btn-default">Right</button>
</div>
複製代碼

button.less樣式文件節選,能夠看到其基本樣式、嵌套內僞類的樣式,button-size的方法類,修飾符的(子模塊的)維護方式,這都是值得咱們借鑑的科學規範思想。

// Base styles
// --------------------------------------------------

.btn {
  display: inline-block;
......
  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);
  .user-select(none);
  &,
  &:active,
  &.active {
    &:focus,
    &.focus {
      .tab-focus();
    }
  }

  &:hover,
  &:focus,
  &.focus {
    color: @btn-default-color;
    text-decoration: none;
  }

  a& {
    &.disabled,
    fieldset[disabled] & {
      pointer-events: none; // Future-proof disabling of clicks on `<a>` elements
    }
  }
}

// Alternate buttons
// --------------------------------------------------
.btn-default {
  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);
}
.btn-primary {
  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);
}

複製代碼

小結

到此爲止總結的技巧點以下:固然確定還有更多的技巧等待你補充

  • 分離容器與內容
  • 單同樣式來源
  • 區分佈局與組件的角色
  • 在標記上使用單一的、扁平的標識
  • 組件修飾符

經過本文咱們瞭解並總結了css代碼的繼承與特殊化的問題,並經過上面的技巧解決了這樣的痛點,並用來顯著提高本身的代碼水平。

相關文章
相關標籤/搜索