整理一些 HTML 和 CSS 中常用的常用概念—— 盒模型、BFC、margin 行为、圣杯/双飞翼布局、Flex、定位和响应式方案。这些点面试和日常开发中都容易出现。

HTML 语义化

用对的标签表达结构,而非全用 <div>

<body>
  <header><nav></nav></header>
  <main>
    <article><section></section></article>
    <aside></aside>
  </main>
  <footer></footer>
</body>

语义化标签举例:

标签用途
<header>页头或区块头部
<nav>导航链接
<main>主内容(页面唯一)
<article>独立可分发的内容(文章、帖子)
<section>文档中的独立区块
<aside>侧栏、附加信息
<footer>页脚或区块底部
<figure> / <figcaption>插图及其说明
<time>日期或时间
<mark>高亮/标记文本

好处:代码可读性、SEO(搜索引擎理解页面结构)、无障碍访问(屏幕阅读器依赖标签构建导航)。

CSS 盒模型

#div1 {
  width: 100px;
  padding: 10px;
  border: 1px solid #ccc;
  margin: 10px;
}
  • content-box(默认)width 只作用于内容区。offsetWidth = width + padding-left/right + border-left/right = 100 + 20 + 2 = 122pxmargin 不参与 offsetWidth 计算。
  • border-boxwidth 包含 padding 和 border。offsetWidth = 100px
content-box:  [margin] [border] [padding] [====content====] [padding] [border] [margin]
border-box:   [margin] [=====border + padding + content=====] [margin]

常见的全局重置:

*,
*::before,
*::after {
  box-sizing: border-box;
}

border-box 让尺寸计算更符合直觉——设置了 width: 50% 就是占一半,不需要额外计算 padding 和 border。

margin 的行为

纵向重叠(Collapse)

相邻块级元素的垂直 margin 会折叠,取较大值而非相加:

p {
  margin-top: 10px;
  margin-bottom: 15px;
  font-size: 16px;
  line-height: 1;
}
<p>AAA</p>
<p></p>
<p></p>
<p>BBB</p>

AAA 和 BBB 之间的间距为 15px(取最大值)。即使中间有空 <p><div> 没有 border/padding,margin 也会穿透并参与折叠。

不重叠的情况:

  • Flex 容器和 Grid 容器的直接子元素(它们处于不同的格式化上下文)
  • 触发了 BFC 的元素(内部 margin 不穿透)
  • 相邻元素之间有 borderpaddinginline 内容隔开
  • 根元素(<html>)的 margin 不参与

为什么 Flex 子元素不重叠?因为 display: flex 会让容器进入 FFC(Flex Formatting Context),其直接子元素各自是独立的 BFC,BFC 之间不会发生 margin 折叠。

margin 负值

设置效果
margin-top: -10px元素自身向上移动
margin-left: -10px元素自身向左移动
margin-right: -10px右侧元素向左移动,自身位置不变
margin-bottom: -10px下方元素向上移动,自身位置不变

margin-right 和 margin-bottom 的负值不影响自身——它们改变的是后续元素的排列起点。这个特性是圣杯布局和双飞翼布局能用 margin 负值实现三栏并排的关键。

BFC(Block Formatting Context)

BFC 是一块独立的渲染区域,内部元素的布局不会影响外部元素。可以理解为隔离的”结界”。

触发条件

条件示例
float 不为 nonefloat: left / right
positionabsolutefixedposition: absolute
overflow 不为 visibleoverflow: hidden / auto / scroll
displayflex / grid / inline-block / table-cell / flow-rootdisplay: flow-root —— 专门为创建 BFC 而设计的值
containlayout / paint / strict / contentcontain: layout

display: flow-root(较新的属性)是只创建 BFC 而不引入其他副作用的方案,比 overflow: hidden 更语义化。

主要应用

1. 清除浮动(高度塌陷)

.container {
  overflow: hidden; /* 触发 BFC,自动包含浮动的子元素 */
  /* 或 display: flow-root; */
}

没有 BFC 时,浮动的子元素会脱离文档流,父容器高度塌陷为 0。触发 BFC 后,容器会”感知”浮动子元素的存在并自动包裹。

2. 阻止 margin 折叠

两个相邻的块级元素如果有 margin,会折叠。把其中一个放入 BFC 容器,折叠就不再发生。

3. 自适应两栏布局

.left {
  float: left;
  width: 200px;
}
.right {
  overflow: hidden; /* 触发 BFC,自动填充剩余空间 */
}

右侧触发 BFC 后不会环绕左侧浮动元素,而是形成独立的列。

圣杯布局与双飞翼布局

目标:三栏布局,中间主内容最先渲染并自适应宽度,两侧固定宽度。两种方案都用 float + margin 负值,区别在于为两侧留白的方式。

方案中间栏留白方式HTML 结构特点
圣杯父容器 padding三栏平级,父级 padding 防止遮挡
双飞翼中间栏内部多包一层 div,用 margin 留白中间栏多一层包裹
/* clearfix —— 清除浮动的标准写法 */
.clearfix::after {
  content: '';
  display: table;
  clear: both;
}
.clearfix {
  *zoom: 1;
} /* IE6/7 兼容 */

这两种布局是 PC 时代的经典方案,现在更常用 Flex 或 Grid 实现三栏布局。但在面试中,它们仍然被用来考察对 float、margin 负值和 BFC 的综合理解。

Flex 布局

容器属性

