热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

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

CSS2.1SPEC:视觉格式化模型之width属性详解(上)
在介绍了包含块之后,CSS2.1标准中介绍了width属性和height属性,这两个属性在我们的页面布局中也发挥着重要的作用。在盒模型中,width和height包围了一个框的内容区域(content area), 是否拥有显式的定义、框的类型、框的布局方式、框与其他框之间的关系以及其他的额外信息 都会影响一个框的最终的width和height值,本文首先介绍width属性以及视觉格式化模型中如何决定width值的相关算法。


阅读本文前,应该首先理解CSS包含块的概念,可参考: CSS2.1SPEC:视觉格式化模型之包含块


1 width属性剖析


首先看一下css标准中对于width属性的定义:


1.1 取值

可以看出,width属性有几种不同的取值方式,有几下几种:

(1)宽度值:也就是用CSS长度值来明确地规定一个盒子的宽度,取值单位可以用CSS中支持的长度单位,比如px,em等。

(2)百分比:百分比是根据 包含块的宽度来计算的。但是如果包含块的宽度需要根据包含的内容来决定,那么最终的布局是未定义的,也就是标准中没有明确规定如何计算宽度值。另外,如果盒子是绝对定位的,那么它的百分比长度在计算时是根据包含块的 padding edge的宽度来计算的。

注: 经过试验发现,如果一个元素的宽度为百分比值,而其包含块的宽度又需要根据包含块的内容来决定时,不同的情况以及不同的浏览器都会有完全不相同的结果,因此建议在布局时不要在这种情况下使用百分比定义宽度值。具体规律还需要再进行总结,有研究过的朋友可以分享一下。

(3)auto:根据CSS标准中规定的宽度计算方法来计算,具体的算法下文中将详细介绍

(4)inherit:事实上width属性是不可继承的,很奇怪为什么会有inherit这个选项,实际情况中width属性一般也很少用到inherit值

其中,默认取值为auto

1.2 适用元素

width适用于除了 非置换的行内元素(默认情况下的span,em等元素), 表格行(tr), 表格行组(tbody)元素之外的所有其他元素。比如说,我们为span设置一个width,这个width是不会产生任何效果的,除非把span的display属性修改为inline-block或者block。另外如1.1中提到的,width属性是不能继承的。


2 width,left,right,margin-left,margin-right值的计算问题


2.1 关于几个属性的默认值

在css盒模型中,影响一个框在页面中所占空间大小的属性包括width、height、margin、border、padding,另外left,right,top和bottom值也会在某些条件(position为非static)下影响框在页面中的位置。如果我们为这几个属性定义了明确的值(数值或者百分比),那么最终的使用值(used value)就是这个明确的值(对于height和width来说,可能还会受max或者min值的影响)。这篇文章只讨论影响元素框在水平方向上的尺寸和位置的属性(width、margin-left、margin-right、padding-left、padding-right、border-left-width、border-right-width、left、right)


对于border-width和padding来说,它们的默认值就是0,而且没有auto值,所以默认情况下,这两个值的取值就为0,另外 margin-left、margin-right 默认情况下的值也是0,但是它们 有auto值 。


但是对于 width、left、right的默认取值为auto,这些属性在默认情况下,就需要css为auto值计算出最终的使用值,而如何计算默认情况下的auto值就是下文将要重点阐述的内容。


2.2几个尺寸和位置属性值的计算方法

首先看一下标准中的阐述:

The values of an element's ’width’, ’margin-left’, ’margin-right’, ’left’ and ’right’ properties as used for layout depend on the type of box generated and on each other. (The value used for layout is sometimes referred to as the used value) In principle, the values used are the same as the computed values, with ’auto’ replaced by some suitable value, and percentages calculated based on the containing block, but there are exceptions.

也就是说元素所使用的width,margin-left,margin-right,left,right属性会依赖于它们所产生的框的类型以及彼此之间的关系,总的来说,最终的使用值与计算值是相同的:即auto被替换成合适的值,百分比依据包含块进行计算。但是也存在例外,而例外的情况才是重点所在。


另外标准中还特别指出:

Note. The used value of ’width’ calculated below is a tentative value, and may have to be calculated multiple times, depending on ’min-width’ and ’max-width’, see the section Minimum and maximum widths below.

也就是说,通过计算出的width值是一个不确定的值,因为width可能还会受到min-width或者max-width值的影响,本文最后也会对此进行介绍。


注:为了显示效果,本文所有的demo中都为body赋予了10px的margin,10px的padding,以及3px的border

2.2.1 非置换的行内元素

对于非置换的行内元素,margin的auto值将被赋予0,而width属性是不适用的。对于非置换的行内元素来说,它的实际宽度要取决于其包含的实际内容(一般都为文本),同时还会受到word-break,word-wrap以及white-space属性的影响。这里列举一个例子:

##DEMO 1 行内非置换元素的宽度问题

有如下的一个span:

<body >

<span >

ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd

span >

body >

      

我们知道,英文字符来说,如果没有出现空格或者标点符号,那么是不允许换行的,所以我们看到span的宽度为:


可以看到,span的宽度为1736px,在IE6+中效果相同。

如果为span增加一个css属性,即: word-wrap: break-word,我们知道,增加这个属性之后就允许英文单词的强制换行了,效果如下:


由于行内框的宽度是由包含块给的,因此到了body的content area的边界时也就到了行框的边界,因为我们增加了

word-wrap:break-word之后,允许强制换行,因此当到了行框边缘时就发生换行,而行内元素span的宽度也与行框的宽度相同了。


