folder_open

30 天打造 MERN Stack Boilerplate

arrow_right
article

Day 10 - Frontend - CSS Module

Day 10 - Frontend - CSS Module

借助 Webpack 的力量,我們可以在 SPA 大量使用 JS 開發的環境下,一樣使用 JS 的形式來 Import CSS。在 Webpack 的世界,所有 Import 的檔案都稱為 Module,因此我們 Import 的 CSS、LESS 或是 SASS 檔案就概稱為 CSS Module。

在 React 中使用 CSS

#

我們先拋開 CSS Module 來看看在 React 中使用 CSS 有哪些做法,後面再來選擇 Boilerplate 應該實作何種方法。

方法一:Style Prop

#

直接將 Style 寫成 JS 物件,當作 Component 的 prop 傳遞進去:

class ExampleComponent extends Component {
render() {
return (
<div
style={{
border: '1px solid red',
}}
>
foo bar
</div>
);
}
}

方法二:Dynamic ClassName

#

將 CSS 獨立寫在外部檔案,再以 Module 形式載入,此方法必須搭配 Webpack 的設定。

/* styles.css */
.redBorder {
border: 1px solid red;
}
import cx from 'classnames';
import styles from './styles.css';
class ExampleComponent extends Component {
render() {
let { className } = this.props;
return (
<div className={cx(styles.redBorder, className)}>
foo bar
</div>
);
}
}

為了避免不同 Component 之間的 className 互相衝突,一般在 Webpack 的設定中會將 中的 class 重新命名,例如加上一段 hash,或是加上 Scope 名稱。所以上例中的 經過 Webpack 的 Loader 轉換後可能會被重新命名為 ,其中 是 Scope, 則是一段 hash。

由於 className 是動態產生的,所以 assign 給 Component 時不能寫死成 ,必須要以變數方式傳遞:

方法三:Fixed ClassName

#

第三種作法和方法二類似,只是 Webpack 的設定少了一點,使用固定的 className,不做重新命名。

通常這個寫法是用在 Library(例如:react-datesopen_in_new),因為元件的 className 是寫死的,所以我們可以不採用 Library 本身提供的預設樣式自己刻一套,如此才能保留 Library 的彈性。

/* styles.css */
.redBorder {
border: 1px solid red;
}
import cx from 'classnames';
import './styles.css';
class ExampleComponent extends Component {
render() {
return (
<div className={cx('redBorder', className)}>
foo bar
</div>
);
}
}

方法四:Styled Component

#

這個方法是最近出現的,筆者也還沒使用過,有興趣的讀者可以看看 styled-componentsopen_in_new 這一套 Library。

在 Boilerplate 中使用 CSS Module

#

我並不擅長前端,所以當初在規劃 Boilerplate 要如何整合 CSS 時並沒有做太多研究,而且開源界的風向也非常亂,前面提及的方法一至方法四都有人使用,當時就隨手挑了方法二 Dynamic ClassName 整合進 Boilerplate 中,而且還搭配了 一起使用。

其實越往後寫越發現方法三 Fixed ClassName 才是最佳解,所以在此跟各位讀者抱歉,我們的 Boilerplate 押錯了寶,選到了方法二,日後我應該會找個時間調整成方法三 QQ