属性作用常用值
flex-direction主轴方向row(默认)/ column / row-reverse / column-reverse
justify-content主轴对齐flex-start / center / flex-end / space-between / space-around / space-evenly
align-items交叉轴对齐(单行)flex-start / center / flex-end / stretch(默认)/ baseline
align-content多行交叉轴对齐flex-start / center / space-between / stretch
flex-wrap换行nowrap(默认)/ wrap / wrap-reverse
gap间距10px / 10px 20px(行 列)

项目属性

属性作用
flex-grow分配剩余空间的比例(默认 0)
flex-shrink空间不足时的收缩比例(默认 1)
flex-basis初始主轴尺寸(默认 auto
flex简写:flex: grow shrink basis
align-self单个项目的交叉轴对齐,覆盖 align-items
order排列顺序(默认 0,越小越靠前)

三点骰子

.box {
  display: flex;
  justify-content: space-between; /* 1 号靠左,3 号靠右 */
}
.item:nth-child(2) {
  align-self: center;
} /* 2 号垂直居中 */
.item:nth-child(3) {
  align-self: flex-end;
} /* 3 号靠下 */

Grid 布局

Grid 是二维布局系统,适合页面级布局,而 Flex 适合一维(行或列)的组件级排列。

.container {
  display: grid;
  grid-template-columns: 200px 1fr 200px; /* 三栏:侧栏固定,中间自适应 */
  grid-template-rows: auto 1fr auto; /* 三行:header、内容、footer */
  gap: 16px;
  min-height: 100vh;
}

常用属性:

容器属性作用
grid-template-columns / rows定义轨道尺寸。1fr 按比例分配剩余空间
grid-template-areas命名区域布局
grid-auto-rows隐式创建的行高度
place-itemsalign-items + justify-items 简写
place-contentalign-content + justify-content 简写
/* 经典圣杯布局用 Grid 实现 */
body {
  display: grid;
  grid-template-areas:
    'header  header  header'
    'nav     main    aside'
    'footer  footer  footer';
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
}
header {
  grid-area: header;
}
nav {
  grid-area: nav;
}
main {
  grid-area: main;
}
aside {
  grid-area: aside;
}
footer {
  grid-area: footer;
}

定位

方式参照物脱离文档流使用场景
static正常流(默认)默认定位
relative自身原始位置否(保留占位)微调位置、为子元素 absolute 提供定位参照
absolute最近的非 static 祖先弹窗、下拉菜单、定位到容器边缘
fixed视口(有 transform 祖先时例外)固定导航栏、悬浮按钮、遮罩层
sticky滚动容器否(达阈值后固定)吸顶导航、表格冻结表头

fixed 定位有个需要留意的例外:如果祖先元素有 transformperspectivefilter 等属性(非 none),fixed 的参照物会变成该祖先而非视口。这是 CSS Transforms 规范规定的。

居中对齐速查

水平居中:

  • inline / inline-block 元素 → 父元素 text-align: center
  • block(定宽)→ margin: 0 auto
  • absolute(定宽)→ left: 50%; margin-left: -宽度/2
  • flexjustify-content: center
  • gridjustify-items: center

垂直居中:

  • 单行文本 → line-height = height
  • vertical-align: middle —— 仅适用于 inline/inline-block/table-cell
  • absolute(不定高)→ top: 50%; transform: translateY(-50%)
  • absolute(定高)→ top: 50%; margin-top: -高度/2
  • absolute(定宽高)→ top: 0; right: 0; bottom: 0; left: 0; margin: auto
  • flexalign-items: center
  • gridalign-items: center

水平垂直居中(一行搞定):

/* Flex */
.parent {
  display: flex;
  align-items: center;
  justify-content: center;
}
 
/* Grid */
.parent {
  display: grid;
  place-items: center;
}
 
/* Absolute + transform */
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

响应式布局

单位

单位相对用途
px无(绝对)固定尺寸、边框、阴影
em父元素 font-size组件内部按比例缩放
rem根元素 <html>font-size全局响应式
vw视口宽度的 1%全屏宽度
vh视口高度的 1%全屏高度
vminmin(vw, vh) 的 1%保证在横屏和竖屏都不会太大
vmaxmax(vw, vh) 的 1%保证覆盖最大维度
%父元素的对应属性相对父级

line-height 的继承

body {
  font-size: 20px;
  line-height: 200%;
}
p {
  font-size: 16px;
}
  • 数字(如 1.5):子元素继承这个比例,pline-height = 16 × 1.5 = 24px
  • 百分比(如 200%):先计算(20 × 200% = 40px),子元素继承计算后的值 40px
  • 长度(如 30px):子元素直接继承 30px

推荐写纯数字(如 line-height: 1.5),语义是”行高为字体大小的 1.5 倍”,子元素自动适配自己的字体大小。

两种响应式方案

方案一:media-query + rem

html {
  font-size: 16px;
}
@media (max-width: 1200px) {
  html {
    font-size: 15px;
  }
}
@media (max-width: 768px) {
  html {
    font-size: 14px;
  }
}
@media (max-width: 480px) {
  html {
    font-size: 12px;
  }
}

优点:兼容性好,完全可控。缺点:阶梯式变化,断点之间不连续。

方案二:vw 动态缩放

1vw = 视口宽度的 1/100

优点:连续平滑,无需媒体查询。缺点:无法限制最大最小值,在超宽屏幕上字会过大,在手机上字会过小。

/* 现代方案:clamp() 同时设置最小、首选、最大值 */
.title {
  font-size: clamp(16px, 4vw, 32px);
}
/* 不小于 16px,不大于 32px,之间按 4vw 缩放 */
 
/* 配合 calc 实现 rem 的动态基准 */
html {
  font-size: clamp(14px, calc(14px + (20 - 14) * ((100vw - 375px) / (1440 - 375))), 20px);
}