重新css(3)温和padding中的诡异CSS现象
盒模型的四大家族,原以为content部分比较复杂,单独写了一章,但在看padding部分的时候又遇到一个非常诡异的CSS现象,经过不断测试,终于得到一个比较接近于“真相”的解释,在测试这个诡异现象之前,先将padding的一些特性简单介绍一下,最后再来解释这个问题。
1.padding与块元素的尺寸
padding是盒模型的内边距(也称内补间),在CSS中,box-sizing默认的值是content-box,所以使用padding会增加元素的尺寸,例如 {width : 60px;padding : 0 20px},如果不考虑其他CSS干扰,此时content-box的宽度是60+20*2=100。为了方便对照设计稿快速的完成页面骨架搭建,我们往往会直接取到元素的宽高,而不考虑内边距是多少,不然你的宽高都需要通过计算才能得到,影响开发效率。因此我们会将box-sizing设成border-box,认为这样宽高就固定了,不会随着padding影响容器尺寸。事实上大部分情况确实如此,但有一种特殊情况你应该了解,就是当padding的值足够大时,padding+content>width时,如下面这种情况:
<style>
.box{
display:block;
width:80px;
padding:0 60px;
box-sizing:border-box;
}
</style>
此时padding > width,那么元素最终的宽度为120px,而不是80px,上述表现是针对块状特性的元素而言的,对于内联元素,会有一些细节需要通过实践来进行说明。
2.padding与内联元素的尺寸
这里先纠正一个错误的观点,内联元素的padding只会影响水平方向,不会影响垂直方向。这种认知是非常片面的,虽然内联元素在垂直方向的行为完全受line-height和vertical-align(CSS2.1,flex布局是CSS3的内容)的影响,视觉上并没有改变上下两行的间距,但我们只需要做一个小测试,给内联元素加上背景色就可以发现,内联元素在垂直方向上的空间也会受到padding的影响。
<div><span class="havePad">hello</span><span class="havePad">world</span></div>
<style type="text/css">
body{
margin: 40px;
}
.havePad{
padding: 20px;
border: 1px solid #ccc;
background: #E6A23C;
}
</style>
由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)
我们可以看到,padding会影响内联元素的尺寸,而且当你给父容器加上overflow:auto的时候,父容器还会出现滚动条,这也印证了上面的观点,所以类似"垂直方向padding对内联元素没用"的说法显然是不正确的。那么,知道了这个特性之后,我们可以利用它做什么呢?最常见的作用就是增加元素的点击区域,比方说文章中的文字链接,默认情况下这些链接的点击区域受font-size字体大小控制,这个时候我们只要增加他的上下padding,便可以在"不影响可视布局"的情况下增大点击区域。
3.padding的百分比值
padding的属性与margin不同,padding是不支持负值的,padding的百分比值和宽高的表现略有不同,padding的百分比值无论是水平方向还是垂直方向,都是相对于父容器的宽度进行计算的,因为CSS默认是水平流,所以宽度值会一直有效。基于padding百分比基于宽度计算的特点可以实现一些特定的功能。作者举了个固定头图的例子,在网页开发的时候需要一个横穿整个屏幕的头图,如果定制了高度,则可能导致在分辨率较低的屏幕中图片被压缩效果不好,这个时候就可以利用padding的宽高百分比都基于宽度计算的特点来实现一个固定宽高比的头图。代码如下
<style>
.box{
position:relative;
padding:10% 50%;
}
.box > img{
position:absolute;
width:100%;
height:100%;
left:0;
top:0;
}
</style>
padding属性的百分比值在内联元素的表现略有不同,下面会通过一个诡异的CSS现象来说明padding的百分比在内联元素中的一些特殊属性。
4.padding百分比值在内联元素中的诡异表现
作者在探究padding百分比值对于内联元素的影响时给出了一段诡异CSS代码,下面会一步步引导你去探究CSS的诡异事件。有兴趣的可以自己在本地测试一下。代码如下:
<div class="box">
<span class="span">一二三四</span>
</div>
<style type="text/css">
body{
margin: 0;
padding: 300px;
}
.box{
width: 400px;
height: 100px;
background: green;
}
.span{
line-height: 40px;
padding: 50%;
background: gray;
}
</style>
产生的结果如下图所示(这里用图片会更清楚一些所以就不直接用HTML代码了)
在结果中产生了两个比较诡异的样式:
(1)"一"这个字不见了
(2)生成了一个“五边形”
原文这样描述这个问题,“CSS的很多现象难以解释,原因在于其表现往往是多个属性多个规则一起生效的结果,例如本例,虽然几乎没用实用价值,但是对我们深入理解内联元素的世界很有帮助”。关于这个问题的产生,我提取了作者三个比较明确的说明。有助于你理解这段CSS是如何作用的。
- 对于内联元素,其padding是会自动断行的。
- padding区域会随着内容一起换行。
- 层叠样式具有覆盖性,层级相同的样式,后者>前者。
下面我会一点点解释这三个点,在这之前,我们可以明确一点,就是padding的百分比值是基于父元素的宽度进行计算的,在本例中,上下左右的padding值均为400px*50%=200px。(关于padding:50%和padding在内联元素中的表现请关注本章对padding基础的一些总结和归纳。)因此该内联元素最终的宽度=内联元素content的宽度+左右padding的值。可以确定的是,这个宽度一定>父级元素的宽度,所以该元素会自动断行也就不奇怪了。至此,我们已经向前迈出了一小步。我们可以看到,"四"这个字,确实是换行了。
这个时候,我们需要做一点小小的改变,我们把内联元素的背景色去掉,看看会发生什么。
当我们把background去掉之后,发现“一”其实就在二三的前面,只是好像被背景色给覆盖了。这里我们就需要用到作者给出的的第二个和第三个解释了,首先,由于“四”换行了,导致“四”后面的padding-right区域会随着内容一起换行。而"一二三"的宽度是padding-left + 3个字的宽度,而"四"换行之后的宽度是padding-left+1个字的宽度,这个时候padding-left和padding-right宽度抵消,由于层叠样式的覆盖性,层级相同的样式,后来的"四"携带着换行的padding正好覆盖了前面一行一个文字长度的区域,导致正好一个"一"字被覆盖了,同时,由于上面的二三的宽度是多出来的部分,下面的四由于padding换行也多出一个字的高度,因此正好产生了右下角的空白区。至此,我们已经解决了,"一"去哪儿了以及右下角空白部分的问题。
看似上面提出的两个问题都解决了,但我仍然不满足,再提出一个问题
(3)为什么是"四"换行,而不是"三四”,也不是"二三四"。
要解决这个问题,我们得往这个内容区多加一些字看看,最终我将字添加到一二三四五六七八九十一二三四,才发现最后两个字"三四"换行了。
由于有两个字换行,因此遮住了开头的"一二",这正好印证了我之前的说法,同时我也提出一个什么时候字会换行的猜想,根据第二章讲到的元素包裹性的内容,我猜测,当内容区未将要超出父容器的宽度减padding-left时,content部分的最后一个子会自动换行,同时宽度自适应,当内容即将要超出父容器的宽度减padding-left时,content多余的部分会换行。这里仅根据元素包裹性提出一个猜想,有更好的说明的欢迎指正。