在实现业务的过程中,我们难免会发现之前由于各种原因存在的代码中正在产生大量的冗余。这时候就需要优化代码,如果有功能的迭代,就是进行重构的好时机了!

最近在搞某一块业务的重构,恰好时间不紧。组内大佬说“放手去干吧”。于是我将目光投向了自认为比较了解的CSS方面。


ITCSS

这是由csswizardry提倡的一个 CSS 设计方法论,他可以让你更好的管理、维护你的项目的 CSS。
它可以帮助你

  • 管理 CSS 代码的书写顺序
  • 通过分层来明确每层 CSS 的作用
  • 更好地使用 CSS cascade(权重)
  • 安全的使用继承

ITCSS 把 CSS 分成了以下的几层:

Layer 作用
Settings 项目使用的全局变量
Tools mixin & function
Generic 最基本的设定 normalize.css,reset
Base type selector
Objects 不经过装饰 (Cosmetic-free) 的设计模式
Components UI 组件
Trumps helper 唯一可以使用 important! 的地方

也就是常说的“七层架构”。

但在实际项目中,我们只需借鉴其思路,达到维护一套完善利于阅读、扩展、复用的css代码即可。

我是怎么做的

首先,上面说的第一层 —— Settings 是很重要的。我们可以在其中放一些公共css变量。比如负责更改主题色的变量。常见的有:

  • 颜色
  • 边框
  • 字体大小
  • 阴影
  • 层级
  • 排版
/* Color
----------------------- */
$color-primary: #FF5777;
$color-white: #FFFFFF;
$color-black: #000000;$color-text-primary: #333333;
$color-text-secondary: #666666;
$color-text-tertiary: $color-white;$background-color-primary: #F1F1F1;
$background-color-secondary: $color-white;
$background-color-tertiary: $color-primary;/* Border
----------------------- */
$border-width-base: 1Px;
$border-style-base: solid;
$border-base: $border-width-base $border-style-base $border-color-base;/* z-index
-------------------------- */
$index-normal: 1;
$index-top: 1000;
$index-popper: 2000;

注意:这里必须是抽取的全局的、多个地方会使用到的公共的样式变量。更加细节的可以放在后面层级中单独写。

但通常,主题色不是这么容易实现的。它甚至需要大量的函数计算以及js的介入 —— 目前流行Ant Design采用了“三套主题色变量” 的方式(将Settings和Theme合并为一层);而elementUI是在 Base 层下又加了一层Theme(这也是为什么选择ITCSS方案的原因:随意扩展和缩减)。

然后是 tools 层,也是不可或缺的。这里面经常被用来放一些“工具样式”:比如当你使用了scss后的一些需要全局处理的mixin函数、比如水平垂直居中、比如溢出省略、清除浮动等样式类或function
关于这一层,网上有好多人推荐_sassMagic.scss库。据说挺好用的!

值得注意的是:上面两层都是 全局层面 的。一般笔者是这样安排的:(在我司的大部分项目中,这两层都属于自研脚手架中内置的)

这里说一句题外话:其实原生 css 越想写简单(提高复用)就越会发现,如果 css 中能引用 css 就好了(非@import形式) —— 这样 css 的东西就可以在 css 内部解决,完成一次复用。到 html 中只需引入一个类/属性名即可!scssmixin就达到了这个效果。

@mixin large-text {color: #737373;
}
.line-title {@include large-text;padding: 4px 0;
}
.code-title {@include large-text;padding: 2px;
}

(css的自定义变量也可以达到这样的效果 —— 不过你要写在:root中。而且 scss 中的自定义变量更加强大!)

对这一层感兴趣的可以研究elementUI 库源码,它的mixin写的非常之精妙。

注意⚠️:这两层的主要代码(涉及创建了 变量、mixinfunction的)是要在vue.config.js中引入的 —— 这样就能在其它css和页面中使用到:

