by Oleg Isonen
由Oleg Isonen
Recently I wrote a higher level overview of CSS-in-JS, mostly talking about the problems this approach is trying to solve. Library authors rarely invest time into describing the tradeoffs of their solution. Sometimes it’s because they are too biased, and sometimes they just don’t know how the users apply the tool. So this is an attempt to describe the tradeoffs I have seen so far. I think it is important to mention that I am the author of JSS, so I should be considered biased.
最近,我写了CSS-in-JS的更高层次的概述 ,主要讨论了这种方法试图解决的问题。 图书馆作者很少花时间描述其解决方案的权衡。 有时是因为他们过于偏见,有时他们只是不知道用户如何使用该工具。 因此,这是一种描述到目前为止我所看到的权衡的尝试。 我认为重要的是要提到我是JSS的作者,因此应该认为我有偏见。
There is a layer of people who work on the web platform and don’t know any JavaScript. Those people are getting paid to write HTML and CSS. CSS-in-JS has made a huge impact on the developers' workflow. A truly transformative change can never be done without some people being left behind. I don’t know if CSS-in-JS has to be the only way, but the mass adoption is a clear sign of problems with using CSS in modern applications.
有一部分人在Web平台上工作,不了解任何JavaScript。 这些人获得了编写HTML和CSS的报酬。 CSS-in-JS对开发人员的工作流程产生了巨大影响。 没有一些人落伍,就不可能实现真正的变革。 我不知道CSS-in-JS是否必须是唯一的方法,但是大量采用是在现代应用程序中使用CSS的明显标志。
A big part of the problem is our inability to communicate accurately the use cases where CSS-in-JS shines and how to use it properly for a task. Many CSS-in-JS enthusiasts have been successful at promoting the tech, but not many critics talked about the tradeoffs in a constructive manner, without taking cheap swings at the tools. As a result, we left many tradeoffs hidden and didn’t make a strong effort to provide the explanation and workarounds.
问题的很大一部分是我们无法准确地传达CSS-in-JS的用例以及如何在任务中正确使用它。 许多CSS-in-JS爱好者都成功地推广了这项技术,但是,很少有批评家以建设性的方式谈论这种折衷,而又不会在工具上花钱。 结果,我们隐藏了许多折衷,没有做出很大的努力来提供解释和解决方法。
CSS-in-JS is an attempt to make complex use cases easier to handle, so don’t push it where it is not needed!
CSS-in-JS旨在使复杂的用例更易于处理,因此不要将其推送到不需要的地方!
When CSS is generated from JavaScript at runtime, in the browser, there is an inherent overhead. Runtime overhead varies from library to library. This is a good generic benchmark, but be sure to make your own tests. Major differences at runtime appear depending on the need to have a full CSS parsing of template strings, amount of optimizations, dynamic styles implementation details, hashing algorithm and framework integrations cost.*
在运行时从JavaScript生成CSS时,在浏览器中存在固有的开销。 运行时开销因库而异。 这是一个很好的通用基准,但是请务必进行自己的测试。 在运行时会出现主要差异,具体取决于对模板字符串进行全面CSS解析的需求,优化量,动态样式实现细节,哈希算法和框架集成成本。*
Besides the potential runtime overhead, you need to consider 4 different bundling strategies, because some CSS-in-JS libraries support multiple strategies and it is up to the user to apply them. *
除了潜在的运行时开销外,您还需要考虑4种不同的捆绑策略,因为某些CSS-in-JS库支持多种策略,并且用户可以应用它们。 *
Runtime CSS generation is a technique that generates a CSS string in JavaScript and then injects that string using a style tag into the document. This technique produces a Style Sheet, NOT inline styles.
运行时CSS生成是一种在JavaScript中生成CSS字符串,然后使用样式标签将该字符串注入到文档中的技术。 此技术生成样式表,而不是内联样式。
The tradeoff of runtime generation is the inability to provide styled content at the early stage, as the document starts loading. This approach usually fits for applications without content that can be useful immediately. Usually, such applications require user interactions before they can really become useful to a user. Often such applications work with content that is so dynamic that it becomes outdated as soon as you load it, so you need to establish an update pipeline early on, for example, Twitter. In addition, when a user is logged-in, there is no need to provide HTML for SEO.
运行时生成的权衡是在文档开始加载时无法在早期提供样式化的内容。 这种方法通常适用于没有立即可用的内容的应用程序。 通常,此类应用程序需要用户交互才能真正对用户有用。 通常,此类应用程序使用的是动态内容,以至于您在加载内容后就过时了,因此您需要尽早建立更新管道,例如Twitter。 另外,当用户登录时,无需为SEO提供HTML。
If the interaction requires JavaScript, the bundle needs to be loaded before the app is ready. For example, you can show the contents of a default channel when loading Slack in the document, but it is likely that the user will want to change the channel right after that. So if you loaded the initial contents just to throw them away immediately.
如果交互需要JavaScript,则需要在应用就绪之前加载捆绑软件。 例如,当您在文档中加载Slack时,您可以显示默认频道的内容,但是用户很可能会在此之后立即更改频道。 因此,如果您加载了初始内容只是为了立即将其丢弃。
Perceived performance of such applications can be improved with placeholders and other tricks to let the application feel more instant than it actually is. Such applications are usually data heavy anyways, so they won’t be useful as quickly as an article.
可以使用占位符和其他技巧来提高此类应用程序的感知性能,以使应用程序比实际感觉更即时。 无论如何,这类应用程序通常都是繁重的数据,因此它们不会像文章中那样有用。
Critical CSS is the minimal amount of CSS that is required to style the page in its initial state. It’s rendered using a style tag in the head of the document. This technique is widely used with and without CSS-in-JS. In both cases, you are likely to double load the CSS rules, once as part of the Critical CSS and once as part of the JavaScript or CSS bundle. The size of Critical CSS can be quite large depending on the amount of the content. Usually, the document won’t be cached.
关键CSS是在初始状态下设置页面样式所需的最少CSS。 它是使用文档标题中的样式标签呈现的。 无论是否使用CSS-in-JS,此技术均得到广泛使用。 在这两种情况下,您都可能会加倍加载CSS规则,一次是作为Critical CSS的一部分,一次是JavaScript或CSS包的一部分。 关键CSS的大小可能会很大,具体取决于内容的数量。 通常,文档不会被缓存。
Without Critical CSS, a static content-heavy single page application with runtime CSS-in-JS will have to show placeholders instead of content. This is bad because it could have been useful to a user much earlier, improving the accessibility on low-end devices and for low-bandwidth connections.
如果没有Critical CSS,则带有运行时CSS-in-JS的静态内容繁重的单页应用程序将必须显示占位符而不是内容。 这很不好,因为它可能对用户更早有用,从而改善了低端设备和低带宽连接的可访问性。
With critical CSS, runtime CSS generation can be done at a later stage, without blocking the UI in the initial phase. Be warned though, on low-end mobile devices, which are approximately 5+ years old, CSS generation from JavaScript can have a negative impact on performance. It strongly depends on the amount of CSS being generated and the library used, so it can’t be generalized.
使用关键CSS,可以在以后阶段生成运行时CSS,而不会在初始阶段阻塞UI。 但是请注意,在使用大约5年以上的低端移动设备上,使用JavaScript生成CSS会对性能产生负面影响。 它在很大程度上取决于生成CSS数量和所使用的库,因此不能一概而论。
The tradeoff of this strategy is the cost of Critical CSS extraction and the cost of runtime CSS generation.
这种策略的折衷是关键CSS提取的成本和运行时CSS生成的成本。
This strategy is the default one on the web without CSS-in-JS. Some CSS-in-JS libraries allow you to extract static CSS at build time.* In this case, no runtime overhead is involved, CSS is rendered on the page using a link tag. The cost of the CSS generation is paid once ahead of time.
此策略是Web上没有CSS-in-JS的默认策略。 一些CSS-in-JS库允许您在构建时提取静态CSS。*在这种情况下,不涉及运行时开销,CSS使用链接标记在页面上呈现。 CSS生成的成本需要提前支付。
There are 2 major tradeoffs here:
这里有两个主要的权衡:
This strategy is also not unique to CSS-in-JS. Full static extraction with critical CSS delivers the best performance when working with a more static application. This approach still has the aforementioned tradeoffs of a static CSS, except that the blocking link tag can be moved to the bottom of the document.
该策略也不是CSS-in-JS独有的。 使用更静态的应用程序时,使用关键CSS进行全静态提取可提供最佳性能。 这种方法仍然具有静态CSS的上述折衷,不同之处在于可以将阻塞链接标记移动到文档的底部。
There are 4 main CSS rendering strategies. Only 2 of them are specific to CSS-in-JS and none of them apply to all libraries.
有4种主要CSS渲染策略。 它们中只有2个特定于CSS-in-JS,并且没有一个适用于所有库。
CSS-in-JS can decrease accessibility when used in the wrong way. This will happen when a largely static content site is implemented without Critical CSS extraction so that HTML can’t be painted before the JavaScript bundle is loaded and evaluated. This can also happen when a huge CSS file is rendered using a blocking link tag in the head of the document, which is the most popular current problem with the traditional embedding and not specific to CSS-in-JS.
错误使用CSS-in-JS可能会降低可访问性。 如果在没有关键CSS提取的情况下实现了一个主要是静态的内容站点,那么这种情况就会发生,这样就无法在加载和评估JavaScript包之前绘制HTML。 当使用文档头中的阻塞链接标记渲染巨大CSS文件时,也会发生这种情况,这是传统嵌入方式中最流行的当前问题,并非特定于CSS-in-JS。
Developers need to take responsibility for accessibility. There is still a strong misguided idea that an unstable internet connection is a problem of economically weak countries. We tend to forget that we have connectivity issues every single day when we enter an underground rail system or a large building. A stable cable-free mobile connection is a myth. It's not even easy to have a stable WiFi connection, for example, a 2.4 GHz WI-FI network can get interference from a microwave oven!
开发人员需要对可访问性负责。 仍然存在一个强烈的误解,认为互联网连接不稳定是经济上较弱的国家的问题。 我们往往会忘记,进入地下铁路系统或大型建筑物时,每天都会遇到连接问题。 稳定的无电缆移动连接是一个神话。 拥有稳定的WiFi连接甚至不容易,例如2.4 GHz WI-FI网络会受到微波炉的干扰!
To get Critical CSS extraction for CSS-in-JS, we need SSR. SSR is a process of generating the final HTML for a given state of an application on the server. In fact, it can be quite a complex and expensive process. It requires a certain amount of CPU cycles on the server for each HTTP request.
要获取CSS-in-JS的Critical CSS提取,我们需要SSR。 SSR是为服务器上应用程序的给定状态生成最终HTML的过程。 实际上,这可能是一个非常复杂且昂贵的过程。 每个HTTP请求在服务器上都需要一定数量的CPU周期。
CSS-in-JS usually leverages the fact that it is hooked into the HTML rendering pipeline.* It knows what HTML was rendered and what CSS it needs so that it is able to produce the absolute minimal amount of it. Critical CSS adds additional overhead to HTML rendering on the server because that CSS also needs to be compiled into a final CSS string. In some scenarios, it is hard or even impossible to cache on the server though.
CSS-in-JS通常利用将其挂接到HTML渲染管道中的事实。*它知道要渲染HTML以及所需CSS,以便能够生成绝对少量HTML。 关键CSS为服务器上HTML渲染增加了额外的开销,因为CSS还需要编译成最终CSS字符串。 在某些情况下,很难甚至根本无法缓存在服务器上。
You need to be aware of how a CSS-in-JS library you are using is rendering your CSS. For example, people are often not aware of how Styled Components and Emotion implement dynamic styles. Dynamic styles is a syntax which allows the usage of JavaScript functions inside of your styles declaration. Those functions accept props and return a CSS block.
您需要了解所使用CSS-in-JS库如何呈现CSS。 例如,人们通常不知道样式化组件和情感如何实现动态样式。 动态样式是一种语法,它允许在样式声明中使用JavaScript函数。 这些函数接受道具并返回CSS块。
In order to keep the source order specificity consistent, both above named libraries generate a new CSS rule if it contains a dynamic declaration and the component updates with new props. To demonstrate what I mean, I created this sandbox. In JSS we decided to take a different tradeoff, which allows us to update the dynamic properties without generating new CSS rules.*
为了保持源顺序的特异性一致,两个以上的命名库都包含一个动态声明并且使用新的props进行组件更新,因此会生成一条新CSS规则。 为了演示我的意思,我创建了这个沙箱 。 在JSS中,我们决定采取不同的权衡方法,这使我们能够在不生成新CSS规则的情况下更新动态属性。
For people who are familiar with CSS, but are new to JavaScript, the initial amount of work to get up to speed with CSS-in-JS might be quite large.
对于熟悉CSS但不熟悉JavaScript的人来说,要赶上CSS-in-JS的初期工作量可能会很大。
You don’t need to be a professional JavaScript developer to write CSS-in-JS, up until the point where complex logic gets involved. We can’t generalize the complexity of styling, as it really depends on the use case. In cases where CSS-in-JS gets complex, it is likely that the implementation with vanilla CSS would be even more complex.
您无需成为专业JavaScript开发人员即可编写CSS-in-JS,直到涉及复杂逻辑为止。 我们不能归纳出样式的复杂性,因为它实际上取决于用例。 在CSS-in-JS变得复杂的情况下,使用普通CSS的实现可能会更加复杂。
For basic CSS-in-JS styling, one needs to know how to declare variables, how to use template strings, and interpolate JavaScript values. If object-notation is used, one needs to know how to work with JavaScript objects and the library-specific object-based syntax. If dynamic styling is involved, one needs to know how to use JavaScript functions and conditionals.
对于基本CSS-in-JS样式,需要了解如何声明变量,如何使用模板字符串以及内插JavaScript值。 如果使用对象符号,则需要知道如何使用JavaScript对象和特定于库的基于对象的语法。 如果涉及动态样式,则需要知道如何使用JavaScript函数和条件。
Overall there is a learning curve, we can’t deny it. This learning curve is usually not much bigger, though, than learning Sass. In fact, I created this egghead course to demonstrate this.
总体而言,这是一个学习曲线,我们不能否认。 但是,这种学习曲线通常不会比学习Sass大很多。 实际上,我创建了这个简单的课程来演示这一点。
Most CSS-in-JS libs are not interoperable. This means that styles written using one library can’t be rendered using a different library. Practically it means you can’t switch your entire application easily from one implementation to another. It also means that you can’t easily share your UI on NPM without bringing your CSS-in-JS library of choice into the consumer's bundle unless you have a build-time static extraction for your CSS.
大多数CSS-in-JS库不能互操作。 这意味着使用一个库编写的样式无法使用其他库进行渲染。 实际上,这意味着您无法轻松地将整个应用程序从一种实现切换到另一种实现。 这也意味着,除非您将CSS的构建时静态提取功能提取到消费者的捆绑包中,否则您无法轻松地在NPM上共享UI,而无需将所选CSS-in-JS库纳入消费者的捆绑包中。
We have started to work on the ISTF format that is supposed to fix this problem, but unfortunately we haven’t had time yet to get it to a production-ready state.*
我们已经开始研究应该解决此问题的ISTF格式 ,但不幸的是,我们还没有时间将其设置为可投入生产的状态。*
I think sharing reusable framework agnostic UI components in the public domain is still a generally hard-to-solve problem.
我认为在公共领域共享可重用的与框架无关的UI组件仍然是一个普遍难以解决的问题。
It is possible to introduce security leaks with CSS-in-JS. Like with any client-side applications, you need to escape user input before rendering it, always.
CSS-in-JS可能会引入安全漏洞。 像任何客户端应用程序一样,您始终需要在呈现之前对用户输入进行转义。
This article will give you more insight and some defacing examples.
本文将为您提供更多的见解和一些污损的示例。
Some people still think it is important that we keep meaningful readable class names on the web. Currently, many CSS-in-JS libraries provide meaningful class names based on the declaration name or component name in development mode. Some of them even let you customize the class name generator function.
某些人仍然认为重要的是,我们在网络上保留有意义的可读类名。 当前,许多CSS-in-JS库基于开发模式中的声明名称或组件名称提供有意义的类名称。 其中一些甚至可以让您自定义类名生成器功能。
In production mode though, most of them generate shorter names for a smaller payload. This is a tradeoff the user of the library has to make and customize the library if needed.
但是,在生产模式下,它们中的大多数会为较小的有效负载生成较短的名称。 如果需要的话,这是库用户必须进行制作和自定义的折衷方案。
Tradeoffs exist, and I probably didn’t even mention all of them. But most of them don’t universally apply to all CSS-in-JS. They depend on which library you use and how you use it.
折衷存在,我可能甚至都没有提到。 但是它们中的大多数并不能普遍应用于所有CSS-in-JS。 它们取决于您使用哪个库以及如何使用它。
* It will take a dedicated article to explain this sentence. Let me know on Twitter (@oleg008) about which one you would like to read more.
*需要专门的文章来解释这句话。 在Twitter( @ oleg008 )上让我知道有关您想阅读的更多信息。
翻译自: https://www.freecodecamp.org/news/the-tradeoffs-of-css-in-js-bee5cf926fdb/