《深入解析CSS》笔记
层叠、优先级和继承
层叠
规则考虑顺序
-
样式表来源
- !important(使用了!important的声明会被当作更高优先级的来源对待)
- 作者样式表(前端开发样式)
- 用户样式表(游览器插件样式)
- 用户代理样式(游览器默认样式)
-
优先级
- 行内样式(可以理解为带作用域的样式声明)
- 选择器
- id -> class -> tag
- 通用选择器(*)和组合器(>、+、~)对优先级没有影响
-
源码顺序
规则作用结果
优先级选择器的数量决定了最终样式作用结果
- 如果选择器的id数量更多,则它会胜出。
- 如果id数量一致,那么拥有最多class选择器的胜出。
- 如果以上两次比较都一致,那么拥有最多tag选择器的胜出。
优先级标记
常用的表示优先级的方式是用数值形式来标记
- 比如1,2,2,表示选择器由1个id、2个class、2个tag组成。
- 优先级最高的id列为第一位,紧接着是class,最后是tag。
- 如果考虑内联样式,则数值标记可以用4位表示,0或1代表内联数量。
选 择 器 | ID | 类 | 标签 | 标记 |
---|---|---|---|---|
html body header h1 | 0 | 0 | 4 | 0, 0, 4 |
body header.page-header h1 | 0 | 1 | 3 | 0, 1, 3 |
.page-header .title | 0 | 2 | 0 | 0, 2, 0 |
#page-title | 1 | 0 | 0 | 1, 0, 0 |
两条经验法则
- 在选择器中不要使用ID
- 不要使用 !important
继承
- 如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。
- 不是所有的属性都能被继承,主要是跟文本和列表属性相关的属性。
- 继承属性会顺序传递给后代元素,直到它被层叠值覆盖。
特殊值
- inherit(继承父元素的属性值)——有时,我们想用继承代替一个层叠值,这时可以用inherit关键字
- initial(重置为属性的默认值)——有时,我们需要撤销作用于某个元素的样式,这时可以用initial关键字
简写属性
简写属性会默默覆盖其他样式
- 大多数简写属性可以省略一些值,只指定我们关注的值,但是这样做仍然会设置省略的值,它们会被隐式地设置为初始值
简写值的顺序
- “上、下、左、右”口诀适用于分别给盒子设置四个方向的值的属性,对应的有:margin、padding
- “水平、垂直”口诀适用于从一个点出发的两个方向的值的属性,对应的有:background-position、box-shadow、text-shadow
相对单位
em和rem
使用em定义字号
- 使用em定义自身font-size时,其值是根据继承的font-size字号来计算的
- 使用em定义其他属性时,会参照本身font-size的计算值来计算
使用rem设置字号
- html根节点有一个伪类选择器:root,优先级相当于类名
- 拿不准的时候,用rem设置字号,用px设置边框,用em设置其他大部分属性
css变量
css变量能够层叠和继承
- 层叠——子级定义的相同变量会覆盖父级定义的变量,类似于“作用域变量”
- 继承——子级会继承父级定义的变量,任何之下的子级都可以使用
使用javascript改变自定义属性
-
访问javascript自定义属性
var rootElement = document.documentElement; // 获取根元素 var styles = getComputedStyle(rootElement); // 获取层叠后的样式 var mainColor = styles.getPropertyValue('--main-bg'); // 获取定义的css变量 console.log(String(mainColor).trim()); // 确保mainColor是一个字符串,并去掉前后空格
-
使用javascript设置自定义属性
var rootElement = document.documentElement; // 获取根元素 rootElement.style.setProperty('--main-bg', '#cdf'); // 设置css变量
盒模型
元素宽度的问题
在设置一个元素的宽/高时,盒模型默认指定的只是内容的宽/高,因此所有内边距、边框、外边距都是追加到该宽/高值上的
解决办法
- calc(宽度值 - 内边距/外框/外边距)
- 调整盒模型
box-sizing: border-box
最佳实践
:root {
box-sizing: border-box;
}
*,
::before,
::after {
box-sizing: inherit;
}
// 涉及到组件库影响的问题时
.component-lib-container {
box-sizing: content-box;
}
元素高度的问题
- 元素宽度的问题的border-box的修改依然适用于高度。
- 普通文档流是为限定的宽度和无限的高度设计的,容器的高度由内容天然地决定,而不是容器自己决定。
控制溢出行为
- 当明确设置一个元素的高度时,内容可能会溢出容器。
- 解决办法:overflow
百分比高度的备选方案
-
用百分比指定高度会存在问题,百分比参考的是元素容器块的大小,但是容器的高度通常是由子元素的高度决定的。这样会造成死循环,浏览器处理不了,因此它会忽略这个声明。
-
要想让百分比高度生效,必须给父元素明确定义一个高度。
-
我们使用百分比高度通常是想让一个容器填满屏幕,不过更好的方式是用视口的相对单位vh,100vh等于视口的高度,还有一个更常见的用法是创造等高列。
-
创造等高列的2种方法:display: table和Flexbox
垂直居中指南
-
可以用一个自然高度的容器吗?——可以采用给容器加上相等的上下内边距让内容居中。
-
容器需要指定高度或者避免使用内边距吗?——对容器使用 display: table-cell和vertical-align: middle。
-
可以用Flexbox吗?——如果不需要支持IE9,可以用Flexbox居中内容。
-
容器里面的内容只有一行文字吗?设置一个大的行高,让它等于理想的容器高度。这样会让容器高度扩展到能够容纳行高。如果内容不是行内元素,可以设置为inline-block。
-
容器和内容的高度都知道吗?将内容绝对定位。(只有当前面提到的方法都无效时才推荐这种方式。)
-
不知道内部元素的高度?用绝对定位结合变形。(只有当前面提到的方法都无效时才推荐这种方式。)
负外边距
不同于内边距和边框宽度,外边距可以设置为负值,负外边距的具体行为取决于设置在元素的哪边。
如果不给一个块级元素指定宽度,它会自然地填充容器的宽度。但如果在右边加上负外边距,则会把它拉出容器。如果在左边再加上相等的负外边距,元素的两边都会扩展到容器外面。
外边距折叠
-
只有上下外边距会产生折叠,左右外边距不会折叠。
-
折叠边距的值会取所有边距中的最大值。
原因
主要原因与包含文字的块之间的间隔相关。
类型
相邻元素折叠
-
同一个容器内,两个上下相邻的元素如果都设置有外边距,会存在折叠。
-
即使两个元素的外边距不是直接来自于自身,而是来自于内部子元素,这两个元素还是会发生折叠。
-
如果在页面中添加一个空的、无样式的div(没有高度、边框和内边距),它自己的顶部和底部外边距就会折叠。
<main class="main"> <h2>123</h2> <!--就算用另一个div包裹,段落的外边距还是会折叠--> <div> <p>456</p> </div> </main>
元素单边折叠
如果容器外部没有相邻元素,或者其相邻元素没有设置外边距,容器本身的边距和内部子元素的边距会存在折叠现象。
解决办法
-
针对相邻元素折叠
- 可以通过设置内边距或者边框避免
- 对容器设置display: flex,flex-direction: column。
-
针对元素单边折叠
- 对容器使用overflow: auto,或者非visible的值,这种方式副作用最小。
- 对容器设置浮动、定位或内联。
- 对容器设置display: flex。
容器内的元素间距
针对容器有固定内边距,但是连续的内容元素(如:li)之间又需要边距时,可以采用猫头鹰布局(+),代码示例如下:
.box * + * {
margin-top: 1.5em;
}
采用猫头鹰布局可以保证只有除首尾外的连续元素之间存在间距,这样就不会和容器的内边距叠加,造成界面不对称的美观问题。
理解浮动
浮动设计的初衷
浮动元素会被移出正常文档流,并被拉到容器边缘。文档流会重新排列,但是它会包围浮动元素此刻所占据的空间。浮动的初衷,就是为了实现文字围绕浮动元素排列的效果。
如果让多个元素向同侧浮动,它们就会挨着排列。
要实现将图片移动到网页一侧,并且让文字围绕图片的效果,浮动仍然是唯一的方法。
如果在段落里浮动图片,段落的高度并不会增长到能够容纳该图片。也就是说,如果图片比段落文字高,下一段会直接从
上一段的文字下面开始,两段文字都会围绕浮动的图片排列。
浮动陷阱
解决办法
清除每行的第一个元素上面的浮动,可以用:nth-child()伪类选择器命中目标元素。
// 使用:nth-child()选择器选取第奇数个元素
li:nth-child(odd) {
clear: left;
}
容器折叠和清除浮动
理解容器折叠
蓝色区域为header头部,底部为main包裹区域,内部分为title和box,main本身设置了白色背景,四个媒体盒子宽度等分,如果将这四个盒子设置浮动到左侧,我们能看到容器折叠的问题,如下图所示:
白色背景延伸到title就结束了,这是怎么回事?因为浮动元素不同于普通文档流的元素,它们的高度不会加到父元素上。这可能看起来
很奇怪,但是恰好体现了浮动的设计初衷。
解决办法:在容器内容尾部插入一个div并对它使用清除浮动clear: both,因为空div本身没有浮动,所以容器就会扩展,直到包含它,因此也会包含该div上面的浮动元素。
理解清除浮动
-
浮动元素的外边距不会折叠到清除浮动容器的外部,非浮动元素的外边距则会正常折叠。
-
外边距无法通过表格单元格元素折叠,表格单元格内设置外边距本身也无效。
清除浮动-版本1
// 该版本不能解决顶部非浮动元素设置外边距造成的折叠问题
.clearfix::after {
display: block;
content: " ";
clear: both;
}
清除浮动-版本2
// 该版本能解决顶部非浮动元素设置外边距造成的折叠问题
.clearfix::before,
.clearfix::after {
display: table; // 通过display: table,充分利用了外边距无法通过表格单元格元素折叠的特性
content: " ";
}
.clearfix::after {
clear: both;
}
BFC
全称块级格式化上下文。它是网页的一块区域,元素基于这块区域布局,虽然BFC本身是环绕文档流的一部分,但它将内部的内容与外部的上下文隔离开。这种隔离为创建BFC的元素做出了以下3件事情:
-
包含浮动元素
-
防止外边距折叠
-
防止文档流围绕浮动元素排列
简而言之,BFC里的内容不会跟外部的元素重叠或者相互影响。如果强制给一个元素生成一个新的BFC,它不会跟其他BFC重叠。
典型场景示例:
在一个容器中,左侧是图片,应用了浮动,右边是一个div包含了上下文字,右边底部的文字因为内容太多,加上浮动的影响,形成的环绕效果,但是我们其实需要的是左右齐分的效果。如果给右侧div添加浮动,它会摆脱浮动影响,但是也会因为div默认100%而自动换行,所以这个时候我们就可以为右侧div创建一个BFC来解决问题。
给元素添加以下的任意属性值都会创建BFC:
- float:left或right,不为none即可。
- overflow:hidden、auto或scroll,不为visible即可。
- position:absolute或fixed。
- display:inline-block、table-cell、table-caption、flex、inline-flex、grid或inline-grid。拥有这些属性的元素称为块级容器(block container)。
需要强调的是:
- 使用浮动或者inline-block方式创建BFC的元素宽度会变成100%,因此需要限制一下元素的宽度,防止因为过宽而换行。
- 相反,使用table-cell方式显示的元素,其宽度只会刚好容纳其中的内容,因此需要设置一个较大的宽度,强制使其填满剩余空间。
- 使用overflow:auto通常是创建BFC最简单的一种方式,它会刚好填充合适的宽度。
- 某些情况下,BFC中的内容可能还是会与别的BFC的内容重叠。比如,内容溢出了容器(比如内容太宽)或者因为负外边距导致内容被拉到容器外面。
Flexbox
Flexbox的原则
Flexbox布局是以主轴和副轴为基础来定义的,子元素按照主轴线排列。
主轴的方向为主起点(左)到主终点(右)。
副轴的方向从副起点(上)到副终点(下)。
Flexbox允许使用margin: auto来填充弹性子元素之间的可用空间。
弹性子元素的大小
flex属性
-
flex属性控制弹性子元素在主轴方向上的大小,它是flex-grow、flex-shrink和flex-basis属性的简写,默认值为0 1 auto。
-
与大部分简写属性不一样,如果在flex中忽略某个子属性,那么子属性的值并不会被置为默认值,而是会设置为更有用的组合值。
-
当flex属性给定一个无单位数值时,如flex:1,实例组合值为:1 1 0%,而非1 1 auto。
-
当flex属性给定一个有单位数值时,如flex:30%,实际组合值为:1 1 30%,而非30% 1 auto。
flex-basis属性
-
定义了元素大小的基准值,即一个初始的主尺寸。
-
可以设置为任意的宽度值,包括px、em、百分比,它的初始值是auto。
-
flex-basis设置了具体值后,会忽略width属性值。
-
子元素基准值考虑顺序:是否有flex-basis具体值->是否有width属性值->auto(用元素内容自身的大小)。
flex-grow属性
-
该属性属于增长因子,可以理解为放大,值为正整数。
-
如果某个弹性子元素的flex-grow值为0,那么它的宽度不会超过flex-basis基准值。
-
如果某个弹性子元素的flex-grow值为非0,那么这些元素会增长到所有的容器剩余空间被分配完。
-
flex-grow的值越大,元素的权重越高,也就会占据更大的剩余宽度。
flex-shrink属性
-
该属性属于收缩因子,可以理解为缩小,值为正整数。
-
计算出弹性子元素的初始主尺寸后,它们的累加值可能会超出弹性容器的可用宽度,如果不用flex-shrink,就会导致溢出。
-
每个子元素的flex-shrink值代表了它是否应该收缩以防止溢出。
-
如果某个弹性子元素为flex-shrink: 0 ,则不会收缩;如果值大于0,则会收缩至不再溢出。
-
按照flex-shrink值的比例,值越大的元素收缩得越多,在整体比例中占据得也就越小。
实际应用
弹性方向
理对齐、间距等细节
弹性容器的属性
弹性子元素的属性
网格布局
网格剖析
重点概念
-
网格容器:设置了display:grid的元素被称为网格容器。
-
网格元素:网格容器的子元素。
-
网格线:网格线构成了网格的框架。一条网格线可以水平或垂直,也可以位于一行或一列的任意一侧。
-
网格轨道:一个网格轨道是两条相邻网格线之间的空间。网格有水平轨道(行)和垂直轨道(列)。
-
网格单元:网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分。
-
网格区域:网格上的矩形区域,由一个到多个网格单元组成。该区域位于两条垂直网格线和两条水平网格线之间。
网格编号
浏览器给网格里的每个网格线都赋予了编号,CSS用这些编号指出每个元素应该摆放的位置。
属性解析
-
grid-template-columns:定义列划分,可以多个(垂直轨道),数值单位不限(fr、px、em或百分数)
-
grid-template-rows:定义行划分,可以多个(水平轨道),数值单位不限(fr、px、em或百分数)
-
grid-gap:网格间距,分别指定垂直和水平方向的间距
-
grid-column:定义了网格元素列的开始和结束位置,是grid-column-start/grid-column-end属性的简写
-
grid-row:定义了网格元素行的开始和结束位置,是grid-row-start/grid-row-end属性的简写
单位/函数/关键字
-
fr —> 分数单位,用于网格布局,跟Flexbox中flex-grow因子的表现一样
grid-template-columns: 1fr 1fr 1fr; // 定义等宽的三列 grid-template-rows: 1fr 1fr; // 定义等高的两行
-
repeat() -> 定义重复模式,接受多个参数,第一个参数为重复次数,后面的参数为被重复参数
-
span -> 告诉浏览器元素需要占据(跨越)的网格轨道,可以用于来指定grid-row和grid-column的值
nav { grid-column: 1 / 3; grid-row: span 1; // 这里会占据一个网格轨道,因为这里没有指出具体是哪一行,所以会根据网格元素的布局算法自动将其放到合适的位置 }
与Flexbox的区别
-
Flexbox是一维的,所以它很适合用在相似的元素组成的行(或列)上。它支持用flex-wrap换行,但是没法让上一行元素跟下一行元素对齐。
相反,网格是二维的,旨在解决一个轨道的元素跟另一个轨道的元素对齐的问题。 -
Flexbox是以内容为切入点由内向外工作的,而网格是以布局为切入点从外向内工作的。Flexbox让你在一行或一列中安排一系列元素,但是它们的大小不需要明确指定,每个元素占据的大小根据自身的内容决定。而在网格中,首先要描述布局,然后将元素放在布局结构中去。虽然每个网格元素的内容都能影响其网格轨道的大小,但是这同时也会影响整个轨道的大小,进而影响这个轨道里的其他网格元素的大小。
替代语法
命名的网格线
示例如下:
// 三条垂直的网格线分别叫作start、center和end
grid-template-columns: [start] 2fr [center] 1fr [end];
// 将网格元素放在1号网格线(start)到2号网格线(center)之间的区域
grid-column: start/center;
还可以给同一个网格线提供多个名称,比如下面的声明:
// 2号网格线既叫作left-end也叫作right-start,之后可以任选一个名称使用
grid-template-columns: [left-start] 2fr
[left-end right-start] 1fr
[right-end];
将网格线命名为left-start和left-end,就定义了一个叫作left的区域,这个区域覆盖两个网格线之间的区域。如果给元素设置grid-column: left ,它就会跨越从left-start到left-end的区域。
// repeat()里声明了一条命名的水平网格线,于是每条水平网格线被命名为row(除了最后一条)。
grid-template-rows: repeat(4, [row] auto);
// 将main元素放在从row 3(第三个叫row的网格线)开始的地方,并跨越两个网格轨道。
.main {
grid-column: left;
grid-row: row 3 / span 2;
}
命名的网格区域
// 通过grid-template-areas属性,将每个网格单元分配到一个命名的网格区域中
.container {
display: grid;
grid-template-areas: "title title"
"nav nav"
"main aside1"
"main aside2";
grid-template-columns: 2fr 1fr;
grid-template-rows: repeat(4, auto);
grid-gap: 1.5em;
max-width: 1080px;
margin: 0 auto;
}
// 通过grid-area属性,将每个网格元素放到一个命名的网格区域
header {
grid-area: title;
}
nav {
grid-area: nav;
}
.main {
grid-area: main;
}
.sidebar-top {
grid-area: aside1;
}
.sidebar-bottom {
grid-area: aside2;
}
每个命名的网格区域必须组成一个矩形,不能创造更复杂的形状,比如L或者U型。
还可以用句点(.)作为名称,这样便能空出一个网格单元。
grid-template-areas: "top top right"
"left . right"
"left bottom bottom";
显式和隐式网格
使用grid-template-*属性定义网格轨道时,创建的是显式网格。
隐式网格轨道默认大小为auto ,也就是它们会扩展到能容纳网格元素内容。
- 可以给网格容器设置和grid-auto-rows,为隐式网格轨道指定一个大小,比如:grid-auto-columns: 1fr。
属性解析
-
grid-auto-rows:为隐式网格轨道列指定一个大小。
-
grid-auto-columns:为隐式网格轨道行指定一个大小。
-
grid-template-columns:repeat(auto-fill, minmax(200px, 1fr))。
-
minmax()函数用于指定最小和最大值,浏览器会确保网格轨道的大小介于这两者之间,如果最大尺寸小于最小尺寸,最大尺寸就会被忽略。
-
repeat()函数里的auto-fill关键字是一个特殊值,设置了之后,只要网格放得下,浏览器就会尽可能多地生成轨道,并且不会跟指定大小(minmax() 值)的限制产生冲突。
-
auto-fill和minmax(200px, 1fr)加在一起,就会让网格在可用的空间内尽可能多地产生网格列,并且每个列的宽度不会小于200px。因为所有轨道的大小上限都为1fr(最大值),所以所有的网格轨道都等宽。
-
如果网格元素不够填满所有网格轨道,auto-fill就会导致一些空的网格轨道。如果不希望出现空的网格轨道,可以使用auto-fit关键字代替 auto-fill。它会让非空的网格轨道扩展,填满可用空间。
-
具体选择auto-fill还是auto-fit取决于你是想要确保网格轨道的大小,还是希望整个网格容器都被填满。
-
-
grid-auto-flow:控制布局算法的行为,精确指定在网格中被自动布局的元素怎样排列。
-
它的初始值是row,如果值为column,它就会将元素优先放在网格列中,只有当一列填满了,才会移动到下一行。
-
还可以额外应用一个关键字dense,它让算法紧凑地填满网格里的空白,让小元素回填大元素造成的空白区域,尽管这会改变某些网格元素的顺序。
-
使用了grid-auto-flow: dense,等价于grid-auto-flow: row dense,因为grid-auto-flow属性默认值是row。
-
定位和层叠上下文
定位
-
静态定位:如果我们用非static值,我们就说元素就被定位了,反之,元素则未被定位。
-
固定定位:让元素相对于视口定位,此时视口被称作元素的包含块。
-
绝对定位:让元素相对于最近的祖先元素定位,如果祖先元素都没有定位,那么绝对定位的元素会基于初始包含块来定位,初始包含块跟视口一样大,固定在网页的顶部。
-
相对定位:让元素相对于自身位置定位,元素仍然处在文档流中,不影响其他元素的布局。
-
跟固定或者绝对定位不一样,不能用top、right、bottom和left改变相对定位元素的大小,只能让元素在上、下、左、右方向移动。
-
可以用top或者bottom ,但它们不能一起用,bottom会被忽略。同理,可以用left或right,但它们也不能一起用,right会被忽略。
-
-
粘性定位:相对定位和固定定位的结合体。正常情况下,元素会随着页面滚动,当到达屏幕的特定位置时,如果用户继续滚动,它就会“锁定”在这个位置。
-
只有当父元素的高度大于粘性元素的高度,并且粘性元素随着父元素一起滚动,滚动到接近屏幕边缘时才会被“锁定”,而且这个“锁定”是有区间范围的,这个范围等于父元素高度减去粘性元素高度。
-
当父元素随着页面向上滚动,内部的粘性元素到达屏幕顶部后会被“锁定”,但是当父元素随着滚动,其底边到达粘性元素的底边时,粘性元素会失去“锁定”,随着父元素继续滚动,直至消失在屏幕视区(页面可以继续滚动的话)。
-
层级高低
有如下3个div:
<div>one</div>
<div>two</div>
<div>three</div>
正常的文档流情况下,元素在HTML里出现的顺序决定了游览器绘制的顺序,如果元素刚好重叠,后绘制的元素就会出现在先绘制的元素前面。
定位元素时,这种行为会改变,浏览器会先绘制所有非定位的元素,然后绘制定位元素。默认情况下,所有的定位元素会出现在非定位元素前面。
不过基于源码顺序的层叠关系并没有改变,因此在定位元素里,第二个定位元素还是出现在第一个定位元素前面,当然可以通过z-index属性进行改变,但是拥有负数z-index的元素出现在静态元素后面。
总结来看,关于层叠问题,层级高低取决于:
-
设置了定位,z-index属性值为正数
-
设置了定位,没设置z-index,源码顺序靠后
-
没设置定位,源码顺序靠后
-
设置了定位,z-index属性值为负数
层叠上下文
-
一个层叠上下文包含一个元素或者由浏览器一起绘制的一组元素,其中一个元素会作为层叠上下文的根。
-
如果给一个定位元素加上z-index就会创建一个层叠上下文,这个元素也就成了一个新的层叠上下文的根。
-
一个层叠上下文之内的元素独立设置的z-index大小不会改变跟其他外部层叠上下文的层叠高低,只有代表这个层叠上下文根的元素设置z-index才能改变层叠高低。
-
创建层叠上下文的其他方式还包括:设置小于1的opacity属性,还有transform和filter属性,由于这些属性主要会影响元素及其子元素渲染的方式,因此一起绘制父子元素。
-
文档根节点html也会给整个页面创建一个顶级的层叠上下文。
-
所有层叠上下文内的元素会按照以下顺序,从后到前叠放:
-
层叠上下文的根
-
z-index为负的定位元素(及其子元素)
-
非定位元素
-
z-index为auto的定位元素(及其子元素)
-
z-index为正的定位元素(及其子元素)
-
模块化CSS
模块化CSS是指把页面分割成不同的组成部分,这些组成部分可以在多种上下文中重复使用,并且互相之间没有依赖关系。最终目的是,当我们修改其中一部分CSS时,不会对其他部分产生意料之外的影响。
模块的变体
有时候我们需要区分一个模块的状态,可以通过定义修饰符来实现,也就是使用两个连字符来表示修饰符,这种写法出自BEM的CSS命名规范。
.message {}
.message--success {}
.message--warning {}
.message--error {}
强调:千万不要使用基于页面位置的后代选择器来修改模块。坚决遵守这个原则,就可以有效防止样式表变成一堆难以维护的代码。
带子元素模块
大多数情况下我们需要处理多层级元素,这个时候可以使用双下划线修饰符来定义元素类名,这样的类名可以清楚地告诉我们这个元素扮演了什么角色、属于哪个模块,这是 BEM命名规范里的另一种约定。
.media {}
.media__image {}
.media__body {}
强调:应该避免在模块选择器中使用通用标签名,因为其命中的范围太宽泛了,谁也说不准以后会不会出于其他目的再添加第二个相同的通用标签,当我们想为其追加类名时,可能会出现多处模块查找,全部改一遍的问题。
模块命名
-
模块的名称应该简单易记,能适用于各种不同场景,而不局限于任何特定用法或者视觉描述。
-
为模块的变体类命名的时候,也遵守同样的原则,应该避免使用精确描述的修饰符,因为不确定后面是否会改变,比如:
-
button--red
-
button--20px
-
工具类
-
工具类应该专注于某种功能,一般只声明一次。
-
工具类应该是唯一应该使用important注释的地方。
-
建议放在样式表的底部,模块代码的下面。
总结
-
把CSS拆解成可复用的模块。
-
不要书写可能影响其他模块或者改变其他模块外观的样式。
-
使用变体类,提供同一模块的不同版本。
-
把较大的结构拆解成较小的模块,然后把多个模块组合在一起构建页面。
-
在样式表中,把所有用于同一个模块的样式放在一起。
-
使用一种命名约定,比如双连字符和双下划线,以便一眼就可以看清楚模块的结构