为什么我们一直在讨论 CSS-in-JS?
你还记得第一次编写 HTML/CSS 代码时的感受吗?是不是感觉很棒?
<div style="color: blue">Hello world</div>
如此简单,如此纯粹。
当然,高级开发人员™会告诉你不要这样编写 CSS,而是把它放在一个单独的文件中。
<div class="blue-text">Hello world</div>
/* style.css */
.blue-text {
color: blue;
}
随着你构建的元素和页面越来越多,你的style.css文件会变得越来越长,所以你需要将其拆分成多个文件。
/* landing-page.css */
.heading {
font-size: 64px;
}
button {
background: orange;
}
/* forms.css */
button {
background: blue;
}
很快,你就会发现原本用于某个元素的样式开始冲突,并覆盖其他元素的样式。于是,你采用了一种命名空间机制来为这些样式创建一个作用域。
或许可以像这样简单一些:
<form>
<input placeholder="email" />
<button>Submit<button>
</form>
/* form.css */
form button {
background: blue;
}
或者更高级的,比如BEM:
<form class="form">
<input class="form__input" placeholder="email" />
<button class="form__button">Submit<button>
</form>
/* form.css */
.form__button {
background: blue;
}
我非常喜欢 BEM(以及其他基于约定的方法,例如 OOCSS、ITCSS 等)。只需在团队中采用一种通用约定,就能解决棘手的问题。
无论哪种方式,你在这里要解决的问题是将样式限定在特定上下文中。
同样的问题和解决方案也适用于 React。例如LoginForm:
function LoginForm() {
return (
<form className="form">
<input placeholder="username" type="text " />
<input placeholder="password" type="password" />
<button className="button">Submit</button>
</form>
)
}
我们无法预知这个按钮是否会与应用程序中其他地方的按钮冲突。因此,我们应该在这里使用某种作用域。即使使用 React,你仍然可以像使用 BEM 一样使用命名空间。
<button className="form__button">Submit</button>
故事从这里开始变得有趣了。在 React 组件中,我们不再编写普通的代码HTML,而是编写JSX……
上述 JSX 代码在构建时会转换为以下 JavaScript 代码块:
React.createElement(
'button',
{ className: 'form__button' },
'Submit'
)
现在,您可以完全掌控编程语言(JavaScript)的强大功能。您可以做到纯 CSS 无法实现的事情。
CSS-in-js 的前景
你可以将创建作用域或命名空间的任务交给语言本身,而不是手动完成。
CSS Modules是进入 css-in-js 生态系统的入门级工具。
你要写的是:
/* form.css */
button {
/* look ma, no name spacing */
background: blue;
}
import styles from './form.css'
function LoginForm() {
return (
<form>
<button className={styles.button}>Submit</button>
</form>
)
}
styles.button编译后的结果如下:
function LoginForm() {
return (
<form>
<button className="form__button__abc1">Submit</button>
</form>
)
}
这与手写样式非常相似,但它让你无需担心样式冲突。能够像局部作用域一样编写样式,让我感到无比自由。
下一代 CSS-in-JS 库
我们已经能够在工具/自动化方面利用语言的力量,我们能否也将其运用到写作风格方面呢?
争议就出在这里。每一种 CSS-in-JS 实现方式都略有不同,它们通过权衡取舍来实现某些新功能。
例如:jsxstyle允许您在元素上编写看起来像经典内联样式的样式,但通过 webpack 插件将其提取到一个文件中。
<Block component="button" backgroundColor="blue" />
另一方面,styled-components它允许你在 CSS 中混合运行时逻辑。这意味着你可以无需修改配置即可开始使用它,但你无法将样式提取出来。
const Button = styled.button`
background: ${getBackground};
`
function getBackground(props) {
if (props.appearance === 'primary') return 'blue'
else if (props.appearance === 'disabled') return 'grey'
else return 'white'
}
linaria它采用了一种有趣的折衷方案css,即通过标签在组件旁边创建类,并在构建过程中使用 Babel 插件提取这些类。这意味着你仍然可以使用 JavaScript,但它不能像之前的示例那样依赖于运行时逻辑。
const button = css`
background: ${colors.blue};
`
function MyComponent() {
return <button className={button}>Click me</button>
}
正如你所见,所有这些库都各有所长,但也都有其不足之处。正因如此,它们才如此具有争议性,你几乎可以找到任何一个库的缺陷。
css-modules它可以自动处理命名空间样式,但需要一些设置,这可能被视为过度设计(我们已经有了无需任何设置的手动 BEM)。
styled-components另一方面,它不需要任何 babel/webpack 设置,但需要在运行时存在该库,这会略微增加 javascript 包的大小。
你必须选择适合你项目的权衡方案。
我们之所以选择Auth0 的设计系统,styled-components是因为它帮助我们基于一组底层令牌和设计模式创建灵活的组件。
上周,我需要构建很多包含表单逻辑的页面,我非常喜欢使用它,css-modules因为它帮助我编写全局样式和页面特定样式,而无需采用像 BEM 这样的手动方法。
你可以使用我朋友Michele Bertoli制作的这张对比表。
希望这对你的旅程有所帮助。
西德
文章来源:https://dev.to/siddharthkp/why-do-we-keep-talking-about-css-in-js-35i8
