At first glance, the styles object looks like CSS written in object notation with additional features, like passing a function to set the value based on props. The generated classes are unique, so you never need to worry about them clashing with other styles. In other words, you get scoping for free! This is how most CSS-in-JS libraries work — of course, with some twists in features and syntax that we’ll cover as we go.
You can see by the attributes that the width of our rendered image starts at 200px, then when the viewport width becomes at least 30rem, the width increases to 400px wide. We generated an extra 800 source to cover even larger screen densities:
1x screens will use 200 and 400
2x screens will use 400 and 800
styled-components is another CSS-in-JS library, but with a much more familiar syntax that cleverly uses tagged template literals instead of objects to look more like CSS:
We often create semantically-neutral elements like
and solely for styling purposes. This library, and many others, allow us to create and style them in a single motion.
My favorite benefit of this syntax is that it’s like regular CSS, minus interpolations. This means that we can migrate our CSS code more easily and we get to use our existing muscle memory instead of having to familiarize ourselves with writing CSS in the object syntax.
Notice that we can interpolate almost anything into our styles. This specific example demonstrates how we can save the media query in the variable and reuse it in multiple places. Responsive images are an excellent use case for this because the sizes attribute contains basically CSS, so we can use JavaScript to make the code more DRY.
Let’s say that we decided we want to visually hide the caption, but still make it accessible for screen readers. I know that a better way of achieving this would be to use an alt attribute instead, but let’s use a different way for the sake of this example. We can use a library of style mixins called polished — it works great with CSS-in-JS libraries making it great for our example. This library includes a mixin called hideVisually which does exactly what we want and we can use it by interpolating its return value:
Even though hideVisually outputs an object, the styled-components library knows how to interpolate it as styles.
CSS-in-JS libraries have many advanced features like theming, vendor prefixing and even inlining critical CSS, which makes it easy to stop writing CSS files entirely. At this point, you can start to see why CSS-in-JS becomes an enticing concept.
Downsides and limitations
The obvious downside to CSS-in-JS is that it introduces a runtime: the styles need to be loaded, parsed and executed via JavaScript. Authors of CSS-in-JS libraries are adding all kinds of smart optimizations, like Babel plugins, but some runtime costs will nevertheless exist.
It’s also important to note that these libraries aren’t being parsed by PostCSS because PostCSS wasn’t designed to be brought into the runtime. Many use stylis instead as a result because it’s much faster. This means that we unfortunately can’t use PostCSS plugins.
The last downside I’ll mention is the tooling. CSS-in-JS is evolving at a really fast rate and text editor extension, linters, code-formatters etc. need to play catch-up with new features to stay on par. For example, people are using the VS Code extension styled-components for similar CSS-in-JS libraries like emotion, even though they don’t all have the same features. I’ve even seen API choices of proposed features being influenced by the goal of retaining syntax highlighting!
The future
There are two new CSS-in-JS libraries, Linaria and astroturf, that have managed zero runtime by extracting CSS into files. Their APIs are similar to styled-components, but they vary in features and goals.
The goal of Linaria is to mimic the API of CSS-in-JS libraries like styled-components by having built-in features like scoping, nesting and vendor prefixing. Conversely, astroturf is built upon CSS Modules, has limited interpolation capabilities, and encourages using a CSS ecosystem instead of deferring to JavaScript.
I built Gatsby plugins for both libraries if you want to play with them:
Two things to have in mind when using these libraries:
having actual CSS files means that we can process them with familiar tools like PostCSS
Linaria uses custom properties (a.k.a. CSS variables) under the hood, be sure to take their browser support into consideration before using this library
Conclusion
CSS-in-JS are all-in-one styling solutions for bridging the gap between CSS and JavaScript. They are easy to use and they contain useful built-in optimizations — but all of that comes at a cost. Most notably, by using CSS-in-JS, we’re essentially ejecting from the CSS ecosystem and deferring to JavaScript to solve our problems.
Zero-runtime solutions mitigate some of the downsides by bringing back the CSS tools, which ascends the CSS-in-JS discussion to a much more interesting level. What are the actual limitations of preprocessing tools compared to CSS-in-JS? This will be covered in the next part of this series.
如果你使用以下元标记:http-equiv=”Content-Security-Policy” content=”default-src ‘self'”,以尝试阻止 XSS 攻击,那么如果你使用这种系统,这是否会阻止注入的内联样式起作用?反过来说,您是否通过注入内联样式创建了漏洞?
有趣,请告诉我更多!举例说明?此外,CSS-in-JS 不会注入内联样式,你是指
style
标签吗?感谢您的回复,Matija。举个例子,这个元标记:被用在这个网站上: http://www.nown.org.au/ 是为了防止 XSS 攻击——恶意代码的注入。详细信息/原因可以在这个链接中找到: https://developers.google.com/web/fundamentals/security/csp/
以这种方式使用内容安全策略会阻止浏览器使用任何不是来自存储 HTML 的服务器的代码,据我所知。
然而,结果是,浏览器将无法识别或运行任何内联 js 代码(例如:onclick=”myFunction()”)或任何内联 CSS(例如 style =”color:black;”)。并且头部部分的 style 标签也会失效;根本不起作用。
所有你的 JS 和 CSS(以及 JQuery)都必须来自与页面存储在同一服务器上的单独文件;即“self”。
所以这就是我的问题:CSS-inJS 注入(例如)style 标签是否与使用严格的内容安全策略(如“self”)兼容?
如果是,这是否会创建一个漏洞?
或者我完全搞错了?
抱歉回复得这么晚,我一直把这个放在我的收件箱里,因为我想查看一下。确实,它会阻止注入样式,我刚刚试过了!不过,似乎可以使用 nonce 来解决它。我不知道这个问题有多大,因为安全不是我的强项。但是 styled-components 有 关于此的资料。
我强烈反对 CSS-in-JS,主要是因为它违背了关注分离原则。
CSS-in-JS 试图解决的问题很大程度上是由于开发人员对 CSS 的知识和经验不足造成的。样式不会“泄漏”。CSS 中的 C 代表“级联”,这意味着 CSS 的全部精神是“向下泄漏”。这是一个特性,而不是弱点,你只需要学习如何使用它。有一些技巧和方法可以做到这一点,而且它们可以完美地扩展。
一个象征?你导入的“hideVisually”。你正在导入一个 JS 对象,它旨在将一个预制类插入到你的组件中,并将其与页面上的其他部分隔离开来。你难道不认为这正是 CSS 的用途吗?将这个类作为标准 CSS 类,在整个页面上可用,在需要它的组件上调用它?它将被共享,没有处理时间,只是纯粹的 CSS。
CSS-in-JS 的确切好处在网络上的其他地方有更好的说明,它们不适合放入一篇文章中。这更像是一个概述,为第二部分做铺垫。
本系列的两个部分密切相关,你可能更喜欢第二部分。;)
所以如果 CSS in JS 的发展趋势是在编译时提取它(我同意),为什么不直接使用 SASS 呢?与组件级 CSS 模块结合使用,你会得到 CSS in JS 的所有功能,但没有大量的额外样板/语法、性能开销和无数实现。当你需要它时,你还有一个一流的级联系统可用,因为,嗯……你正在设计一个主题,它应该为某个东西提供独特的品牌。
我相信这听起来很生气(是的,我见过那些聪明、爱炫耀的时髦人士的模因),但在我见过的所有前端变化中,大多数都让我兴奋,但这件事让我感到沮丧,以至于我时常怀疑我是否还想要继续做前端开发。我绝对讨厌进入一个使用 CSS in JS 的项目。它会将组件变成一团乱麻,如果不分离关注点或无法快速迭代和重用 20 年的社区 CSS,就很难推理。更不用说它的各种架构了。它会极大地减慢我的速度,而且不好玩。我是一个热爱优质代码的全栈开发人员。
主要问题是 CSS 模块的出现太晚了,很多人都没有注意到。CSS 模块证明了关于封装的论点是虚假的,这种论点不应该再被用来作为论点。SASS、LESS 拥有你需要的灵活性。它们所做的很多事情在运行时是不必要的。使用 CSS in JS,你既在运送大量额外的字节,又在做比使用简单样式元数据更多的处理。
我理解你的沮丧。作为一个样式爱好者,我一直在拼命地寻找最佳实践,虽然我很享受 CSS-in-JS 的灵活性,但我无法跟上它。这让我找到了本系列的第二部分,我建议你看一下。;)
严肃问题:与简单地替换一两个类或使用构建工具来实现相同效果相比,CSS-in-JS 的用例是什么?也许我参与的应用程序规模还不够大,无法看到其益处,但我就是不相信这是一个好主意。
这条 Twitter 线程 可能会有所帮助。
我是一个有点老派的开发者。我记得我们曾经为了将 HTML、CSS 和 JS 分开而进行了艰苦的斗争,当人们开始分别存储 HTML、JS 和 CSS 时,这在 web 开发中是一场伟大的胜利。如今,新一代的 web 开发者登场了,一切都回到了我们大约 15 年前开始的地方。抱歉,但对我来说,CSS-in-JS 的想法是不可接受的。我已经看到了它可能导致的结果。
CSS-in-JS 只是其中一种方法,本系列的第二部分介绍了一种现代方法来处理老式的 CSS。;)
CSS-in-JS 肯定可以帮助很多人。某些实现方式可能工作得很好……如果并且只有如果它们以一种明智的方式实现。
然而,CSS-in-JS 的实现方式,尤其是在本文中提到的从“props”中注入值(作为 JS 变量)的方式,可能会直接影响我们心爱的浏览器的渲染循环的性能!
这是因为,不幸的是,并非所有开发者都了解浏览器的内部工作原理。大多数人读完这篇文章后甚至不会记得其中提到的缺点。因此,在 W3C 等标准化组织提出一个适当的解决方案之前,请不要提倡使用 CSS-in-JS。
这篇文章有可能让“互联网”变得更糟,而不是更好。
想想用户的幸福,而不是开发者的幸福!
有很多因素需要考虑。例如,内联关键 CSS 也能让用户满意,但这很难做到,所以许多开发者都没有这样做。CSS-in-JS 可以免费为您提供它。:)
请注意,CSS-in-JS 库的作者一直在优化它们,甚至去除了运行时!重要的是检查 CSS-in-JS 实际编译后的内容。
Matija Marohnić,你无法完全去除运行时,那样整个东西就会退回到普通的旧 CSS。CSS-in-JS 的确存在性能损失,这将永远存在。
Ashley,大多数 CSS-in-JS 库确实有运行时,是的,但 astroturf 和 Linaria 没有运行时,这就是我所指的。自己看看,它们编译成实际的 CSS 文件。现在,这是否是一个好主意,取决于你。;)
我真想弄清楚这一点,但我一直想:如果你了解 CSS,CSS“泄漏”就永远不会成为问题。我遇到的唯一问题是库中存在不好的 CSS。我只要删除这些样式,然后快速重写以适合项目。
如果你真的不喜欢级联的东西,为什么不使用 ID?React 由模块构成,给该模块一个 ID,然后从那里进行样式化——完成了。样式将永远不会泄漏。我认为这是一种不好的做法,但它本质上与将 CSS 模块化相同?这是否也意味着模块化是一种不好的做法?你仍然需要一些全局样式,对吧?
我仍然不明白 CSS-in-JS 应该带来的好处。我一直在想我是不是忽略了什么,我真的很想理解。
好处远不止模块化,这条 Twitter 线程 可能会有所帮助。就我个人而言,我正在寻找替代方案,所以请查看本系列的第二部分。;)
JS 组件中的 CSS 越来越受欢迎,因为传统主义者正在被挤出 FED 游戏,纯 JS 程序员正在取代他们,而不是因为这是一个更好的主意……实际上它并不是。
这感觉像是一种潮流,而且是一个糟糕的主意……因为它就是。
Javascript 中的 CSS 是一个糟糕的主意!层叠样式表的真正优势之一是层叠,大多数现代开发者都不理解它带来的强大功能。如今,人们不再将 CSS 视为皮肤,也不再将 HTML 视为脚手架。将关注点分离还可以让开发者并行工作,一个人负责脚手架,另一个人负责皮肤。还有人记得http://www.csszengarden.com吗?展示了 CSS 的真正力量!(我可以写一篇关于这个主题的文章,也许我将来会写。;)
只使用过一次 CSS-in-JS,使用的是 styled components,那是一次糟糕且令人沮丧的体验,比使用普通样式表复杂得多,但可重用性更低。我们使用了 3 个库来实现比只使用 CSS 更复杂的解决方案,在我看来,这显得非常过度设计,而且违背了关注点分离的旧原则。
我同意这里其他人的观点,CSS in JS 被推崇的原因是许多开发者不想学习如何正确使用 CSS,这很不幸,因为精通 CSS 并结合合理的 HTML 可以使用最少的代码创建最优雅、最简单的解决方案。似乎开发者体验正变得比用户体验更重要,即事情都是为了让开发者受益,而不是用户。
我猜我是在对牛弹琴。