盒模型、浮动与清除、定位、Flexbox与Grid在旧浏览器中的支持情况

说实话,CSS 兼容性这块坑特别多。我早年刚入行时,以为写出来的页面在哪都一样——结果在 IE 里一打开,整个布局稀碎。从那以后,我养成了一个习惯:动手前先想清楚,这段 CSS 在目标浏览器里会不会「翻车」。

这一章咱们就聊聊布局体系里的几个核心模块——盒模型、浮动、定位、Flexbox 和 Grid。每个都会碰到兼容性问题,但解决思路不太一样。我把经验拆开来讲。

核心观点:旧浏览器的兼容性排查,不是「能不能用」的问题,是「用哪个版本」以及「有没有 fallback」的问题。

CSS 布局兼容性知识体系:第三章节核心脉络 CSS 布局兼容性 盒模型 浮动与清除 定位 Flexbox Grid box-sizing: border-box IE 怪异模式 clearfix 方案 IE 双倍 margin sticky 不支持 z-index 堆叠 旧版 display: box 属性前缀 IE 10/11 旧语法 盒模型 浮动 定位 Flexbox Grid

盒模型:那个让无数人头疼的 border-box

盒模型兼容性,说到底就一句话——IE 的怪异模式跟标准 W3C 盒模型算宽高的方式不一样。你想想看,一个元素设了 width: 200px,再 padding: 20px,标准模式下实际占 240px,但怪异模式里 content 只剩 160px。页面错位就这么来的。

我在项目里遇到过好几次,设计师给的设计稿明明很精准,一放到 IE8 里布局全宽了半截。排查到最后,发现是 box-sizing 没统一。

解决思路其实很清晰:全局统一用 box-sizing: border-box,再给 IE6/7 做降级。你只要保证 content-box 和 border-box 的宽度计算方式一致,就不会出现「算不准」的问题。

推荐方案:

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

对于不支持 box-sizing 的 IE6/7,可以用 polyfill 或直接避免对 padding 敏感的场景使用固定宽高。

注意:IE8 虽然支持 box-sizing,但必须写 -ms-box-sizing 前缀。IE8 里不加前缀直接写 box-sizing 是无效的——我踩过这个坑,排查了半小时。

浮动与清除:clearfix 的「版本进化史」

浮动本身兼容性问题不大,但清除浮动的方式在不同浏览器里表现差很多。我见过有人用 overflow: hidden 来清浮动,结果在 IE7 里把阴影裁掉了——嗯,这种边界情况特别多。

浮动最典型的兼容性 bug 有两个:

  • IE6 双倍 margin:当元素浮动且与 margin 方向相同时,IE6 会把 margin 值翻倍。解决办法很简单——加 display: inline。
  • 清除浮动的高度塌陷:父容器不感知浮动子元素的高度,在老旧浏览器里尤其频繁。

我个人习惯用这个 clearfix 方案,兼容到 IE8 以上都没问题:

.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

如果项目还得支持 IE6/7,那就老老实实加一个额外的 <br clear="all"> 或者用 zoom: 1 触发 hasLayout。

小技巧:我在重构老项目时,经常遇到大量浮动布局。用上面的 clearfix 统一替换掉散乱的 <div style="clear:both">,代码干净多了,而且在 IE8-11 里测试通过。

定位:position: sticky 是「老大难」

定位的兼容性问题其实不多。position: relative 和 position: absolute 从 IE6 开始就支持得不错。真正让人头疼的是 position: sticky。

sticky 在 Chrome 里很早就支持了,但直到近几年才在 Safari 和 Firefox 里稳定下来。IE 全系不支持——对,IE11 也不吃这一套。我记得有个需求要做「吸顶导航」,产品经理说所有浏览器都要有,我只好用 position: fixed + JS 计算滚动位置来模拟。

z-index 堆叠上下文也是定位里的隐藏雷区。在 IE7 里,z-index 的默认行为跟现代浏览器不太一样:只要是定位元素就会创建新的堆叠上下文。这会导致明明是兄弟元素,z-index 却互相不生效。

