Css in Js

3,907 阅读4分钟

出现背景


传统“关注点分离”

各种技术只负责自己的领域,不要混合在一起,形成耦合。对于网页开发来说,主要是三种技术分离。

  • HTML 语言:负责网页的结构,又称语义层
  • CSS 语言:负责网页的样式,又称视觉层
  • JavaScript 语言:负责网页的逻辑和交互,又称逻辑层或交互层

并且大家会说,尽量不要写"行内样式"(inline style)和"行内脚本"(inline script)。

React的出现

React 是组件结构,强制要求把 HTML、CSS、JavaScript 写在一起。这个传统的“关注点分离”的思想,完全是背道而驰。但是,这有利于组件的隔离。每个组件包含了所有需要用到的代码,不依赖外部,组件之间没有耦合,很方便复用。所以,随着 React 的走红和组件模式深入人心,这种"关注点混合"的新写法逐渐成为主流。

image 表面上,React 的写法是 HTML、CSS、JavaScript 混合在一起。但是,实际上不是。现在其实是用 JavaScript 在写 HTML 和 CSS。

React 在 JavaScript 里面实现了对 HTML 和 CSS 的封装,我们通过封装去操作 HTML 和 CSS。也就是说,网页的结构和样式都通过 JavaScript 操作。

Css in Js是什么(what?)


React 对 CSS 封装非常简单,就是沿用了 DOM 的 style 属性对象。用JS来写CSS,这就是Css in Js,他是Js脚本的一部分。

怎么使用(how?)


const style = {
  'color': 'red',
  'fontSize': '14px'
};

const clickHandler = () => alert('hello stone'); 

ReactDOM.render(
  <h1 style={style} onclick={clickHandler}>
     Hello, world!
  </h1>,
  document.getElementById('root')
);

不同的实现


CSS-in-JS的实现方法上区分大体分为两种:唯一CSS选择器和内联样式(Unique Selector VS Inline Styles)。接下来我们会分别看一下对应于这两种实现方式的两个比较有代表性的实现:styled-components和radium。

Styled-components

动态生成CSS选择器,并把对应的CSS样式通过style标签的形式插入到head标签里面。动态生成的CSS选择器会有一小段哈希值来保证全局唯一性来避免样式发生冲突。

// 查看https://www.cssinjsplayground.com/
import React from 'react';
import styled from 'styled-components';

import Form from './form';
import Header from './header';

const Container = styled.main`
  display: flex;
  flex-direction: column;
  min-height: 100%;
  width: 100%;
  background-color: #f6f9fc;
`;

const Stripe = styled.div`
  height: 10vh;
  overflow: hidden;
  transform: skewY(-8deg);
  transform-origin: 0;
  background: linear-gradient(-150deg, rgba(255, 255, 255, 0) 40%, #ddecf7 70%);
`;

export default function Login() {
  return (
    <Container>
      <Header />
      <Stripe />
      <Form fields={['email', 'phoneNumber']} />
    </Container>
  );
}

Radium

Radium和styled-components的最大区别是它生成的是标签内联样式(inline styles)。由于标签内联样式在处理诸如media query以及:hover,:focus,:active等和浏览器状态相关的样式的时候非常不方便,所以radium为这些样式封装了一些标准的接口以及抽象。

import React, { Component } from 'react';
import Radium from 'radium';

import Form from './form';
import Header from './header';

function Login() {
  return (
    <div style={styles.container}>
      <Header />
      <div style={styles.stripe} />
      <Form />
    </div>
  );
}

const styles = {
  container: {
    display: 'flex',
    flexDirection: 'column',
    minHeight: '100%',
    width: '100%',
    backgroundColor: '#f6f9fc'
  },

  stripe: {
    height: '10vh',
    overflow: 'hidden',
    transform: 'skewY(-8deg)',
    transformOrigin: 0,
    background:
      'linear-gradient(-150deg, rgba(255, 255, 255, 0) 40%, #ddecf7 70%)'
  }
};

export default Radium(Login);

优缺点(Why?)


优势
  • 局部样式 - Scoping Styl
    • CSS-in-JS会提供自动局部CSS作用域的功能,你为组件定义的样式会被限制在这个组件,而不会对其他组件的样式产生影响。不同的CSS-in-JS库实现局部作用域的方法可能有所不一样,一般来说它们会通过为组件的样式生成唯一的选择器来限制CSS样式的作用域
  • 避免无用的CSS样式堆积 - Dead Code Elimination
    • CSS-in-JS会把样式和组件绑定在一起,当这个组件要被删除掉的时候,直接把这些代码删除掉就好了,不用担心删掉的样式代码会对项目的其他组件样式产生影响。而且由于CSS是写在JavaScript里面的,我们还可以利用JS显式的变量定义,模块引用等语言特性来追踪样式的使用情况,这大大方便了我们对样式代码的更改或者重构。
  • 基于状态的样式定义 - State-based styling
劣势
  • 学习成本高
  • 运行时消耗
  • 代码可读性差
  • 没用统一的标准