module.exports = {css: {loaderOptions: {scss: {prependData: `@import "@/style/settings/var.scss";@import "@/style/theme/scss/index.scss";@import "@/style/tools/_sassMagic.scss";`},}
}

第三层 Generic。这一层就是专门放置一些css样式初始化等功能。你可以选择normalize.css这样成型的第三方css;也可以根据项目中用到的标签做针对性初始化处理。
这一层没什么说的。

第四层 Base 层:这一层可以用来放定制化css样式 —— 它是对基础样式的补充。比如你的网站中 a 链接点击后是什么样、或者 li 的前面几个点是什么样的。

这两层是 组件级别 的。
一般来说,“全局级别”的样式主要负责供应“全局”、“其它低级别样式文件”以及“极少量独立样式代码”;而“组件级别”主要负责供应所有构成页面的组件中需要的样式、制定本项目样式规范以及特殊情况。

第五层 Object 和第六层 Components 其实可以合并为一层:component。它其实就是写组件。

这一层首先在结构上不再维护在和其它目录同级的目录下(如上面的style),而是放在组件存放的 components 目录下。
在这一层你要做的就是:自行/利用第三方库封装一个具有“基本架子(结构)”的组件。考虑到复用性,所以这里使用最多的就是slot了。比如:

<!-- src/components/layout/footer.vue -->
<template><footer class="c-footer"><slot></slot></footer>
</template>
<script>
export default {name: 'VFooter'
}
</script>
<style lang="scss" scoped>
/** 使用到tools层的mixin:底部固定,且有一个高zIndex */
@include b(c-footer) {position: fixed;bottom: 0px;width: 100%;
}
</style>

由于这一层的“特殊性”,再加上根据 css 中的就近原则来说他们对html的影响是最大的,也是最小的(只负责一个文件的样式,一般一个文件就是一个部分的功能)。所以推荐OOCSS(面向对象css)的进阶写法:BEM

BEM规范

场景一:开发一个弹窗组件,在现有页面中测试都没问题,一段时间后,新需求新页面,该页面一打开这个弹窗组件,页面中样式都变样了,一查问题,原来是弹窗组件和该页面的样式相互覆盖了,接下来就是修改覆盖样式的选择器…每次为元素命名都心惊胆战

场景二:承接上文,由于页面和弹窗样式冲突了,所以把页面的冲突样式的选择器加上一些结构逻辑,比如子选择器、标签选择器,借此让选择器独一无二。一段时间后,新同事接手跟进需求,对样式进行修改,由于选择器是一连串的结构逻辑,看不过来,嫌麻烦,就干脆在样式文件最后用另一套选择器,加上了覆盖样式…接下来又有新的需求…最后的结果,一个元素对应多套样式,遍布整个样式文件…

以往开发组件,我们都用“重名概率小”或者干脆起个“当时认为是独一无二的名字”来保证样式不冲突,这是不可靠的。
理想的状态下,我们开发一套组件的过程中,我们应该可以随意的为其中元素进行命名,而不必担心它是否与组件以外的样式发生冲突。

BEM解决这一问题的思路在于,由于项目开发中,每个组件都是唯一无二的,其名字也是独一无二的,组件内部元素的名字都加上组件名,并用元素的名字作为选择器,自然组件内的样式就不会与组件外的样式冲突了。
这是通过组件名的唯一性来保证选择器的唯一性,从而保证样式不会污染到组件外。

这也可以看作是一种“硬性约束”,因为一般来说,我们的组件会放置在同一目录下,那么操作系统中,同一目录下文件名必须唯一,这一点也就确保了组件之间不会冲突。

BEM的命名规矩很容易记:block-name__element-name--modifier-name,也就是模块名 + 元素名 + 修饰器名

这里面还涉及到一个问题:要不要用scope?这个问题值得深思,比如vue中的scoped会形成一个样式隔离。如果需要样式复用还需要样式穿透的介入,非常麻烦。但是一味的遵循“开放”反而会引来“无妄之灾”。

OOCSS中,最重要的便是“结构与皮肤分离”。结构就是指“基础对象”,也就是我们说的“搭好一个架子”。

<div class="media"><div class="m-img"></div><span class="m-content"></span>
</div>

遇到上面的HTML,一般会先给一个“固定的样子”:

.media {.m-img {}.m-content {}
}

这时候如果有新的样式或者颜色之类的改动。就需要另写一个类名:

<div class="media m-color"><div class="m-img"></div><span class="m-content"></span>
</div>
.m-color {color: red;
}

但是在其它组件中,就完全不受影响:

<div class="media"><div class="m-img"></div><p class="m-content"></p>
</div>

OOCSS的复用就是体现在“架子的重复使用”上。这一点和“组件复用”有异曲同工之妙!也是这一层的基本思想。

ACSS规范

有时候我们还会在 component 上(样式的优先级比component低)再加一层:ACSS。

ACSS是原子类样式。通俗的讲就是“一个类只写一个样式”。这样的好处是可以达到对css的极限复用。而不好的地方就是让css失去了语义化

可以用属性选择器解决无语义化的痛点。

在 scss 强大的函数加持下,比如你写不同透明度的background可以这样:

/** 背景颜色
[bgaxxx] {background-color: rgba(0, 0, 0, 0.xxx);
}
*/
@each $i in 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 {[bga#{$i * 10}] { background-color: rgba(0, 0, 0, $i);}
}

像我司这种电商平台,会有“今日必抢”、“限时抢购”这样的为了抓住用户眼球而区别于一般字体的艺术字存在。而这种字体并不是所有地方都要用到的,而且它只作用于字体样式。我们就可以在 ACSS 层下新建 font 文件夹实现。

最后一层 Trumps ,其实就是在你的业务(组件)中进一步“描述”功能的差异性。结合之前层次样式的复用展现想要的效果。

为什么架构

css架构的目的不是“为了在页面不写css代码”,而是“为了更好的复用,更简单的维护,和更清晰的结构”!

在上面的内容中,很明显看到:

  • “层级越靠前,优先级越低、复用性越强”
  • “下一层永远继承上面(所有)层”

意犹未尽,说点其他的

在只有少量功能迭代的场景下,如果碰上周期不那么长其实是没法“推翻重来”的。这时候我们只能做一点点的优化(当然,本文说的都是结构上的,这里也不例外)。

上面的文字翻来覆去的看,其实核心也就两个字 —— 复用 。尽量减少重复代码的编写、甚至是文件的数量。而这一点在大多数项目中都可以优化:

比如提升层级:有时候刚开始写就是为了功能的实现,但是有可能这个 div 下包裹的文字和 div 同级的某个地方的文字是一样的,不管大小还是family,简直就是一个 family 的!其实可以将文字抽离出来,作为单独的一个样式类(或者属性选择器)。甚至是按照上面的ACSS层规范来,因为字体这玩意不可能只有一个页面有。花点时间嘛,哪怕花一点呢!

还比如溢出省略这些效果、可能某些公司业务场景还有css特效。这些不是妥妥的Tools层吗?

最后,我和某人聊起的时候他说会不会到后面文件(夹)太多。我觉得不会影响大局,它带来的收益是大于损耗的。而且像我司自研脚手架是确保文件按需加载的,就完全没有这个担心了,哈哈。

说说我对项目中css架构的浅显理解相关推荐

  1. Atitit.css 规范 bem  项目中 CSS 的组织和管理

    Atitit.css 规范 bem  项目中 CSS 的组织和管理 1. 什么是BEM?1 1.1. 块(Block)2 1.2. 元素(Element)2 1.3. BEM树(和DOM树类似).3 ...

  2. vue项目中css样式如何使用data中定义的动态变量

    vue项目中css样式如何使用data中定义的动态变量 直接上代码: 在这里是因为需要根据接口返回的数据控制对应父级盒子的高度以及子级盒子的宽度,所以需要用到动态样式.具体代码如下: <temp ...

  3. 项目管理手记(四) DRP项目中软件系统架构的比较

    项目管理手记(四) DRP项目中软件系统架构的比较                                                                   Drate(at ...

  4. 基于微软Synchronization Services双向同步技术在企业项目中的架构应用研究

    项目应用场景: 某客户是一个大型集团企业的信息部门,掌管着企业几百台服务器,并且以后会不断扩充:    为了更好的维护信息办的服务器:信息部门需要开发一套维护系统,来记录各个服务器的相关状态信息(如, ...

  5. 关于J2EE项目中三层架构如何在开发中得到正确的实施

    我现在参与了一个广电项目的开发,项目采用了目前比较流行的框架进行系统的架构Struts2+sping+hibernate,项目的包结构主要分成Action.Service.dao这三层,Action层 ...

  6. VUE项目中CSS设置动态宽度的方法

    网上找到三种方法: 一.使用cumputed 首先你务必看Vue的官方文档.涉及到的基础知识有: 绑定内联样式的使用 computed的使用 文档写的都是基础使用.那么在项目实战中如何使用,两步就能实 ...

  7. 项目中css的初始化

    一.目的:为了消除各浏览器对css默认的设置,保持网页在各浏览器中的外观保持一致 1./* 把我们所有标签的内外边距边框清零,盒子为边框盒型,不会因为padding而变大 */* {margin: 0 ...

  8. laravel项目中css样式表的背景图片不显示

    刚学laravel,遇到了很多坑,感觉laravel是挺强大的. 建好后台项目,奈何css样式表的背景图片不显示 .mainhd {background: url(../images/sky/body ...

  9. Vue项目中 css样式的作用域(深度作用选择器)

    vue官方文档 父组件对子组件设置的样式,只能作用到子组件的根节点上!!!

最新文章

  1. Git 创建两个“本地分支”协同工作
  2. linux kernel中__setup()函数介绍
  3. 随机数排列JAVA_随机数生成器,按排序顺序
  4. CUDA性能优化----线程配置
  5. arm中的.a文件如何产生的_可变文件系统:如何在IPFS中处理文件?
  6. php加本地音乐代码,WordPress添加音乐播放器(纯代码实现)
  7. css a4纸_一把刀、一张2毛钱的纸,刻出的动物太逼真,一幅卖上千美元
  8. quartz入门案例
  9. 维护IBM DB2数据库所应了解的根蒂基本常识-9
  10. Just Say It!——DNN在语音识别系统中的应用
  11. Protel 99SE详细安装教程(附安装包)
  12. 你知道 1 + 1 等于几吗?
  13. 第6章 索引和数据完整性
  14. 爱因斯坦的逻辑思维题
  15. 使用BenchMarkSQL测试openGauss
  16. 多边形(polygon)
  17. 客户/供应商主数据批导
  18. abp .net core linux,Abp vNext框架 从空项目开始 使用ASP.NET Core Web Application-笔记
  19. BLOB/TEXT column ‘sup_content‘ used in key specification without a key length
  20. 检测计算机故障五大原则,电脑故障维修的基本原则及流程

热门文章

  1. Web漏洞之文件包含漏洞
  2. MySql学习完后总结的知识点
  3. 华秋约定您!7月11-13日慕尼黑上海电子展不见不散~
  4. enclosing的意思_enclosing class是什么意思
  5. 拼多多“因为灰黑产被薅走200亿”的谣言
  6. 数据结构 || 二维数组按行存储和按列存储
  7. Android黑白照片上色APP,老照片上色app
  8. 陀螺速递 | 姚前:对货币我们要有敬畏之心
  9. access+asp演示
  10. 前端调用SOE服务接口