Skip to content
微信公众号

CSS-IN-JS

什么是CSS-IN-JS呢?实际上它就是一种解决方案,在这种解决方案中,它提倡我们使用JavaScript代码去编写CSS代码,也就是它提倡将CSS代码写到JavaScript文件当中。

为什么会有CSS-IN-JS

CSS-IN-JS 是 WEB 项⽬中将 CSS 代码捆绑在 JavaScript 代码中的解决⽅案。这种⽅案旨在解决 CSS 的局限性, 例如缺乏动态功能, 作⽤域和可移植性。具体原因如下:

在React中我们已经将html和js写在一起了,如果再将css写入其中,那么html、css和js都在一起了。这与我们的认知背道而驰了,我们认知中应该将html、css和js应该分别编写。这里的原因是为什么呢?其实就是开发方式的变化,以前我们开发前端项目中都是以页面为单位的,例如开发一个首页和列表页,这时候css文件是通过link标签引入html中,由于css没有作用域的概念,所以整个css代码都会被应用到html文件当中,这在当时是没有问题的。

而现在开发前端项目都是以组件为单位的,既然以组件为单位,我们希望css代码指定用于某一个组件,也就是说css代码只在组件范围内生效。这样的好处是组件与组件的css代码不会有冲突,但是要实现这样的功能就需要css要有作用域的概念,但是css没有这样的功能。如果使用CSS-IN-JS解决方案的话,就可以通过JavaScript作用域模拟CSS作用域,这样css代码就可以只用于组件内部了。这就是第一个原因。

第二个原因是增加了组件的独立性和可移植性,如果我们把CSS代码都写在不同的css文件中,当我们想把组件放到其他地方的时候,在移动的时候可能少复制css文件,如果采用CSS-IN-JS解决方案的话,我们把css写在js中,这样组件就是一个单独的文件,当我们想移动组件的时候直接移动组件本身即可,而不用担心其依赖问题。

第三个原因是css缺乏动态功能,不能根据条件来给某个元素添加什么样的样式,如果写在js中,可以使用js动态功能来为元素动态添加样式了。

CSS-IN-JS介绍

CSS-IN-JS ⽅案的优点:

  1. 让 CSS 代码拥有独⽴的作⽤域, 阻⽌ CSS 代码泄露到组件外部, 防⽌样式冲突
  2. 让组件更具可移植性, 实现开箱即⽤, 轻松创建松耦合的应⽤程序
  3. 让组件更具可重⽤性, 只需编写⼀次即可, 可以在任何地⽅运⾏. 不仅可以在同⼀应⽤程序中重⽤组件, ⽽且可以在使⽤相同框架构建的其他应⽤程序中重⽤组件
  4. 让样式具有动态功能, 可以将复杂的逻辑应⽤于样式规则, 如果要创建需要动态功能的复杂UI, 它是理想的解决⽅案

CSS-IN-JS ⽅案的缺点:

  1. 为项⽬增加了额外的复杂性.
  2. ⾃动⽣成的选择器⼤⼤降低了代码的可读性

Emotion库

Emotion介绍

Emotion 是⼀个旨在使⽤ JavaScript 编写 CSS 样式的库,要想使用这个库需要下载两个模块。

shell
npm install @emotion/core @emotion/styled

emotion提供了一个css属性,css属性的作用就是为元素添加样式

jsx
import React from 'react';

function App(){
    return <div css={{width:200,height:200,background:'red'}}>App works</div>
}

export default App

默认项目中并不知道如何解析css属性,所以我们需要使用babel配置让项目知道css如何被解析。

css属性支持

  1. JSX Pragma:在项目中添加jsx以及注释。通知 babel, 不再需要将 jsx 语法转换为 React.createElement ⽅法, ⽽是需要转换为 jsx ⽅法
jsx
import React from 'react';
/** @jsx jsx */
import { jsx } from '@emotion/core'

function App(){
    return <div css={{width:200,height:200,background:'red'}}>App works</div>
}

export default App
  1. Babel Preset,通过babei预置方式实现
  • 使用npm run eject 把react底层的配置弹射出来
  • 安装@emotion/babel-preset-css-prop
  • 在 package.json ⽂件中找到 babel 属性, 加⼊如下内容
js
"presets":[
    "react-app",
    "@emotion/babel-preset-css-prop"
]

