项目中如何管理CSS代码?

从组织管理的角度出发,如何管理项目中的CSS代码

组织样式文件?

管理样式文件的目的就是为了让开发人员更方便地维护代码

具体来说就是将文件进行分类,将相关的文件放在一起,方便开发在修改样式文件时,更容易找到目标文件,创建文件时,更容易找到对应的目录

CSS提供了import命令支持文件引用 但由于其存在一些问题(比如影响浏览器并行下载、加载顺序错乱等)导致使用率极低 更常见的做法是通过预处理器或编译工具插件来引入样式文件

开源项目中的样式文件

先看看热门的UI开源项目中都是如何管理样式文件的。以Bootstrapant-designelement为例

image.png

Bootstrap

根目录存放了组件样式文件和目录,其他样式文件放在不同的目录中。 目录中的文件分类清晰,但目录结构相对于大多数实际项目而言过于简单(只有样式文件)

  • forms/:表单组件相关样式
  • helpers/:公共样式,包括定位、清除等
  • mixins/:可以理解为生成最终样式的函数
  • utilities/:媒体查询相关样式
  • vendor/:依赖的外部第三方样式

ant-design

该项目采用less预处理器,主要源码在components/目录下。

各个组件按文件区分,查看其中的alert文件夹你会发现,组件相关代码,测试代码,demo示例、样式文件、描述文档都在其中

image.png

全局样式和公共样式在components/的子目录style/目录下

  • color/:颜色相关的变量与函数
  • core/:全局样式,根标签样式、字体样式等
  • mixins/:样式生成函数
  • themes/:主题相关的样式变量

组件代码及相关样式放在一起,开发的时候修改会很方便。 但在组件目录comnponents/下设置style/目录存放全局和公共样式,这些“样式”文件并不是一个单独的“组件”,再看style目录内部结构 相对于设置单独的color/目录来管理样式中的颜色,更推荐像Bootstrap一样设立专门的目录或文件来管理变量

element

同样按组件划分目录,与ant-design不同的是组件样式文件,并没有和组件代码放在一起。

image.png

element将样式文件放入了theme-chalk/目录下

  • common/:一些全局样式和公共变量
  • date-picker/:日期组件相关样式
  • fonts/:字体文件
  • mixins/:样式生成函数及相关变量

把样式当成“组件”看待,组件同级目录设立了theme-chalk/目录存放样式文件。theme-chalk/目录下的全局样式reset.scss与组件样式同级,这也有些欠妥。

这种为了将样式打包成模块,在独立项目中直接嵌入另一个独立项目并不推荐。(可以简单理解为一个项目不要有多个pages.json文件) 更符合Git使用规范的做法,即是以子模块的方式引用进项目,而且将组件样式和源码分离这种方式开发的时候也不方便,经常需要跨多层目录查找和修改样式

样式文件管理模式

7-1模式

这种模式建议将目录结构划分为7个目录和1个文件

1个文件

样式的入口文件,它会将会用到的样式所有样式都引入进来 ,一般命名为main.scss

7个目录

  • base/:模板代码,比如默认标签样式重置
  • components/:组件相关样式
  • layout/:布局相关,包括头部、尾部、导航栏、侧边栏等
  • pages/:页面相关样式
  • themes/:主题样式,即使有的项目没有多个主题,也可以进行预留
  • abstracts/:其他样式文件生成的依赖函数及mixin,不能直接生成css样式
  • vendors/:第三方样式文件

目录结构示例

示例代码

sass
|- abstracts/
|-|- _variables.scss
|-|- _functions.scss
|-|- _mixins.scss
|-|- _placeholders.scs
|- base/
|-|- _reset.scss
|-|- _typography.scss
|-|- ...
|- components/
|-|- buttons.scss
|-|- cover.scss
|-|- ...
|- Layout/
|-|- _navigation.scss
|-|- _grid.scss
|-|- _header.scss
|-|- ...
|- pages/
|-|- _home.scss
|-|- -contact.scss
|-|- ...
|- themes/
|-|- _theme.scss
|-|- _admin.scss
|-|- ...
|- vendors/
|-|- _bootstrap.scss
|-|- _jquery-ui.scss
|-|- ... 
|-main.scss

由于这个划分模式是专门针对scss项目提出的,所以为了更加符合单页应用的项目结构,可以稍作优化 。

  • main.scss文件存在意义不大

    页面样式、组件样式、布局样式都可以在页面和组件中引用,全局样式也可以在根组件中引用。 每次添加、修改样式文件都需要在main.scss文件中同步,这种过度中心化的配置方式也不方便

  • layout/目录也可以去除

    因为像footer、header这些布局相关的样式,放入对应的组件中来引用会更好 至于不能被组件化的样式存在性也不大,因为对于页面布局,既可以通过下面介绍的方法来拆分成全局样式,也可以依赖第三方UI库来实现

  • themes/目录也可以去除

    毕竟大部分前端项目是不需要设置主题的,即使有主题也可以新建一个样式文件来管理样式变量

  • vendors/目录可以根据需求添加

    因为将外部样式复制到项目中的情况比较少,更多的是通过npm来安装引入UI库,或者通过webpack插件来写入对应的cdn地址

