Published on

shrink-to-fit(自适应宽度)

Authors
  • avatar
    Name
    Pursue
    Twitter

开篇

自适应宽度是指当未明确设定容器的宽度(或外边距设为 auto)时,再特定的情况下容器的宽度会根据情况自行设定,而设定的结果往往并不是我们想要的。

W3C 规范中描述的几种 shrink-to-fit 的情况

规范中提到了一个基本概念,我们先来了解一下。

replaced elements & non-replaced elements

css 把 html 元素分为了两类:替换元素和非替换元素。

  • 1.可替换元素

可替换元素是这样一些元素,其展现不是由 CSS 来控制的。这些外部元素的展现不依赖于 CSS 规范。 典型的可替换元素有 <img>、 <object>、 <video>以及 <textarea>、 <input>这样的表单元素。 一些元素,比如 <audio><canvas> ,只在一些特殊情况下是可替换元素。 使用了 CSS content 属性插入的对象被称作匿名的可替换元素。

  • 2.不可替换元素

反之,则为不可替换元素。

了解了概念后,我们回归主题。shrink-to-fit 的情况有多种,这里介绍一种最常见的情况,即不可替代元素浮动时的自适应宽度(Floating, non-replaced elements),听起来有点抽象,先看一个例子:

html&css

<!DOCTYPE html>
<html>
  <style type="text/css">
    .outer {
      width: 800px;
      background: black;
      overflow: hidden;
    }
    .inner {
      float: left;
      background: red;
    }
    .sub1 {
      width: 26%;
      background: blue;
    }
    .sub2 {
      width: 50%;
      background: green;
    }
  </style>
  <head> </head>
  <body>
    <div class="outer">
      <div class="inner">
        <div class="sub1">this is 1th line this is 2th line this is 3th line this is 4th line</div>
        <div class="sub2">sub2 block</div>
      </div>
    </div>
  </body>
</html>

这段样式定义了一个 outer 容器,背景为黑色且有宽度,它里面还有一个内部容器 inner,无宽度且左浮动,inner 里有两个小块 sub1 和 sub2。

那么问题来了,请问inner,sub1,sub2具体的宽度为多少?

先看效果图再回答:

结果应该会出乎你的意料:inner(红色背景)的宽度并不是 outer(黑色背景)的宽度(正常情况下应该可以继承父容器的宽度),因而 sub1 和 sub2 比我们预想的要小得多。

再回答这个问题之前,我们先试图修改一下,看能否从中找到出现这个问题的原因。经过调试,发现两种最简单的方案可以解决这个问题:

  • 1.给inner加宽度width: 100%;

  • 2.取消inner的浮动。

解决后的效果如下:

这的确是我们想要的,可这却巧妙地'躲'过了不可替换元素浮动这个场景。老实讲,我多次遇到过这个场景,但是无非也就是利用上述两个方案去尝试,可并不知晓真正的原因,于是还是啃了一下 W3C 有关这方面的规范,规范的描述如下:

首先不说英文的问题,单纯的'Roughly'和‘CSS 2.1 does not define the exact algorithm’这两句就让人哭笑不得,然后还给出了 shrink-to-fit 的一个公式:

min(max(preferred minimum width, available width), preferred width)

呵呵,然并卵啊,天知道这三个值怎么算。

再网上 google 一下,发现很多人都遇到这个问题,但也是读不懂规范,也有人把上面一段翻译了一下,大家可以看看:

CSS2.1 并未给出 preferred minimum width、available width 和 preferred width 确切算法,通常,将内容中非明确的换行外的其他部分强制不换行来计算 preferred width;反之,尝试将内容尽可能的换行,以得到 preferred minimum width;available width 即该元素的包含块的宽度减去 'margin-left','border-left-width','padding-left','padding-right','border-right-width','margin-right' 的值以及任何存在的纵向滚动条的宽度。

已被这段翻译绕晕的请举手。。。。。。。。。。。。。

再次回归主题,经过近一个小时的摸索,终于让我把这段难懂的英文捋顺了:

这里有三个参数,分别为:preferred minimum width, available width, preferred width. 只需关心 preferred width 的计算方式即可,preferred width 的计算方式如下:

让元素内容强制不换行后的最大宽度即为shrink-to-fit后的宽度

具体拿上面的例子,inner 中的 sub1 的内容由于宽度不够被换行了,将其强制不换行算出的宽度就是 inner 自适应的宽度(inner 本身没设宽度喔~),如何强制不换行也很简单,慢慢的将 sub1 的宽度调大,就会发现调至 100%时恰好足够用一行来现实其内容,这时内容的宽度就是 inner 自适应后的宽度。直接上图:

总结:对于浮动或者特殊的定位方式,推荐显式的设置容器宽度,避免出现意想不到的结果