If you are not paying for the product, you are the product.
當一個商品是「免費」的,那每每你成了商品。css
終於有時間靜下心學點東西,把這個系列最後一篇填上。 中篇 介紹了 tachyons, 本篇介紹我的的最愛,沒有之一:styled-jsx。html
在打算使用一個新 css 框架前,須要好好想清楚它是否在你的全部使用場景裏圓滿完成任務,我總結了幾點:vue
zeit 的一系列產品從 now,到 next.js,我算是一個腦殘粉。簡潔好用是我對 zeit 的項目的印象。並且一套庫自成系統,styled-jsx 和 next.js 完美兼容。node
styled-jsx 歸納第一印象就是 React css 的 vue 解決。
yarn add styled-jsx
安裝後,不用import
,而是一個babel插件,.babelrc
配置:react
{
"plugins": [
"styled-jsx/babel"
]
}
複製代碼
而後就直接用了git
render () {
return <div className='table'> <div className='row'> <div className='cell'>A0</div> <div className='cell'>B0</div> </div> <style jsx>{` .table { margin: 10px; } .row { border: 1px solid black; } .cell { color: red; } `}</style> </div>;
}
複製代碼
<style>
的位置能夠按喜愛自定,樣式老是做用於組件的全部元素className
例如const App = () => (
<div> <p>只有這個p會被上樣式</p> <style jsx>{` p { color: red; } `}</style> </div>
)
複製代碼
會被轉化成github
import _JSXStyle from 'styled-jsx/style'
const App = () => (
<div className='jsx-123'> <p className='jsx-123'>只有這個p會被上樣式</p> <_JSXStyle styleId='123' css={`p.jsx-123 {color: red;}`} /> </div> ) 複製代碼
從實現到原理,對比vue是否是很是像呢?若是你不喜歡將樣式寫在 render 裏,styled-jsx 提供了一個 css
的工具函數:面試
import css from 'styled-jsx/css'
export default () => (
<div> <button>styled-jsx</button> <style jsx>{button}</style> </div>
)
const button = css`button { color: hotpink; }`
複製代碼
很是完美的css解決方案。 下面針對「選擇標準」裏提到的各個方面考察一下 styled-jsxapi
和 styled-components,Motion 等模板字符串的解決方案同樣,動態css垂手可得瀏覽器
export default (props) => (
<div> <button>styled-jsx</button> <style jsx>{ `button { color: ${props.color}; }` }</style> </div>
)
複製代碼
同個組件裏能夠寫無限個<style>
標籤,這裏的最佳實踐是將靜態的css放一個標籤,動態的放另外一個,每次渲染時只有動態的從新計算和渲染
const Button = (props) => (
<button> { props.children } <style jsx>{` button { color: #999; display: inline-block; font-size: 2em; } `}</style> <style jsx>{` button { padding: ${ 'large' in props ? '50' : '20' }px; background: ${props.theme.background}; } `}</style> </button>
)
複製代碼
兩點注意:
兩個字,插件。
包羅萬象。以Sass爲例:
yarn add -D node-sass styled-jsx-plugin-sass
複製代碼
.babelrc
配置
{
"plugins": [
[
"styled-jsx/babel",
{ "plugins": ["styled-jsx-plugin-sass"] }
]
]
}
複製代碼
便可使用Sass。
如同 Vue 以 scoped
爲關鍵字,styled-jsx 以 global
爲關鍵字。
export default () => (
<div> <style jsx global>{` body { background: red } `}</style> </div>
)
複製代碼
全局樣式註明 global 便可。
有極少狀況(好比傳一個全局類給三方庫)須要使單個選擇器全局化,語法相似 css-module
div :global(.react-select) {
color: red
}
複製代碼
相對有點繁瑣,思想是取得styled-jsx轉化事後的類名,注入到三方庫的className props裏,這樣即解決了支持,又保全了局部css,代碼以下
import Link from 'react-router-dom' // 例子,給Link組件添加樣式
const scoped = resolveScopedStyles(
<scope> <style jsx>{'.link { color: green }'}</style> </scope>
)
const App = ({ children }) => (
<div> {children} <Link to="/about" className={`link ${scoped.className}`}> About </Link> {scoped.styles} </div>
);
function resolveScopedStyles(scope) {
return {
className: scope.props.className, //就是被styled-jsx添加的獨特className
styles: scope.props.children //就是style,注入到App組件中
}
}
複製代碼
固然,若是你不介意局部不局部,可使用上面提到的:global()
語法
// 好比Form組件有類名form-item
export default () => (
<div> <Form /> <style jsx>{` div > :global(.form-item) { color: red } `}</style> </div>
)
複製代碼
我使用VSCode:
其餘的見 github 上 readme。
謝謝ziven27提議,我試着說說和如今最流行的 styled-components 庫的區別。(方便討論,「前者」代指style-jsx,「後者」代指style-components)
&
嵌套,後者也是能夠包裹組件最外層元素而後將其餘元素樣式通通寫入的。雖然感受不是後者的初衷。className
props的三方庫完美整合(比前者簡潔太多):const RedButton = styled(Button)`background: red;`
複製代碼
但對不提供className
props的三方庫束手無策(固然這種狀況不太出現)。
.extends
樣式繼承以及.attrs
封裝公用props。這裏提到一個話題,究竟是「魔術」好呢,仍是樸實好呢?舉個例子,好比theme(主題):
// styled-components 使用Provider提供主題,主題能夠是樣式,也能夠是函數
const Button = styled.button` color: ${props => props.theme.fg}; border: 2px solid ${props => props.theme.fg}; background: ${props => props.theme.bg}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border-radius: 3px; `;
// 主題的樣式
const theme = {
fg: 'palevioletred',
bg: 'white'
};
// 換前景色和背景色的函數
const invertTheme = ({ fg, bg }) => ({
fg: bg,
bg: fg
});
render(
<ThemeProvider theme={theme}> <div> <Button>Default Theme</Button> <ThemeProvider theme={invertTheme}> <Button>Inverted Theme</Button> </ThemeProvider> </div> </ThemeProvider>
);
複製代碼
甚至還提供了一個HOC,在styled-components外使用theme
import { withTheme } from 'styled-components'
複製代碼
強大不強大?對比之下,styled-jsx沒有任何與theme相關的api,只是樸樸實實地靠props傳遞達成主題:
// styled-jsx
import { colors, spacing } from '../theme'
import { invertColor } from '../theme/utils'
const Button = ({ children }) => (
<button> { children } <style jsx>{` button { padding: ${ spacing.medium }; background: ${ colors.primary }; color: ${ invertColor(colors.primary) }; } `}</style> </button>
)
複製代碼
這個問題要看應用場景和我的喜愛吧,我屬於不喜歡過多「魔術」,愛簡單api(哪怕多點代碼)的那派。你們有啥想法和指正,多多留言。
有2個細小缺點
react-app-rewired
來加入 babel plugin 的設置。以前有小夥伴留言表示有坑(謝謝,看到這樣的留言以爲寫blog的決定太對了)
一樣以爲styled-jsx很是好,最近一直在用。
但目前仍是有些不成熟的地方,主要是:
一、局部樣式沒法支持第三方組件標籤,只能支持普通html標籤
二、對stylelint缺少支持,官方出的stylelint插件只是一個demo。在vscode中用stylelint插件時也是有很大的坑。
複製代碼
我的以爲1的場景已經在上面討論了,能夠兼容。2的話,本人上個項目裏裸prettier,因此沒試過那個插件,在這裏提一下。
總之目前用過一次,我很喜歡,也很滿意。但願你們也找到本身喜歡的一個或者是一套解決方法。
最近面試,明白了本身有許多須要重點研究的課題。看了些 PWA 相關的文和視頻,已經上船了。一句話:PWA 是將來,並且是近在眼前的將來。以後打算分享一下本身的學習筆記。
我寫的其餘專欄文章列表 傳送門。