你知道我们平时在CSS中写的%都是相对于谁吗?

8,291 阅读9分钟

     

0.引言

在我们编写CSS的时候,经常会用到百分比赋值(%)实现自适应。像我们最常使用的流式布局设计模式,基本所有的column的宽度都是通过%来取值的。或者比如经常会遇到的元素水平垂直居中问题,我们常常会使用下面这样的CSS代码加以实现(absolute+transform思路):

.wrap {
  position:absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
}

大家因为经常使用,肯定都知道前面两个50%指的是wrap的定位参照物的宽、高的50%,而translate()里的50%指的是wrap自身,这应该不会有什么疑问,但在这简单的三行代码中,就出现了两类不同的%值,一种是相对于参照物盒子的,一种是相对自身的。不过你以为CSS世界里就只有这两类百分比值吗?一切可没这么简单,下面我会列举出不同的情况下%值的参照对象,且听我娓娓道来。


1.第一类——定位类

熟悉的小伙伴都知道CSS中的定位分为四种,默认值static,相对定位relative,绝对定位absolute还有固定定位fixed。虽然说每一类定位的%值的参照物都各不相同,但因为都具有定位的特殊性质,所以我把它们归为一类,现在对四种不同的定位分类讨论:

  • static:这个就不用说了吧,position的默认值,并没有对元素起到定位的作用,所以left、right等位置属性并不能被有效赋值,所以不存在在定位功能上的%值。
  • absolute:作为一个最为常用的定位属性,absolute不知道给多少前端小白挖了数不清的坑,相信大家早年在这上面学习的过程都是艰辛的。不扯远了,给一个元素absolute定位后就可以赋予left等位置值,参照物就是祖先元素中存在定位的元素,那么自然而然,位置值如果取得是%,那么这个%相对的元素便是这个参照物。left、right是相对于width,top和bottom是相对于height,这我就不必多说了吧。
  • relative:小伙伴们肯定都听说过子绝父相,而且肯定经常用,那么relative它是相对与自身定位的,那么位置值自然就是相对于自身的宽高喽。
  • fixed:这是一个很特殊的定位值,因为我们知道它是相对于视窗定位的,那么自然%的参照物便是视窗了。

2.第二类——盒子模型

在一个盒子模型内有很多特别常见的属性值,大家天天用也天天看,就是这些:width,height,margin,border,padding,width和height就不用说了,是相对于父盒子的,重点讲下margin和padding

  • margin&padding:这两个小伙子很特别,如果设置了%值,那么他们参照的是父元素的宽度!!父元素的宽度!!!父元素!!!宽度!!!重要的事情说三遍,不信的话我们可以亲手试试。的确很奇葩,不过你还真得记住,别开发的时候糗了你还以为是BUG。我们可以使用padding的这一特殊性质实现16:9或4:3等各比例响应式图片、视频盒子的构建。
  • border:border的话我一般是没见过有人用%的值,如果你在开发的时候用的是%,请收下我的膝盖。这边要讲的实际上是border-width,因为border实际上是个简写属性。其实是骗你们的啦,border-width目前还不允许输入%值,未来会不会允许并且参照的是谁都还是未知,如果你写了%的值浏览器是不会渲染的哦,所以border不存在%值。
  • border-radius:既然说到了border,就顺带提一下border-radius,圆角。平时我们用这个属性的时候基本都是给他赋4个参数,代表四个角,分别是左上、右上、右下、左下,以顺时针的顺序排序。但实际上,border-radius最多可以取八个值,前四个值和后四个值用 / 隔开,斜杠前表示各角水平方向上的圆角半径,斜杠后表示各角竖直方向上的圆角半径。范例如下:
border-radius:top-left|top-right|bottom-right|border-left / top-left|top-right|bottom-right|border-left

3.第三类——背景值

  • background-size:设置背景时常用的属性,虽然我们平时常用contain或者cover代替,但是当我们想要让背景充满整个盒子的时候,也会这样子写:
background-size:100% 100%;

