css工程化解决类名冲突、重复样式等问题

CSS工程化

在前端的不断发展,css也出现了很多问题,类名冲突、重复样式定义、css文件需要细分等问题。这篇文章我们来依次介绍如何解决这些问题的。

1、命名约定:BEM规范

BEM是一套针对css类样式的命名方法。

其他命名方法还有:OOCSS、AMCSS、SMACSS等等

BEM全称是:Block Element Modifier

一个完整的BEM类名:block__element_modifier,例如: banner__dot_selected,可以表示:轮播图中,处于选中状态的小圆点

三个部分的具体含义为:

  • Block:页面中的大区域,表示最顶级的划分,例如:轮播图(banner)、布局(layout)、文章(article)等等
  • element:区域中的组成部分,例如:轮播图中的横幅图片(banner__img)、轮播图中的容器(banner__container)、布局中的头部(layout__header)、文章中的标题(article_title)
  • modifier:可选。通常表示状态,例如:处于展开状态的布局左边栏(layout__left_expand)、处于选中状态的轮播图小圆点(banner__dot_selected)

在某些大型工程中,如果使用BEM命名法,还可能会增加一个前缀,来表示类名的用途,常见的前缀有:

  • l: layout,表示这个样式是用于布局的
  • c: component,表示这个样式是一个组件,即一个功能区域
  • u: util,表示这个样式是一个通用的、工具性质的样式
  • j: javascript,表示这个样式没有实际意义,是专门提供给js获取元素使用的

2、css in js

一看这个名字,我们应该差不多就能才出来,把css写在js中。它是把css变成js中的对象, 这样就可以完全运用js语言的优势。举个例子:


const styles = {
    width: "400px",
    height: "500px",
    backgroundColor: "#ccc",
}

css变成对象,就完全不会出现命名冲突的问题。

css in js就有了一下几个优点:

  • 绝无冲突的可能:由于它根本不存在类名,所以绝不可能出现类名冲突
  • 更加灵活:可以充分利用JS语言灵活的特点,用各种招式来处理样式
  • 应用面更广:只要支持js语言,就可以支持css in js,因此,在一些用JS语言开发移动端应用的时候非常好用,因为移动端应用很有可能并不支持css

但css in js同时也会出现一些问题:

  • 书写不便:书写样式,特别是公共样式的时候,处理起来不是很方便
  • 在页面中增加了大量冗余内容:在页面中处理css in js时,往往是将样式加入到元素的style属性中,会大量增加元素的内联样式,并且可能会有大量重复,不易阅读最终的页面代码

那么如何使用css in js,我们可以通过我们学过的各种技术将其应用到页面上,比如写个循环,使用框架等等方式,只要支持js,就可以使用。vue和react都支持css in js

3、css module

见名知意,css module就是把css写在不同的文件中,最后通过webpack构建工具合并成一个文件。多个不同的文件有相同的类名,合并之后没有冲突的类名。
在这里插入图片描述

在webpack中,我们使用css-loader来处理css文件,它就实现了css module的思想(css-loader使用在webpack常用插件中有讲述)。要启用css module,需要将css-loader的配置modules设置为true

css module原理非常简单,css-loader会将样式中的类名进行转换,转换为一个唯一的hash值。由于hash值是根据模块路径和类名生成的,因此,不同的css模块,哪怕具有相同的类名,转换后的hash值也不一样。
在这里插入图片描述

因此css-loader使用css module后,源代码的类名和最终生成的类名是不一样的,而开发者只知道自己写的源代码中的类名,并不知道最终的类名是什么,css-loader会导出二者的对应关系,但还包括了很多其他信息。而style-loader就是去除其他信息,仅暴露类名和对应生成的hash值

举个例子:

/*----------index.css----------*/
body{
    background-color: #ccc;
}
h1{
    color: #f40;
}
:global(.yellow){
    color: yellow;
}
.red{
    color: red;
}
/*----------index.js----------*/
import style from "./index.css"
console.log(style)
let h1 = document.getElementsByTagName("h1")[0]
h1.className = style.red
/*----------webpack.config.js----------*/
modules:{
	rules[
       {
		test:/\.css$/,
        use:["style-loader",
             {
            	loader:"css-loader",
            	options:{modules:true}
        	 }
			]
		}
	]
}

解释

  • 全局类名:某些类名是全局的、静态的,不需要进行转换,仅需要在类名位置使用一个特殊的语法即可:
:global(.main){
    ...
}
  • 局部类名:默认就是局部类名local,是可能会造成冲突的类名,会被css module进行转换

因为css-loader转换css代码后,交给style-loader进习性处理,sytle-loader是用一段js代码,将样式加到style文件中。而我们通常更需要的是生成一个css文件。于是就有了库mini-css-extract-plugin,这个库提供了一个plugin和一个loader:

  • plugin:负责生成css文件
  • loader:负责记录要生成的css文件的内容,同时导出开启css-module后的样式对象
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader?modules"]
               
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename:"[name].[hash:5].css"
        }) //负责生成css文件,name是chunk的name
    ]
}

其中"css-loader?modules"等同于

{
    loader:"css-loader",
    options:{
        modules:true
    }
}

4、预处理器

关于预处理器看这篇文章吧!十分钟带你学会Less预编译器

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值