iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 10
0
Modern Web

30 天打造 MERN Stack Boilerplate系列 第 10

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 的設定中會將 styles.css 中的 class 重新命名,例如加上一段 hash,或是加上 Scope 名稱。所以上例中的 redBorder 經過 Webpack 的 Loader 轉換後可能會被重新命名為 styles_redBorder_vgo,其中 styles 是 Scope,vgo 則是一段 hash。

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

方法三:Fixed ClassName

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

通常這個寫法是用在 Library(例如:react-dates),因為元件的 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-components 這一套 Library。

在 Boilerplate 中使用 CSS Module

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

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


上一篇
Day 09 - Frontend - (React) & Flux & React-Redux
下一篇
Day 11 - Infrastructure - Introduction
系列文
30 天打造 MERN Stack Boilerplate30

尚未有邦友留言

立即登入留言