搞懂盒模型与选择器,让每一个像素都听话——这是写好样式的基本功。
上一课我们搭好了 HTML 骨架,这一课给它穿样式。CSS 的知识点很多,但底层只有两件事最关键:一是“盒子怎么算尺寸”,二是“哪条规则说了算”。把盒模型和选择器优先级吃透,后面写布局、做动效才不会一头雾水。
浏览器把每个元素当成一个矩形盒子,从内到外分成四层:content(内容)、padding(内边距)、border(边框)、margin(外边距)。记住一个口诀:“content 装内容,padding 留呼吸,border 画边框,margin 隔别人”。
.box {
width: 200px; /* content 宽度 */
padding: 20px; /* 内边距:内容到边框的留白 */
border: 2px solid #7FB069;
margin: 16px; /* 外边距:与其他盒子的距离 */
}
四层里只有 content 是“自己的”,padding 和 border 会撑大盒子,margin 则影响盒子之间的间距。理解这一点,是控制尺寸的前提。
padding 在边框内侧,会撑大盒子(默认情况下),颜色用元素背景色。border 介于 padding 和 margin 之间,可单独设样式、宽度、颜色。margin 在最外侧,是透明的,只控制间距不显示颜色。相邻块级元素的垂直 margin 会“合并”,取较大值。margin: 20px,它们之间的间距是 20px 而不是 40px,这就是 margin 合并。解决方式是用 padding 代替,或借助 Flex/Grid 布局(它们不会触发 margin 合并)。
默认的 box-sizing: content-box 下,你写 width:200px 只管 content,加上 padding 和 border 后实际宽度会变大。这在排版时很容易“溢出”。实际项目里几乎都会改成 border-box:width 直接就是盒子的总宽度,padding 和 border 向内挤压 content。
/* 默认:width 只算 content,加 padding/border 会变大 */
.box-a {
box-sizing: content-box;
width: 200px;
padding: 20px;
border: 2px solid #7FB069;
/* 实际宽 = 200 + 20*2 + 2*2 = 244px */
}
/* 推荐:width 算总宽,padding/border 向内挤 */
.box-b {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 2px solid #7FB069;
/* 实际宽 = 200px,content 自动缩到 156px */
}
项目里通常在全局重置时统一设成 border-box,一劳永逸:
*, *::before, *::after {
box-sizing: border-box;
}
样式要生效,得先选中元素。最常用的四类选择器:
/* 标签选择器:选中所有该标签 */
p { line-height: 1.8; }
/* 类选择器:选中带某 class 的元素,可复用 */
.card { padding: 20px; }
/* ID 选择器:选中某 id,整页唯一 */
#header { position: sticky; }
/* 后代选择器:选中某容器内的元素 */
.card p { color: #5A6660; }
日常 90% 的场景用类选择器就够了。ID 选择器虽然优先级高,但因为不能复用、优先级又太强,反而不好覆盖,现代项目里更多用类。
当多条规则都指向同一个元素时,浏览器按“优先级”决定谁生效。优先级用四位数表示:(内联, ID, 类/属性/伪类, 标签/伪元素)。从左到右依次比较,左边大的直接赢。
/* (0,0,0,1) 标签 */
p { color: #5A6660; }
/* (0,0,1,0) 类 */
.text { color: #4A7C3A; }
/* (0,0,1,1) 类 + 标签 */
.text p { color: #6B9BD1; }
/* (0,1,0,0) ID */
#main { color: #2A3328; }
/* (1,0,0,0) 内联样式 */
<p style="color:#c0392b">最高</p>
/* !important 直接破规则,慎用 */
.text { color: #c0392b !important; }
!important,否则后面覆盖时会越写越乱。
选好基础选择器后,伪类和组合能让选择更精准。下面是高频写法:
/* 伪类:交互状态 */
.btn:hover { background: #4A7C3A; }
.btn:focus-visible { outline: 2px solid #6B9BD1; }
.link:active { color: #c0392b; }
/* 结构伪类:第几个 */
.list li:first-child { font-weight: 700; }
.list li:nth-child(odd) { background: #E4F0DC; }
/* 直接子代:只选亲生,不选孙级 */
.menu > li { padding: 10px; }
/* 相邻兄弟:选紧跟其后的同级 */
h2 + p { margin-top: 0; }
/* 群组选择器:一次给多组同样的样式 */
h1, h2, h3 { line-height: 1.3; }
组合使用时要注意优先级会叠加。比如 .list li:nth-child(odd) 的优先级是 (0,0,2,1),比单独的 li 强很多,覆盖时记得带上同等或更高的选择器。
把盒模型和选择器合起来用,做一个简单的信息卡片。HTML 结构:
<article class="info-card">
<h3 class="info-card__title">盒模型</h3>
<p class="info-card__desc">四层结构撑起所有尺寸。</p>
</article>
对应的 CSS:
*, *::before, *::after { box-sizing: border-box; }
.info-card {
width: 280px;
padding: 24px;
border: 1px solid #DFD9CC;
border-radius: 16px;
margin-bottom: 20px;
background: #ffffff;
}
.info-card__title {
margin-bottom: 8px;
color: #2A3328;
}
.info-card__desc {
color: #5A6660;
line-height: 1.8;
}
/* 悬停时换色,用伪类提升交互感 */
.info-card:hover {
border-color: #A8D5BA;
box-shadow: 0 10px 36px rgba(74, 124, 58, 0.10);
}
这个例子里,border-box 让你设的 280px 就是卡片实际宽度,伪类 :hover 改变边框和阴影,类选择器保证样式可复用。把这些组合用熟,就掌握了 CSS 的基本盘。
下一课我们进入布局,看 Flex 和 Grid 怎么把这些盒子稳定地排起来。