第三部分 项目
第九章 模块化 css
确保 css 应用在对的地方
编写网页的每个部分 按需组合
模块化 CSS
模块化 CSS(Modular CSS)是指把页面分割成不同的组成部分,这些组成部分可以在多种上下文中重复使用,并且互相之间没有依赖关系。最终目的是,当我们修改其中一部分 CSS 时,不会对其他部分产生意料之外的影响。
封装
将相关函数和数据装在一起,内部情况外部不可调整
组成部分 1 基础样式
开头的,适用给所有的规则 参见第三章
完成默认渲染 方便之后覆盖
:root {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
font-family: Helvetica, Arial, sans-serif;
}
a {
color: var(--primary-color);
text-decoration: none;
}
%% 其他一些base.css %%
颜色
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--background-color: #ecf0f1;
--text-color: #2c3e50;
}
链接
a {
color: var(--primary-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
通用容器
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1em;
}
标题
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
margin: 0 0 1rem 0;
}
图片
img {
max-width: 100%;
height: auto;
display: block;
}
表单
input, button, textarea, select {
font-family: inherit;
font-size: inherit;
margin: 0;
}
清除浮动
.clearfix::after {
content: "";
display: table;
clear: both;
}
flex类
.flex {
display: flex;
}
.flex-column {
flex-direction: column;
}
.flex-center {
justify-content: center;
align-items: center;
}
响应式设计
body {
font-size: 100%;
}
@media (min-width: 600px) {
body {
font-size: 110%;
}
}
@media (min-width: 900px) {
body {
font-size: 120%;
}
}
<link rel="stylesheet" href="base.css">
%% chrome里通过检查可以查看手机端情况 %%
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css/normalize.min.css">
组成部分 2 模块样式
通过类名指向模块 模块选择器由单个类名构成
修饰符
一种命名方式 来自 BEM 命名规范
--连接具体功能
双连字符的写法
双连字符的写法可能看起来有点儿多余,但当我们开始创建名称很长的模块的时候,比如导航菜单或者文章摘要,好处就显现出来了。为这些模块添加修饰符后,类名将如 nav-menu--horizontal
或者 pull-quote--dark
。
双连字符的写法很容易区分哪部分是模块名称,哪部分是修饰符。nav-menu--horizontal
和 nav--menu-horizontal
分别代表了不同的含义。这样一来,即使项目里有很多名称相似的模块,也很容易分辨它们。
说明
这种双连字符的写法是从一个叫 BEM 的 CSS 命名规范流行起来的。本章快结束的时候,会介绍 BEM 和其他一些类似的方法论。
.message{}
.message--sucess{}
.message--error{}
用例
<div class="message message--error">
Invalid password
</div>
消息模块
.message {
padding: 0.8em 1.2em;
border-radius: 0.2em;
border: 1px solid #265559;
color: #265559;
background-color: #e0f0f2;
}
按钮模块
.button {
padding: 0.5em 0.8em;
border: 1px solid #265559;
border-radius: 0.2em;
background-color: transparent;
font-size: 1rem;
}
.button--success {
border-color: #cfe8c9;
color: #fff;
background-color: #2f5926;
}
.button--danger {
border-color: #e8c9c9;
color: #fff;
background-color: #a92323;
}
.button--small {
font-size: 0.8rem; 小号变体
}
.button--large {
font-size: 1.2rem; 大号变体
}
提示 要把一个模块所有的代码集中放在同一个地方,这样一个接一个的模块就会组成 我们最终的样式表。
为了可维护性,类名不应该依赖语境,不要反复用很多选择器选择一个要素,这会使得后面的修改更加麻烦。
- 不要基于页面位置的后代选择器来修改模块
- 只有模块自己能够决定本身的样式表现
多元素模块
.media {
padding: 1.5em;
background-color: #eee;
border-radius: 0.5em;
}
.media::after {
content: "";
display: block;
clear: both;
}
.media__image {
float: left;
margin-right: 1.5em;
}
.media__body {
overflow: auto;
margin-top: 0;
}
.media__body > h4 {
margin-top: 0;
}
<div class="media">
<img class="media__image" src="runner.png">
<div class="media__body">
<h4>Strength</h4>
<p>
Strength training is an important part of
injury prevention. Focus on your core—
especially your abs and glutes.
</p> </div>
</div>
模块名称__子元素 双下划线
模块组合
每个模块只干一件很小的具体的事情,当不得不使用 并
与 和
这种词的时候说明可能可以拆分
= 单一职责原则
拆分模块职责
例子:下拉菜单=下拉控制显示和隐藏,菜单控制菜单内容
触发-动作 列表-内容
<div class="dropdown">
<button class="dropdown__toggle">Main Menu</button>
<div class="dropdown__drawer">
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials">Specials</a></li>
<li><a href="/about">About us</a></li>
</ul> </div>
</div>
<script type="text/javascript">
(function () {
var toggle =
document.querySelector('.dropdown__toggle');
toggle.addEventListener('click', function (event) {
event.preventDefault();
var dropdown = event.target.parentNode;
dropdown.classList.toggle('is-open');
} );
}());
</script>
.dropdown {
display: inline-block;
position: relative;
}
.dropdown__toggle {
padding: 0.5em 2em 0.5em 1.5em;
border: 1px solid #ccc;
font-size: 1rem;
background-color: #eee;
}
.dropdown__toggle::after {
content: "";
position: absolute;
right: 1em;
top: 1em;
border: 0.3em solid;
border-color: black transparent transparent;
}
.dropdown__drawer {
display: none;
position: absolute;
left: 0;
top: 2.1em;
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;
}
- 模块中定位 要关联同模块其他要素
- 状态类 通过 js 控制 is- has-开头
预处理器可以把多个样式合并成一个文件 减少请求次数
.menu {
margin: 0;
padding-left: 0;
list-style-type: none;
border: 1px solid #999;
}
.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;
}
模块命名
- 避免视觉效果命名
- 思考模块代表什么意义
- 简单记忆
- 消息,媒体,下拉,菜单,面板,警告,可折叠,表单控制
- 有时可以用两个词更准确 避免重复
- 不要使用精确修饰
原则应用的实例:比起button--red button--alert更合适,不使用外观,而是着眼意义
组成部分 3 工具类
用一个类对要素做简单操作 例如居中 浮动等
工具类是唯一应该使用!important 的地方
最多十几个工具类
.text-center {
text-align: center !important;
}
.float-left {
float: left;
}
.clearfix::before,
.clearfix::after {
content: " ";
display: table;
}
.clearfix::after {
clear: both;
}
.hidden {
display: none !important;
}
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.pt-0 { padding-top: 0; }
.pb-0 { padding-bottom: 0; }
.text-uppercase { text-transform: uppercase; }
.text-lowercase { text-transform: lowercase; }
.text-bold { font-weight: bold; }
.d-block { display: block !important; }
.d-inline { display: inline !important; }
.d-inline-block { display: inline-block !important; }
.d-flex { display: flex; }
.flex-row { flex-direction: row; }
.flex-column { flex-direction: column; }
.align-items-center { align-items: center; }
.justify-content-center { justify-content: center; }
.w-100 { width: 100%; }
.h-100 { height: 100%; }
.max-w-full { max-width: 100%; }
.visibility-hidden { visibility: hidden; }
.visibility-visible { visibility: visible; }
.cursor-pointer { cursor: pointer; }
.cursor-default { cursor: default; }
同时使用变体和子元素
.media--right > .media__image {
float: right;
}
只在media--right中生效改为右浮动
避免在模块选择器中使用通用标签名
我们在媒体模块中使用了选择器 .media__body > h4
来匹配标题元素。这么做是允许的,因为 <h4>
标签就是用来标识一个次要标题的。同样的方式也可以用在带列表的模块上。相较于列表里的每个项目都添加 menu__item
类名,使用 .menu > li
匹配菜单项简单多了,尽管这种写法有些争议。
我们应该避免使用基于通用标签类型的匹配选择器,比如 div
和 span
。类似 .page-header > span
的选择器就太宽泛了。最初建立模块的时候,可能只是用 span
标签做一件事,但谁也说不准以后会不会出于其他目的再添加第二个 span
。后面再为 span
添加类名就比较麻烦了,因为我们需要在 HTML 标记中找到所有用到模块的地方,全部改一遍。
css 方法论
最近可以完全通过 js 控制 css 称为 css in js 或者内联样式
第十章 模式库
模式库 或者 style guide是单独的一组网页,用来展示每个 css 模块
KSS 工具
https://kss-node.github.io/kss-node/
kss 已经是 10 年前的东西了 我觉得有点太过时了,本章简单记录下
kss 是一个在 css 里写注释然后生成模式库的工具
kss 不会主动删除旧页面
<img src="https://via.placeholder.com/300x200" alt="placeholder image">
- 任务管理 gulp 自动更新=检测更新后自动重新运行
- https://gulpjs.com/
- 模式库更适合大型项目
- 迭代最好弃用旧模块重写一个新的
css 优先方案
- [x] 建立一个自己的 css 模式库 (@2024-08-30 11:00)
语义版本
软件包命名方式 使用 3 个数字 1.2.3 表示主版本,次版本和修订号
-
主版本号(Major):
- 当你做了不兼容的 API 修改时,需要递增主版本号。
- 这意味着新版本可能无法与旧版本完美兼容,可能需要用户或开发者作出相应的调整。
-
次版本号(Minor):
- 当你在保持向后兼容的情况下添加了新功能时,需要递增次版本号。
- 这通常表明添加了新的功能或改进,但是不会破坏现有系统的工作。
-
修订号(Patch):
- 当你进行了向后兼容的问题修正时,需要递增修订号。
- 主要用于修复已知的错误或漏洞,这些修复通常不会影响软件的主要功能或API。
示例:
- 如果当前版本是
1.0.0
,并且你添加了一个新功能,没有破坏任何现有的API,那么新版本应该是1.1.0
。 - 如果你修复了一些小错误,并且没有改变任何API,那么新版本应该是
1.0.1
。 - 如果你重新设计了整个系统,改变了多个API,那么新版本应该是
2.0.0
。
bootstrap 等框架
所有框架都是模块化的 - 模式库更加定制化