惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
S
SegmentFault 最新的问题
Microsoft Security Blog
Microsoft Security Blog
J
Java Code Geeks
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
量子位
P
Proofpoint News Feed
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
F
Fortinet All Blogs
C
Check Point Blog
博客园_首页
I
InfoQ
Jina AI
Jina AI
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
美团技术团队
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research

GeekPlux

一代人的博客,一代人的青春注脚 那些年我打过的日结工 来美国的两年后 2023 一蓑烟雨 在美国拥有一辆 Tesla 的成本 我的 Workspaces 十年进化史 How to Sync Logseq Plugins, Themes and Settings Across Multiple Devices Setting Up Umami as Your Google Analytics Alternative: A Step-by-Step Guide 迁移豆瓣读书记录到 goodreads Enhance Your Internet Privacy in 2023 Refactor your blog comments system with Webmention.io 来美国之后,如何快速安顿下来 Three Levels of Information Perception 疫情三年 与人聊天的美好 我获取信息的方法 2022 版 我是如何学会编程的 Legacy code best practice: how to take over an existing project smoothly 2020 恍如隔世 接外包的一些坑和小技巧 论交友 往返香港隔离指南 即将失明,还能继续做程序员吗 小谈我对新技术的态度 How to use tailwindcss with AMP in a Next.js project 远程工作如何提高效率 复式记账、财报、量化与图论 我为什么从阿里巴巴离职 2019 柳暗花明 投资被动型指数基金正在造成下一次金融泡沫?
Collapsing margins——合并的外边距
GeekPlux · 2014-03-15 · via GeekPlux

原文地址:https://geekplux.com/2014/03/14/collapsing_margins

昨天在写 CSS 时遇到一个小问题,困扰了我好长时间,最后 Google 之,发现早有前人踩过此坑。为免以后再掉进坑,记下来比较好。

昨天遇到的问题是这样的。我设置了一对父子元素如下:

<div class="parent">Parent
    <div class="children">Children
    </div>
</div>
<div class="divider"></div>

它们的样式如下:

.parent {
    margin-bottom: 10px;
    width: 80px;
    height: 20px;
    background-color: yellow;
}
.children {
    margin-bottom: 20px;
    width: 80px;
    height: 20px;
    background-color: red;
}
.divider {
    height: 1px;
    background-color: black;
}

产生的效果如图所示:

为什么分割线跑到了 Children 里面?这两个父子元素都设置了 margin-bottom,加起来应该是 30px,为什么现在成了 20px?种种疑问在我脑中盘旋。刚开始以为是万恶的 position,但是我把所有能想到的属性排列组合都设置了一遍,发现还是不行。果断 Google,才知道这个问题由来已久……

collapsed margin

关于 collapsing-margin,有 W3C 的官方介绍

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

在 CSS 中,两个或多个毗邻(父子元素或兄弟元素)的普通流中的块元素垂直方向上的 margin 会发生叠加。这种方式形成的外边距即可称为外边距叠加(collapsed margin)。

  • 何为毗邻:是指没有被非空内容、padding、border 或 clear 分隔开。
  • 何为普通流:除浮动( float )、绝对定位( absolute )外的代码即为普通流。

好吧,这下理解了,原来 挨着的、且没有任何东西分割的 两个普通元素会在垂直方向上合并 margin。我们可以想象出有 4 种情况会发生合并,看图比较直观(图来自网络):

  • 兄弟元素

  • 父子元素

  • 空元素

  • 以上三种混合

到底怎么才算毗邻,其实官网对于毗邻作了很详细的解释(保证你看完会晕):

首先是一个大前提:元素之间没有被非空内容、padding、border 或 clear 分隔开。然后有下面几种情况算是毗邻:

  • top margin of a box and top margin of its first in-flow child

一个元素的 margin-top 和它的第一个子元素的 margin-top

  • bottom margin of box and top margin of its next in-flow following sibling

普通流中一个元素的 margtin-bottom 和它的紧邻的兄弟元素的的 margin-top

  • bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height

一个元素( height 为 auto )的 margin-bottom 和它的最后一个子元素的margin-bottom

  • top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero or 'auto' computed 'height', and no in-flow children

一个没有创建 BFC、没有子元素、height 为0的元素自身的 margin-top 和 margin-bottom

不管你晕不晕,反正我晕了……

如何避免

避免外边距叠加,只要破坏它的 4 个必要条件(2 个或多个、毗邻、垂直方向、普通流)中的一个即可。下面是官网不构成外边距叠加的各种情况。

  • 浮动元素和其他任何元素之间不发生外边距叠加 (包括和它的子元素).
  • 创建了 BFC 的元素不会和它的子元素发生外边距叠加
  • 绝对定位元素和其他任何元素之间不发生外边距叠加(包括和它的子元素).
  • inline-block 元素和其他任何元素之间不发生外边距叠加 (包括和它的子元素).
  • 普通流中的块级元素的 margin-bottom 永远和它相邻的下一个块级元素的 margin-top 叠加(除非相邻的兄弟元素 clear)
  • 普通流中的块级元素(没有 border-top、没有 padding-top )的 margin-top 和它的第一个普通流中的子元素(没有 clear )发生 margin-top 叠加
  • 普通流中的块级元素( height 为 auto、min-height 为 0、没有 border-bottom、没有 padding-bottom )和它的最后一个普通流中的子元素(没有自身发生 margin 叠加或 clear )发生 margin-bottom 叠加
  • 如果一个元素的 min-height 为 0、没有 border、没有 padding、高度为 0 或者 auto、不包含子元素,那么它自身的外边距会发生叠加

同样会看晕,总结下来,我们最好的办法是

  • 为父元素设置 BFC 或 padding 或 border
  • 兄弟元素间设置 float 或 inline-block 或 absolute
  • 写结构的时候最好用一个方向,要不都 top 要不都 bottom

整个问题解决下来,我感觉其实并没有那么复杂的东西却被文档表述的很复杂,也可能是我英语比较差。而且在开发过程中许多细节我认为没必要去抠它,只要遇到时能迅速定位出原因(我昨天遇到这个问题,第一时间就无法定位,不停换关键词去搜才慢慢明白,还是经验少啊),就可以依靠 Google 搜索出解决方案,这样可以保证开发效率。如果想深入了解,还是抽业余时间吧……下面的文章可供参考(如怎么计算 margin 的最终值)。网上的资源太丰富了,感谢这些前辈。