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

拆!对比详解 Flutter Widget 和 CSS,你关心的布局原理都在这儿了

时间:2023-03-31 12:08:50 CSS

拆除!详细对比讲解FlutterWidget和CSS的布局原理,你关心的布局原理都在这里Plan,帮你理清思路,内容可以分为这几个部分:1.CSS和Widget参赛选手介绍2.让我们战斗吧!从五个角度来坚韧3.Love&Peace探讨相互学习的可行性4.HappyEnding最重要的部分作者|张翰(门六)制作|阿里巴巴新零售淘技术部我在之前的一篇文章《打破重重阻碍,Flutter 和 Web 生态如何对接?》中提到过这句话:“CSS和Widget的对接也是一个非常繁琐的过程。而且存在完整性问题。”我直接给出了结论,没有给出原因。现在把这个洞填上。本文致力于对比FlutterWidget的布局原理和CSS布局原理的区别,分享对接过程中会遇到的问题和解决方法,帮助大家理清思路。内容可分为以下几部分:CSSandWidget参赛者介绍Let'sBattle!《爱与和平》从五个角度探讨取长补短、取长补短的可行性。最重要的部分,CSSCSS是CascadingStyleSheets的简称,是一种描述样式的标记语言,最初的想法诞生于1994年,1996年完成第一版规范(参考20YearsofCSS).HTML描述页面的结构,CSS描述页面的外观。这对CP合作了20、30年,依然是布局圈内效率最高的组合。?CSSisAwesomeCSS描述布局非常高效,这一点毋庸置疑。随之而来的各种布局方案,如JS中的前端框架CSS、XML描述文件、Flutter等,即使不直接照搬CSS的功能,也深受CSS设计的影响。CSS易于使用。经典的盒子模型,一学就会。文字相关的属性,从名字就可以知道。Flexbox也很好用,但是CSS逐渐出现了一些难用的功能,多列布局有点难,CSSGrid...这段代码太难写了,我觉得是设计出来的对于AI,不是手写,再加上clip-path、filter、cssHoudini等,功能越来越强大,可以制作滤镜、画皮卡丘、画油画,甚至可以玩游戏。功能很强大,但是不实用。以上功能在生产环境基本都是用JS实现的,没时间打磨CSS。?渲染布局过程CSS在浏览器中的渲染过程可以简化为四个过程:加载、解析、查询并应用到DOM节点、计算布局。浏览器首先加载HTML文件,然后浏览器根据DOM树用ComputedStyle生成LayoutTree。节点的显示特性不同,生成的LayoutObject类型也不同,然后布局算法会多次遍历类树,计算节点的每个Rect。这个过程很复杂,不是一个DOM节点对应一个Layout节点,需要考虑display:none、伪元素、文本节点、shadowdom等,而且整个过程是同步的,解析完DOM节点后已经铺好了out完成后,如果浏览器解析到一个布局完成,就会执行Paint,将布局信息逐层提交给compositor线程,然后分块交给GPU线程进行绘制。我觉得最后两步比较快,主线程中的Layout和Paint是最耗时的,而且还夹杂着JS代码的执行。FlutterWidget不同于CSS。FlutterWidget精心设计,分类清晰,功能清晰。与CSS不同的是,各种属性耦合在一起,相互影响。Widget的设计是比较原子化的,基本不会互相影响。为了保持布局算法的高效,对Widget的嵌套方式有要求。Flutter设计合理。一个原因不容忽视。Google的Flutter开发团队与Chrome有很多联系。有些人多年参与CSS规范的制定,在这方面都非常有经验。总的来说,没有CSS那么多的冗余和历史包袱。新框架可以吸取前人的教训,站在巨人的肩膀上设计得越来越好。换句话说,如果让CSS设计者抛开历史包袱,不考虑向后兼容性进行重新设计,很有可能设计成现在的FlutterWidget的样子。?渲染布局过程关于Flutter的渲染过程,官方文档Flutter的工作原理是很好的学习资料。最大的亮点是次线性布局,性能接近O(n),效率比CSS高很多。具体过程我们去官网了解一下。这是一张照片。本文的重点是对战!让我们战斗吧!?第一轮:他们背后的大佬在真正开始比较之前,我们先来看看他们背后有一个什么样的机构在支持和运营他们。CSS的背后是W3C,它是业界公认的标准化组织,各大浏览器都在实施,浏览器厂商也在积极推动标准的制定。CSS是一种开放技术。其背后的大佬是W3C、Chrome、Safari、Firefox等一系列营利或非营利组织,大家共同受益,共同发展。然而,Flutter背后只有Google。虽然它也是开源的,但设计和实现是由谷歌团队主导的。其他人正在使用它。真正有能力、有机会参与开发的人很少。PR只是小修小补。.框架和标准之间的一个区别是它是否向后兼容。该框架可能会在明天宣布推出2.0,优化和突破性的变化非常棒,而且不向后兼容是家常便饭。从这个角度看,CSS虽然臃肿,但却是一门具有顽强生命力的标准化技术。你现在写的CSS代码,五年后还能跑,但是你现在写的Flutter代码,五年后就不好说了。如果谷歌宣布不再维护Flutter,很可能社区会瞬间失去信心,那么Flutter就会消亡;如果Chrome宣布不支持CSS,CSS还活得好好的,Chrome很可能会死(指IE),FireFox笑醒吧。?第二轮:学习成本要说学习成本,当然CSS是高效的。先不说原理,先从几个边例来说明。市面上有培训班说“零基础,三个月成为前端高手!”,也说明前端学习成本低。事实上,他们的口号是错误的。他们三个月肯定学不会前端。使用CSS剪切页面。但是,没有“三个月掌握Flutter”的培训班。一个熟练的前端开发者,三个月就可以学会Flutter。退钱。此外,微信还可以举办面向中小学生的“青少年微信小程序编程创意营”。小程序的UI是用有限的HTML+CSS写的,但Flutter要想参与这种比赛,必须要有熟练的编程经验。人们。从语法的角度来看,CSS简单易学,因为它只是一种描述性语言,没有复杂的编程逻辑。设计目标是描述“我想要什么UI”,是一种结果导向的描述,而Widget是通过写Dart代码实现的,UI和代码逻辑是写在一起的,通过代码逐行描述“我如何组合UI”的描述,是面向过程的描述,所以CSS是更直观,编写的代码更容易理解。还有一个小原因就是像FluterWidget这样的嵌套代码,编写和修改起来都非常麻烦。太依赖编辑器了,不方便复制粘贴(如果差不多,可以复制代码)。另外CSS诞生这么多年了,学习资料也多到不行!规范本身就很详细,还有MDN、CSSTricks、CodePen等手把手教你钓鱼,手把手教你钓鱼的网站。各种在线培训也为你清晰地安排了知识框架和学习路线。相比之下,FlutterWidget只有官网,学习资料和社区生态还差得很远。?第三回合:开发效率CSS易学难精。没有几年的开发经验,没有被它虐过上千次,是不可能驾驭它的。如果要画出CSS的学习曲线,前期一定是快速上升,到达一定高度后就会变缓,甚至迷茫下降。但是当你刚开始学习Flutter的时候,你要理解很多概念,你必须改变你的想法。上手有点慢,但越学越快。打个不恰当的比方,写CSS可以看作是操作木偶,写Widget相当于搭乐高积木。因为各种CSS属性可以相互影响,输入输出不是简单的对应关系,你是不是觉得写width:100px,宽度就一定是100px?就好比一个木偶,系了上百根线,要你拉五根,做一个OK的手势。如果你拉一根绳子,它可能不仅会移动一个部位,还会移动整个上半身。FlutterWidget更加原子化,对谁能嵌套谁有要求,就像搭乐高积木一样,每一块积木都很小,但是有清晰的卡口模型,首先要符合它的设计,然后再进行创意和拼装成各种形状。它迫使您以理想的方式组合Widget,以避免编写性能不佳的代码。CSS的意思是任何属性都可以和任何属性一起写,标准总能给你一个合理的解释,所以写的代码很乱,也增加了排版的难度。所以CSS一开始开发效率比较快,但是积累和积累难度大,难以管理大规模协作(高耦合,全局作用域等),而Flutter封装性更好,这有利于协作,开发效率会越来越高效。快速地。?第四回合:武侠世界,唯快不破!谁更快,Flutter的Widget还是CSS?每个人的共识是Flutter更快。我认为Flutter相比CSS布局有两大性能优势:一是亚线性布局算法,二是更合理的线程模型。Widget的布局原理比CSS更高效。这是以牺牲一些灵活性为代价的。以后扩展Widget的时候,一定要遵循这些设计,才能继续保持高效率。CSS简单的属性背后,可以挖掘出特别复杂的细节,使得布局模型越来越复杂,渲染管线越来越长,光是显示就有十几二十个值,每一个其中对布局的影响很大,方便了开发者,但对布局性能带来了很大的挑战。关于线程模型,也是浏览器一直被诟病的性能瓶颈。主线程太忙了。JS执行、HTML/CSS解析、DOM构建、布局计算都在主线程中。相比之下,Flutter划分的四个线程就比较均衡了。GPU线程所做的工作与浏览器类似,但宿主平台(Android/iOS)的代码运行在Platform线程中,而FlutterFramework主要运行在UI线程中。还有IO线程实现网络和图片字体等文件的加载。?第五轮:未来发展分享几个关于CSS现状的数据。W3C官方定义的CSS样式有520种,在Chrome平台上算起来有703种样式,其中还包括一些带前缀的样式,数量庞大。非常低。支付宝小程序的同学总结了Top100小程序使用的不同CSS样式,共有184项。总结一下:W3C标准定义了520个样式,Chrome也支持额外的180+个私有项,但是常用的样式不超过200个。CSS有很多历史包袱,我也觉得自己不使用大部分样式,有些甚至在最佳实践中被禁止。学会50个CSS,80%的情况下你都能写出布局。对于难写的Style,我多加几层标签然后写一些JS也可以实现。但是,这些样式不能被丢弃,必须继续得到支持。在添加一个有用的属性时,有必要解释清楚它如何与当前所有属性相匹配。CSS负重前行,注定会越来越复杂。Widgets轻量化,解耦更好。它们是可插拔和可组合的。如果以后要丢弃一些Widgets,只需将这些Widgets从主包中移除,放到一个独立的插件中即可。如果你想使用它们,你可以自己导入它们。.整个迭代过程受历史包袱的影响较小。爱与和平:有可能联系吗?战斗结束了,友谊第一,竞争第二。我们不讨论结果,让我们继续爱与和平环节。Flutter的线性布局让人眼前一亮,CSS的灵活性深受大家喜爱。能不能取其精华,去其糟粕,让开发者写CSS,底层用Flutter做渲染?没有一个人有这种想法,所以有很多解决方案可以将前端框架或小程序连接到Flutter。在实现的时候,你会遇到如何将CSS转化为Widget的问题。?技术可行性当然在技术上是可行的。我在之前的文章《打破重重阻碍,Flutter 和 Web 生态如何对接?》中介绍了各种实现方案。自己也写了代码并做了对接(使用C++魔改方案),跑完了整个渲染链路。下面介绍一下我的实现方法,可以简单的分为三步:1.解析CSS语法我写了一个简化版的CSSOM,它是标准CSSOM的一个子集。用于实现样式表和样式属性、增删改查、样式值分析计算、选择器匹配查询等功能。(功能是独立的,需要的话可以自己拿)CSSOM主要是处理CSS的上层语法,转换成一致的数据格式,为下一次转换做准备。在这个过程中实现了一些CSS语法,例如CSS选择器,包括伪类选择器和选择器关系,以及@media和@keyframes等函数,也可以实现CSS变量和calc()。不管上层是直接写CSS还是在JS中写CSS,都保证了下一次转换时输入数据的格式一致,可以简化后续的实现。2、实现CSS属性与Widget数据格式的映射这部分是将CSS的基础数据格式转换为FlutterWidget所依赖的数据格式。比如CSS的color属性会转为Flutter的Color类,margin和padding会转为EdgeInsets类,flex-direction会转为Axis枚举,文本相关的属性会转为TextStyle类。这部分也是原子转换。技术上看起来比较简单,只是转换数据格式,但需要对CSS和Widget设计有很好的理解,知道双方语义上相同概念的对应关系。技术细节。如果这个对应关系转换错了,后面的布局就调整不正确了(经历过的人的经验。。。)3.构建Widget树从CSSOM中获取数据,掌握CSS的语义转换和Widget数据结构,然后结合HTML和定义好的结构,就可以生成真正的Widget树。在构建Widget树时,不能只考虑CSS。HTML+CSS相当于Widget。这里我们还需要处理不同类型的HTML节点和Widgets的对应关系。节点上的布局样式不同,生成的节点也不同。Widgets的深度比HTML更深。例如,如果一个普通的div标签只包含普通的盒模型样式,它将被转换为Container;如果包含flex相关属性,则根据具体配置转换为Flex/Center/Row/Column;如果它包含绝对定位,它将转换为Positioned/Stack。这个过程也很繁琐,包含很多细节。需要了解默认的HTML标签、CSS层模型和BFC等语义,还需要了解FlutterWidgets之间的嵌套限制,才能组合成CSS想要的效果。?使用限制对于开头提到的问题,之前的技术可行性分析回答的是“复杂性”。让我们讨论“完整性”。CSS灵活,Widget有限。将灵活的语法转换为有限的实现必然是不完整的。在CSS中,任何属性都可以和任何属性一起写。W3C标准中总是有明确的解释。HTML和CSS没有错,只有意想不到。但是在Flutter中,对于一个Widget中可以放置哪些Widget有明确的限制。比如Positioned外层必须有Stack,Center只能有一个子Widget。如果嵌套不符合预期,就会报错。写代码不会乱七八糟,所以布局算法可以很快。从这个角度来看,CSS的复杂度为O(n!),而Widget的复杂度为多项式。用Widget实现CSS注定是不完整的。(这是P和NP问题吗...?)在限制CSS写法的情况下,能不能对接Widget的实现呢?这个有可能。如果想要Widget次线性布局的表现,就必须牺牲一部分CSS的灵活性。想用技术突破这个限制吗?那么我们需要改变这个次线性布局算法。改完之后就不再是Flutter了,性能优势也没有了。从我的实践经验来看,Widget只能支持一定范围内的CSS样式。它对CSS使用的限制不在于样式的数量。并不是说某种风格不能实现,而是在多种风格的混合使用中。即使支持500个CSS,也不能同时使用某些属性。外层使用样式A内层使用样式B无效,只有C和D写在一起才有效。我估计Widget对CSS的支持上限会比现在的ReactNative/Weex大一些,可以满足大部分业务和小程序的需求。但是业务需求会增加,达到支持范围上限后就很难再扩展了。因此,需要对开发人员进行教育,这会对开发体验产生影响。