软件开发架构师

Emotion 10发布:支持更灵活的样式和全局样式以及服务器端渲染

前端 127 2019-04-22 22:53

CSS-in-JS 库 Emotion 最近发布了一个主要版本,这是一个备受期待的大版本,带来了很多新特性、改进和缺陷修复,其中有很多很突出的特性。现在可以使用 css 属性给组件添加样式,可以通过更自然的语法来访问主题属性。新增了一个新的 Global 组件,用于动态添加全局样式。这些变更促进了零配置的服务器端渲染。

Emotion 10.0 现在不需要通过 Babel 插件在组件中使用 css 属性,因此,使用 Emotion 库的开发人员可以禁止在项目中使用自定义 Babel 配置(Create React App、codesandbox.io,等等)。现在可以在使用了 css 属性的源文件头部加入 Emotion 的 jsx pragma:

复制代码
/** @jsx jsx */ import { jsx } from '@emotion/core'

Emotion 10.0 确定了样式优先规则,并提供了文档。在选择了优先规则之后,通过 css 属性定义的组件样式可以通过父组件传递过来的 className 属性进行自定义。文档对优先规则进行了概括:

包含来自 className 属性指定的 Emotion 样式将覆盖 css 属性指定的样式。

不是来自 Emotion 的类名将被忽略,并被追加到计算好的 Emotion 类名中。

文档中还提供了清晰的示例。组件 ArticleText 覆盖了组件 P 的默认样式,但 P 与 SmallArticleText(覆盖了 ArticleText)有相同的颜色。

复制代码
/** @jsx jsx */ import { jsx } from '@emotion/core' const P = props => ( <p css={{ margin: 0, fontSize: 12, lineHeight: '1.5', fontFamily: 'sans-serif', color: 'black' }} {...props} // <- props contains the `className` prop /> ) const ArticleText = props => ( <P css={{ fontSize: 14, fontFamily: 'Georgia, serif', color: 'darkgray' }} {...props} // <- props contains the `className` prop /> ) const SmallArticleText = props => ( <ArticleText css={{ fontSize: 10 }} {...props} // <- props contains the `className` prop />

与 CSS 规范当中的出现次序规则一样,后面通过 + 定义的属性值将覆盖前面通过 - 定义的属性值。

复制代码
.css-result { + margin: 0; - font-size: 12px; + line-height: 1.5; - font-family: 'sans-serif'; - color: black; - font-size: 14px, + font-family: Georgia, serif, + color: darkgray; + font-size: 10px; }

SmallArticleText 的样式将包含来自 P 的“margin: 0”和来自 ArticleText 的“color: ‘darkgray’”。不过,为 SmallArticleText 定义的字体大小“font-size: 10px”将覆盖上层组件定义的字体大小。类似的,在 ArticleText 中定义的颜色样式将覆盖在 P 中定义的颜色样式(color: ‘black’)。

正如上述的第二条优先规则所提到的,不是来自 Emotion 的类名对优先规则不会有任何影响。

Emotion 10.0 现在支持组件同时具有 css 属性和通过对象延展语法传递进来的其他属性。css 属性还可以支持用于暴露主题属性的函数式语法,如下所示:

复制代码
/** @jsx jsx */ import { jsx } from "@emotion/core"; import { ThemeProvider } from "emotion-theming"; import { render } from "react-dom"; function Header(props) { return ( <h1 css={theme => ({ fontSize: 48, fontWeight: 600, color: theme.colors.header })} {...props} /> ); } function BodyText(props) { return ( <p css={theme => ({ color: theme.colors.primary, fontFamily: "sans-serif", fontSize: 18, "&:hover": { color: theme.colors.hover } })} {...props} /> ); } function App() { return ( <ThemeProvider theme={{ colors: { primary: "hotpink", hover: "crimson", header: "dimgray" } }} > <div> <Header>Header Title</Header> <BodyText>Hello Emotion 10!!!</BodyText> </div> </ThemeProvider> ); } render(<App />, document.getElementById("root"

上面的例子展示了 css 属性函数式语法(css = { theme => ({…)以及对象延展语法和 css 属性(<p css = {theme => (…) {…props}/>)并存。

新的 Global 组件可用于动态更新或移除全局样式,具体请参考相关的特性文档

复制代码
import { Global, css } from '@emotion/core' render( <div> <Global styles={css` * { color: hotpink !important; } `} /> <Global styles={{ '.some-class': { fontSize: 50, textAlign: 'center' } }} /> <div className="some-class"> Everything is hotpink now! </div> </div> )

用于显示内容的 div 将会显示一个居中的粉色文本。在样式发生改变或 Global 组件被卸载时,全局样式会被更新或移除。

通过上述的这些变更可以实现零配置的服务器端渲染,发布公告中写道:

如果你使用的是新的 css 属性或 styled,只需要调用 React 的 renderToString(或 renderToNodeStream),其他什么都不用做。这对于组件来说是非常友好的,因为用户不需要做特别的事情就可以使用组件。

你现在可以将带有样式的组件发布到 NPM,用户不需要做额外的事情就可以在服务器端渲染它们。

Emotion 10.0 还包含了很多其他变更、改进和缺陷修复。官网为增量升级到新的 API 提供了一个迁移指南,并且可以借助ESLint 插件来自动化部分迁移过程。

CSS-in-JS 是一种 CSS 编排模式,即通过 JavaScript 编排 CSS,而不是把它们定义在外部的 CSS 文件中。Emotion 是一个运行时 CSS-in-JS 库,可以通过对象或 CSS 风格的字符串样式来定义组件样式。运行时 CSS-in-JS 库(如 Emotion 或Styled-components)可以在运行时修改样式,比如在运行时将样式标签注入到文档中。零运行时 CSS-in-JS 库(如LinariaAstroturf)则在构建时抽取所有的 CSS。

Emotion 是一个基于 MIT 许可的开源项目,开发者可以通过Emotion GitHub 项目参与贡献,不过需要遵循 Emotion 项目的行为准则和贡献指南。

查看英文原文Emotion 10: CSS-in-JS with Flexible Scoped and Global Styling, and Server-Side Rendering

文章评论