本文承接CSS2.1SPEC:视觉格式化模型之width属性详解(上),继续分析CSS视觉格式化模型中width以及相关值的计算问题:

注:与上节不同,本节的demo中由于出现了float,absolute等定位方式,因此为了便于效果显示,所有的demo都把body的margin属性设为10px,并且增加了一个class为container的div元素,它具有10px的padding,3px的border,500px的width,并通过设置float:left,_zoom:1来形成一个BFC从而清除浮动。

2.2.5 非置换的浮动元素

我们知道,元素在设置了float属性之后,就具有了“收缩性”,此时在计算width值的时候也有一个特殊的算法,首先看CSS标准中的计算规则:

首先,margin-left、margin-right的auto值将被设为0。
然后,元素的宽度则根据"shrink-to-fit"方法来计算,我们看一下"shrink-to-fit"算法的计算过程:
[1]计算preferred-width:在 除非包含的内容有明确的换行符(比如有<br/>标签时),否则就不换行的情况下,容纳其包含的内容所需要的宽度。
[2]计算preferred-min-width:在 能换行时(英文碰到空格或标点符号,出现了块级元素,当然也包含出现了<br/>标签时)就换行的情况下,容纳所包含的内容需要的宽度。
[3]计算available-width:即利用2.2.3节中的公式:
available-width =width of containing block -  'margin-left' - 'border-left-width' - 'padding-left' - 'padding-right' - 'border-right-width' - 'margin-right,这里也包括所有滚动出去的宽度。
最终的width则为:min(preferred-width, max(preferred-min-width, available-width))。最终的公式可以总结为:最终的宽度以available-width为基准,同时保证不能大于preferred-width以及不能小于preferred-min-width

available-width应该还比较容易理解,但是preferred-width和preferred-min-width相对不好理解一下,我们通过DEMO来分析一下:

##DEMO 1 shrink-to-fit算法示例一
 

我们有如下代码:

<div class="container">
<div style="float: left;border: 1px solid #f00;">
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
</div>
</div>

我们知道,英文在不出现空格的情况下是不允许换行的,而且这里的这个“单词”长度肯定超出了500px的长度,我们看一下效果:

分别标记一下各个宽度:

注:这个demo在IE6中的显示效果会有些不同,因为IE6下及时定义了框的width属性,但是还是有可能会被内容撑开,这个问题本文后面会进行介绍
由于英文单词不允许换行,所以在这里,preferred-min-width和preferred-width都是相同的,也就是说,这个"单词"有多长,那么这两个宽度值也是多少,在这里是756px(还有左右各1px的边框),而available-width很明显就是包含块的宽度了,这里是500px,带入shrink-to-fit的公式中计算即可得到最终的width值为756px。

##DEMO 2 shrink-to-fit算法示例二

我们对DEMO1中的代码进行下改动,也就是把DEMO1中的"单词"加几个空格:

<div class="container">
<div style="float: left;border: 1px solid #f00;">
ddddddddddddddddddd dddddddddddd ddddddddddd dddddddddddddddddddddddddddddddddddddddddddddd
</div>
</div>

这样一来,就变成了一句英文句子了,并且在空白处时候允许换行,我们看最终的显示效果:

标记一下各个宽度:

 

把这个几个值带入公式计算,也不难得出最终的宽度值就是available-width,即500px

 

2.2.6 浮动置换元素

首先,margin-left、margin-right的auto值将被设为0。

而width属性的计算则与行内置换元素的计算方法相同,可参照2.2.2节中的介绍。

2.2.7 绝对定位的非置换元素

为了方便显示,我们为container设置了100px的height值,另外需要明确的是,对于绝对定位的元素来说,如果它的包含块是一个块容器框产生,那么包含块的宽度是这个框的padding edge所形成;如果是一个行内元素,那么由包围其行框的区域形成;另外还有可能是初始包含块,具体可参照《CSS2.1SPEC:视觉格式化模型之包含块》的3.3节。

在本节和下一节中,需要首先明确一个概念"static position":
the term "static position" (of an  element) refers, roughly, to the position an element would have had in the normal 
flow. 
也就是,"static position"是指正常流中的第一个元素应该所处的位置(该元素的position属性为"static",并且没有float),这个元素其实是一个假想的元素。
此外,"left"值指的是包含块的左边缘到绝对定位元素所产生的框的左外边距边缘(left margin edge)的距离。"right"指的是包含块的右边缘到绝对定位元素所产生的框的右外边距的边缘(right margin edge)的距离。
我们用下面的demo演示一下包含块的direction为默认的ltr情况下的"static position":
##DEMO 3 "static position"说明

