由一个绝对定位引起overflow:auto滚动问题产生的关于包含块(containing block)的思考

前言

今天在项目中有一个需求,就是一个可滚动的列表的每一列鼠标悬浮上去就会产生一个浮动框显示其详细内容。简化下情景的代码以下:css

<div class="box">
  <div class="item">
  我是列表项
    <div class="susp">我是悬浮框</div>
  </div>
</div>

.box {
  height: 200px;
  border: 1px solid red;
  overflow: auto;
}
.item {
  position: relative;
  height: 150px;
  border-bottom: 1px solid blue;
}
.susp {
  position: absolute;
  left: 0;
  top: 150px;
  height: 100px;
  background-color: #eee;
}

预览html

我原本觉得的效果是这样子的:
图片描述web

实际倒是这样的:
图片描述post

个人心里是崩溃的,为什么绝对定位能够触发容器的滚动效果?之前用css太随意了,根本没考虑过这些问题。spa

问题分析

万幸我在Stack Overflow找到了真有人提问过这个问题...下面的回答其实解释的也不是很明朗,可是看到了核心的概念containing block,也就是包含块。好吧,让还没看懂解释一脸懵逼的我忽然把包含块说清楚也是有点困难...直接搬运W3C中文规范的定义:.net

  1. 根元素所在的包含块是一个被称为初始包含块的矩形
  2. 对于其它元素,若是该元素的position是'relative'或者'static',包含块由其最近的块容器祖先盒的内容边界造成
  3. 若是元素具备'position: fixed',包含块由连续媒体的视口或者分页媒体的页区创建
  4. 若是元素具备'position: absolute',包含块由最近的'position'为'absolute','relative'或者'fixed'的祖先创建

对照这个定义,咱们的目前的情景就是符合第四条,个人悬浮框是absolute,列表项relative就是其包含块,而列表项的包含块就是容器box。理解到这个地步应该差很少能够推测出问题所在,悬浮框的包含块属于容器之内,所以其高度能够触发容器的滚动。虽然我没有在官方规范中找到对应的解释,可是这个理解应该是没有问题的,还请有看官大佬指点更好的分析。设计

解决方法

问题缘由找到了,问题也就迎刃而解,既然是由于悬浮框的包含块在容器内,那么咱们就让悬浮框的包含块在其外不就能够了么,就将其包含块默认为初始包含块便可,除非悬浮框的高度超出页面会触发页面的滚动...但悬浮框的设计高度确定是不可能要超出页面视口的。修改后的代码以下:code

<div class="box">
  <div class="item">
  我是列表项
    
  </div>
  <div class="susp">我是悬浮框</div>
</div>

.box {
  height: 200px;
  border: 1px solid red;
  overflow: auto;
}
.item {
  /* position: relative; */
  height: 150px;
  border-bottom: 1px solid blue;
}
.susp {
  position: absolute;
  /* left: 0; */
  /* top: 150px; */
  height: 100px;
  background-color: #eee;
}

其实就是注释掉列表项的position: relative,让悬浮框的包含块指向初始包含块,可是此时注意不能再加定位了,由于你无法算出来的,所以再注释掉lefttop,同时要把悬浮框的div放在列表项div的相邻下面,这样悬浮框是一个BFC,也达到咱们想要的位置效果。这个其实和BFC关系不大,可是之前我没总结过,给个参考1参考2有空好好总结一下。htm

总结

仍是那句话,若是一个块的包含块在容器内(包含容器自己),那么其高度就会触发容器的滚动。blog

参考

文中Stack Overflow问题

相关文章
相关标签/搜索