CSS盒模型
标准盒模型:W3C的默认选择
标准盒模型(content-box)是CSS规范定义的默认模型,它由内到外分为四层:
- 内容区域(Content) - 显示文本、图片等实际内容
- 内边距(Padding) - 内容与边框之间的缓冲带
- 边框(Border) - 元素的边界线
- 外边距(Margin) - 元素与其他元素的安全距离
关键特点
- width/height只决定内容区域大小
- 元素的总宽度 = width + padding-left + padding-right + border-left + border-right
- 元素的总高度 = height + padding-top + padding-bottom + border-top + border-bottom
.standard-box {
width: 300px; /* 内容区域宽度 */
height: 200px; /* 内容区域高度 */
padding: 20px; /* 所有方向的内边距 */
border: 10px solid #333; /* 边框 */
margin: 30px; /* 所有方向的外边距 */
background-color: #f0f0f0;
box-sizing: content-box; /* 明确指定使用标准盒模型(默认值) */
}
- 内容区域: 300px × 200px
- 总宽度: 300px + 20px × 2 + 10px × 2 = 360px
- 总高度: 200px + 20px × 2 + 10px × 2 = 260px
- 外边距不计入元素实际尺寸,但会影响元素在页面中占据的空间二、怪异盒模型:更直观的布局方案
怪异盒模型:更直观的布局方案
与标准盒模型的区别
在怪异盒模型中:
- width和height属性设置的是元素的总宽度和总高度,包括内容、内边距和边框
- 内容区域的实际尺寸会根据内边距和边框自动调整
尺寸计算
- 内容区域宽度 = width - padding-left - padding-right - border-left - border-right
- 内容区域高度 = height - padding-top - padding-bottom - border-top - border-bottom
.border-box {
width: 300px; /* 总宽度,包括内容、内边距和边框 */
height: 200px; /* 总高度,包括内容、内边距和边框 */
padding: 20px; /* 所有方向的内边距 */
border: 10px solid #333; /* 边框 */
margin: 30px; /* 所有方向的外边距 */
background-color: #e0f0ff;
box-sizing: border-box; /* 使用怪异盒模型 */
}
- 总宽度: 固定为300px
- 总高度: 固定为200px
- 内容区域宽度: 300px - 20px × 2 - 10px × 2 = 240px
- 内容区域高度: 200px - 20px × 2 - 10px × 2 = 140px
两种盒模型的比较
<div class="box standard-box">标准盒模型 (content-box)</div>
<div class="box border-box">怪异盒模型 (border-box)</div>
.box {
width: 300px;
height: 100px;
padding: 20px;
border: 10px solid #333;
margin: 20px;
background-color: #f0f0f0;
}
.standard-box {
box-sizing: content-box;
}
.border-box {
box-sizing: border-box;
}
实际应用中的选择
* {
box-sizing: border-box;
}
JavaScript中的"三剑客"属性
这三组属性是JavaScript中用于获取元素尺寸和位置信息的重要工具,它们与CSS盒模型密切相关。
client 系列
client系列属性用于获取元素的可视区域信息,不包括边框、外边距和滚动条。
- clientWidth: 内容宽度 + 内边距宽度(不包括边框和滚动条)
- clientHeight: 内容高度 + 内边距高度(不包括边框和滚动条)
- clientLeft: 元素左边框的宽度
- clientTop: 元素上边框的宽度
// 获取元素的可视区域宽度(内容+内边距)
const visibleWidth = element.clientWidth;
// 获取元素的可视区域高度(内容+内边距)
const visibleHeight = element.clientHeight;
offset 系列
offset系列属性用于获取元素的尺寸和相对于父元素的位置信息,包括边框和内边距。
- offsetWidth: 内容宽度 + 内边距宽度 + 边框宽度
- offsetHeight: 内容高度 + 内边距高度 + 边框高度
- offsetLeft: 元素左边框外侧到最近定位父元素左边框内侧的距离
- offsetTop: 元素上边框外侧到最近定位父元素上边框内侧的距离
- offsetParent: 最近的定位父元素(position不为static)
// 获取元素的总宽度(内容+内边距+边框)
const totalWidth = element.offsetWidth;
// 获取元素相对于定位父元素的左偏移
const leftPosition = element.offsetLeft;
// 获取元素相对于页面的绝对位置
functiongetElementPosition(el) {
let left = 0, top = 0;
while (el) {
left += el.offsetLeft;
top += el.offsetTop;
el = el.offsetParent;
}
return { left, top };
}
scroll 系列
scroll系列属性用于获取元素滚动相关的信息。
- scrollWidth: 元素内容的总宽度,包括因溢出而不可见的部分
- scrollHeight: 元素内容的总高度,包括因溢出而不可见的部分
- scrollLeft: 元素水平滚动条已滚动的距离
- scrollTop: 元素垂直滚动条已滚动的距离
// 获取元素内容的总高度(包括不可见部分)
const totalContentHeight = element.scrollHeight;
// 获取元素已滚动的垂直距离
const scrolledDistance = element.scrollTop;
// 检测元素是否已滚动到底部
functionisScrolledToBottom(el) {
return el.scrollHeight - el.scrollTop <= el.clientHeight + 1; // 添加1像素容差
}
// 平滑滚动到元素顶部
element.scrollTo({
top: 0,
behavior: 'smooth'
});
实战应用场景
内容区:宽度陷阱与流体写法
<style>
.fluid {
width: 90%; /* 相对于父元素 */
max-width: 1200px; /* 不要无限拉伸 */
min-width: 320px; /* 移动端最小体验 */
margin: 0 auto; /* 水平居中 */
}
</style>
<div class="fluid">响应式宽度</div>
内边距:逻辑写法 + 响应式
/* 逻辑属性:自动适应 RTL/LTR */
.logical {
padding-block: 1rem; /* 上下 */
padding-inline: 2rem; /* 左右 */
}
/* clamp() 让内边距随视口连续变化 */
.clamp-pad {
/*
一条 clamp() 即可让间距、字号、圆角等无缝缩放,告别大量断点媒体查询。
8px → 最小安全间距(手机小屏不会更窄)
2vw → 理想值,随视口宽度线性变化
24px → 最大上限(大屏或横屏时不再膨胀)
*/
padding: clamp(8px, 2vw, 24px);
}
边框:圆角 + 阴影 + 图像
<style>
.round { border-radius: 12px; } /* 统一圆角 */
.circle { border-radius: 50%; } /* 正圆 */
.shadow { box-shadow: 0 4px 12px #0003; } /* 柔和阴影 */
.gradient-border {
border: 4px solid;
border-image: linear-gradient(45deg, #e91e63, #2196f3) 1;
}
</style>
<div class="round shadow gradient-border">炫酷边框</div>
外边距:折叠、负值、auto
<style>
/* 1. 上下 margin 折叠演示 */
.a { margin-bottom: 20px; }
.b { margin-top: 30px; } /* 实际间距 = 30px(取大) */
/* 2. 负值重叠 */
.overlap { margin-top: -10px; } /* 向上提 10px,实现贴合 */
/* 3. 水平居中经典写法 */
.center { width: 300px; margin: 0 auto; }
</style>
margin 塌陷与解决方案
现象:上下相邻兄弟或父子 margin 合并为最大值。
解决:
- 兄弟层:只写单边 margin
- 父子层:给父级加
- padding-top: 1px 或
- border-top: 1px solid transparent 或
- display: flow-root / overflow: hidden
<style>
.dad { background: #ffc; }
.son { margin-top: 40px; } /* 无塌陷:dad 加 overflow:hidden */
.dad.fix { overflow: hidden; }
</style>
<div class="dad fix">
<div class="son">不再塌陷</div>
</div>
检测元素是否在视口中
- 布局计算:使用offset属性获取元素的实际尺寸和位置
- 滚动检测:使用scroll属性检测滚动位置,实现无限滚动、懒加载等功能
- 可视区域检测:使用client属性确定元素的可视区域大小
- 元素位置调整:根据这些属性动态调整元素位置
检测元素是否在视口中
function isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// 使用方法
const element = document.querySelector('.my-element');
if (isElementInViewport(element)) {
console.log('元素在视口中可见');
} else {
console.log('元素不在视口中');
}
生产级卡片组件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>生产级卡片组件</title>
<style>
/* 1. 全局统一 */
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }
/* 2. 卡片本体 */
.card {
/* 尺寸 */
inline-size: clamp(300px, 90%, 600px); /* 逻辑属性:行内方向宽度 */
block-size: auto; /* 块方向高度由内容决定 */
/* 内边距:随视口连续变化 */
padding-block: clamp(12px, 3vw, 24px); /* 上下 */
padding-inline: clamp(16px, 4vw, 32px); /* 左右 */
/* 边框与圆角 */
border: 1px solid #e0e0e0;
border-radius: 12px;
/* 阴影 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
/* 居中 */
margin-inline: auto; /* 逻辑写法:LTR=左右,RTL=右左 */
/* 内容溢出 */
overflow: hidden;
}
/* 3. 内部元素 */
.card__title {
margin-block: 0 0.5rem; /* 逻辑上下边距 */
font-size: clamp(1.125rem, 2.5vw, 1.5rem);
}
.card__body {
line-height: 1.6;
}
</style>
</head>
<body>
<article class="card">
<h2 class="card__title">响应式卡片</h2>
<p class="card__body">宽度在 300-600px 之间连续变化,内边距随视口缩放,始终贴合。</p>
</article>
</body>
</html>
总结回顾
- 标准盒模型(content-box):width/height只包括内容区域,不包括内边距和边框
- 怪异盒模型(border-box):width/height包括内容区域、内边距和边框
- client系列:获取元素可视区域信息(内容+内边距)
- offset系列:获取元素完整尺寸(内容+内边距+边框)和位置信息
- scroll系列:获取元素内容完整尺寸和滚动信息