代码如下:
<div class="container">
<div style="width: 100px;height: 100px;background: #34538b;">
static posotion演示
</div>
</div>

我们的container有10px的padding,对于正常流中的块级元素来说,在水平方向上,默认就是紧贴包含块的content area左侧的,而这个位置和content area的padding edge的距离就是padding-left。
标准中还指出,用户代理不一定必须去计算这个假想的box的尺寸。

另外,这一节的内容都必须基于以下等式:

'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = width of containing block

=》IF:       left,right和width的值都是auto,那么首先将margin-left、margin-right的auto设为0,如果包含块的direction属性为ltr,则把left值设为"static position"的位置,并按照下面的规则3计算width和right的值;如果包含块的direction属性为rtl,则把right值设为"static position"的位置,并按照下面的

规则1

计算left和width的值。[1]

=》ELSE IF:left,right和width的值都不是auto,如果margin-left和margin-right都是auto,则它们将会拥有相同的值并且必须使得等式成立,从而实现居中效果。但如果这样得出的margin值为负值,那么在包含块的direction属性为ltr的情况下需要将margin-left置为0,并且按照等式计算margin-right的值;反之则将margin-right的值置为0,然后按照等式计算margin-left的值。[2]
=》ELSE IF:margin-left或者margin-right只有一个为auto,那么就按照等式计算auto值。[3]

=》ELSE IF:所有的值都不为auto(过约束),那么在包含块的direction属性为ltr的情况下,忽略right值,并按照等式重新计算right;反之则忽略left的值,并按照等式重新计算。[4]

=》ELSE IF:上面的几种情况如果都不符合,那么就先把margin的所有auto值置为0,然后按照下面的规则进行计算。[5]
规则:
 

[1]:如果left和width是auto,那么先按照"shrink-to-fit"算法计算width值,然后再根据等式计算left值。
 

[2]:如果left和right都是auto,但是width不是auto,那么如果包含块的direction属性为ltr,则把left置为"static position"的位置,然后再根据等式求right值;反之,则把right置为"static position"的位置,然后再根据等式求left值。

 

[3]:如果width和right是auto,那么首先根据"shrink-to-fit"算法计算width值,然后再根据等式计算right值

 

[4]:标准原文中的4,5,6条规则其实可以归结为一条,即如果left,right和width只有一个auto值,那么直接根据等式计算auto值。

绝对定位元素的width计算相对复杂一些,我们通过几个demo来看一下:
##DEMO 4 width,left和right都为auto的情况

代码如下:
<div class="container">
<div style=height: 100px;background: #34538b;position: absolute">
绝对定位演示
</div>
</div>


在demo4中,我们定义了一个绝对定位的元素,并且width,left和margin都是默认的auto值,可以看到元素的width是按照"shrink-to-fit"得出的,而left值被设置为了static position的位置,这里其实就是包含块的padding-left:10px。置于right值,虽然浏览器的调试工具并没有给出具体right值的used value,但还是有理由相信浏览器会根据标准中的规则计算相应的值。

##DEMO 5 width,left和right都不为auto的情况

我们把demo4中的代码修改一下,为绝对定位元素设置显式的width,left和right值,并且为margin-left和margin-right设置auo值:
<div class="container">
<div style="width:100px;height: 100px;background: #34538b;position: absolute;left: 0px;right: 0px;margin-left: auto;margin-right: auto;">
绝对定位演示
</div>
</div>

可以明显看到,在width,left和right都不为auto,并且水平margin为auto时,会按照平分margin-left和margin-right的方式布局,从而也可以达到元素居中的效果。
注:IE6/7并不会按照这个规则计算margin值,而是直接将margin的auto置为0然后再进行计算。

我们再修改一下代码,看一下只有一个margin值为auto时的情况:

<div class="container">
<div style="width:100px;height: 100px;background: #34538b;position: absolute;left: 0px;right: 0px;margin-left: auto;margin-right: 0px;">
绝对定位演示
</div>
</div>

我们把margin-right置为0px,而把margin-left置为auto,显示效果如下:

可以看到,margin-left值是根据公式计算得出的值。
注:IE6/7同样还是把margin的auto值置为0,然后等于是在过约束的条件下进行计算,right的值就要被重新计算了,显示效果如下:

这样同时验证了过约束条件下的right或left值被重新计算的规则。

