樣式庫(kù)設(shè)計(jì)指南

前言

1、分析 Class

Class 類似于簡(jiǎn)單的 js 對(duì)象,由鍵值對(duì)組成(property & value)。

層疊樣式表( Cascading Stylesheet ,簡(jiǎn)稱CSS ), 其基本目標(biāo)是讓瀏覽器以指定的特性去繪制頁(yè)面元素,比如顏色,定位,裝飾。CSS的語(yǔ)法反映了這個(gè)目標(biāo),由下面兩個(gè)部分構(gòu)建:

  • 屬性( property)是一個(gè)標(biāo)識(shí)符,用可讀的名稱來(lái)表示其特性。
  • 值(value)則描述了瀏覽器引擎如何處理該特性。每個(gè)屬性都包含一個(gè)有效值的集合,它有正式的語(yǔ)法和語(yǔ)義定義,被瀏覽器引擎實(shí)現(xiàn)。

一個(gè) Class 所擁有的 property,表明了該 Class 所擁有的樣式屬性, value 則代表了該 Class 所擁有的樣式屬性的具體表現(xiàn)。

.Class {
    property: value;
}

CSS 樣式有一個(gè)覆蓋的規(guī)則,默認(rèn)遵循的是后來(lái)者居上。

.Class1 {
    width: 100px;
    width: 50px;
}

.Class2 {
    width: 100px;
}

.Class2 {
    width: 50px;
}

此時(shí), Class1Class2 實(shí)際表現(xiàn)出來(lái)的樣式都是width: 50px;。

不過(guò),凡事總會(huì)有特殊情況,

.Class1 {
    width: 100px !important;
    width: 50px;
}

.Class2 {
    width: 100px !important;
}

.Class2 {
    width: 50px;
}

在這種情況下, Class1Class2 實(shí)際表現(xiàn)出來(lái)的樣式都是width: 100px;


由于!important的壓倒性實(shí)力,以及對(duì) CSS 樣式表現(xiàn)的破壞性, 不可隨意使用!important ,需要嚴(yán)格注意使用的場(chǎng)景以及使用的方式。

  • Never 永遠(yuǎn)不要在全站范圍的 css 上使用 !important
  • Only 只在需要覆蓋全站或外部 css(例如引用的 ExtJs 或者 YUI )的特定頁(yè)面中使用 !important
  • Never 永遠(yuǎn)不要在你的插件中使用 !important
  • Always 要優(yōu)化考慮使用樣式規(guī)則的優(yōu)先級(jí)來(lái)解決問(wèn)題而不是 !important

2、分析 property & value

首先,需要明確幾個(gè)概念:初始值,繼承,計(jì)算值應(yīng)用值。

參照 MDN

Property

TODO


Value

在 js 中,有多種數(shù)據(jù)類型,比如:String 類型,Object 類型,Number 類型。

在 CSS 中,同樣也有數(shù)據(jù)類型,通常稱之為數(shù)據(jù)格式,即 Data types 。

常用的 CSS 數(shù)據(jù)格式,有如下幾種。

<number> 表示數(shù)字,整數(shù)或小數(shù)。

10, 0.5, -1

<length> 表示距離尺寸。

100vw, 100vh, 16px, 1em, 1rem

<color> 表示顏色。

#f03, #F03, #f03f03, #F03F03

rgb(255,0,0), rgba(255,0,0,1)

hsl(0,100%,50%), hsla(0,100%,50%,1)

其他的就不列舉了,可參照 MDN


組件樣式庫(kù)的設(shè)計(jì)

1、如何解構(gòu)組件,如何規(guī)劃組件,如何分析組件)

從 HTML 標(biāo)簽的角度來(lái)考量,組件是可以分成兩種的,分別是: 多標(biāo)簽組件單標(biāo)簽組件。

  • 對(duì)于單標(biāo)簽組件來(lái)說(shuō),結(jié)構(gòu)實(shí)際上更多指的是,組件的樣式構(gòu)成。
  • 對(duì)于多標(biāo)簽組件來(lái)說(shuō),結(jié)構(gòu)則更多指的是 HTML 標(biāo)簽結(jié)構(gòu)。
