跳到主要内容

包含块

2023年02月15日
柏拉文
越努力,越幸运

一、认识


元素的尺寸及位置,常常会受它的**包含块(containing block)**所影响。对于一些属性,例如 width, height, padding, margin,绝对定位元素的偏移值(比如 position 被设置为 absolutefixed),当我们对其赋予百分比值时,这些值的计算值,就是通过元素的包含块计算得来。

二、规则


确定一个元素的包含块的过程完全依赖于这个元素的position属性:

  • 如果 position 属性为 staticrelativesticky 时: 包含块可能由它的最近的祖先块元素(比如说 inline-block, blocklist-item 元素)的内容区的边缘组成,也可能会建立格式化上下文

  • 如果 position 属性为 absolute , 包含块就是由它的最近的 position 的值不是 static (也就是值为fixed, absolute, relativesticky)的祖先元素的内边距区的边缘组成。

  • 如果 position 属性是 fixed,在连续媒体的情况下 (continuous media) 包含块是 viewport ,在分页媒体 (paged media) 下的情况下包含块是分页区域 (page area)。

  • 如果 position 属性是 absolutefixed,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:

    • transformperspective 的值不是 none

    • will-change 的值是 transformperspective

    • filter 的值不是 nonewill-change 的值是 filter

    • contain 的值是 paint

    • backdrop-filter 的值不是 none

三、计算


如果某些属性被赋予一个百分值的话,它的计算值是由这个元素的包含块计算而来的。这些属性包括盒模型属性偏移属性

  • 要计算 heighttopbottom 中的百分值, 是通过包含块的 height 的值。如果包含块的 height 值会根据它的内容变化,而且包含块的 position 属性的值被赋予 relativestatic ,那么,这些值的计算值为 auto

  • 要计算 width, left, right, padding, margin 这些属性由包含块的 width 属性的值来计算它的百分值。

3.1 计算 margin 百分比

margin 百分比 根据包含块的 width 值计算得出

  • box-sizing: content-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
      }
      const child = {
        width: "40px",
        height: "40px",
        margin: "20%",    
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

    包含块宽度: parentWidth + 2 * parentPadding = 400 + 2 * 24 = 448

    child 水平 margin: child margin-left = child margin-right = 包含块宽度 * 20%

    child 垂直 margin: child margin-top = child margin-bottom =包含块宽度 * 20%

  • box-sizing: border-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "border-box",
        border: "10px solid black",
      }
      const child = {
        width: "40px",
        height: "40px",
        margin: "20%",    
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

    包含块宽度: parentWidth - 2 * border = 400 - 2 * 10 = 380

    child 水平 margin: child margin-left = child margin-right = 包含块宽度 * 20%

    child 垂直 margin: child margin-top = child margin-bottom =包含块宽度 * 20%

3.2 计算 padding 百分比

padding 百分比 根据包含块的 width 值计算得出

  • box-sizing: content-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
      }
      const child = {
        padding: "20%",    
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

    包含块宽度: parentWidth + 2 * parentPadding = 400 + 2 * 24 = 448

    child 水平 padding: child padding-left = child padding-right = 包含块宽度 * 20%

    child 垂直 padding: child padding-top = child padding-bottom =包含块宽度 * 20%

  • box-sizing: border-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "border-box",
        border: "10px solid black",
      }
      const child = {
        padding: "20%",    
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

    包含块宽度: parentWidth - 2 * border = 400 - 2 * 10 = 380

    child 水平 padding: child padding-left = child padding-right = 包含块宽度 * 20%

    child 垂直 padding: child padding-top = child padding-bottom =包含块宽度 * 20%

3.3 计算 relative 包含块大小

relative 元素的包含块由最近的祖先块元素内容区的边缘组成, 即content

实时编辑器
function Test(props) {
    const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
    }
    const child = {
        width: "20%",
        height: "20%",
        position: "relative",
        bottom: "24px",
        right: "0",
        backgroundColor: "blue"
    }

    return (
        <div style={ parent }>
            <div style={ child }></div>
        </div>
    );
}
结果
Loading...

包含块宽度: parentWidth

3.4 计算 absolute 包含块大小

position: absolute 元素的包含块由它的最近的非 static 祖先元素的内边距区的边缘组成, 也就是 padding + content。当这样的祖先元素不存在时, 则相对于 ICB(inital container block, 初始包含块)

  • box-sizing: content-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
      }
      const child = {
        width: "50%",       // 包含块宽度 = parentWidth + 2 * parentPadding
        height: "50%",      // 包含块高度 = parentHeight + 2 * parentPadding
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...
  • box-sizing: border-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "border-box",
        border: "10px solid black",
      }
      const child = {
        width: "50%",       // 包含块宽度 = parentWidth - 2 * parentBorder
        height: "50%",      // 包含块高度 = parentHeight -  2 * parentBorder
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

3.5 计算 absolute 百分比宽度

  • box-sizing: content-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
      }
      const child = {
        width: "50%",       // child 宽度 = child 的包含块宽度 / 2
        height: "50%",       // child 高度 = child 的包含块高度 / 2
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...
  • box-sizing: border-box:

    实时编辑器
    function Test(props) {
      const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "border-box",
        border: "10px solid black",
      }
      const child = {
        width: "50%",       // child 宽度 = child 的包含块宽度 / 2
        height: "50%",      // child 高度 = child 的包含块高度 / 2
        position: "absolute",
        backgroundColor: "blue"
      }
    
      return (
         <div style={ parent }>
            <div style={ child }></div>
         </div>
      );
    }
    
    结果
    Loading...

3.6 计算 fixed 屏幕视口包含块大小

fixed 元素的包含块默认由屏幕视口viewport的内容区边缘组成, 即content

实时编辑器
function Test(props) {
    const parent = {
    width: "400px",
    height: "400px",
    padding: "24px",
    position: "relative",
    backgroundColor: "red",
    boxSizing: "content-box",
    border: "10px solid black",
    }
    const child = {
    width: "20%",
    height: "20%",
    position: "fixed",
    bottom: "24px",
    right: "0",
    backgroundColor: "blue"
    }

    return (
        <div style={ parent }>
            <div style={ child }></div>
        </div>
    );
}
结果
Loading...

包含块宽度: htmlWidth

3.7 计算 fixed 祖先元素包含块大小

fixed 元素的祖先元素中transformperspectivefilterbackdrop-filter 属性非 none 时,包含块由该祖先的内边距边缘组成,即content + padding

实时编辑器
function Test(props) {
    const parent = {
        width: "400px",
        height: "400px",
        padding: "24px",
        position: "relative",
        backgroundColor: "red",
        boxSizing: "content-box",
        border: "10px solid black",
        transform: "scale(1)"
    }
    const child = {
        width: "20%",
        height: "20%",
        position: "fixed",
        bottom: "24px",
        right: "0",
        backgroundColor: "blue"
    }

    return (
        <div style={ parent }>
            <div style={ child }></div>
        </div>
    );
}
结果
Loading...

包含块宽度: parentWidth + 2 * parentPadding

参考资料


MDN-包含块