關注點分離(separation of concerns)原則多年來大行其道,實踐中通常將 HTML
、CSS
、JavaScript
分開編寫維護,早期框架 angularjs
便是如此,直到 React
爭議中問世,引領關注點混合趨勢,驅使開發者從新審視 CSS
工程化發展。javascript
相對於 JavaScript
的日新月異,CSS
的發展緩慢,相對止步不前。隨着前端職能擴大化成爲常態,前端工程化日趨成熟,CSS
先天缺陷愈發明顯:css
最大的缺陷 來自於全局做用域,class name
全局生效,多人協做中的風格不一致,隨時可能引起蝴蝶效應。爲規避多人協做的風格衝突,社區提出 OOCSS
,BEM
等方法論,但實踐中徹底取決於團隊執行力度,筆者也曾苦惱於合理的命名,爲避免衝突,致使類名冗長,無聊且痛苦。前端
缺少高級編程特性 影響一樣深遠,社區發展的預處理器可以有效緩解,sass
,less
,stylus
異曲同工,postcss
異軍突起,基本實現變量、嵌套、變量、混合、擴展和邏輯等。隨着 CSS
規範逐步推動,高級編程特性徹底可期。筆者大膽斷言,前端工程化的推動,已經基本解決 CSS高級編程特性缺少 的問題。java
代碼冗餘,極限壓縮對開發的影響相對很小,經典的 bootstrap
就包含大量的冗餘代碼,但絲絕不影響其流行程度。react
目前難以解決的是依賴管理,NPM
已經成爲事實上的 JavaScript
包管理工具,而 CSS
始終沒有發展出可用的管理模式,sass
的淺嘗輒止,例如 bootstrap-sass
, Bourbon
等,顯然沒法知足需求。隨着 React
引領的關注點混合,以組件爲核心的開發模式,有效規避了 CSS
缺少依賴管理的缺陷,筆者認爲,依賴管理弊端徹底可控,將來的發展,留給將來述說。angularjs
前端發展突飛猛進,React
在衆人爭議中進入視野,典型的 React
組件同時包含結構、樣式、行爲,示例以下:編程
/** * @description - lite component * @author - huang.jian <hjj491229492@hotmail.com> */
export class Counter extends Component {
constructor(props) {
super(props);
this.state = {
timestamp: Date.now()
};
}
render() {
return (
<Card title="React Timestamp">
<Alert message={`React Timestamp: ${this.state.timestamp}`} type="success"/>
<Alert message={`React Timestamp: ${this.state.timestamp}`} type="info"/>
<Alert message={`React Timestamp: ${this.state.timestamp}`} type="warning"/>
</Card>
);
}
}
複製代碼
前端應用由組件聚合而成,組件層面對 CSS
進行抽象,從而解決大型應用的 CSS
維護難題。社區出現的 CSS IN JS
解決方案,目前看來就是可行解決方案,其本質在於經過 JavaScript
來聲明,維護樣式,以 styled-components
舉例:bootstrap
const Button = styled.button`
border-radius: 3px;
padding: 0.25em 1em;
color: palevioletred;
border: 2px solid palevioletred;
`;
function Buttons() {
return (
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
);
}
複製代碼
樣式寄生組件之中,組件掛載時,動態插入樣式,實現按需加載,動態生成類名,隔離做用域。另一種思路,經過 style
屬性傳入內嵌樣式,徹底規避選擇器全局做用域的問題。前端工程化
// 官方示例有刪減
var Radium = require('radium');
var React = require('react');
var color = require('color');
// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
base: {
color: '#fff',
},
primary: {
background: '#0074D9'
},
warning: {
background: '#FF4136'
}
};
@Radium
class Button extends React.Component {
render() {
return (
<button style={[ styles.base, styles[this.props.kind] ]}> {this.props.children} </button>
);
}
}
複製代碼
面向組件開發,爲樣式管理提供更多的可能性,徹底使用 JavaScript
抽象,管理,維護樣式,略顯激進,但也不失爲一種解決方案。sass
目前主流的 CSS IN JS
方案與傳統的方式對好比下:
優點:
NPM
生態進行包管理;劣勢:
disabled、:before、:nth-child
)支持詭異;筆者並不徹底認同 CSS IN JS
的理念,也不反對將其應用於生產項目。CSS
中最嚴重的問題,不經過 CSS-in-JS
也能 有其餘解決方案,也就是筆者當前使用的 CSS Module
方案。經過工程化的方式,將選擇器編譯爲獨一無二的類名,使用 JavaScript
管理選擇器與元素的關聯,僅此而已。
// Header.jsx
import style from './Header.css'
// { header: 'Header__header--3kSIq_0' }
export default function Header() {
return (<div className={style.header}>Header!!!</div>);
}
複製代碼
優點:
tree-shaking
機制,僅保留存在引用的選擇器,有效避免樣式冗餘;NPM
機制進行包管理;sass
,postcss
高級編程特性;劣勢:
本文未涉及的 單文件組件 也是可行方案之一,目前 Vue
,Angular
等框架採用。筆者始終認爲,與其創造更多抽象的技術讓前端學習曲線更加陡峭,不如經過工程化的手段來修復存在的缺陷,理念上求同存異。面對各類技術方案,適合實際項目的方案纔是最好的方案,選用預處理器 PostCSS
,BEM
,亦或動態編譯,都須要結合業務場景、團隊習慣等因素決策。
關注公衆號,獲取動態,支持做者。