绝对定位元素的width及left,margin-left,margin-right,right值的计算问题稍显复杂,但是如果理解清楚之后也是比较好理解的,建议大家都通过实验来验证一下。另外,IE6/7不管在哪一种情况下就会将margin值置为0的特点也要务必牢记。

2.2.8 绝对定位的置换元素

绝对定位的置换元素在计算时,上一节中关于"static position"以及等式都是适用的,但是计算逻辑并不相同,具体如下:
=》IF:       width是根据“行内置换元素width值计算规则”计算得到。而如果margin-left和margin-right的计算值都为auto时,它们的使用值由如下规则计算得出。[1]

=》ELSE IF:left,right的计算值都是auto,那么在包含块的direction属性为ltr的情况下需要将left置为"static position"的left位置;反之则把right值置为"static position"的right位置。[2]
=》ELSE IF:left或right为auto,那么将margin-right和margin-left的auto值置为0。[3]

=》ELSE IF:此时如果margin-right和margin-left都为auto,则它们将会拥有相同的值并且必须使得等式成立,从而实现居中效果。但如果这样得出的margin值为负值,那么在包含块的direction属性为ltr的情况下需要将margin-left置为0,并且按照等式计算margin-right的值;反之则将margin-right的值置为0,然后按照等式计算margin-left的值。[4]

=》ELSE IF:此时如果只有一个值为auto,那么则按照等式计算auto值[5]
=》ELSE IF:此时如果形成了过约束,那么在包含块的direction属性为ltr的情况下,忽略right值,并按照等式重新计算right;反之则忽略left的值,并按照等式重新计算。[6]

这几个例子我们就不通过demo来实证了,大家可以亲自敲一敲代码来实验一下,当然IE6/7还是会把margin-left和margin-right的auto置为0。

2.2.9 非置换的行内块
display属性为"inline-block"的元素形成了一个行内块,基于我们已经了解过的规则,对于行内块,在计算margin-left,margin-right和width时就比较容易了,事实上,它的计算规则和浮动元素的计算规则是基本相同的。

首先,margin-left和margin-right的auto值被置为0;
然后,width值根据“shrink-to-fit"算法计算得到。

2.2.10 行内块置换元素
行内块置换元素的计算方法与2.2.2节行内置换元素的计算方法是完全相同的

3 min-width和max-width

在文章的开头部分曾提到,我们通过上述规则计算得出的width值只是一个tentative value,即暂定的一个值,原因就在于最终width的使用值可能还会受到min-width,和max-width值的影响,下面我们来介绍一下min-width和max-width。

3.1 min-width和max-width属性剖析
CSS标准中对min-width和max-width的定义如下:

These two properties allow authors to constrain content widths to a certain range.
这两个属性的作用就是可以让开发者将一个框的width限定在一个范围中,即[min-width:max-width]范围内。与width属性相同,这两个属性也不适用于行内非置换元素,表格行和表格行组,并且都不具有继承性,可以取绝对的长度值,也可以使用百分比,这些与width属性都是相似的,同时两个属性都不允许负值。

另外,min-width的默认值为0,即所有元素的width都不能小于0;max-width的默认值为none,即不限定元素width的最大值。

3.2 min-width,max-width的使用
min-width和max-width对于width使用值的具体影响如下:
[1]:首先根据第二节中介绍的规则计算得出width值以及相关的margin,left和right值。
[2]:如果计算得出的width值大于max-width,那么就把max-width作为width的使用值,再带入计算规则中计算一遍。
[3]:如果计算得出的width值小于了min-width,那么就把min-width作为width的使用值,再带入计算规则中计算一遍。
下面通过一个实例来实证一下,这里以max-width为例:
##DEMO 6

max-width的使用

 
代码如下:
<div class="container">
<div style="height: 100px;background: #34538b;max-width: 400px;">
max-width演示
</div>
</div>

我们为div定义max-width为400px,如果我们没有定义这个属性的话,由于width值在这里是auto,因此width值应该和包含块的content edge宽度相同,即为500px,但由于我们限定了max-width,并且500px>400px,所以最终width值的使用值就为400px,再把这个值带入到2.2.3节的规则中,就形成了一个过约束的条件,因此忽略margin-right值根等式重新计算,最终得到margin-right:100px。

 

