我们都知道,display: inline-block
属性可以呈现内联块级元素,元素可以在同一行上面显示,而且可以设置宽度、高度、上下边距和内边距等。
那么,元素应该如何设计,可以用使其既可以作为块级也可以作为内联元素呢。
其实,每个元素都有两个盒子,外在盒子和内在盒子(容器盒子)。外在盒子负责元素是一行显示,还是换行显示,内在盒子(容器盒子)负责元素的宽高以及内容呈现。
所以,按照display
的属性值不同,值为block
的元素盒子实际上是由外在的块级盒子和内在的块级容器盒子组成,值为inline-block
的盒子是由外在的内联盒子和内在的块级容器盒子组成,值为inline
的元素是由外在的内联盒子和内在的内联盒子组成。
我们都知道,width
的默认属性是auto
,但是这个属性至少包含了以下4种不同的宽度表现:
<div>
、<p>
这些元素的宽度默认是父级容器的100%。inline-block
元素或table
元素。table-layout
为auto
的表格中,当每一列的空间都不够的时候,文字就会换行,中文可以在文字任意处断,英文单词在每个词的时候断。width
相关设置,否则上面3种情况的宽度都不会主动超过父元素的宽度,但是有一些特殊情况,比如,内容很长的连续的英文和数字,或者内联元素被设置了white-space: nowrap
,就会表现为子元素超出了父元素宽度。CSS世界中,盒子分“内在盒子”和“外在盒子”,显示也分“内部显示”和“外部显示”,同样地,尺寸也分“内部尺寸”和“外部尺寸”。在上面的4中宽度表现中,只有第一种,div
默认宽度100%显示,是外部尺寸,其余三种表现都是内部尺寸。
当我们在一个容器中倒入一定量的水时,水一定会铺满整个容器,同样,在页面中放入一个div
元素,这个div
也会像水流一样铺满容器,这就是块级容器的特性。但是,表现为外部尺寸的块级元素一旦设置了宽度,这种流动性就消失了,这种流动性就是一种margin/border/padding/content
自动分配水平空间的机制。
比如下面这个例子,两个导航均有margin
和padding
,一个没有width
设置,一个width
设置了100%,结果后者的尺寸超过了外部的容器,并没有完全利用容器空间:
<h4>无宽度,借助流动性</h4>
<div class="nav">
<a href="" class="nav-a">导航1</a>
<a href="" class="nav-a">导航2</a>
<a href="" class="nav-a">导航3</a>
</div>
<h4>width:100%</h4>
<div class="nav">
<a href="" class="nav-a width">导航1</a>
<a href="" class="nav-a width">导航2</a>
<a href="" class="nav-a width">导航3</a>
</div>
.width {
width: 100%;
}
.nav {
background-color: #cd0000;
}
.nav-a {
display: block;
margin: 0 10px;
padding: 9px 10px;
border-bottom: 1px solid #b70000;
border-top: 1px solid #de3636;
color: #fff;
}
.nav-a:first-child { border-top: 0; }
.nav-a + .nav-a + .nav-a { border-bottom: 0;}
格式化宽度仅出现在绝对定位模型中,也就是出现在position
属性值为absolute
或fixed
的元素中。在默认情况下,绝对定位元素的宽度表现是“包裹性”,宽度由内部尺寸决定,对于非替换元素,当left/right
或top/bottom
对立方位的属性值同时存在的时候,元素的宽度表现为“格式化宽度”,其宽度大小相对于最近的具有定位特性(position
属性值不是static
)的祖先元素计算。
例如下面这段代码:
div {
position: absolute;
left: 20px;
right: 20px;
}
假设该<div>
元素最近的具有定位特性的祖先元素的宽度是100px,那么这个div
的宽度就是60px(100 - 20 - 20)px。
所谓的内部尺寸,就是元素的尺寸是由内部元素决定的,而不是由外部的容器决定的。如果一个元素里面没有内容,宽度是0,那么这个元素就是内部尺寸。
内部尺寸有下面三种表现形式:
包裹性除了包裹,还有自适应性。所谓的自适应性,就是元素尺寸由内部元素决定,但是永远小于包含块容器的尺寸,除非容器的尺寸小于元素的首选最小宽度。
比如说按钮,按钮元素通常会以以下两种形式出现在页面代码中:
<button>按钮</button>
<input type="button" value="按钮">
按钮是代表性的inline-block
元素,当按钮文字越多时按钮宽度越宽,但是如果文字足够多,则会在容器的宽度处自动换行。
<div class="box">
<button>按钮</button>
<button>长一点的按钮</button>
<button>超长的按钮超长的按钮超长的按钮超长的按钮超长的按钮超长的按钮超长的按钮</button>
</div>
.box {
width: 240px;
}
首选最小宽度,指的是元素最适合的最小宽度。在上面例子中,外部容器的宽度是240px,假设宽度是0,里面的inline-block
元素的宽度也不是0,此时里面的元素表现出来的就是首选最小宽度。
首选最小宽度具体表现规则如下:
<div class="demo">橘猫吃不胖</div>
.demo {
width: 0;
padding: 10px;
background-color: pink;
}
2. 英文最小宽度由特定的连续的英文字符单元决定,一般会在空格(普通空格)、短横线、问号以及其他非英文字符等地方换行。比如<div class="demo">hello world</div>
,就会在空格处换行,比如display:inline-block
会在“-”处换行。
3、类似图片这样的替换元素的最小宽度就是该元素内容本身的宽度。
最大宽度就是元素可以有的最大宽度,如果内部没有块级元素或者块级元素没有设定宽度值,则“最大宽度”实际上是最大的连续内联盒子的宽度。
例如,下面是一段连续内联盒子demo:
<div>
橘猫吃不胖
<span>一个span标签</span>
<button>一个button按钮</button>
<br>
换行了换行了换行了
<p>又又又又又换行了</p>
</div>
在上面这段代码中,有3个连续内联盒子,如下所示:
运行上面的代码,我们会发现在最大宽度下,盒子最后的宽度就是第一个连续内联盒子的宽度。
height
和width
有一个比较明显的区别就是对百分比单位的支持不一样。对于width
属性,如果父元素width
为auto
,也会支持百分比值;但是,对于height
属性,如果父元素height
为auto
,只要子元素在文档流中,其百分比值完全就被忽略了。
我们有时会遇到这样的场景,我们在页面中插入一个div
,想要满屏显示背景图,于是写了这样一段CSS:
div {
width: 100%;
height: 100%;
background: url("xxx");
}
但是我们会发现,这个div
的高度永远都是0,哪怕其父级<body>
塞满了内容也是如此,因此我们还需要如下设置:
html, body {
height: 100%;
}
并且,仅仅设置body
的样式也是没有效果的,所以我们发现,对于普通文档流中的元素,百分比高度值要想起作用,其父级必须有一个可以生效的高度值。
那么,为什么height: 100%;
会无效呢?
这是因为百分比高度的计算依赖于父元素的确切高度。当我们设置height: 100%;
时,浏览器会尝试将子元素的高度设置为父元素的百分比高度。如果父元素的高度没有明确设置,浏览器无法计算百分比。
当父元素的高度未知时,百分比高度的计算就失去了参考依据。浏览器不知道要将百分比应用到多高,因此无法正确计算子元素的高度。
那为什么width: 100%;
就不需要父元素宽度已知就可以生效呢?
这是因为在默认情况下,块级元素(如div
)的宽度会自动扩展以填充其父元素的可用宽度,块级元素默认具有100%
的宽度,当你设置width: 100%;
时,子元素的宽度会相对于其包含块(即父元素)的宽度进行计算。
有两种方法可以使元素支持height: 100%
效果:
height: 800px
,比如html, body { height: 100%; }
div { position: absolute; height: 100%; }
,此时的height:100%
就会有计算值,即使祖先元素的height
计算为auto
也是如此。需要注意的是,绝对定位元素的百分比计算和非绝对定位元素的百分比计算是有区别的,区别
在于:绝对定位的宽高百分比计算会把padding
大小值计算在内,但是,非绝对定位元素则是只会把content
大小计算在内。
例如下面这个例子:
<div class="box">
<div class="child">高度100px</div>
</div>
<div class="box1">
<div class="child1">高度160px</div>
</div>
.box {
height: 160px;
padding: 30px;
box-sizing: border-box;
background-color: #beceeb;
}
.child {
height: 100%;
background-color: #cd0000;
}
.box1 {
height: 160px;
padding: 30px;
box-sizing: border-box;
background-color: #beceeb;
position: relative;
}
.child1 {
height: 100%;
width: 100%;
background-color: #cd0000;
position: absolute;
}
在上面的例子中,第一个box
的高度为160px,其子元素宽度和高度设置了100%,那么子元素的真实高度就是(160 - 30 - 30)px,100px正好为父元素content
的高度,宽度是(父元素宽度 - 30 - 30)px。
第二个box1
的高度也是160px,子元素宽度和高度也设置了100%,但是不同的是,子元素使用了绝对定位,那么这时子元素的高度就是160px,宽度和高度都是父元素content
+padding
的大小。