因此,background-size的参照物和border-radius一样,都是盒子自身的宽高。

  • background-position:这个属性和relative类似,起到的也是定位的效果,因此它的参照对象就是原盒子。但是这个属性比较特殊,他不是参照原盒子的宽高值,而是原盒子的宽高值减去背景图片的宽高值所得到的剩余值,更为形象的说,下面这两个属性值是等价的:"center center"和"50% 50%",如果你设置了后者,背景图片会自动居中,不用像定位那样还需要transform偏移了。这应该是优秀的前人在设计这个属性的时候就考虑到它将来的应用了吧。

4.第四类——transform

  • translate():在第一个模块中,我们讲到了这样一个属性:translate(),在CSS3中还有还有translate3d(),这个属性的含义想必大家都知道,就是在指定方向上进行2d偏移,它的参照物是自身的宽高。而transform3d()的第三个属性,指的是在z轴上的偏移,因为z-index的默认值是auto,所以%值并不能起作用,也就是说对translateZ()赋予百分比的值是无意义的。
  • transform-origin:这个属性是改变元素变形的原点,它和width还有height的特点一模一样,这里就不作过多详述了。
  • scale():控制元素的缩放比例,传入的参数是一般是浮点数,指的是相对于元素本身放大或缩小的比例。
  • zoom:zoom并不是transform的属性值,它是一个独立的CSS属性,之所以把他放在transform这一个模块讨论,是因为恰好它与scale()有共同的特征,它的取值既可以是浮点数,也可以是%,包括参照物,都与scale()等价。

5.第五类——字体

  • font-size:这个属性和我们的height一样,是参照父盒子的字体大小的。
  • line-height:我们所说的行高也是很特别的一个属性,如果给它赋予不同类型的值,会有不同的特性。如果它的属性值是一个无单位的数字,那么最后的结果便是这个数字与该元素字体大小的乘积。这是我们设置line-height的首选方法,因为字体大小font-size是继承自祖代元素的,通过这个方法设置的值基本不会出现异常情况。但如果我们的值是%,最后的结果是给定的百分比值乘以元素最后计算出的字体大小。
  • text-indent:这个属性是用来设置首行缩进的,我们最长用的是2em,首行缩进两个字符,这边的2em指的就是两倍的font-size,按道理来说如果它取%应该也是要相对于本身的font-size的,但是偏偏就那么特别,和padding和margin一样,如果设置的是%,则参照的是父元素的width。这应该算是一个特例吧。

6.结语

大家可能大概看一遍下来还是一脸懵逼,为了给大家加强记忆,我就以参照物的不同类别为主线做个总结:

  • 相对于父盒子:

最常见的应该就算是参照父盒子(containing box)的属性,但是还有一些特例参照的是父盒子的width,只有这个类别还需要分两类讨论:

  • 相对于盒子自身:

以盒子自身为参照的属性就比较多了,参照的属性一般也是与自身有关联的属性,属于这一类的属性值有:定位中的relative;盒子模型中的border-radius;背景中的background-size;背景中的background-position比较特殊,还记得吗,它需要减去你的背景图片的宽高,你可以联想到flex布局中的flex属性值;在transform变换中,translate()、transform-origin、scale()还有我们拓展的与transform相似的zoom属性,他们都是参照自身的;line-height行高与它的字体大小有关,所以参照的就是自身的font-size。

  • 相对于定位元素:

因为定位的性质比较特殊,所以将他单独分出一类,定位元素参照的是他的定位对象,因为relative是相对于自身定位,所以我把他归为相对盒子自身一类中去了,其他的属性值我们都可以看作是参照他们的定位元素。

文章列出的所有属性具体的一些属性值的特性可以参考MDN官网,其实像上文列出的属性,我们并不需要全部去记忆,也很难做到把所有的都记下来,很多时候,我们只需要自己在浏览器中测试一下就知道这些CSS是参照谁的啦。

最后留下一个小问题,如果不用px,只用%,如何实现一个宽高相等的正方形div?

成文不易,希望大家能多多支持,如果您有补充,欢迎在评论区里提出,谢谢。


作者:IMWeb jerryOnlyZRJ
原文:你知道我们平时在CSS中写的%都是相对于谁吗? - 腾讯Web前端 IMWeb 团队社区



微信小程序开发-NEXT学位 课程火热报名中,感兴趣的小伙伴快点击图片,了解课程详情吧!