width和height作用的具体细节
# 深藏不露的width:auto
# 外部尺寸与流体特性
# 正常流宽度
在页面中随便扔一个<div>
元素,其尺寸表现就会和这水流一样铺满容器。这就是block容器的流特性。这种特性在所有浏览器的表现都是一致的。
所谓流特性,并不是看上去的宽度100%那么简单,而是一种margin/border/padding和content内容区域自动分配水平空间的机制。
因此,想让一个div自动铺满是不需要写“width:100%”的,多此一举而。
# 格式化宽度
格式化宽度仅出现在“绝对定位模型”中,也就是出现在position
属性为absolute
或fixed
的元素中。
在默认情况下,绝对定位元素的宽度表现是“包裹性”,宽度由内部尺寸决定。
但是对于非替换元素,当left/right
或top/bottom
对立方位的属性同时存在时,元素的宽度表现为“格式化宽度”,其宽度大小相对于最近的具有定位特性(position属性不是static)的祖先元素计算。
“格式化宽度”具有完全的流体性,也就是margin、border、padding和content内容区域同样会自动分配水平(和垂直)空间。
# 内部尺寸与流体特性
所谓“内部尺寸”,简单来讲就是元素的尺寸由内部的元素决定,而非由外部的容器决定。
Q:如何快速判断一个元素使用的是否为“内部尺寸”
假如这个元素里面没有内容,宽度就是0,那就是应用的“内部尺寸”。
内部尺寸的三种表现形式:
# 包裹性
包裹的意思就是“shrink-to-fit”,即收缩到合适,除了“包裹性”,还有“自适应性”。
所谓“自适应性”,指的是元素尺寸由内部元素决定,但永远小于“包含块”容器的尺寸(除非容器尺寸小于元素的“首选最小宽度”)。
因此如果一个元素的display
属性值是inline-block
,那么即使其里面内容再多,只要是正常文本,宽度也不会超过父容器。
“按钮”元素是 inline-block 元素
按钮文字越多宽度越宽(内部尺寸特性),但如果文字足够多,则会在容器的宽度处自动换行(自适应特性)。(button标签按钮才会自动换行,input标签按钮默认 white-space:pre,需要将pre值重置为默认的normal)
“包裹性”对实际开发有什么作用呢?
请看这个需求: 页面某个模块的文字内容是动态的,可能是几个字,也能是一句话。然后希望文字少的时候居中显示,文字超过一行就居左显示。该如何实现呢?
核心css代码如下:
.box {
text-align: center;
}
.content {
display: inline-block;
text-align: left;
}
2
3
4
5
6
7
这样,box的center控制的是 content元素居中,而content元素在文字少的时候没有那么长,因此整体文字看起来就是居中的,一旦超过一行,content元素的宽度占满box,box的center看起来就不起作用了(实际上还是起作用的,只不过是content太宽了,此时content上设置的text-align:left就显现出来了。)
文字内容
除了inline-block
元素,浮动元素以及绝对定位元素都具有包裹性,均有类似的只能宽度行为。
# 首选最小宽度
所谓“首选最小宽度”,指的是元素最适合的最小宽度。
Q:假如外部容器宽度为0,请问里面的inline-block元素的宽度是多少?
是0吗?不是!!!在CSS世界中,图片和文字的权重要远大于布局。此时所表现的宽度就是“首选最小宽度”。如下的例子:
“首选最小宽度”具体表现规则如下:
- 东亚文字(如中文)最小宽度为每个汉字的宽度。
- 西方文字最小宽度由特定的连续的英文字符单元决定。
并不是所有的英文字符都会组成连续单元
一般会终止于
空格(普通空格)
、短横线
、问号
以及其他非英文字符等。如果想让英文字符和中文一样,每个字符都用最小宽度单元,可以试试使用CSS中的
word-break:break-all
。 - 类似图片这样的替换元素的最小宽度就是该元素内容本身的宽度。
应用:实现凹凸效果
看不懂?把鼠标浮上去就知道了。核心css代码如下:
.ao {
display: inline-block;
width: 0;
}
.ao:before {
content: 'love你love';
outline: 2px solid #cd0000;
color:#fff;
}
2
3
4
5
6
7
8
9
# 最大宽度
“最大宽度”就是元素可以有的最大宽度。如果内部没有块级元素或者块级元素没有设定宽度值,最大宽度实际上是最大的“连续内联盒子”的宽度。
连续内联盒子指的是全部都是内联级别的一个或一堆元素,中间没有任何的换行标签或其他块级元素。
# width值作用的细节
css盒模型
我们的内在盒子又被分成四个盒子:
- content box
- padding box
- border box
- margin-box
margin(透明)borderpaddingcontent
width:100px是如何作用到div元素上的呢?
width:100px 作用在 content box上,由于div元素默认的padding、border和margin都是0,因此,该div所呈现的宽度就是100像素。
所以,假如padding和border不为0,该元素的宽度就不止100了。
# CSS流体布局下的宽度分离原则
所谓“宽度分离原则”,就是CSS的widths属性不与影响宽度的padding/border(有时候包括margin)属性共存。
那怎么写呢?如下,width单独用一个标签:
.father {
width: 180px;
}
.son {
margin: 0 20px;
padding: 20px;
border: 1px solid;
}
2
3
4
5
6
7
8
这样写的好处是不用计算width了,但是会多一层嵌套标签。
# 改变width/height作用细节的box-sizing
# box-sizing的作用
box-sizing改变了width作用的盒子。默认情况下,width是作用在content box上的,box-sizing还可以是 border-box。此时,content-box从宽度值中释放,形成了局部的流动性,和padding,border一起自动分配width。
谨慎写 *{box-sizing:border-box}
这种做法易产生没必要的消耗
通配符 * 应该是一个谨慎用的选择器,因为它会选择所有的标签。这种做法并不能解决所有问题
只有当元素没有水平margin的时候,box-sizing才能真正无计算,box-sizing绝不是发明来让那些对block水平元素滥用width属性的人少出bug的。
# 关于height:100%
height和width有个比较明显的区别就是对百分比单位的支持。
对于width属性,就算父元素width为auto,其百分比也是支持的。
但是对于height属性,如果父元素height为auto,只要子元素在文档流中,其百分比值完全就被忽略了。
注意
对于普通文档流中的元素,百分比高度值想起作用,其父级必须有一个可以生效的高度值!
# 为何 height:100% 无效
先来思考一下下面的红色父级元素宽度为什么没有进一步增大?
<div class="box">
<img src="1.jpg">
<span class="text">红色背景是父级</span>
</div>
2
3
4
.box {
display: inline-block;
white-space: nowrap;
background-color: #cd0000;
}
.text {
display: inline-block;
width: 100%;
background-color: #34538b;
color:#fff;
}
2
3
4
5
6
7
8
9
10
11
为什么要这样表现呢?
要明白其中的原因要先了解浏览器渲染的基本原理。
首先,先下载文档内容,加载头部的样式资源(如果有的话),然后按照从上而下、自外而内的顺序渲染DOM内容。即:先渲染父元素,后渲染子元素,是有先后顺序的。
因此,当渲染到父元素的时候,子元素的width:100%并没有渲染,宽度就是图片加文字的内容的宽度;等渲染到文字这个子元素的时候,父元素宽度已经固定,此时的width:100%就是已经固定好的父元素的宽度。宽度不够怎么办?溢出就好了,overflow属性就是为此而生的。
为什么宽度支持,高度不支持100%呢?
规范中给出了答案,“如果包含块的高度没有显示指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为auto”
因为解释成了auto,因此没有办法和百分比进行计算。
# 如何让元素支持 height:100% 效果
- 设定显示的高度
比较常见的就是
html,body { height: 100% }
- 使用绝对定位
div {
height: 100%;
position: absolute;
}
2
3
4
此时height:100%有计算值的,在绝对定位下,即使祖先元素的height计算为auto也是如此。
绝对定位元素 和 非绝对定位元素的百分比计算有区别
绝对定位的宽高百分比计算是相对于 padding-box 的,也就是说会把 padding 大小值计算在内。 非绝对定位元素则是相对于 content-box 计算的。