模块化CSS是指把页面分割成不同的组成部分,这些组成部分可以在多种上下文中重复使用,并且相互之间没有依赖关系,当修改其中一部分CSS时,不会对其他部分产生意料之外的影响。
1 基础样式
基础样式是指,在开始写模块化样式之前,需要先配置好环境,每个样式表的开头都要写一些给整个页面使用的通用规则。具有以下特点:
1,基础样式不是模块化的,但它为后面编写模块化样式打好基础。配置完成后,很少会再修改。
2,应该是通用的,只添加那些影响页面大部分或全部内容的样式。
3,不应该使用类名或者Id来匹配元素,应只用标签类型或者偶尔用伪类选择器。
2 模块
每个模块都需要一个独一无二的名称。
模块的选择权由单个类名构成,没有其他规则来约束这些样式仅作用在页面上的某个地方。
<div class="message">消息通知</div>
.message {
padding: 0.8em 1.2em;
border-radius: 0.2em;
border: 1px solid #265559;
color: #265559;
background-color: #e0f0f2;
}
模块可以保证视觉一致性,精简代码。
2.1 模块的变体
有时需要特意避免一致,比如上面的消息模块,需要提供成功和失败状态时的消息展示,这两种状态的样式结构上一致,但是在字体及背景的颜色上不同。
用“修饰符”来定义这写不同的状态。 修饰符的写法是:模块名称 + 两个连字符。 例如 message--success 与 message--fail。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="flex">
<div class="message">默认状态</div>
<div class="separate-10"></div>
<div class="message message--success">成功状态</div>
<div class="separate-10"></div>
<div class="message message--fail">失败状态</div>
</div>
</body>
</html>
<style>
.message {
padding: 0.8em 1.2em;
border-radius: 0.2em;
border: 1px solid #265559;
color: #265559;
background-color: #e0f0f2;
}
.message--success {
color: #2f5926;
border-color: #2f5926;
background-color: #cfe8c9;
}
.message--fail {
color: #59262f;
border-color: #59262f;
background-color: #e8c9cf;
}
.flex {
display: flex;
}
.separate-10 {
width: 10px;
}
</style>
图 不同状态下的“消息”模块
2.1.1 不要使用依赖语境的选择器
不要使用基于页面位置的后代选择器来修改模块。否则,会有以下问题:
1)必须考虑这段代码放在哪里(和谁放在一起),后续需要修改样式,很难想起它们放在哪里。
2)提升了选择器优先级。当下次需要修改代码时,需要满足或继续提升优先级。
3)可能需要在其他场景用到这些样式,但是需要为这些样式规则添加新的选择器来匹配新的场景,或完整复制一遍样式。
4)会产生越来越长的选择器。
只能是模块本身可以决定自己的样式表现,其他模块不能进入别的模块内部去修改它。
2.2 多元素模块
一个模块通常由多个元素组成。
子元素命名,模版名称 + 双下划线 + 子元素名称。 这样可以清楚表明元素扮演的角色,属于哪个模块。
避免在模块选择器中使用通用标签签名。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="media media--right">
<img src="../asset/dog.jpeg" alt="" class="media__image"/>
<div class="media__body">
<h4>吉娃娃</h4>
<p>
这是一只可爱的吉娃娃,个头小小的,脾气大大的。非常可爱的呀!
</p>
</div>
</div>
</body>
</html>
<style>
.media {
padding: 1.5em;
background-color: #eee;
border-radius: 0.5em;
}
.media:after {
content: " ";
display: block;
clear: both;
}
.media__image {
float: left;
max-width: 60px;
margin-right: 1.5em;
}
.media--right > .media__image{
float: right;
margin-right: 0;
margin-left: 1.5em;
}
.media__body {
overflow: auto;
margin-top: 0;
}
.media__body h4 {
margin-top: 0;
}
</style>
图 “媒体”模块
3 更大的结构
每个模块应该只做一件事(符合单一职责原则)。
模块之间完全独立,这样使得代码更简洁,不需要理解这个模块之前先搞懂另一个,有助于更加灵活地复用模块。
1, 模块里使用定位:
尽量让需要定位的元素关联到同一个模块内的其他元素。只有这样,把模块放在另一个有定位的容器里时,才不会弄乱样式。
2, 状态类:
一般以is-或has-开头。例如:is-open,has-error等。
修饰符类 |
通常是静态的。命名方式与状态类不同。 |
状态类 |
用于描述元素在响应用户操作或应用交互时的状态。 |
表 修饰符类与状态类的区别
3.1 模块命名
1,模块的命名应该有意义,无论使用场景是什么。
2,避免使用简单地描述视觉效果的名称。
3,建议强制使用两个词命名每个模块,可以避免模块指代不明确。
4,不要使用像button--20px这样特别精确的修饰符。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="dropdown">
<button class="dropdown__toggle">下拉组件</button>
<div class="dropdown__drawer">
<ul class="menu">
<li>
<a href="/">菜单项1</a>
<a href="/">菜单项2</a>
<a href="/">菜单项3</a>
<a href="/">菜单项4</a>
<a href="/">菜单项5</a>
</li>
</ul>
</div>
</div>
</body>
</html>
<script lang="js">
(function() {
const toggle = document.querySelector(".dropdown__toggle")
toggle.addEventListener('click',(event) => {
event.preventDefault()
const parent = event.target.parentNode
parent.classList.toggle('is-open')
})
}())
</script>
<style>
.dropdown {
display: inline-block;
position: relative;
}
.dropdown__toggle {
padding: 0.5em 2em 0.5em 1.5em;
}
.dropdown__toggle:after {
content: "";
display: block;
border: solid 0.3em;
border-color: black transparent transparent;
position: absolute;
right: 1em;
top: 1em;
}
.dropdown__drawer {
display: none;
position: absolute;
top: 2.1em;
left: 0;
min-width: 100%;
background-color: #eee;
}
.dropdown.is-open .dropdown__toggle:after{
top: 0.7em;
border-color: transparent transparent black;
}
.dropdown.is-open .dropdown__drawer {
display: block;
}
.menu {
list-style-type: none;
margin: 0;
padding-left: 0;
border: 1px solid #999;
font-size: 13px;
}
.menu > li + li {
border-top: 1px solid #999;
}
.menu > li > a {
display: block;
padding: 0.5em 1.5em;
background-color: #eee;
color: #369;
text-decoration: none;
}
.menu > li > a:hover {
background-color: #fff;
}
</style>
图 “下拉菜单”模块
4 工具类
需要用一个类来对元素做一件简单明确的事,比如让文字居中、让元素左浮动。
工具类有点像小号的模块,应该专注于某种功能,一般只声明一次。通常吧工具类放在样式表的底部,模块代码的下面。
不要滥用工具类,最多十几个工具类就够用了。
工具类是唯一应该使用important注释的地方,应该优先使用它。