Strong opinions are very useful to others.css
Those who were undecided or ambivalent can just adopt your stance.html
But those who disagree can solidify their stance by arguing against yoursreact
鲜明的观点很是有用。摇摆不定的人能够省心直接接受你的观点。不一样意的人则能够经过讨论更加巩固本身的观点。webpack
----Derek Siversgit
不得不认可 Vue 的css解决方式很是天然简洁,相比之下 css 一直是 React 的痛。 从旧宠 css modules 到 JSS 的各类衍生,到新宠 styled-components。几十种的解决方式,上百篇的教程和比较,已经说明了一切。你们一直在寻找最好的最适合本身的解决方式。 我试着先回顾一下一路下来用过和没用过的各类React的css解决方案,最后说说我最爱的方式。固然只要你喜欢,使用普通的 css 或者是 sass 来完成React的样式是彻底可行的。用本身最喜欢的方式编程是最重要的。github
随着你们对新开发模式(组件化)下 css 使用的各类反思,我的总结主要有三个:web
<style> /* 全局样式 */ </style>
<style scoped> /* 本地样式 */ </style>
复制代码
一旦加上 scoped
属性,css 就只做用于所在组件。简洁漂亮的解决。美中不足的是样式并不能直接访问组件状态,因而乎须要另外规定动态css的语法与此合并使用。编程
const textStyles = {
color: 'white',
backgroundColor: this.state.bgColor
};
<p style={textStyles}>inline style</p>
复制代码
原生的解决方式就是inline style,这种在旧式开发上不推崇的css写法却很是适合组件化开发。inline style解决了以前提到的三个问题。但相对的,我的以为不喜欢的地方在于:bootstrap
:before
和:nth-child
等 pseudo selectors因为1,3只是我的偏好问题,因此以后一批css-in-js库都坚持了inline和jss,只是致力于解决对css的不彻底支持问题。这些虽然不是个人菜,但都是流行的解决方式:数组
专门针对原生方法不彻底支持css的不足,完成的改良版。
// 支持 hover, sass的 &, media query 等。
const styles = {
button: {
fontSize: 12,
'&:hover': {
background: 'blue'
}
},
ctaButton: {
extend: 'button',
'&:hover': {
background: color('blue')
.darken(0.3)
.hex()
}
},
'@media (min-width: 1024px)': {
button: {
width: 200
}
}
}
复制代码
JSS 是一个底层库,要在 React 中使用能够用 React-JSS, Styled-JSS 等。选择多样,是此类解决法里不错的一个选择。
import Radium from 'radium';
const Button = () => (
<button style={styles.base}> {this.props.children} </button>;
)
var styles = {
red: {
backgroundColor: 'red'
}
};
Button = Radium(Button);
复制代码
多个样式使用数组方便合并
<button style={[styles.base,styles.primary]}>
{this.props.children}
</button>
复制代码
使用了HOC的方式注入样式,能够方便传入各类配置
Radium(config)(App)
复制代码
import React, { Component } from 'react';
import { StyleSheet, css } from 'aphrodite';
const Button = () => (
<span className={css(styles.red)}> This is red. </span>
)
const styles = StyleSheet.create({
red: {
backgroundColor: 'red'
},
});
复制代码
并非全部人都接受jss的书写。因此另外一种解决方式是继续使用 css 的同时,解决样式的scope 问题,使得样式只做用于import它的组件。这类解决方法目前就一家
Css Modules 并非React专用解决方法,适用于全部使用 webpack 等打包工具的开发环境。以 webpack 为例,在 css-loader 的 options 里打开modules:true
选项便可使用 Css Modules。
通常配置以下
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: true,
localIdentName: "[name]__[local]___[hash:base64:5]" // 为了生成类名不是纯随机
},
},
复制代码
使用以下
import styles from './table.css';
render () {
return <div className={styles.table}> <div className={styles.row}> <div className={styles.cell}>A0</div> <div className={styles.cell}>B0</div> </div> </div>;
}
复制代码
/* table.css */
.table {}
.row {}
.cell {}
复制代码
在解决了 scoped 的同时留下些许遗憾:
styles.table
来引用:local
和 :global
切换,不方便{style.className}
的形式这个解决方法能够照常写css是一大优点,不过我对 2,3 比较不能容忍。一个轻量级的 babel-plugin-react-css-modules库提出了解决法,你能够照常写 'table-size' 之类带横杠的类名,在js里正常书写字符串类名,惟一的区别在于使用 styleName
关键字代替 className
, 以上例,结果以下
import './table.css';
render () {
return <div styleName='table'> <div styleName='row'> <div styleName='cell'>A0</div> <div styleName='cell'>B0</div> </div> </div>;
}
复制代码
使用styleName这一新关键字,甚至连局部css和全局css的区分也迎刃而解了。
<div className='global-css' styleName='local-module'></div>
复制代码
使用时.babelrc
配置:
{
"plugins": [
["react-css-modules", {
// options
}]
]
}
复制代码
这一解决法已经很接近个人喜爱了,不过使用 styleName
遇到三方UI库该怎么办呢?
顺带一提,目前 create-react-app
还不支持 Css Modules,但处于 beta 的 create-react-app v2
已经支持。使用方法为一概将css文件命名为 XXX.modules.css
, 以上例,即为 table.modules.css
, 便可使用。这一解决法的优雅在于,全局的css能够正常使用,只有带.modules.css
后缀的才会被modules化。
Css Modules还有一大缺憾:和Vue的解决同样,由于css写在css文件,没法处理动态css。
有不少人并不买JSS的账(我算一个),Vue 的解决方式也算一个启发,因而新的库尝试了使用 ES6 的模板字符串,在js文件里写纯粹的css。
` .table { background: #333; color: rebeccapurple; } `
复制代码
这很是天然地解决了前面提到的原生方法缺陷之2:不支持全部css语法。这类解决法中最有名的是 styled-components,相似的还有 Emotion。起初这一方法的一大不即是编辑器不能格式化,lint和自动补完js中的css,但如今基本每一个流行编辑器都能找到相应的插件解决这一问题。
import styled from 'styled-components';
// `` 和 () 同样能够做为js里做为函数接受参数的标志,这个作法相似于HOC,包裹一层css到h1上生成新组件Title
const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `;
// 在充分使用css所有功能的同时,很是方便的实现动态css, 甚至能够直接调用props!
const Wrapper = styled.section` padding: 4em; background: ${props => props.bgColor}; `;
const App = () => (
<Wrapper bgColor='papayawhi'> <Title>Hello World, this is my first styled component!</Title> </Wrapper>
)
复制代码
值得注意的是支持对其余元素引用,且语法至关天然:
const Link = styled.a` padding: 5px 10px; background: papayawhip; color: palevioletred; `;
const Icon = styled.svg` transition: fill 0.25s; width: 48px; height: 48px; ${Link}:hover & { fill: rebeccapurple; } `;
复制代码
而且能方便的给暴露className
props的三方UI库上样式:
const StyledButton = styled(Button)` ... `
复制代码
有人喜欢给每一个须要样式的标签重命名一个更有意义的名称的作法,但也有人以为重命名很是繁琐。这类人能够试试Emotion
import styled, { css } from 'react-emotion'
const Container = styled('div')` background: #333; `
const myStyle = css` color: rebeccapurple; `
const app = () => (
<Container> <p className={myStyle}>Hello World</p> </Container>
)
复制代码
Emotion 支持 styled-components 的样式注入方式,同时也能够用 css()
关键字直接注入。同时也支持JSS和& :hover
等Sass语法,例如:
// sass
<div className={css` background-color: hotpink; &:hover { color: ${color}; } `} >
// JSS
<div className={css({ backgroundColor: 'hotpink', '&:hover': { color: 'lightgreen' } })} >
复制代码
以前没注意,Emotion 容许直接写子元素样式!
import { css } from 'emotion'
const paragraph = css` color: turquoise; a { border-bottom: 1px solid currentColor; } `
render(
<p className={paragraph}> Some text. <a> A link with a bottom border. </a> </p>
)
复制代码
若是使用 babel-plugin-emotion
,你甚至能够直接使用 css 做为 props:
<div css={` color: blue; font-size: ${props.fontSize}px; &:hover { color: green; } & .some-class { font-size: 20px; } `} >
复制代码
很是简洁也独具亮点,且提供了符合各类胃口的解决方式。
Glamorous 和前两个库有不少相似之处,最大的不一样是它坚守了JSS的阵线。不支持模板字符串写纯css。 Glamorous 基础用法有三种选择:
import
import glamor from 'glamorous'
// className 注入
const styles = glamor.css({
fontSize: 20,
textAlign: 'center',
})
<div
className={styles}
/>
// 2. 类styled components
const MyStyledDiv = glamor.div({margin: 1, fontSize: 1, padding: 1})
// 3. 使用自带组件,接受样式名和css为props
const { Div } = glamor
<Div
fontSize={20}
textAlign="center"
css={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
}}
>
Hello world!
</Div>
// 4. 以及混用
const MyStyledDiv = glamor.div({margin: 1, fontSize: 1, padding: 1})
const myCustomGlamorStyles = glamor.css({fontSize: 2})
<MyStyledDiv className={`${myCustomGlamorStyles} custom-class`} />
复制代码
Next.js 的 zeit 出品,必属精品。
两个css库,与 bootstrap 走上彻底不一样的路线,所谓的“原子类”。写小项目和demo我基本上第一件事就是
yarn add tachyons
篇幅意想不到变得太长了,在下篇我会展开讲解这两个我的偏心的解决方法。本篇对现行的流行解决法作了个小概括。方便你们查询和选择。在本篇里我用的最多的仍是styled-components
,但如今已经切换到styled-jsx
了。 以后最想尝试的应该是Emotion
。说到底没有孰优孰劣,更多的是我的喜爱。但愿这篇概括对你们有帮助。不足之处,也请你们能留言指出,互相学习,谢谢!