單標(biāo)簽組件
<!-- 單標(biāo)簽組件 -->
<button class="btn btn-primary">I am primary button</button>
<button class="btn btn-outline-primary">I am outline primary button</button>
/* 基本樣式 .block */
.btn {
    /* ... */
    color: black;
    /* ... */
}

/* 修飾樣式 .block-modifier */
.btn-primary {
    /* ... */
    color: blue;
    /* ... */
}

/* 修飾樣式 .block-modifier */
.btn-outline-primary {
    /* ... */
    color: blue;
    background-color: transparent;
    /* ... */
}
多標(biāo)簽組件
<!-- 多標(biāo)簽組件 -->
<ul class="sidenav">
    <li class="sidenav-item">
        <a href="/nav1">nav1</a>
    </li>
    <li class="sidenav-item">
        <a href="/nav2">nav2</a>
    </li>
    <li class="sidenav-item">
        <a href="/nav3">nav3</a>
    </li>
    <li class="sidenav-item">
        <a href="/nav4">nav4</a>
    </li>
</ul>

從組件的直觀表現(xiàn)上來(lái)看,組件則可以按照四個(gè)部分來(lái)解構(gòu),分別是: 結(jié)構(gòu)、 配色、 尺寸狀態(tài)

a) 結(jié)構(gòu)

結(jié)構(gòu)是組件的根基,是組件的骨架。但 單標(biāo)簽組件 與 多標(biāo)簽組件 在結(jié)構(gòu)的表現(xiàn)上,是有一些不同的。

* 對(duì)于單標(biāo)簽組件來(lái)說(shuō),結(jié)構(gòu)實(shí)際上更多指的是,組件的樣式的構(gòu)成。
* 對(duì)于多標(biāo)簽組件來(lái)說(shuō),結(jié)構(gòu)則更多指的是 HTML 標(biāo)簽的結(jié)構(gòu)。
b) 配色

組件可以擁有不同的的配色,配色可以理解成是組件的樣貌。

<button class="btn btn-style1">style1 is my style</button>

<button class="btn btn-style2">style2 is my style too</button>

<button class="btn btn-style3">style3 is my style too</button>
c) 尺寸

人有高有矮,組件會(huì)有不同的尺寸。

<button class="btn">I am a button</button>

<button class="btn btn-small">I become a small button</button>

<button class="btn btn-medium">I become a medium button</button>

<button class="btn btn-large">I become large button</button>
d) 狀態(tài)

狀態(tài)可以理解為是用戶和組件互動(dòng),使組件產(chǎn)生的狀態(tài)。

狀態(tài)可以大致分為兩類:enable statedisabled state。

enable state 亦可稱為 element state

.Class:active { property: value; }
.Class:focus { property: value;  }
.Class:hover { property: value;  }
.Class:visited { property: value; }

亦可用如下方式,來(lái)表示 enable state 的持久化狀態(tài)

.Class.active { property: value; }
.Class.focus { property: value;  }
.Class.hover { property: value;  }
.Class.visited { property: value; }

disabled state 亦可稱為 special state

.Class.disabled { property: value; }
.Class.loading { property: value; }

2、如何設(shè)計(jì)組件

組件樣式的 Class 命名依據(jù) BEM 方式命名,即 Block & Element & Modifier。

書寫方式有兩種,如下所示:

下文中 .block & .block-element & .block-element-modifier 皆為代指。

/* 第一種寫法 */
.block {}
.block--modifier {}
.block__element {}
.block__element--modifier {}
/* 第二種寫法 */
.block {}
.block-modifier {}
.block-element {}
.block-element-modifier {}

第一種寫法是標(biāo)準(zhǔn)寫法,第二種寫法算是簡(jiǎn)潔的寫法。下面按照第二種寫法進(jìn)行詳細(xì)說(shuō)明。

按照 BEM 方式書寫的 Class ,在單標(biāo)簽組件和多標(biāo)簽組件中,所代表的含義大部分都是相同,小部分有差異。

BEM 之 .block

單標(biāo)簽組件