CSS2.1SPEC:视觉格式化模型之width属性详解(下)的更多相关文章

  1. CSS2.1SPEC:视觉格式化模型之width属性详解(上)

    在介绍了包含块之后,CSS2.1标准中介绍了width属性和height属性,这两个属性在我们的页面布局中也发挥着重要的作用.在盒模型中,width和height包围了一个框的内容区域(content ...

  2. CSS2.1SPEC:视觉格式化模型之包含块

    原汁原味的才是最有味道的,在阅读CSS标准时对这一点的体会更加深刻了,阅读文档后的一大感觉就是很多看上去理所应当的样式表现也都有了对应的支持机制.本文首先从包含块写起,一方面总结标准中相应的阐述,并且 ...

  3. CSS学习笔记——视觉格式化模型 visual formatting model

    CSS 视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制.他有一套既定的规则(也就是W3C规范),规定了浏览器该怎么处理每一个盒子.以下内容翻 ...

  4. CSS中的视觉格式化模型

    视觉格式化模型 1. 简介 在视觉格式化模型中,文档树中的每个元素都将会根据盒模型产生零到多个盒子.这些盒子的布局由如下因素决定: 盒子的尺寸和类型 定位策略(正常文档流,浮动或者绝对定位) 和文档树 ...

  5. CSS视觉格式化模型

    CSS视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制.这是CSS 2.1的一个基础概念.视觉格式化模型根据CSS盒模型为文档的每个元素生成0 ...

  6. 大前端学习笔记整理【二】CSS视觉格式化模型

    1. 概念 在视觉格式化模型中,文档树中的每个元素都将会根据盒模型产生零到多个盒子.这些盒子的布局由如下因素决定: 盒子的尺寸和类型 定位策略(正常文档流,浮动或者绝对定位) 和文档树中其他元素的关系 ...

  7. Css盒模型属性详解(margin和padding)

    Css盒模型属性详解(margin和padding) 大家好,我是逆战班的一名学员,今天我来给大家分享一下关于盒模型的知识! 关于盒模型的属性详解及用法 盒模型基本属性有两个:padding和marg ...

  8. 行盒(line box)垂直方向的属性详解:从font-size、line-height到vertical-align

    视觉格式化模型 在一个文档中,每个元素都被表示为0.1或多个矩形的盒子.确定这些盒子的尺寸, 属性 --- 像它的颜色,背景,边框方面 --- 和位置是渲染引擎的目标.① 在CSS中,使用标准盒模型描 ...

  9. border-sizing属性详解和应用

    box-sizing用于更改用于计算元素宽度和高度的默认的 CSS 盒子模型.它有content-box.border-box和inherit三种取值.inherit指的是从父元素继承box-sizi ...

随机推荐

  1. OC 里面 webView与js

    webView与js的交互流程吗,iOS端暴露函数 ,js直接调用 [链接]WKWebView-如何通过JS调用OC方法 https://www.jianshu.com/p/68f799d6679e ...

  2. JTemplate学习(三)

    另一种模板写法 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xh ...

  3. How to set an Apache Kafka multi node – multi broker cluster【z】

    Set a multi node Apache ZooKeeper cluster On every node of the cluster add the following lines to th ...

  4. PythonQt进阶

    本文介绍PythonQt和qt之间是如何进行交互操作的 例子是以Qt的TreeView为实例进行介绍 在该例子中,TreeItem不是从Qt中进行的继承,这样的类如果要和Python进行交互,首先需要 ...

  5. Netty 零拷贝(一)NIO 对零拷贝的支持

    Netty 零拷贝(二)NIO 对零拷贝的支持 Netty 系列目录 (https://www.cnblogs.com/binarylei/p/10117436.html) 非直接缓冲区(HeapBy ...

  6. javascript札记

    bind和unbind对应,live和die对应,千万别用bind绑定,用die解除.还有bind可以多次绑定同一个函数,可能会被执行多次同一个函数 正则表达式的使用 var email_reg = ...

  7. 2014.1.14 struts 的default.properties 配置文件详述

    转自  http://justsee.iteye.com/blog/723993 Struts 2框架有两个核心配置文件:struts.xml和struts.properties 其中struts.x ...

  8. 20155317 王新玮 2016-2017-2 《Java程序设计》第9周学习总结

    20155317 王新玮 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以 ...

  9. 2018.08.02 hdu1558 Segment set(并查集+计算几何)

    传送门 这个直接用并查集维护. 每加入一条线段就将它与其他能相交的集合合并,维护一个size" role="presentation" style="posit ...

  10. 2018.07.22 洛谷P1967 货车运输(kruskal重构树)

    传送门 这道题以前只会树剖和最小生成树+倍增. 而现在学习了一个叫做kruskal" role="presentation" style="position: ...