css 选择器优先级
注意:
给标签指定的所有选择器都被应用,冲突的代码,优先级高的覆盖掉优先级低的。比如id选择和class选择器同时给background-color指定不同的颜色,id选择器指定的background-color覆盖掉class选择器指定的background-color。
理解这个概念很重要,不要认为只有优先级高的选择器中的样式才会被应用,这是错误的。
老师的建议:
翻译:
- 使用
!important标记的 CSS 声明拥有最高优先级。 - 但是,只有在万不得已时才使用
!important。
最好利用正确的选择器特异性来写样式 —— 这样代码更容易维护! - 行内样式(inline styles,例如写在标签上的
style="")
永远优先于外部样式表(external stylesheet)中的样式。 - 一个包含 1 个 ID 的选择器,优先级会比 包含 1000 个 class 的选择器更高。
- 一个包含 1 个 class 的选择器,优先级比 包含 1000 个元素选择器 的选择器更高。
- 通配选择器
*的特异性为 0, 0, 0, 0(即没有特异性)。 - 编写样式时,应当 更依赖特异性(specificity),而不是选择器的书写顺序。
- 但在使用第三方 CSS 库时(如 Bootstrap 等),需要依赖加载顺序:
始终把你自己的样式表放在最后加载,以保证能覆盖第三方样式。
css继承属性
父容器的文本属性可以被子容器继承:
body {
font-family: ....;
color: ...;
font-weight: ...;
line-height: ...;
....其它文本属性;
}
综合选择器 *
综合选择器*可以选择页面上的所有dom元素,注意,*不能选择伪类元素。
所以初始化浏览器样式的时候我们经常这样写:
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
因为:
- 伪元素 不是实际存在于 DOM 的元素节点;
- 它们是 CSS 生成的内容(generated content) ;
- 所以
*根本选不到它们。
但伪元素也能有:
- 自己的 margin / padding;
- 以及影响布局的 box-sizing。
box-sizing
传统盒子模型的问题
在默认的 content-box模式下:
- 元素的
width和height只包含内容区域 - 内边距(padding)和边框(border)会在内容尺寸之外额外增加
/* 默认情况:content-box */
.box {
width: 200px;
padding: 20px;
border: 5px solid black;
/* 实际占用宽度 = 200 + 20×2 + 5×2 = 250px */
}
border-box 的作用
box-sizing: border-box让元素的 width和 height包含:
- 内容区域 + 内边距 + 边框
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid black;
/* 实际宽度就是 200px,内容区域自动调整为 200 - 20×2 - 5×2 = 150px */
}
Margin 合并问题
先看描述:
源代码:
这是 父子元素之间的外边距合并(Parent-Child Margin Collapsing)导致的。
官方解释(MDN):
如果 父元素没有上边框、上内边距、内联内容(如文字)或创建新的 BFC(块级格式化上下文) ,那么 子元素的
margin-top会与 父元素的margin-top合并,看起来就像是父元素被“推”了下去。
解决方法:
| 方法 | 原理 |
|---|---|
✅ 给父元素加 padding-top: 1px; | 打破合并 |
✅ 给父元素加 border-top: 1px solid transparent; | 打破合并 |
✅ 给父元素创建BFC | 创建新 BFC |
BFC
什么是 BFC(Block Formatting Context)?
BFC(块级格式化上下文) 是浏览器在页面中布局块级盒子时的一个独立的“布局环境”。
可以理解成:
BFC = 一堵无形的墙,
让里面的盒子布局不影响外面,外面的盒子也影响不到里面。
常见触发(创建)BFC 的方式:
| 方式 | 示例代码 | 备注 / 记忆点 |
|---|---|---|
1️⃣ float 不为 none | float: left; / float: right; | 浮动元素自成一个 BFC |
2️⃣ position 为 absolute 或 fixed | position: absolute; | 相对定位(relative)不行 |
3️⃣ display: inline-block | display: inline-block; | 行内块元素自带独立布局 |
5️⃣ display: flex / inline-flex | display: flex; | flex container 创建 BFC |
6️⃣ display: grid / inline-grid | display: grid; | grid container 创建 BFC |
7️⃣ overflow 不为 visible | overflow: hidden; / auto; / scroll; | 经典触发手段 |
8️⃣ display: flow-root | display: flow-root; | 专门用于创建 BFC 的现代写法(推荐) |
Overflow
overflow设置了元素溢出时所需的行为——即当元素的内容太大而无法适应它的区块格式化上下文时,应该怎么处理。
/*
默认值。
内容不会被裁剪,可能会渲染到元素的 padding 盒(甚至 border 盒)之外。
*/
overflow: visible;
/*
内容会被裁剪以适应元素的 padding 盒。
不会显示滚动条,也无法通过滚轮、拖动等方式查看被裁剪的内容。
*/
overflow: hidden;
/*
浏览器总是显示滚动条(无论是否有溢出内容),
以防止滚动条在内容变化时出现或消失导致布局跳动。
*/
overflow: scroll;
/*
如果内容没有溢出,效果与 `visible` 相同;
如果内容溢出,则浏览器会在需要的方向(水平/垂直)提供滚动条。
具体显示哪些滚动条由实际溢出方向决定。
*/
overflow: auto;
overflow 是简写形式,我们可以通过overflow-y,overflow-x精准控制。
background简写
很多大神都喜欢简写background的属性,有时候看着很蒙,下面讲一下background的简写:
下面这些都可以写在一起(顺序基本随意):
| 属性 | 示例 |
|---|---|
background-image | url(...) |
background-repeat | no-repeat, repeat-x |
background-position | center, top right, 20px 30px |
background-size | cover, contain, 100% 50% |
background-attachment | fixed, scroll |
background-origin | padding-box, border-box |
background-clip | padding-box, text |
background-color | #000, transparent |
书写格式:
background: <image> <repeat> <position> / <size> <attachment> <origin> <clip> <color>;
注意:
position 和 size之间一定要由/
background中可以写多个背景层,比如:
background:
url(a.png) center/cover no-repeat,
url(b.png) center/contain no-repeat,
#ff0000;
- 每一层背景之间用 逗号分隔
也就是:多个 background-image(等属性) + 一个 background-color。
显示顺序:
background:
url(a.png) no-repeat center, /* 最上层:a.png */
#ff0000; /* 最底层:红色背景 */
又比如:
background:
url(top.png) no-repeat center, /*最上层*/
url(middle.png) no-repeat center, /*中上层*/
#000; /*底层*/
backdrop-filter和filter
作用范围:影响“该元素背后能看到的内容”
例如:
- 背后的图片
- 背后的颜色
- 背后的任何 DOM 元素
它会对背景做处理,但不改变元素自身。
块元素
行内块元素
注意事项:
在 HTML 里并没有“原生的 inline-block 元素”。
inline-block本质上是 CSS display 属性的一种值,
而不是某些 HTML 元素的默认 display 类型。
行内元素
举个例子:
注意事项:
img 是特殊的 inline-replaced 元素
<img>、<input>、<textarea>、<video> 这些属于 “inline-replaced elements”(内联替换元素) 。
💡 “替换元素(replaced element)”
指的是:元素内容不是由 HTML 文本直接定义,而是由外部资源替换(如图片、视频、输入框等)。
这类元素的特点:
- 虽然它们是 inline-level 元素(不会强制换行),
但它们有固有的尺寸(intrinsic size) ,并且width/height是可以控制的。 - 浏览器渲染时会“替换”为一个有尺寸的盒子。
注意:flex,grid container的子项不用设置display:inline-block,我们可以把这些子项看作是行内块元素。
比如:
<div class="container">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
</div>
.container {
display: flex; /*或者display:grid*/
}
a {
/*可以设置宽,高,上下padding,margin等等*/
height: 200px;
width: 200px;
padding: 30px;
margin: 30px;
}
a 元素的样式设置
我们一般经常这样设置 a 元素的样式:
a {
color: red;
font-size: 18px;
}
但这不是一个最佳实践,我们应该这样写:
/*
只选择设置了href的a元素
*/
a:link {
...
}
/*
链接访问之后的样式
*/
a:visited {
...
}
一般我们把这两种状态统一设置:
a:link, a:visited {
...
}
还有很重要的hover, active:
/*
鼠标滑过时候的样式
*/
a:hover {
...
}
/*
链接点击时候的样式
*/
a:active {
...
}
这两种状态也建议统一设置:
a:hover, a:active {
...
}
定位
css 定位position有以下几个属性:
- static(静态定位,默认)
- relative(相对定位)
- absolute(绝对定位)
- fixed(固定定位)
- sticky(粘性定位)
下面看一个示例(这个示例由ai生成):
inset
MDN 链接:developer.mozilla.org/zh-CN/docs/…
inset 是一个对应于,top,right,bottom,left属性的简写属性。
示例:
<div>
<span class="exampleText">示例文本</span>
</div>
div {
position: relative;
background-color: yellow;
width: 150px;
height: 120px;
}
.exampleText {
position: absolute;
/* top: 20px, right: 40px, bottom: 30px, left: 10px */
inset: 20px 40px 30px 10px;
background-color: #c8c800;
}
写法和padding,margin一样:
| 写法 | 意味着 |
|---|---|
inset: 20px; | top/right/bottom/left = 20px |
inset: 20px 40px; | top/bottom = 20px;right/left = 40px |
inset: 20px 40px 30px; | top = 20;right/left = 40;bottom = 30 |
inset: 20px 40px 30px 10px; | top/right/bottom/left 分别对应 |
注意:inset 仅对定位元素(非 static)生效。
flout 布局
MDN上是这样定义float布局的:
The
floatproperty places an element on the left or right side of its container, allowing text and inline elements to wrap around it. The element is removed from the normal flow of the page, though still remaining a part of the flow (in contrast to absolute positioning.
经常使用的两个属性:
- left
- right
浮动之后,这个元素不再占据原来那一行里的“空间”。
它变成:
➡ 挨到父元素的最左边或最右边
➡ 后面的普通文本或 inline(span)会绕过去
➡ 但后面的 块级元素(block) 会把它当成不存在(不避让)
跟position布局比较:
| 特性 | float | absolute |
|---|---|---|
| 文本会绕着它排版 | ✔ 会 | ❌ 不会 |
| 会影响浮动兄弟的布局 | ✔ 会(浮动之间会避让) | ❌ 不会 |
| 影响父元素高度 | ❌ 不会(除非清除) | ❌ 不会 |
| 完全脱离流 | ❌ 不完全 | ✔ 完全 |
所以浮动之后经常出现浮动后父元素高度塌陷(因为父元素看不见这个浮动的孩子)
怎么解决这个问题呢?
- 第一种方法,给父盒子触发BFC:
我们说过BFC是一个无形的墙,这个墙里面的东西不能影响墙外面的东西,外面的东西也不能影响里面的东西。
所以对父盒子我们可以使用任何可以创建BFC的方法,比如最常用的:
- overflow:auto/hidden(最常用,但是内容很多会出现滚动条或者被截断)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
background-color: orange;
overflow: auto; /* 给父容器触发一个块格式化上下文(BFC) */
}
.box1 {
float: left;
width: 200px;
height: 200px;
background-color: lightcoral;
}
.box2 {
float: right;
width: 200px;
height: 200px;
background-color: lightgreen;
}
</style>
</head>
<body>
<div class="container">
<div class="box1">hello</div>
<div class="box2">world</div>
</div>
</body>
</html>
- display:flow-root(现代首选,可能有兼容性问题)
.container {
background-color: orange;
display: flow-root; /* 给父容器触发一个块格式化上下文(BFC),现代方法 */
}
- 第二种方法,也是最经典,最古老的方法:清除浮动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
background-color: orange;
}
/* 清除浮动 */
.container::after {
content: "";
clear: both;
display: block; /* clear 只能作用于块级元素, 为元素默认是inline元素,所以这里需要改成block元素 */
}
.box1 {
float: left;
width: 200px;
height: 200px;
background-color: lightcoral;
}
.box2 {
float: right;
width: 200px;
height: 200px;
background-color: lightgreen;
}
</style>
</head>
<body>
<div class="container">
<div class="box1">hello</div>
<div class="box2">world</div>
</div>
</body>
</html>
注意:float布局现在已经过时了,所以页面布局请使用更主流的flex,grid等布局。float布局现在可以适用于文字绕图等场景,但是不要用float来进行页面布局,不是说不行,而是这种做法现在不主流。
flex布局
flex-basis是什么意思?
flex-basis我们可以这么理解:
我希望这个子项最初占这么大,至于最后能不能保持,看 flex-grow / flex-shrink 再决定。
注意,flex-basis的优先级高于width和height。
flex布局主要用来实现一维布局,比如用于对水平一行元素进行布局,或者对垂直一列元素进行布局。
如果是二维布局,尽量使用grid布局,这样更方便。
特别注意:flex子项是没有justify-self这个属性的,所以如果想单独控制某个元素在主轴方向上的对齐,我们可以配合margin实现。
比如,看这个例子:
下面看一下什么是一维布局,什么是二维布局:
grid布局
示例代码:
grid-templete-coloms可以设置的单位有:fr,px,auto
注意:如果想使用这个单位,比如grid-row: 1 / -1或者grid-column: 1 / -1必须要事先指定对应的grid-template-columns或者grid-template-rows
所以上面代码中:
.container {
background-color: #ccc;
padding: 16px;
/* grid 布局 */
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.el--1 {
grid-row: 1 / -1; // 这个不生效,虽然看着是2行,但是grid不知道现在有几行,因为没有明确指定.
background-color: orange;
}
如果这样写就生效了:
.el--1 {
grid-row: 1 / 4;
background-color: orange;
}
媒体差选
写媒体查询之前,一定要在html的头部写这行代码:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
通过这个例子我们可以看到,当max-width:1200px的时候定义的background-color会覆盖掉原来的background-color。原来的样式和媒体查询中写的样式都被应用,但是冲突的部分,媒体查询覆盖掉原来的样式。
这里也是,原来的样式,然后两个媒体查询中的样式都被应用,但是冲突的部分,以max-width:700px的为准,因为现在页面宽度小于700px。
desktop first
desktop first design就是优先适配电脑屏幕(宽屏),比如我们开发的时候就是用电脑来开发的,所以自然而然地就是desktop first design。
这个时候媒体查询应该使用max-width。
意思就是,当屏幕宽度小于这个时候媒体查询里面的代码生效。
/*
默认颜色,也就是我们电脑(宽屏)状态下的样式
*/
.section-hero {
padding: 4.8rem 0 9.6rem 0;
background-color: #fdf2e9;
}
/*
当屏幕宽度小于1200px的时候生效
*/
@media (max-width: 1200px) {
.section-hero {
background-color: #51cf66;
}
}
/*
当屏幕宽度小于700px的时候生效
*/
@media (max-width: 700px) {
.section-hero {
background-color: violet;
}
}
通过上面的例子我们可以明白,desktop first design就是默认屏幕宽度是电脑(宽屏),然后一步一步使用媒体查询适配更小的屏幕。
breakpoint(断点)怎么选择
-
Bad:按照设备型号设置断点(比如 iPhone、iPad)
-
Good:按照常见宽度范围设置断点(比如 600px、900px、1200px)
-
Prefect 根据你自己的设计什么时候“坏掉”来设置断点
Prefect 讲的是什么方法?
不要根据某个设备,也不要根据固定区间,而是根据你自己的设计什么时候“坏掉”来设置断点。
也就是:
当你的页面布局在某个宽度看起来怪怪的、重叠了、不好看了、挤了、太松散了。
就在那个宽度设置一个 break point。
单位
组件驱动开发
写代码之前,想好布局是什么样的,不要什么都没有规划好就动笔:
组件驱动开发:
- 组件化:
- BEM 规范
- 目录结构
绘制形状
第一种办法
如果是比较复杂的形状,应该使用clip-path:
MDN: developer.mozilla.org/zh-CN/docs/…
第二种方法是使用transform: skew:
MDN:developer.mozilla.org/zh-CN/docs/…
第三种方法 linear-gradient
MDN:developer.mozilla.org/zh-CN/docs/…
几种特殊的选择器
+ 是相邻兄弟选择器
先看示例代码:
相邻兄弟选择器的格式是这样的:
A + B
表示:选择紧跟在 A 后面的 B。
比如上面示例中的input:placeholder-shown + .label:
当 input 的 placeholder 在显示时,选中 跟在这个 input 后面的 label。
再看下面这个示例:
~通用兄弟选择器
选择同一个父元素下,位于前一个元素之后的所有兄弟元素(不要求紧挨着)
什么时候用~,而不用+ :
比如:
<input class="radio-input" type="radio">
<span>中间插了点东西</span>
<label class="radio-label">
<span class="radio-button"></span>
</label>
我想根据input的状态设置label的样式,这个时候要用~:
.radio-input:checked ~ .radio-label .radio-button::after
因为 label 不再是紧挨着 input 的第一个兄弟,
+就失效。
vertical-align
MDN链接:vertical-align - CSS:层叠样式表 | MDN
vertical-align属性用来指定行内(inline)、行内块(inline-block)盒子的垂直对齐方式。