CSS Handbook · 布局

第六章 / 6.1 盒模型与定位

第六章 · 6.1 节

盒模型与定位


在深入 Flexbox 与 Grid 之前,必须先把地基打牢:每一个 HTML 元素在渲染时都会生成一个矩形的"盒子",理解这个盒子如何被测量、如何脱离或留在正常文档流中,是掌握一切布局技术的前提。

盒模型的四层结构

从内到外,一个盒子由内容区、内边距、边框、外边距四层同心矩形组成:

盒模型分层示意
margin 外边距
border 边框 / padding 内边距
content 内容区
层相关属性说明
内容区width / height实际承载文字、图片等内容的区域
内边距padding内容与边框之间的留白,继承背景色
边框border环绕内边距的可见线条
外边距margin盒子与相邻盒子之间的间距,透明、不计入背景

box-sizing:两种计算方式

这是初学者最容易困惑的一点:设置了 width: 200px,为什么最终渲染出来的盒子比 200px 更宽?答案取决于 box-sizing。

取值width/height 包含的范围
content-box(默认)仅内容区;最终渲染宽度 = width + padding + border
border-box内容区 + padding + border;width 就是最终渲染宽度
/* 几乎所有现代项目的第一行 CSS */
*, *::before, *::after {
  box-sizing: border-box;
}
为什么推荐 border-boxcontent-box 模式下,一旦调整 padding 或 border,元素的总宽度会跟着变化,破坏原本设计好的网格比例;border-box 让 width 所见即所得,是绝大多数现代 CSS 框架的默认选择。

display:外部与内部显示类型

display 同时控制两件事:这个盒子在"外部"如何参与父级的排列(外部显示类型),以及它的"内部"子元素如何排列(内部显示类型)。

取值外部类型特点
block块级独占一行,可设置 width/height
inline行内不换行,width/height 无效,只有水平方向 padding/margin 生效
inline-block行内不换行,但可设置 width/height 与垂直方向 padding/margin
none—不生成盒子,从渲染树移除,不占据空间

display: flex 与 display: grid 则是把"内部显示类型"切换为弹性 / 网格排布,这正是 4.2 与 4.3 节的主题。

position 五种取值

取值是否脱离文档流定位基准
static(默认)否正常文档流,偏移属性无效
relative否相对自身原本的位置偏移,原位置仍占据空间
absolute是相对最近的"已定位"祖先元素(见下)
fixed是相对浏览器视口,滚动时不移动
sticky否(临界脱离)在阈值内正常流动,超出阈值后表现如 fixed
relative + absolute 组合示例
badge
父元素设为 relative,子元素的 absolute 就以它为基准定位。
.card { position: relative; }
.badge {
  position: absolute;
  top: 10px; right: 10px;
}

sticky 的常见用法

.section-title {
  position: sticky;
  top: 0;
  background: #f4f5f0;
}

本教程页面左侧的"本节目录"侧栏,就是用 position: sticky 实现的滚动跟随效果。sticky 元素必须有明确的 top(或 left/right/bottom)取值才会生效,且不能超出其父容器的可视范围。

偏移属性与包含块

absolute 元素究竟相对谁定位?规则是:沿 DOM 树向上查找,第一个 position 不为 static 的祖先元素,就是它的"包含块"(containing block)。如果一路找不到,就以整个文档(<html>)为基准。这也是为什么"父元素加 relative,子元素用 absolute 定位"是最常见的组合拳。

z-index 与层叠上下文

z-index 只在"层叠上下文"内部比较大小,且只对 position 不为 static 的元素(以及 flex/grid 子项)生效。多个层叠上下文之间互不干扰——子级里再大的 z-index,也无法超越父级层叠上下文之外的兄弟元素。

/* 会创建新的层叠上下文的常见属性 */
.modal {
  position: fixed;
  z-index: 1000;
}
/* opacity < 1、transform、filter 等同样会创建层叠上下文 */
排查技巧当 z-index "不生效"时,先检查元素是否已脱离 static 定位;再检查它的祖先链上是否存在某个更早创建的层叠上下文,把它"锁"在了较低的层级里。

小结

  • 用 border-box 统一盒模型计算方式,让宽高所见即所得。
  • display 决定盒子对外的排列方式与对内的排布规则。
  • position 五种取值中,relative 常与 absolute 搭配,sticky 适合滚动跟随,fixed 适合全局悬浮元素。
  • z-index 只在同一层叠上下文内比较,排查层级问题要先定位"创建了层叠上下文"的祖先。