2.2.2 行内置换元素

置换元素的内容并不受CSS渲染模型的控制,并且往往有着固有的尺寸。计算行内置换元素所产生的框的width时,则要把置换元素固有的尺寸考虑在内。

首先, margin的auto值将被赋予0


对于width值,计算逻辑如下:

=》 IF : height和width都是auto,但是元素有着固有的宽度,那么固有宽度就是width使用值,比如 文本输入框(input[type=text]) ,如果它的width和height都为默认的auto值,那么最终的宽度就是其固有的width,但是在不同浏览器中这个宽度值可能存在差异。[1]

=》 ELSE IF:width为auto值,但元素有固有的宽高比ratio,并且height有确切的值(或者有固有的高度),则width的使用值为:

(used height) * (ratio) [2]

=》 ELSE IF: width和height都为auto,元素有固有的宽高比ratio,但是却没有固有的宽度或者高度,那么元素的宽度是未定义的。(在这种情况下,CSS2.1标准推荐在包含块的宽度不依赖于内容的情况下,按照计算正常流中的块级非置换元素的width值的方法来计算,见本章第3部分)[3]

=》 ELSE IF:元素的width属性为auto,但是有固有的宽度值,那么固有的宽度值就是元素width的使用值 [4]

=》 ELSE IF:元素的width属性为auto,但是上述的几种情况都不符合,那么宽度的使用值为 300px,如果300px超出了用户代理的宽度,那么用户代理应该用能够容纳的最大矩形框的宽度作为width的使用值,并且这个矩形的宽高比为2:1。典型的例子比如canvas和iframe。 [5]

##DEMO 2 iframe的width

有如下代码:

      

      

      

显示的效果为:


可以看到,显示的宽度为300px,高度为150px。


2.2.3 正常流中的块级非置换元素

这种情况是我们在布局时经常会遇到的,我们在body中添加了一个p时,它的宽度是多少?为什么两个正常流的p不能在同一行中显示?学习了这一节的内容,就能解答这两个问题了。


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

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


如果width不是auto,而且'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width'

(再加上所有非auto的margin)的值大于包含块的宽度,那么 margin-left和margin-right的所有的auto值在下面的计算中都将被视为0.


=》 IF : 如果上面的值都不是auto,那么这种情况被称为“过约束”,在这种情况下,有一个属性的值将会不同。如果包含块的direction属性为ltr,那么就忽略margin-right,并且利用其它值以及上面的等式计算margin-right的使用值。如果是rtl,那么就重新计算margin-left的值。 [1]


##DEMO 3 过约束条件下的margin值重新计算

我们有如下代码:

<body >

<p style= " width : 100 px ; height : 30 px ; border : 1 px solid #f00 ; " id= "p" >p >

body >

在这种情况下,元素的显示效果如下:


我们再修改一下代码,为元素显式加一个margin-right:

<body >

<p style= " width : 100 px ; height : 30 px ; border : 1 px solid #f00 ; margin-right : 200 px " id= "p" >p >

body >



事实上两种情况是一样的情况,因为margin-right本身的默认值就是0,从显式的效果中可以看出元素的margin-right是被重新计算了的,我们再修改一下代码,把body的direction属性修改为rtl:

<body style= " direction : rtl " >

<p style= " width : 100 px ; height : 30 px ; border : 1 px solid #f00 ; " id= "p" >p >

body >


显式效果也符合标准中所述,IE6+在这一点上都是符合标准的。


=》 ELSE IF:上面这些值中如果只有一个auto值,那么就按照公式计算得出这个auto值[2]


##DEMO 4 只有一个auto值的情况

我们有如下代码:

      

      

     

这种情况下,只有margin-left属性是auto值(默认为auto),我们看一下显示的效果:


元素的 margin-left 值就等于 包含块的宽度- border-left-width - border-right-width - width


=》 ELSE IF:width是auto,那么其他所有的auto值都设为0,width按照等式来计算。[3]

=》 ELSE IF:margin-left和margin-right都是auto,那么它们的使用值将会相同,并且最终的结果会使得该元素产生的block居中。实际上,这就是我们常用的margin auto居中的方案。[4]

我们用一个DEMO来展示这个效果:

##DEMO 5 width为auto以及margin-left,margin-right都为auto的情况

我们有如下代码:

<p style="width:auto;margin-left: auto;margin-right:auto;height: 30px;border: 1px solid #f00;" id="p">p>

显示效果为:


验证了规则3,即如果width为auto,那么就把其他所有的auto设为0,并且用等式计算width值。


我们再修改一下代码,为width设置一个显式的值:


可以看到p居中了,并且左右两侧的margin值相等,验证了规则4。这个居中方案在IE6中同样适用。


2.2.4 正常流中的块级置换元素

对于正常流中的块级置换元素,在计算width值时仍然遵循2.2.2节中的规则;

得到置换元素的width值之后,再按照2.2.3中的规则计算margin值。

我们用一个实例来验证一下:

##DEMO 6 正常流中的块级置换元素的width和margin

我们有如下代码:

<body >

<input type= "text" style= " margin : auto " />

body >

效果为:


因为input默认并不是一个块级元素,而是一个行内级元素,所以不符合2.2.3节中的规则4,我们修改一下代码,为input元素添加一个display:block的样式,使其成为一个块级元素:

<body >

<input type= "text" style= " margin : auto ; display : block " />

body >

效果为:


可以看到,input元素居中显示了。

推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
author-avatar
紫岚蓝魂_578
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有