数据API 案例 开发者 关于
掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务
新闻动态 > 媒体报道

Styled Components:让样式也成为组件

前言

为了应对越来越复杂的web应用,组件化应运而生,React、Vue等组件化框架使我们的程序更简单更加可维护。在一个组件内会将结构、样式和逻辑写在一起,虽然这违背了关注点分离的原则,但是这有利于组件间的隔离。为了顺应组件化的潮流,人们开始考虑使用JS上编写CSS,styled components就是其中一种解决方案。styled components是一个React第三方库,作用是可以将样式写成组件的形式,实现在JS上编写CSS。

基本用法

安装

1
2

npm install -S styled-components
 

使用styled-components不需要再使用className属性来控制样式,而是将样式写成更具语义化的组件的形式,如下例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import React from 'react';
import styled from 'styled-components';
import { render } from 'react-dom';
 
const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
class App extends React.Component {
    render() {
        return (
            <Title>Hello world</Title>
        )
    }
}
 
render(
    <App />,
    document.getElementById('app')
);
 

结果:

上例中的styled.h1是一个标签模板函数,紧跟其后的是一个模板字符串参数,“标签模板”和“模板字符串”都是es6的语法,具体可以参考阮一峰老师ECMASCRIPT6入门中的模板字符串标签模板

styled.h1函数返回一个React Component,styled components会为这个React Component添加一个class,该class的值为一个随机字符串。传给styled.h1的模板字符串参数的值实际上是CSS语法,这些CSS会附加到该React Component的class中,从而为React Component添加样式:

更简单地控制样式 —— props参数

在React中是通过控制className和style来控制样式的,如下例,Title组件需要判断是否有primary属性来判断是否渲染”title-primary”类的样式:

1
2
3
4
5
6
7
8
9

class Title extends React.Component {
    render() {
        const className = `title${this.props.primary ? ' title-primary' : ''}`;
        return (
            <div className={className}>{this.props.children}</div>
        );
    }
}
 

1
2

<Title primary>Hello world</Title>
 

styled components使用props来控制样式,将控制样式代码放在样式组件中,使React组件更加简洁:

1
2
3
4
5
6

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: ${props => props.primary ? 'SteelBlue' : 'palevioletred'};
`;
 

1
2

<Title primary>Hello world</Title>
 

上面两种写法非常相似,实际上还是要用CSS的语法编写样式。但是第一种写法需要className或style作为“中间人”使JS找到对应的样式,而styled components的写法中样式组件暴露props让外层JS来控制样式,不再需要className或style这样的“中间人”,移除了样式和组件间的映射关系

支持全部CSS特性

实际上styled components使用的还是CSS,因此完美支持CSS的所有特性。伪类,媒体查询,keyframes都可以在styled components中实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
 
    &:hover {
        background-color: #ddd;
    }
 
    @media (max-width: 650px) {
        font-size: 1em;
    }
 
`;
 

上例中,鼠标放在“Hello world”的时候会变成灰色,窗口宽度少于650px的时候文字大小会变成1em。

CSS作用域

CSS有一个痛点——CSS的作用域是全局的。当两个CSS选择器有冲突时,会根据选择器的权值确定使用哪一个选择选择器。当项目较大时,编写的css选择器很难判断会不会把另外一个选择器冲掉。
解决CSS作用域的其中一个方法就是使用后代选择器,这种用法和命名空间相似,即在每个选择器前添加一个父元素的选择器,从而减少选择器冲突的概率:

1
2
3
4
5
6
7
8

#myParent .title {
    /*...*/
}
 
#myParent .title-primary {
    /*...*/
}
 

LESS和SASS的持选择器嵌套的语法,该语法最终会编译成后代选择器的形式,和上述方法实际上是一样的:

1
2
3
4
5
6
7
8
9
10

#myParent {
    .title {
        /*...*/
    }
 
    .title-primary {
        /*...*/
    }
}
 

使用嵌套语法能较好的解决CSS全局作用域的问题,但是,由于编译出来的CSS选择器过于具体,一个组件组件难以复用另一个组件的当时,你的组件样式变得孤立起来。

上文有提到,使用styled components会给生成的React组件添加一个值为随机字符串的className。使用同一个styled components生成的多个React组件的className是不同的,这种随机className的机制使得组件之间的className值不会冲突,从而解决了CSS全局作用域的问题。

styled components也支持css的嵌套语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
const Wrapper = styled.div`
    font-size: 1.2em;
 
    .content1 {
        color: red;
    }
 
    .content2 {
        color: green;
    }
`;
 

1
2
3
4
5
6

