当前位置: 首页 > Web前端 > JavaScript

精读《我们为何弃用 css-in-js》

时间:2023-03-27 16:41:09 JavaScript

情感排名第二的维护者Sam的公司放弃了css-in-js的方案,引起了很多讨论:WhyWe'reBreakingUpwithCSS-in-JSOverview&精读原文是很有用的整理一下,先从css-in-js的优点说起,然后再说缺点,讲解css-in-js这个新东西,优点和缺点都很明显;然后从性能问题出发,解释你所在的公司为什么要放弃css-in-js;最后告诉读者,目前的解决方案是css-modules。之后还有一点扩展性的思考,就是还有一批编译期的css-in-js方案,但是在遇到性能问题的时候还是徒劳无功。让我们花点时间了解一下作者的具体想法。css-in-js的优缺点作为一个比较新的开发思路,css-in-js有以下明显的优缺点。优点:没有全局样式冲突。就像js文件天生就支持模块化的好处一样,原生css因为没有模块化,自然容易出现全局样式污染。如果不刻意使用BEM命名,只能使用css-in-js来避免冲突。(css-modules也可以)结合js代码。很自然的集成到js代码中,方便模块化管理,这样css就可以绑定到一个本地模块上了。(css-modules也可以,但是你得单独一个style文件)可以给styles应用js变量。css变量虽然也可以解决这个问题,但是没有css-in-js那么直观。inline-style也可以解决这个问题,但是会产生很多重复的局部样式,这个优势是css-modules无法实现的。缺点:css-in-js运行时解析的实现版本增加了运行时性能压力,尤其是在React18调度机制模式下,存在无法解决的性能问题(运行时插入样式会导致React渲染暂停,浏览器解析一次样式,渲染继续,然后浏览器再次解析样式)。增加了包装尺寸。与原生或css-modules方案相比,运行时框架代码增加了约8kb。使ReactDevTools的结构复杂化,因为css-in-js包裹了一层额外的React组件用于样式插入。除了以上缺点,css-in-js还有三个只有深入使用后才能发现的陷阱:多个不同(甚至相同)版本的css-in-js库同时加载时可能会出错时间。作者在使用styled-components的时候也遇到过类似的问题,甚至连语法都会不兼容。虽然可以解决这些问题,但是需要计算额外花费的时间。与css-in-js相比获得的好处是否值得?无法自定义样式插入的优先级,导致在生成样式覆盖时,业务无法对样式覆盖的优先级有一个稳定的预期。Class优先级由header定义顺序决定,而不是className的字符顺序,header定义顺序由资源加载和css-in-js插入执行时机决定,业务几乎不可能有稳定的样式覆盖命令。这里的问题是业务代码的不断增加!imprtant定义。对于不同React版本的SSR,css-in-js需要适配不同的实现,对框架作者来说不是很友好。除了性能问题,其他问题都可以容忍,但是涉及到性能问题,css-in-js就遇到了无解的场景。无法解决的性能问题第一个缺点中提到的运行时解析是css-in-js解决方案永远无法克服的困境。即使是编译时的css-in-js方案,在渲染时也难免做额外的逻辑执行拖慢渲染速度:functionApp(){return;//正是这种代码导致了性能问题}原因是React在重新渲染组件时,需要重新解析样式定义和序列化className。当渲染非常频繁时,会造成明显的性能瓶颈。解决办法是抽取样式定义,但是这样会失去第三个优势,即无法读取js变量:constmyCss=css({backgroundColor:"blue",width:100,height:100,});不得不说React的渲染机制真的是有问题。如果换用SolidJS,这个问题会好办一些。因为运行时的样式代码只会运行一次,组件重新渲染不会导致这段解析代码重复执行。这时候css-in-js在样式变化的时候进行一次准确的样式更新,性能问题就可以解决了。向上。切换到css模块scss-modules同时支持优势1和2,优势3可以通过一些特定的语法糖绕过:使用:import:export伪类导入和导出css变量,使用webpack-loader在js中实现对css变量的引用。使用css变量实现css引用js变量。所以当性能问题是一个绕不开的话题,而css-modules性能最好的时候,有一些曲线方案可以同时支持css-in-js的优点,也就可以理解作者为什么要放弃了css-in-js已启动。包裹体积真的变大了吗?原文章中提到的css-in-js增加了8~16kb。其实就是强行堆缺点,除非你的项目只有一行css定义。如果我们只考虑传输时的包大小和HTML中样式定义的数量,而忽略运行时的性能负担,那么css-in-js无疑是大型项目的最优选择。原因是css-in-js样式是按需插入的,没有渲染的组件是不会插入样式的。即使渲染的组件也不一定会插入样式,因为css-in-js可以对包含相同样式定义的场景合并className,类似于webpack将不同模块的公共代码提取到一个chunk中。编译时的css-in-js解决方案是出路吗?理论上是的,但是限制了css-in-js的灵活性。从vanilla-extract等compile-timecss-in-js框架来看,确实解决了runtimecss-in-js的性能问题,但是带来了更多的语法限制,比如在使用前需要预先定义样式它:从'@vanilla-extract/css'导入{style}constmyStyle=style({display:'flex',paddingTop:'3px'})constApp=()=>compile-timecss-in-如果js要实现通用性,只能提供一个className,使其不受任何框架和环境的限制,但这也限制了声明语法的灵活性。显然,不可能以内联方式定义样式。此外,这个编译时解决方案与css-modules本质上是一样的。后面定义了一些静态样式名。它只是意味着这些样式问题是在.sass或.ts中定义的。如果使用.ts定义,配合编译工具,可以让代码nativeimport更顺手。因此,使用编译时的css-in-js方案,本质上是抛弃了运行时的css-in-js,投入到变体css-modules阵营。总结一下,css-in-js本身的方向是对的,就是css和js融合,但是css-in-js在运行时过于灵活的方案遇到了几乎无解的性能问题,而css-in-js在编译时的解决方案可能是更好的出路。css-in-js这个名字本身就意味着它具有injs的灵活性,而css-in-js在编译期的解决方案本质是css-module,所以难免会有一些奇怪的限制。如果js中的代码不能像真正的js那样灵活,或许还是回到.scss或者.less的后缀更好理解。讨论地址为:Jingdu《我们为何弃用 css-in-js》·Issue#450·dt-fe/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号版权声明:免费转载-非商业-非衍生保留属性(CreativeCommons3.0License)