在單標(biāo)簽組件中,.block多數(shù)情況是作為 基礎(chǔ)樣式 來(lái)存在。

<!-- 單標(biāo)簽組件 -->
<button class="btn btn-primary">I am component</button>

多標(biāo)簽組件

在多標(biāo)簽組件中,.block更多是作為 容器 的存在。

<!-- 多標(biāo)簽組件 -->
<div class="modal">
    <div class="modal-header">
        <div class="modal-title">title</div>
    </div>
    <div class="modal-body">
        <div class="modal-text">
            <a href="#" class="modal-link">link</a>
        </div>
    </div>
    <div class="modal-footer">
        <div class="modal-text">
            ![](#)
        </div>
    </div>
</div>

BEM 之 .block-modifier

單標(biāo)簽組件

在單標(biāo)簽組件中,.block-modifier.block 疊加使用,作為 .block 的修飾。

<!-- 單標(biāo)簽組件 配色-->
<button class="btn btn-primary">I am component</button>
<button class="btn btn-primary-ghost">I am component</button>

<!-- 單標(biāo)簽組件 尺寸-->
<button class="btn btn-small">I am component</button>
<button class="btn btn-large">I am component</button>

<!-- 單標(biāo)簽組件 狀態(tài)-->
<button class="btn btn-primary btn-loading">I am component</button>
<button class="btn btn-primary btn-disabled">I am component</button>

這里的.btn-primary-ghost實(shí)際上是作為.block-modifier存在的,這是一種比較特殊的情況,也是用簡(jiǎn)潔方式書寫 BEM 可能會(huì)遇到的情況。

多標(biāo)簽組件

在多標(biāo)簽組件中,.block-modifier.block 疊加使用,一般只會(huì)影響組件的容器 .block

<!-- 多標(biāo)簽組件 -->
<div class="modal modal-center">
    <div class="modal-header">
        <div class="modal-title">title</div>
    </div>
    <div class="modal-body">
        <div class="modal-text">
            <a href="#" class="modal-link">link</a>
        </div>
    </div>
    <div class="modal-footer">
        <div class="modal-text">
            ![](#)
        </div>
    </div>
</div>

BEM 之 .block-element

單標(biāo)簽組件

在單標(biāo)簽組件中,實(shí)際上是沒有 .block-element 的。

多標(biāo)簽組件

在多標(biāo)簽組件中,.block-element 是位于 .block 之內(nèi)的。

<!-- 多標(biāo)簽的組件,.block-element 需在 .block 之內(nèi)。 -->
<div class="modal">
    <div class="modal-header"></div>
    <div class="modal-body">
        <!-- .modal-text-right 將文字右對(duì)齊 -->
        <div class="modal-text modal-text-right">
            <a href="#" class="modal-link">link</a>
        </div>
    </div>
    <div class="modal-footer"></div>
</div>

BEM 之 .block-element-modifier

單標(biāo)簽組件

皮之不存毛將焉附。

多標(biāo)簽組件

在多標(biāo)簽組件中,.block-element-modifier.block 疊加使用,類似于 .block-modifier.block 的用法。

<!-- 多標(biāo)簽的組件,.block-element 需在 .block 之內(nèi)。 -->
<div class="modal">
    <div class="modal-header"></div>
    <div class="modal-body"></div>
    <div class="modal-footer"></div>
</div>

3、組件的父容器布局

父容器并不是必須的。

組件一般來(lái)說(shuō),都是會(huì)被其他的容器包裹的。用組件的父容器進(jìn)行頁(yè)面布局,組件則作為內(nèi)容填充。

一般通過(guò)以下兩種方式來(lái)設(shè)置父容器。

a) 用組件的 .block 作為父容器的 .block

常用的容器命名有以下幾種。

.block-container { property: value; }   /* 常用于只有一個(gè)直接子元素的組件 */
.block-list { property: value; }        /* 常用于列表式的布局 */
.block-group { property: value; }       /* 常用語(yǔ)包裹 inline 的組件 */

以下是示例:

<!-- .modal-container -->
<div class="modal-container">
    <!-- .modal 應(yīng)是 .modal-container 的直接子元素。-->
    <div class="modal">
        <div class="modal-header">
            <div class="modal-title">title</div>
        </div>
        <div class="modal-body">
            <div class="modal-text">
                <a href="#" class="modal-link">link</a>
            </div>
        </div>
        <div class="modal-footer">
            <div class="modal-text">
                ![](#)
            </div>
        </div>
    </div>
</div>
<!-- .card-list -->
<!-- .card-list 的直接子元素只可以是 .card-->
<div class="card-list">
    <!-- .card 應(yīng)是 .card-list 的直接子元素。-->
    <div class="card">
        <div class="card-text"></div>
    </div>
    <div class="card">
        <div class="card-text"></div>
    </div>
    <div class="card">
        <div class="card-text"></div>
    </div>
</div>
<!-- .image-group -->
<div class="image-group">
    <!-- .image 應(yīng)是 .image-group 的直接子元素。-->
    <a class="image">
        ![](#)
    </a>
    <a class="image">
        ![](#)
    </a>
    <a class="image">
        ![](#)
    </a>
</div>

其實(shí)這里避免的是 .block-item 的出現(xiàn)。

在一些情況下,也可以使用 .block 作為父容器, .block-item 作為內(nèi)容體。

<div class="nav">
    <div class="nav-item"><a href=""></a>nav-a</div>
    <div class="nav-item"><a href=""></a>nav-b</div>
    <div class="nav-item"><a href=""></a>nav-c</div>
</div>

不過(guò),推薦不用 .block-item。

<div class="nav">
    <div class="nav-link"><a href=""></a>nav-a</div>
    <div class="nav-link"><a href=""></a>nav-b</div>
    <div class="nav-link"><a href=""></a>nav-c</div>
</div>

b) 設(shè)置專用的布局容器,來(lái)進(jìn)行布局

定義專門的布局容器,來(lái)包裹組件。

/* 以下只是進(jìn)行舉例 */
/* container */
.container { property: value; }

/* list */
.list { property: value; }
.list-item { property:value; }

/* group */
.group { property: value; }
.group-item { property: value; }

<!-- .container -->
<div class="container">
    <!-- .modal 應(yīng)是 .container 的直接子元素-->
    <div class="modal">
        <div class="modal-header"></div>
        <div class="modal-body"></div>
        <div class="modal-footer"></div>
    </div>
</div>
<!-- .list -->
<div class="list">
    <div class="list-item">
        <!-- .card 是 .list-item 的直接子元素-->
        <div class="card">
            <div class="card-img"></div>
            <div class="card-text"></div>
        </div>
    </div>
</div>
<!-- .group -->
<div class="group">
    <!-- .image 應(yīng)是 .group 的直接子元素。-->
    <div class="group-item">    
        <a class="image">
            ![](#)
        </a>
    </div>
    <div class="group-item">    
        <a class="image">
            ![](#)
        </a>
    </div>
    <div class="group-item">    
        <a class="image">
            ![](#)
        </a>
    </div>
</div>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見瀏覽器兼容性問(wèn)題與解決方案? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,814評(píng)論 1 92
  • 作者:狼狼的藍(lán)胖子原文地址:http://luopq.com/2016/01/05/css-optimize/ 寫...
    IT程序獅閱讀 1,748評(píng)論 2 51
  • 轉(zhuǎn)載說(shuō)明 一、介紹 瀏覽器可以被認(rèn)為是使用最廣泛的軟件,本文將介紹瀏覽器的工作原理,我們將看到,從你在地址欄輸入g...
    17碎那年閱讀 2,471評(píng)論 0 22
  • 【譯】前端BEM命名方法論之一:BEM 官方簡(jiǎn)介文檔【譯】前端BEM命名方法論之三:命名慣例 重要概念 Block...
    咚門閱讀 5,302評(píng)論 0 7
  • 早起KO《旅居者和外國(guó)人》讀后感【微信發(fā)布】貼士照片要注意想表達(dá)的是笑臉,但是要注意照片中的人物英年早逝人的照片讓...
    dq920813閱讀 165評(píng)論 0 0