优化后的目录结构示例

这只是推荐的一种,具体使用可以根据实际情况进行调整。比如在项目的src/目录下,创建模块目录,按照模块拆分路由、页面以及组件,所以每个模块下都会有pages/、components/来管理样式

src
|- abstracts
|-|- _variables.scss
|-|- _functions.scss
|-|- _mixins.scss
|-|- _placeholders.scss
|- base
|-|- reset.scss
|-|- typography.scss
|- components
|-|- buttons.scss
|-|- cover.scss
|-|- header/
|-|-|- header.tsx
|-|-|- header.sass
|-|- footer/
|-|-|- footer.tsx
|-|-|- footer.sass
|- pages
|-|- _home.scss
|-|- _contact.scss

避免样式冲突?

CSS的规则是全局的,任何一个样式规则,都对整个页面有效,如果不对选择器的命名加以管控会很容易产生冲突。

Vue和React是常见的前端框架,在处理样式冲突方面有不同的解决方法:

  • Vue中

    Vue组件使用局部作用域的CSS,每个组件都有自己的作用域,避免了全局样式的冲突。

    在Vue组件的<style>标签中添加scoped属性,使样式仅适用于当前组件内的元素。

    Vue 编译过程中,会为每个组件生成一个唯一的哈希值,然后将该哈希值添加到组件中的每个选择器上,使得选择器具有唯一性。

  • React中

    React通常使用CSS模块化技术来避免样式冲突。

    使用类似于PostCSS的工具或CSS-in-JS库(如styled-components)将样式封装在组件内部,确保样式只适用于特定的组件。

手动命名

最简单有效的命名管理方式就是制定一些命名规则。比如oocss、BEM、AMCSS,其中推荐比较常用的BEM

BEM的命名具有语义,非常适合组件样式类

工具命名

规范约束也不能绝对保证样式名的唯一性,而且也没有有效的校验工具来保证命名正确无冲突,所以聪明的开发者想到了通过插件将原命名转化成不重复的随机命名,从根本上避免命名冲突,比较著名的解决方案就是CSS Modules

// css
.className{
  color:green;
} 
// HTML
<div class=${styles.className}></div>
​
// 编译之后的代码
​
//css
._3zyde4l1yATCOkgn-DBWEL{
  color:green;
}
// HTML
<div class="_3zyde4l1yATCOkgn-DBWEL"></div>

因为这种方式编译后命名变得随机,所以会导致覆盖原来样式困难。

高效复用样式?

在开发中会发现有些样式会高度频繁使用,这很违背DRY(Don’t Repeat Yourself)原则,完全可以通过设置为全局公共样式来减少重复定义。

哪些可设置为公共样式?

枚举值的属性

在 CSS 中,有一些属性的取值是预先定义好的有限集合,也被称为枚举值(enumerated values)。

如:

  • display 属性的取值:`block、inline、inline-block“
  • `position 属性的取值:static、relative、absolute、fixed、sticky
  • float 属性的取值:left、right、right、none
  • text-align 属性的取值:left、right、center、justify

特定数值的样式属性

特殊的固定值

如:margin:0;left:0;height:l00%;

特殊的组合

如:display: flex;justify-content: center;align-items: center;

display: flex;flex-direction: column;align-items: center;

设计规范所使用的属性

比如设计稿中规定的几种颜色

如何命名公共样式

全局样式是基于样式属性和值的,是无语义的。其次对于这种复用率很高的样式应该尽量保证命名简短方便记忆

我们团队所使用的就是属性名首字母 + 横线 + 属性值首字母的方式进行命名。

对于display:inline-block的样式属性值,它的属性为display缩写为d,值为inline-block,缩写为ib,通过短横线连接起来就可以命名成d-ib

知识支撑

BEM

BEM是Block、Element、Modifier三个单词的缩写。

  • Block:代表独立的功能组件
  • Element:代表功能组件的一个组成部分
  • Modifier:表示对应状态信息
.button{
  ...
}
.button-state-success{
  ...
}
.button-state-danger{
  ...
}

CSS in JavaScript

值得关注的CSS in JavaScript。其实Web标准,是提倡结构、样式、行为分离(分别对应HTML、CSS、JavaScript三种语言)。

但React.js的一出现就开始颠覆了这个原则。

在React.js中

  • 通过JSX将HTML代码嵌入进JavaScript组件
  • 通过CSS in JavaScript的方式将CSS代码也嵌入进JavaScript组件

这种all in JavaScript的方式确实有悖Web标准,但这种编写方式和日益盛行的组件化概念非常契合,具有“高内聚”的特性

React.js这种方式有两个不那么明显的优势

  • 可以通过随机命名解决作用域问题,但命名规则和CSS Modules都可以解决这个问题
  • 样式可以使用JavaScript语言特性,比如函数、循环,实现元素不同的样式效果,可以通过新建不同样式类修改元素样式类来实现

当然styled-components只是CSS in JavaScript的一种解决方案,可以在GitHub上的资料学习其他解决方案

最后一句
学习心得!若有不正,还望斧正。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY9dd93F' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片