Chapter 6 · Section 6.1

The Box Model and Positioning


Before diving into Flexbox and Grid, you need a solid foundation: every HTML element generates a rectangular "box" when it is rendered. Understanding how this box is measured, and how it leaves or stays in the normal document flow, is the prerequisite for mastering every layout technique.

The Four Layers of the Box Model

From the inside out, a box consists of four concentric rectangles: the content area, padding, border, and margin.

The layers of the box model
margin
border / padding
content
LayerRelated propertiesDescription
Content areawidth / heightThe area that actually holds text, images, and other content
PaddingpaddingThe space between the content and the border; it inherits the background color
BorderborderThe visible line surrounding the padding
MarginmarginThe gap between this box and its neighbors; transparent and not part of the background

box-sizing: Two Ways to Calculate

This is one of the most confusing points for beginners: you set width: 200px, but why does the rendered box end up wider than 200px? The answer depends on box-sizing.

ValueWhat width/height includes
content-box (default)Only the content area; the final rendered width = width + padding + border
border-boxContent + padding + border; width is the final rendered width
/* The first line of CSS in almost every modern project */
*, *::before, *::after {
  box-sizing: border-box;
}
Why border-box is recommendedWith content-box, adjusting the padding or border changes the element's total width and breaks the grid proportions you designed; border-box makes width what-you-see-is-what-you-get, which is why most modern CSS frameworks default to it.

display: Outer and Inner Display Types

display controls two things at once: how this box participates in its parent's arrangement on the "outside" (the outer display type), and how its "inner" children are arranged (the inner display type).

ValueOuter typeCharacteristics
blockBlock-levelTakes a whole line; width/height can be set
inlineInlineDoes not break lines; width/height have no effect; only horizontal padding/margin apply
inline-blockInlineDoes not break lines, but width/height and vertical padding/margin can be set
none—Generates no box; it is removed from the render tree and takes up no space

display: flex and display: grid switch the "inner display type" to flex / grid arrangement, which is the topic of sections 4.2 and 4.3.

The Five Values of position

ValueRemoved from the flow?Positioning reference
static (default)NoNormal document flow; offset properties have no effect
relativeNoOffset from its original position; the original space is still occupied
absoluteYesRelative to the nearest "positioned" ancestor (see below)
fixedYesRelative to the browser viewport; it does not move when scrolling
stickyNo (detaches at the threshold)Flows normally within the threshold; behaves like fixed past it
relative + absolute example
badge
The parent is set to relative, so the child's absolute positioning uses it as the reference.
.card { position: relative; }
.badge {
  position: absolute;
  top: 10px; right: 10px;
}

A Common Use of sticky

.section-title {
  position: sticky;
  top: 0;
  background: #f4f5f0;
}

The "section contents" sidebar on the left of this tutorial's pages uses position: sticky to follow the scroll. A sticky element needs an explicit top (or left/right/bottom) value to take effect, and it cannot go beyond the visible area of its parent container.

Offset Properties and the Containing Block

Which element does an absolute element position itself against? The rule is: walk up the DOM tree and find the first ancestor whose position is not static — that ancestor is its "containing block". If none is found, the whole document (<html>) is used as the reference. That is why "give the parent relative, position the child with absolute" is the most common combination.

z-index and the Stacking Context

z-index only compares values within a "stacking context", and it only takes effect on elements whose position is not static (and flex/grid items). Stacking contexts do not interfere with one another — however large a z-index is inside a child, it cannot outrank a sibling outside its parent's stacking context.

/* Common properties that create a new stacking context */
.modal {
  position: fixed;
  z-index: 1000;
}
/* opacity < 1, transform, filter, etc. also create a stacking context */
Troubleshooting tipWhen z-index "doesn't work", first check whether the element has left static positioning; then check whether an ancestor higher in its chain created an earlier stacking context that "locks" it into a lower level.

Summary

  • Use border-box to unify the box model calculation, so width and height are what you see.
  • display decides how the box is arranged outward and how its children are laid out inward.
  • Among the five position values, relative is often paired with absolute, sticky suits scroll-following, and fixed suits globally floating elements.
  • z-index only compares within the same stacking context; to debug layering problems, first locate the ancestor that "created a stacking context".