<Wrapper>
    <div>You'd better don't do that like so:</div>
    <div className="content1">I am red</div>
    <div className="content2">I am green</div>
</Wrapper>
 

不推荐在styled components中使用嵌套,因为样式组件的子组件的className不会被编译成随机值,这些子组件的类还是会受CSS的全局作用域影响。

分离逻辑组件和展示组件

使用styled components,可将组件分为逻辑组件和展示组件,逻辑组件只关注逻辑相关的部分,展示组件只关注样式。通过解耦成两种组件,可以使代码变得更加清晰可维护。
当逻辑有变化,如后台拉取的数据的格式有所变化时,只需关注并修改逻辑组件上的代码,展示组件的代码不用动。而当UI需要变化时,只需改变展示组件上的代码,并保证展示组件暴露的props接口不变即可。逻辑组件和展示组件各司其职,修改代码时错误发生率也会有所减少。

CSS Module vs Styled Components

CSS Module是另一种解决全局作用域的方案,还没了解CSS Module的朋友可以参考CSS Modules 入门及 React 中实践 和CSS Modules 用法教程这两篇博文。
CSS Module只需修改构建代码和使用模块依赖引入className的方式即可使用,且支持less和sass的语法,样式代码不用修改即可让使用CSS语法的旧项目零成本接入。而styled components是一种全新的样式组件化的编程方式,不支持less和sass语法。
CSS Module还是JS和CSS分离的写法,而styled components实际上是在JS上写CSS。习惯JS、CSS和HTML都分离的人或许不习惯styled components的写法。

最后

styled components一种全新的控制样式的编程方式,它能解决CSS全局作用域的问题,而且移除了样式和组件间的映射关系。传统的web开发推崇HTML、CSS、Javascript都分离,styled components则有点“离经叛道”的味道——在JS上编写CSS,什么东西都在JS里写感觉是近几年前端开发的趋势,React就是一个活生生的例子。究竟这是不是一个好趋势,现在还不好判断,但是实践和时间总会给我们一个答案。

参考文章

1.Styled Components: Enforcing Best Practices In Component-Based Systems
2.[译] 一个关于 Styled Components 的五分钟介绍
3.CSS Modules vs Styled Components

原文来自:AlloyTeam

掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务
新闻动态 > 媒体报道
Styled Components:让样式也成为组件
发布:2017-05-31

前言

为了应对越来越复杂的web应用,组件化应运而生,React、Vue等组件化框架使我们的程序更简单更加可维护。在一个组件内会将结构、样式和逻辑写在一起,虽然这违背了关注点分离的原则,但是这有利于组件间的隔离。为了顺应组件化的潮流,人们开始考虑使用JS上编写CSS,styled components就是其中一种解决方案。styled components是一个React第三方库,作用是可以将样式写成组件的形式,实现在JS上编写CSS。

基本用法

安装

1
2

npm install -S styled-components
 

使用styled-components不需要再使用className属性来控制样式,而是将样式写成更具语义化的组件的形式,如下例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import React from 'react';
import styled from 'styled-components';
import { render } from 'react-dom';
 
const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
class App extends React.Component {
    render() {
        return (
            <Title>Hello world</Title>
        )
    }
}
 
render(
    <App />,
    document.getElementById('app')
);
 

结果:

上例中的styled.h1是一个标签模板函数,紧跟其后的是一个模板字符串参数,“标签模板”和“模板字符串”都是es6的语法,具体可以参考阮一峰老师ECMASCRIPT6入门中的模板字符串标签模板

styled.h1函数返回一个React Component,styled components会为这个React Component添加一个class,该class的值为一个随机字符串。传给styled.h1的模板字符串参数的值实际上是CSS语法,这些CSS会附加到该React Component的class中,从而为React Component添加样式:

更简单地控制样式 —— props参数

在React中是通过控制className和style来控制样式的,如下例,Title组件需要判断是否有primary属性来判断是否渲染”title-primary”类的样式:

1
2
3
4
5
6
7
8
9

class Title extends React.Component {
    render() {
        const className = `title${this.props.primary ? ' title-primary' : ''}`;
        return (
            <div className={className}>{this.props.children}</div>
        );
    }
}
 

1
2

<Title primary>Hello world</Title>
 

styled components使用props来控制样式,将控制样式代码放在样式组件中,使React组件更加简洁:

1
2
3
4
5
6

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: ${props => props.primary ? 'SteelBlue' : 'palevioletred'};
`;
 

1
2

<Title primary>Hello world</Title>
 

上面两种写法非常相似,实际上还是要用CSS的语法编写样式。但是第一种写法需要className或style作为“中间人”使JS找到对应的样式,而styled components的写法中样式组件暴露props让外层JS来控制样式,不再需要className或style这样的“中间人”,移除了样式和组件间的映射关系

支持全部CSS特性

实际上styled components使用的还是CSS,因此完美支持CSS的所有特性。伪类,媒体查询,keyframes都可以在styled components中实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
 
    &:hover {
        background-color: #ddd;
    }
 
    @media (max-width: 650px) {
        font-size: 1em;
    }
 
`;
 

上例中,鼠标放在“Hello world”的时候会变成灰色,窗口宽度少于650px的时候文字大小会变成1em。

CSS作用域

CSS有一个痛点——CSS的作用域是全局的。当两个CSS选择器有冲突时,会根据选择器的权值确定使用哪一个选择选择器。当项目较大时,编写的css选择器很难判断会不会把另外一个选择器冲掉。
解决CSS作用域的其中一个方法就是使用后代选择器,这种用法和命名空间相似,即在每个选择器前添加一个父元素的选择器,从而减少选择器冲突的概率:

1
2
3
4
5
6
7
8

#myParent .title {
    /*...*/
}
 
#myParent .title-primary {
    /*...*/
}
 

LESS和SASS的持选择器嵌套的语法,该语法最终会编译成后代选择器的形式,和上述方法实际上是一样的:

1
2
3
4
5
6
7
8
9
10

#myParent {
    .title {
        /*...*/
    }
 
    .title-primary {
        /*...*/
    }
}
 

使用嵌套语法能较好的解决CSS全局作用域的问题,但是,由于编译出来的CSS选择器过于具体,一个组件组件难以复用另一个组件的当时,你的组件样式变得孤立起来。

上文有提到,使用styled components会给生成的React组件添加一个值为随机字符串的className。使用同一个styled components生成的多个React组件的className是不同的,这种随机className的机制使得组件之间的className值不会冲突,从而解决了CSS全局作用域的问题。

styled components也支持css的嵌套语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
const Wrapper = styled.div`
    font-size: 1.2em;
 
    .content1 {
        color: red;
    }
 
    .content2 {
        color: green;
    }
`;
 

1
2
3
4
5
6

<Wrapper>
    <div>You'd better don't do that like so:</div>
    <div className="content1">I am red</div>
    <div className="content2">I am green</div>
</Wrapper>
 

不推荐在styled components中使用嵌套,因为样式组件的子组件的className不会被编译成随机值,这些子组件的类还是会受CSS的全局作用域影响。

分离逻辑组件和展示组件

使用styled components,可将组件分为逻辑组件和展示组件,逻辑组件只关注逻辑相关的部分,展示组件只关注样式。通过解耦成两种组件,可以使代码变得更加清晰可维护。
当逻辑有变化,如后台拉取的数据的格式有所变化时,只需关注并修改逻辑组件上的代码,展示组件的代码不用动。而当UI需要变化时,只需改变展示组件上的代码,并保证展示组件暴露的props接口不变即可。逻辑组件和展示组件各司其职,修改代码时错误发生率也会有所减少。

CSS Module vs Styled Components

CSS Module是另一种解决全局作用域的方案,还没了解CSS Module的朋友可以参考CSS Modules 入门及 React 中实践 和CSS Modules 用法教程这两篇博文。
CSS Module只需修改构建代码和使用模块依赖引入className的方式即可使用,且支持less和sass的语法,样式代码不用修改即可让使用CSS语法的旧项目零成本接入。而styled components是一种全新的样式组件化的编程方式,不支持less和sass语法。
CSS Module还是JS和CSS分离的写法,而styled components实际上是在JS上写CSS。习惯JS、CSS和HTML都分离的人或许不习惯styled components的写法。

最后

styled components一种全新的控制样式的编程方式,它能解决CSS全局作用域的问题,而且移除了样式和组件间的映射关系。传统的web开发推崇HTML、CSS、Javascript都分离,styled components则有点“离经叛道”的味道——在JS上编写CSS,什么东西都在JS里写感觉是近几年前端开发的趋势,React就是一个活生生的例子。究竟这是不是一个好趋势,现在还不好判断,但是实践和时间总会给我们一个答案。

参考文章

1.Styled Components: Enforcing Best Practices In Component-Based Systems
2.[译] 一个关于 Styled Components 的五分钟介绍
3.CSS Modules vs Styled Components

原文来自:AlloyTeam

电话 0512-88869195
数 据 驱 动 未 来
Data Drives The Future