前端优化之拆分CSS】前端三剑客的分分合合

简介:

几年前,我们这样写前端代码:

<div id="el" style="......" onclick="......">测试</div>

慢慢的,我们发现这样做的很多弊端,单就样式一块,改一个样式会涉及到多处调整,所以慢慢的dom标签中的css全部去了一个独立的css文件

再后来,交互变得异常复杂,onclick也不好使了,所以js也分离开了,经典的html+css+javascript结构分离逐步清晰,三种代码各司其职

HTML+CSS+Javascript体现着结构、表现、交互分离的思想,分离到极致后,css相关便完全由独立团队(UED)负责,会给出不包含javascript的“原型”demo

事有利弊,分离只是第一步,最终他们还是得合到一起,所以过度的拆分反而会有问题,最近工作中遇到了两个令人头疼的问题:

① 框架UI组件的CSS在UED处,一旦在线的UI出了样式问题,UED需要改动DOM结构和CSS的话,无论是框架还是UED先发布必定会导致生产样式问题(发布系统分离)

② H5站点会等依赖的CSS全部加载结束才能渲染页面。框架的css文件尺寸必定过100K,3G情况不稳定时要等很长时间,2G情况下5S秒以上更是家常便饭

PS:问题一是一个典型的发布依赖问题,本来与今天的内容不太相关,但是在讨论问题一的时候引出了问题二,解决问题二的时候又顺便解决了问题一,所以这里一并提出来,讲述了前端html、css、javascript的分分合合

做过全站前端优化的同学都会明白,优化做到最后,法宝往往都是减少请求,减低尺寸,所以缓存、轻量级框架在前端比较流行,但CSS却不容易被拆分,css业务分离还带来了重用性与发布依赖的问题,分离是问题产生的主要原因。而“分离”也是这里的优化手段:

① 分离:将全站的css“分离”到各个UI中

② 合并:将分离的html、css、javascript重新“合并”

css非常容易引起变量“污染”,UI中的css应该最大程度的保证不影响业务css,并且不被影响,这一前提若是完全依赖与.css文件很难处理。

传说中web应用的未来:Web Components也提将HTML、CSS、JS封装到一起。其中比较令人惊讶的是不论js还是css会处于一沙箱中不会对外污染,学习web components的过程中意识到将css放到各自UI中的方案是可行的,也是上面问题的一种解决方案:

Web Components:组件相关html、css、js全部处于一个模块!

所以,似乎我应该将框架css分为两部分: ① 核心通用css(10k左右) ② 各部分UI样式

框架加载时候只需要加载10k的通用部分,或者常用UI;剩下的UI对应样式以及js文件便按需加载,并且UI的样式还不会互相影响,于是一个“奇怪”的做法出现了,以num组件为例

原来num组件包括两个文件:

① ui.num.js
② ui.num.html

文件一为核心控制器,文件二为html实体,对应样式在全局css中,现在新增文件三:

① ui.num.js
② ui.num.html
③ ui.num.css

这个时候将全局css中对应的UI样式给抽出来了,放到了具体UI中,以实际代码为例我们数字组件变成了这个样子:

这里涉及到的文件有:

  ui.abstract.view
  ui.num.js
  ui.num.html
  ui.num.css

断点一看,对应文本拿出来了:

因为这个特性是全组件共有的,我们将之做到统一的基类ui.abstract.view中即可:

  View Code

