前端一面:盒模型、BFC 与经典布局题

CSS 相关的一面题里,盒模型和 BFC 几乎是高频中的高频,这一篇把“盒子长啥样”“BFC 能解决什么问题”和几道经典布局题放在一起梳理一下。

标准盒模型下,一个元素的可视区域可以拆成几层:

  • content:内容区域;
  • padding:内边距;
  • border:边框;
  • margin:外边距。

默认情况下,元素的 width/height 只包含 content,不包含 padding 和 border:

1/* content-box(默认) */
2.box {
3  box-sizing: content-box;
4  width: 100px;  /* 只算内容宽度 */
5  padding: 10px; /* 实际渲染宽度是 100 + 10*2 + border */
6  border: 2px solid;
7}

在实际项目中,更常用的是:

1/* border-box:width 包含 padding + border */
2*,
3*::before,
4*::after {
5  box-sizing: border-box;
6}

这样可以避免在布局时不断手工相加减 padding/border。

BFC 听起来很玄乎,本质上可以先记住两点:

  • 它是一个独立的布局区域,内部盒子如何排列不会影响到外部;
  • 一些与浮动、清除浮动、margin 折叠相关的问题,可以通过制造一个新的 BFC 来解决。

常见的触发 BFC 的方式包括:

  • float 不为 none
  • overflowhidden / auto / scroll
  • display: inline-block / table-cell / flex / grid 等;
  • position: absolute / fixed

典型应用场景:

  • 清除浮动:给父元素加 overflow: hidden,让它形成 BFC,将内部浮动元素包含起来;
  • 避免兄弟块级元素之间的 margin 折叠:让其中一个元素形成 BFC。

一面里 CSS 布局经常以“实现某种布局”为题出现,常见的有:

  • 行内/块级元素的水平居中:

    • 行内:text-align: center
    • 块级、固定宽度:margin: 0 auto
  • 容器内单个元素的水平垂直居中(flex 方案):

1.container {
2  display: flex;
3  justify-content: center; /* 水平居中 */
4  align-items: center;    /* 垂直居中 */
5}
  • 经典两栏布局:左侧固定宽度,右侧自适应:

    • Flex 方案:左列 width: 200px,右列 flex: 1
    • 旧方案(float + margin)可以略提一下,表明知道历史方案即可。
  • 圣杯/双飞翼布局(可以简单知道有这么回事,不必细写代码)。

在一面答这种布局题时,重点是:

  • 能给出一套现代、可维护的方案(Flex/Grid),
  • 如果顺带提一句 IE 老方案,算加分项,不是硬性要求。

参考答案要点:

  • 标准盒模型(content-box):width/height 只包含内容区域,不包含 padding 和 border;
  • IE 盒模型(border-box):width/height 包含内容 + padding + border;
  • 可以通过 box-sizing 切换:
1.box {
2  box-sizing: border-box; /* 切到“IE 盒模型”行为 */
3}

可以顺带提一下“在实际项目里通常会全局设置 border-box,更符合直觉”。

参考答案要点:

  • BFC 是块级格式化上下文,可以理解为一个独立的布局上下文,内部元素的布局不会影响外部;
  • 触发方式有很多,比如 floatoverflowvisibledisplay: flex/gridposition: absolute/fixed 等;
  • 常见用途:
    • 包裹浮动元素,让父元素撑开高度(清除浮动);
    • 避免兄弟块级元素之间的 margin 折叠,通过让其中一个元素单独形成 BFC。

如果面试官继续追问 margin 折叠,可以简要描述“相邻块级元素的上下 margin 会合并成一个”,通过 BFC 把它们“隔开”。

参考实现:

 1.layout {
 2  display: flex;
 3}
 4
 5.layout-left {
 6  width: 200px;
 7  flex-shrink: 0; /* 防止过窄时被压缩 */
 8}
 9
10.layout-right {
11  flex: 1;
12  min-width: 0; /* 避免内容过长撑爆布局 */
13}

参考讲法:

  • 左边通过固定 width + flex-shrink: 0 保证宽度不被压缩;
  • 右边设置 flex: 1 占据剩余空间;
  • 如果提到 min-width: 0,可以说明是为了解决某些浏览器中长内容撑爆的问题。

这一题主要是考你对 Flex 的基本属性是否熟悉,回答时可以顺带提一句“实际项目中基本都用 Flex 来解决这类布局问题”。