避坑指南:我曾经有一个弹出层死活盖不住遮罩,调了 z-index: 9999 都没用。最后发现父容器用了 position: relative 且没有设 z-index,在 IE7 里它自己形成了一个堆叠上下文,子元素再大也跳不出去。解决办法:给父容器显式设 z-index: 0 或改用 position: static。

Flexbox:一个「前缀地狱」的故事

Flexbox 的兼容性分三个阶段:2009 年旧版(display: box)、2011 年过渡版(display: flexbox)、以及现在的标准版(display: flex)。IE10 支持的是 2012 年的草案版,需要加 -ms- 前缀。IE11 支持标准版,但有一堆 bug。

说白了,如果项目要支持 IE10,你就得写三套属性:

.flex-container {
  display: -webkit-box;   /* Safari 旧 */
  display: -ms-flexbox;   /* IE10 */
  display: flex;          /* 标准 */
}

我建议用 Autoprefixer 自动处理前缀,别手写——手写太容易漏了。而且 Flexbox 在 IE11 里有个经典 bug:min-height 配合 flex-direction: column 时,子元素高度可能不收缩。我当初排查了整整一个下午,最后加了一行 flex-shrink: 0 才搞定。

兼容性速查表:

浏览器 Flexbox 支持情况 需要前缀
Chrome 21+ 标准版 无(早期需 -webkit-)
Firefox 28+ 标准版 无(早期需 -moz-)
IE10 草案版(有 bug) -ms-
IE11 标准版(有 bug) 无(但需注意 flex 子项默认 min-height 问题)
Safari 6.1+ 标准版 -webkit-

Grid:新世界的布局,旧世界的「叹息」

CSS Grid 是布局体系里最晚成熟的。它太强大了,但兼容性也是五个模块里最差的。IE10 和 IE11 支持的是老版 Grid 语法——没错,又一次「草案版」。而且那个语法写起来跟标准版完全不一样。

举个例子,标准版写 grid-template-columns: 1fr 1fr,在 IE10 里要写成 -ms-grid-columns: 1fr 1fr。更麻烦的是,IE 里没有 grid-gap,所有间距得用 margin 模拟。

我曾经在一个需要兼容 IE11 的项目里用了 Grid,结果发现 IE 根本不认 grid-area 的简写。每一行都得拆开写 -ms-grid-row 和 -ms-grid-column,而且 span 的写法也不一样。最后我把 Grid 降级成了 Flexbox + 百分比宽度,才让所有浏览器保持一致。

实践经验告诉我:如果项目受众里 IE 用户占比还不低(比如一些政府或企业内部系统),用 Grid 之前一定先评估好 fallback 方案。可以用 @supports 做渐进增强:

.grid-container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

@supports (display: grid) {
  .grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
  }
}

这样旧浏览器走 Flexbox 降级,新浏览器走 Grid——两者布局效果接近,用户基本感觉不到差异。

补充一点:gap 属性在 Flexbox 里支持吗?从 2021 年起主流浏览器都支持了,但 IE11 不支持。如果用 @supports 判定,记得把 gap 也放在 Grid 分支里,避免 IE 看到不认识 gap 而崩溃。

小结一下这几个布局模块的「脆弱指数」

模块 兼容性风险等级 主要问题浏览器 推荐 fallback 策略
盒模型 中 IE6/7 全局 box-sizing + 避免怪异模式
浮动与清除 低 IE6(双倍 margin) clearfix + display: inline
定位 低(sticky 高) IE 全系(sticky) sticky 用 fixed + JS 模拟
Flexbox 中高 IE10/11(bug) Autoprefixer + 注意 min-height
Grid 高 IE10/11 旧语法 @supports 降级到 Flexbox

做兼容性排查,说白了就是搞清楚两件事:目标浏览器支持什么,以及不支持的该怎么兜底。你不需要记住每个 bug 的细节——但你得知道去哪里查、用什么工具测、fallback 怎么写。这一章的内容帮你把五个核心模块的「坑位」标出来了,在实际项目里碰到具体问题时,翻回来对照一下就行。