margin-right右边距失效

Ghostzhang 发表于 更新于

不小心看了下知乎,万年潜水,突然看到有一个邀答,问题在这里,进去看了下,觉得这个问题很有意思,于是想试着回答:

先试着还原最初的状态,在题主的Demo上改改:

修改的部分

于是变成这样

最初的样式

用Chrome的开发者工具看看:

父元素的盒模型

子元素的盒模型

可见子元素的margin跟父级元素重叠了,这是外边距合并的现象,具体可以看看这几篇:《外边距合并》、《盒模型》、《CSS 外边距(margin)重叠及防止方法》、《What You Should Know About Collapsing Margins

但都没能解释这次的问题,右边距为何失效了。

当父元素设置了overflow:auto之后,变成了下面这样

激活父元素的BFC

正常哈,因为激活了父元素的BFC1,margin合并的规则失效,现在看到的才是我们预期的样子。

激活父元素的BFC后的子元素盒模型

从Chrome的开发者工具来看,子元素的margin只有top、left、bottom有效,右边距失效。试着移动下子元素:

子元素外边距宽度随子元素移动

可以看到子元素的外边距位置是随着子元素移动的,所以才会出现了移到右边后右边的外边距没有显示的结果。

找了下margin合并,或叫外边距塌陷(margin collapsing)相关的内容,基本上都只是提到上下边距的问题,于是试着给父元素也设置了margin,然后就看到,右边距基本也是无效的,一个auto的状态:

父元素也设置外边距后的盒模型

总结下:

  • 默认状态下的块级元素右边距是无效的 设置float(除了none以外的值)、display (inline-block,inline-flex,inline-grid,inline-table,inline-box,table)、position(absolute,fixed)之后会生效

  • 当父元素的宽度小于子元素的宽度时,子元素的右边距无效。scrollWidth取到的值也是不包括右边距的,跟盒模型的规则有点冲突,不知道算不算是BUG。通过设置display(inline-block,inline-flex,inline-grid,inline-table)可以让右边距生效。

如果非要子元素有右边距,可以这样:

  • 子元素设置右浮动,但会导致父元素的overflow失效,抱脸~~
  • 子元素的左边距为auto,并且父元素的宽大于子元素的宽;

对于当前问题的解决方案也很简单,为子元素再加一个父级,然后为它设置一个跟子元素实际宽度相等的宽即可:

效果展示

或者,加一个兄弟元素,让它隐藏起来,宽度为实际宽度,应该更实用些:

效果展示

只是,为什么会无效,我没找到答案。

更新:重新又检查了遍,找到一个更简单的方法,设置子元素的display

效果展示
  1. BFC(W3C CSS 2.1 规范中的一个概念)就是所谓的Block formatting contexts (块级格式化上下文)。创建了 BFC的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素,反之亦然,同时BFC仍然属于文档中的普通流。

讨论