波及到的代码片段是:

 1 createRoot: function (html) {
 2 
 3   var style = this.createInlineStyle();
 4   if (style) {
 5     this.formateStyle = '<style id="' + this.id + '_style">' + style + '</style>';
 6     html = this.formateStyle + html;
 7   }
 8 
 9   this.$el = $('<div class="view" style="display: none; " id="' + this.id + '"></div>');
10   this.$el.html(html);
11 },
12 
13 //创建内嵌style相关
14 createInlineStyle: function () {
15   //如果不存在便不予理睬
16   if (!_.isString(this.uiStyle)) return null;
17   var style = '', uid = this.id;
18 
19   //创建定制化的style字符串,会模拟一个沙箱,该组件样式不会对外影响,实现原理便是加上#id 前缀
20   style = this.uiStyle.replace(/(\s*)([^\{\}]+)\{/g, function (a, b, c) {
21     return b + c.replace(/([^,]+)/g, '#' + uid + ' $1') + '{';
22   });
23 
24   return style;
25 
26 },
27 
28 refresh: function (needEvent) {
29   var html = '';
30   this.resetPropery();
31   if (needEvent) {
32     this.create();
33   } else {
34     html = this.render();
35     this.$el.html(this.formateStyle ? this.formateStyle + html : html);
36   }
37   this.initElement();
38   if (this.status == 'show') this.show();
39   this.trigger('onRefresh');
40 },

这个时候对应ui.num.js只需要一点点变化即可:

  View Code
 1 define(['UIView', getAppUITemplatePath('ui.num'), getAppUICssPath('ui.num')], function (UIView, template, style) {
 2   return _.inherit(UIView, {
 3     propertys: function ($super) {
 4       $super();
 5       //......
 6 
 7       this.template = template;
 8       this.uiStyle = style;
 9 
10       //......
11     }
12 
13     //......
14   });
15 });

这个时候形成的dom结构变成了这个样子:

如图所示,对应的css被格式化为带id的选择器了,不会对外污染,这个样子解决了几个问题:

① html、css、js统一归UI管理,不存在发布不同步的问题

② css也可以按需加载

③ 一定程度解决组件css污染问题

④ 组件destroy时候样式节点会被移除

但是也引起了一些新的问题:

① ui占用节点增多,不destroy组件的情况下,是否会引起手机性能问题,对于webapp尤其重要

② 其中的css依然是UED分拆过来的,是否会引起更新不同步问题

③ html是不能跨域的,css是否会有同样问题,未做实际验证

④ css通用模块需要得到处理,防治重复代码

......

抛开以上问题不管,实现了相关功能的js钩子保持一致的情况下,甚至可以以一个开关/版本号管理当前究竟显示哪个样式的组件,比如我们将html与css还原到以前:

到底使用V1版本或者标准版本,完全控制到requireJS的管理,这里简单依赖于这两个方法的实现:

window.getAppUITemplatePath = function (path) {
  return 'text!' + app + 'ui/' + path + '.html';
}

window.getAppUICssPath = function (path) {
  return 'text!' + app + 'ui/' + path + '.css';
}

我们可以简单的在这里定制开关,我们也可以在一个页面里面让两个组件同时出现,并且他们是同一个控制器,ver不同显示的版本就不一样:

1 //在此设置版本号,或者由url取出或者由服务器取出...
2 var ver = 'v1';
3 window.getAppUITemplatePath = function (path) {
4   return 'text!' + app + 'ui/' + path + (ver ? '_' + ver : '') + '.html';
5 }
6 window.getAppUICssPath = function (path) {
7   return 'text!' + app + 'ui/' + path + (ver ? '_' + ver : '') + '.css';
8 }

当然,也可以走更加合理的模块管理路线,我们这里不做论述,这里做一番总结,便结束今天的学习。

该问题的引出最初是由于发布配合问题,结果上升了一下便成了性能优化问题,最后发现居然是解耦的问题,HTML、CSS、Javascript应该分离,但是业务应该在一块,过度分离反而会引起开发效率问题,上面处理的方式,依旧是主动由UED将需要的CSS拿了回来,因为三者密不可分。

demo地址:http://yexiaochai.github.io/cssui/demo/debug.html#num

代码地址:https://github.com/yexiaochai/cssui/tree/gh-pages

文中有误或者有不妥的地方请您提出



本文转自叶小钗博客园博客,原文链接:http://www.cnblogs.com/yexiaochai/p/4165386.html,如需转载请自行联系原作者

相关文章
|
5月前
|
前端开发 JavaScript 开发者
前端 CSS 优化:提升页面美学与性能
前端CSS优化旨在提升页面美学与性能。通过简化选择器(如避免复杂后代选择器、减少通用选择器使用)、合并样式表、合理组织媒体查询,可减少浏览器计算成本和HTTP请求。利用硬件加速和优化动画帧率,确保动画流畅。定期清理冗余代码并使用缩写属性,进一步精简代码。这些策略不仅加快页面加载和渲染速度,还提升了视觉效果,为用户带来更优质的浏览体验。
|
2月前
|
前端开发
|
2月前
|
前端开发
|
2月前
|
前端开发 JavaScript
|
2月前
|
XML 前端开发 JavaScript
|
2月前
|
前端开发 容器
|
4月前
|
前端开发
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
111 1
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
|
5月前
|
前端开发 开发者 UED
《前端技术基础》第02章 CSS基础【合集】
层叠样式表(Cascading Style Sheets,简称CSS)是一种用于描述网页视觉表现的语言。该语言与HTML协同工作,其中HTML负责构建网页的结构,而CSS则负责定义网页的外观和格式。CSS通过一系列规则来实现样式的应用,这些规则由选择器(Selectors)和声明块(Declaration Blocks)构成。选择器的作用是明确指出哪些HTML元素将受到特定样式规则的影响,而声明块则包含了具体的样式声明,这些声明定义了元素的视觉属性和相应的值。
126 1
|
7月前
|
前端开发 JavaScript 搜索推荐
HTML与CSS在Web组件化中的核心作用及前端技术趋势
本文探讨了HTML与CSS在Web组件化中的核心作用及前端技术趋势。从结构定义、语义化到样式封装与布局控制,两者不仅提升了代码复用率和可维护性,还通过响应式设计、动态样式等技术增强了用户体验。面对兼容性、代码复杂度等挑战,文章提出了相应的解决策略,强调了持续创新的重要性,旨在构建高效、灵活的Web应用。
122 6
|
7月前
|
Web App开发 前端开发 JavaScript
揭秘!前端大牛们如何巧妙利用CSS3,打造炫酷视觉效果!
【10月更文挑战第31天】前端开发面临复杂布局的挑战,本文介绍了几种提升开发效率和代码质量的工具和技术。基础的HTML和CSS可以应对大部分布局需求,而Firefox开发者工具、VS Code、Vue、React等则能应对更复杂的布局,帮助开发者构建高性能、用户友好的网页应用。
172 4