![cfd83909a043fca945c8d6c548cb2679.png](https://i-blog.csdnimg.cn/blog_migrate/d25f6d1416af67db11d542b12b445987.jpeg)
作者: Luke Hall 原文:Why I prefer Styled components to build React apps
在我的开发栈系列文章的Part #1中,我说明了为什么我使用React作为主框架的几个理由。现在你可能会想知道……
“这家伙是怎么处理CSS的?”
答案是:
用Styled components简单又轻松
npm install styled-components
你要做只有这些。真的!这就是我为什么喜欢它!不用Babel,不用Webpack,不用CSS前后处理。只有JavaScript,别的不需要。
CSS in JS
“大哥,你意思是在JS里写CSS,这很奇怪,我永远不会这么做!”
但是让我们先来写一些Styled component:
import styled from 'styled-components;
const Title = styled.h1`
font-size: 18px;
`;
这里的styled变量中包含的函数可以表示所有已知的HTML元素。看起来怪异的h1` `语法其实一个标记模板字面量。它实际上相当于调用了一个函数:h1(' ')
得到的Title组件 和其他的一般React 组件用法相同:
<Title>I'm styled and I know it!</Title>
要注意的是只有React可以使用Styled components。
Props
“等等, 里面的Props是怎么回事?”
这就是它强大的地方。请看:
const Button = styled.button`
background: ${props => props.primary ? 'green' : 'gray'};
`;
<Button primary>Click me!</Button>
在模板字符串中用箭头函数提供props变量。这样你可以给CSS样式传入任意值。
换句话说,不仅可以传入CSS属性值,还可以这么做:
import styled, { css } from 'styled-components;
const Position = styled.div`
position: absolute; ${({ side, value }) => css`
${side}: ${value};
`}
`;
<Position side="right" value="50%">
I'm positioned!
</Position>
代码片段
“上面的css变量是什么?”
这是一个用于构建CSS代码片段的helper函数。当你需要一些反复出现的CSS时很有用。只需这么做:
const underlineOnHover = css`
text-decoration: none;
:hover {
text-decoration: underline;
}
`;
然后将它用在任意你需要的组件中:
const Link = styled.a`
color: green;
${underlineOnHover};
`;
(无需)class
“但是……怎么才能添加classname属性呢?我要改变嵌套在组件中的另一个组件的样式”
忘了class吧!你可以不需要它们了。
只需这么选择被嵌套组件:
const Button = styled.button`
${Icon} {
width: 20px;
}
`;
在如下两种情况中都可以这么做:
- Icon是Styled component组件。
- Icon不是Styled component组件,但想给它里面的元素传入classname属性。例如这里的Icon可以是react-router里的Link组件。
在HTML和CSS之间,定义class不是必须的步骤。
你不必根据props有条件的对组件应用class。只需直接根据props有条件的编写CSS。
别误解我的意思,当然在浏览器渲染后还是使用的class。但那些是动态生成的,你不需关心它们。
它们看起来像这样:
.cAqXJf {
padding: 10px;
}
Debugging
“得了吧,那太可怕了!那你怎么在浏览器中debug呢?你不知道这莫名其妙的class是属于哪个组件!”
你是对的,你知不道。还记得我说你不需要为Styled components设置Babel吗?这里是个例外。
这里可以用babel-plugin-styled-components插件。设置好后,你就可以在浏览器里看到可读的class名,像这样:
<div class="ProductList-cAqXJf">...</div>
CSS特性支持
“开始有点意思了。但我打赌我可以发现某些Styled components不能做的事情。你怎么处理伪选择器和伪元素,嗯?”
方法和在普通的CSS里面一样:
const Link = styled.a`
:hover {
color: orange;
}
:before {
content: 'styled components are awesome'
}
`;
总之,你在CSS里可以做的任何事都可以在Styled components里做。
Media queries, animation keyframes, gradients, transformations……所有东西都是开箱即用的
全局样式
“我想到了!全局样式!我知道我会找到!你不能做到这个!你不可能让<html>或<body>元素成为Styled组件!”
好吧,你不能让<html>成为Styled组件,但是Styled components的作者没有忘记这点。别担心。
你可以很容易在全局使用自定义字体。正如官方文档的例子:
import { injectGlobal } from 'styled-components';injectGlobal`
@font-face {
font-family: "Operator Mono";
src: url("../fonts/Operator-Mono.ttf");
}
body {
margin: 0;
}
`;
注:injectGlobal现已弃用,更改为createGlobalStyle。
SSR和性能
“你难住我了。那么服务器端渲染怎么样呢?”
这也支持的很好。不用担心用户会在页面载入前看到没有样式的页面。
而且它的优点是,CSS是JS组件的一部分。从性能的角度上看:
- 你只需用一个包中就载入所有东西
- 你只载入那些你确实需要的组件的样式
React native
“但我主要是用React Native开发移动应用,所以这东西我用不上……”
没想到吧!Styled components对React Native也支持。别担心。
import styled from 'styled-components'const View = styled.View`
display: flex;
`;
你甚至可以构建一组平台无关的Styled 组件。然后将它们用在web,IOS,Android的开发中。
主题
“哇,听起来很棒!也许我会在我下一个项目中考虑Styled components”
我再给你一个理由,无疑你应该试试。这是我最喜欢它的地方。
Styled components支持开箱即用的主题:
import styled, { ThemeProvider } from 'styled-components';
const theme = {
colors: {
primary: '#4e812b',
secondary: '#ee921a'
}
}
const App = props => (
<ThemeProvider theme={theme}>
{props.children}
</ThemeProvider>
);
现在你app内的任意组件都有theme属性了。
const Button = styled.button`
background: ${({ theme, primary }) => (
primary ? theme.color.primary : theme.color.secondary
)};
`;
<Button primary>Click me!</Button>
在app里的所有地方改变颜色变得非常简单,传入primary或secondary即可。
扩展样式
另一个超级有用的特性是可以很容易扩展任意组件的样式。
import styled from 'styled-components';
import Button from './Button';
const DisabledButton = styled(Button)`
background: gray;
cursor: not-allowed;
`;
这将把原始组件的样式与新样式合并在一起。
还有更多……
使用Styled components还有更多可能性。请查阅官方文档。
注意事项
在Styled components中有些事情会让你感到奇怪。
嵌套元素
其中一件事是,你不能创建一个返回超过一个HTML子元素的Styled component组件。
Styled component组件 = 单个HTML元素(或React Native中的原生元素)。
解决的办法也很简单,如果你需要一个结构复杂的组件。只需创建一个普通的React组件,它由多个Styled component组件构成:
const Wrapper = styled.div`
display: flex;
`;
const Left = styled.div`
flex-grow: 1;
`;
const Right = styled.div`
flex-grow: 2
`;
const Layout = props => (
<Wrapper>
<Left>Left column</Left>
<Right>Right column</Right>
</Wrapper>
);
HTML可读性变差
我在上面已经提到过,渲染出来的HTML默认包含随机生成的class名。但babel-plugin-styled-components可以很容易解决这个问题。
编辑器的语法支持
一些编辑器会对模板字面量语法感到困惑。但一般都会有插件支持,有些编辑器默认就支持CSS突出显示和建议。
React only
Styled components只支持React。如果你用其他的JS框架你必须寻找其他CSS方案。