css方法

css方法是与css属性配合在一起使用,通过调用css方法可以把css行内样式放到外面中编写。

  1. 模板字符串函数,String Styles
jsx
import { css } from '@emotion/core'
const style=css'
    width:100px;
    height:100px;
    background:skyblue;
';
<div css={style}>App works....</div>
  1. Object Styles
jsx
import { css } from '@emotion/core'
const style=css({
    width:100,
    height:100,
    background:'pink'
});

function App(){
    return <div css={style}>App works....</div>
}

推崇第一种方式。

css属性优先级

props 对象中的 css 属性优先级⾼于组件内部的 css 属性,在调⽤组件时可以在覆盖组件默认样式。

Styled Components 样式化组件

样式化组件就是⽤来构建⽤户界⾯的,是 emotion 库提供的另⼀种为元素添加样式的⽅式

js
import styled from '@emotion/styled'
  1. String Styles
js
const Button = styled.button`
    color:red
`
  1. Object Styled
js
const Button = styled.button({
    color: 'green'
})

根据props属性覆盖样式

  1. String Styles
js
const Button = styled.button`
    width: 100px;
    height: 30px;
    background: ${props=>props.bgColor || 'skyblue'};
`;
  1. Object Styles
js
const Container = styled.div(props=>({
    width: props.w || 1000,
    background: 'pink',
    margin: '0 auto'
}));

对象样式另一种语法

js
const Button = styled.button({
    color: 'red'
},props=>({
    color: props.color
}))

为任何组件添加样式

  1. String Styles
jsx
const Demo = ({className})=><div className={className}>Demo</div>
const Fancy = styled(Demo)`
    color: red;
`
  1. Object Styles
js
const Demo = ({className})=><div className={className}>Demo</div>
const Fancy = styled(Demo)({
    color: 'red'
})

通过父组件设置子组件样式

  1. String Styles
js
const Child = styled.div`
    color: red;
`
const Parent = styled.div`
    ${Child}{
        color: green;
    }
`
  1. Object Styles
js
const Child = styled.div({
    color: 'red'
})

const Parent = styled.div({
    [Child]:{
        color: 'green'
    }
})

通过父组件设置子组件样式(需要babel插件支持)

  1. npm install babel-plugin-emotion
  2. 在package.json文件中找到babel属性,加入如下内容
js
"babel":{
    "plugins": ["emotion"]
}

嵌套选择器& ,&表示组件本身

js
const Container = styled.div`
    color: red;
    & > a{
        color: pink;
    }
`

as属性,要使用组件中的样式,但是要更改呈现的元素,可以使用as属性

jsx
const Button = styled.button`
    color: red
`
<Button as="a" href="#">button</Button>

样式组合

在样式组合中,后调用的样式优先级高于先调用的样式

jsx
const base = css`
    color: yellow
`;
const danger = css`
    color: red;
`;
<button css={[base,danger]}>button</button>

全局样式

jsx
import {css,Global} from '@emotion/core'
const styles = css`
    body{margin:0;}
`;
function App(){
    return <>
        <Global styles={styles}/>
        App works...
    </>;
}

关键帧动画

jsx
const move=keyframes`
    0% {left:0;top:0;background:pink;}
    100% {top:300px;left:600px;background:skyblue;}
`;
const box = css`
    width: 100px;
    height: 100px;
    position: absolute;
    animation: ${move} 2s ease infinite alternate;
`
function App(){
    return <div css={box}>
        App works ...
    </div>;
}

主题

  1. 下载主题模块
shell
npm install emotion-theming
  1. 引入ThemeProvider组件
js
import {ThemeProvider} from 'emotion-theming';
  1. 将ThemeProvider放置在视图最外层
jsx
function App(){
    return <ThemeProvider></ThemeProvider>;
}
  1. 添加主题内容
jsx
const theme={
    colors:{
        primary: 'hotpink'
    }
}
<ThemeProvider theme={theme}></ThemeProvider>
  1. 获取主题内容
jsx
const getPrimaryColor = props=>css`
    color:${props.colors.primary}
`;
<div css = {getPrimaryColor}></div>
js
import { useTheme } from 'emotion-theming'
function Demo(){
    const theme = useTheme();
}

本站总访问量次,本站总访客数人次
Released under the MIT License.