css宽度计算算法

宽度计算在CSS中看似平常的一项技能,但是其中却有不少需要注意的地方,比如shrink-to-fit、repleaced-element等…

C.B.

要想真正的弄明白宽度的计算,那么对于包含块的理解那肯定是不可或缺的。

  1. 根元素的包含块是一个叫做初始包含块的方形区域,通常在流媒体中被称之为view port
  2. 对于其他的position 为 ‘relative’ 或者 ‘static’ 的元素,他们的包含块是最近的块级祖先元素的 content box 边框
  3. 如果元素的position 为 fixed,那么他的包含块为viewport(在流媒体中)
  4. 如果元素的position 为 absolute, 那么他的包含块由最近的position为’relative’ 、’absolute’或者’fixed’的祖先元素的padding edage所创建

关于宽度

非替换性的行内元素

宽度的属性对于non-replaced的inline元素是不起作用的,non-replaced元素的宽度是由框内所渲染的内容所决定的。

替换性的行内元素

  • 如果元素的width和height的计算值都是”auto”, 但是元素有一个自带的宽度,那么width的使用值就是这个自带的宽度
  • 如果元素的width和height的计算值都是”auto”, 但是元素没有自带的宽度,但是有自带的高度和自带的比例;或者是width的计算值是’auto’,但是height的计算值为其他非auto的值,元素拥有一个自带的比例,这时width的使用值为:(自带高度) * (自带比例)

    这个方式在img标签的高度和宽度设置中有所体现,例如一张235 80的图片放在img标签中,当给其设置高度为:100px, 通过调试工具我们可以发现元素的宽度变成了:
    100
    ( 235 / 80) ~= 294

repalced element

常规流中块级的非替换元素

下面的公式用于计算相应的值:

1
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = C.B.的宽度

如果’margin-left’和’margin-right’都是auto,那么他们的使用值相等

常规流中的块级替换元素

width的使用值和替换的行内元素计算方式相同

浮动,非替换元素

  • 如果’margin-left’和’margin-right’都是’auto’, 那么它们的使用值为’0’
  • 如果’width’的计算值为’auto’, 那么它的使用值是 ‘shrink-to-fit’的宽度
    1
    2
    3
    4
    5
    
      preferred width = 将内容进行格式化,去除非显示声明的换行后的宽度
      preferred minimum width = 加上所有可能的换行
      available width = C.B.的宽度  - ('margin-left' + 'border-left-width' +
      'padding-left' + 'padding-right' + 'border-right-width' + 'margin-right' + 相关滚动条的宽度)
      shrink-to-fit width = min(max(preferred minimum width, available width), preferred width)
    

浮动,替换元素

  • 如果’margin-left’和’margin-right’都是’auto’, 那么它们的使用值为’0’
  • width的使用值和替换的行内元素计算方式相同

绝对定位, 非替换元素

下面的公式用于计算相应的值:

1
'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = C.B.的宽度
  • 如果’left’, ‘width’和’right’ 都是 auto。首先设置’margin-left’和’margin-right’ 为auto的使用值为0,如果’direction’为’ltr’, 那么设置left为静态位置。width和right的计算套用下面的规则3
  • 如果这个三个值都不是auto, 如果’margin-left’和’margin-right’的值为’auto’, 那么将’margin-left’和’margin-right’假设为相等的值带入公式进行计算, 如果解出的值为负数,当方向为’ltr’时,将’margin-left’设置为0,然后解出’margin-right’的值 如果padding, margin, border, width, left, right的和大于C.B.的宽度,那么忽略’right’值(direction 为 ‘ltr’)
  1. ‘left’和’width’为auto, ‘right’不为’auto’, width为shrink-to-fit, 然后解出left值
  2. ‘left’和’right’为auto, ‘width’不为’auto’, ‘left’或者’right’为静态定位位置
  3. ‘width’和’right’为auto, ‘left’不为’auto’, width为shrink-to-fit, 然后解出right值
  4. ‘left’为auto, ‘width’和’right’不为auto, 带入公式算出’left’
  5. ‘width’为auto, ‘left’和’right’不为auto, 带入公式算出’width’
  6. ‘right’为auto, ‘left’和’width’不为auto, 带入公式算出’right’

个人总结

关于shink-to-fit使用场景:

  • 宽度为auto的非替换浮动元素
  • 非替换绝对定位元素,width为auto,非确定性定位(left, right只设置一个或者都没有设置)

See the Pen arDyH by shawnxiao (@f2ecouple) on CodePen.

当宽度为auto时,该元素总的使用面积不会超过C.B.的width