4

终于搞懂了 CSS 中的百分比是基于什么工作的了!

 2 years ago
source link: https://segmentfault.com/a/1190000040666444
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者:Khang
译者:前端小智
来源:dev

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

大家有没有对 CSS 中的百分比是如何工作的感兴趣?有没有想过,为什么它有时会乱七八糟,没啥头绪?反正我是有,所以今天分享这篇文章,对自己来说是加深理解,同时也希望对大家有所帮助。

什么百分比?

作为百分比,显然应该有一个目标作为参考源,这个参考一般是父元素。 这是正确的,但并不涵盖所有情况。 最正确的答案应该是包含块(containing block),即包含我们元素的块且它不必是直接的父元素。

看看下面的例子:

image.png

<div class="grandparent">
  <div class="parent">
    <div class="child"></div>
  </div>
</div>
.grandparent {
  position: relative;
  width: 200px;
  height: 200px;
  background: #eaeaea;
}

.parent {
  width: 100px;
  height: 100px;
  background: #aaa;
}

.child {
  position: absolute;
  width: 50%;
  height: 50%;
  top: 25%;
  left: 25%;
  background: red;
}

在上面的例子中,我创建了 3 个嵌套 div,它们是具有以下特征的3个正方形

  • 最外面的组元 div 是一个浅灰色,大小为 4x4
  • 父元素 div的颜色为深灰色,大小为 2x2
  • 以及分配 50% 大小的红色子 div

如果百分比单位以父级为来源,则子级的大小应该是它的 1/2,但上面的不是,子级的大小实际上等于父级,也就是祖父级的 1/2。 原因是祖父级 div 是子级 div 的真正包含块,因为子级具有 position: absolute ,对应于在祖父级中设置的 position:relative

因此,为了确定哪个是元素的实际包含块,它完全基于元素本身的 position 属性。

但是,对于某些属性,百分比单元的引用源既不是父块也不是包含块,而是它本身—— 自身元素

百分比的属性

width/height

如上面的例子中看到的,当一个元素为其宽度分配一个百分比值时, width 是基于包含块的width, height 是基于包含块的 height

padding

对于 padding,垂直(padding-top/padding-bottom)或水平(padding-left/padding-right)都是基于包含块的 width 来计算。

来个例子:

image.png

<div class="parent">
    <div class="child"></div>
</div>
.parent {
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  display: inline-block;
  background: red;
  padding-top: 50%;
  padding-left: 50%;
}

.parent {
  position: relative;
}

线上地址:https://codepen.io/khangnd/pe...

在这个例子中:

  • div 的大小为 6x4
  • div的大小为 0,但 padding-toppadding-left 分别为 50%

最后的结果是,子元素的大小相当于父级元素 1/2宽度,也就是一个 3x3 的正方形。

margin

paddingmargin 的百分比(垂直和水平)也是相对于包含块的宽度来计算。

来个事例:

image.png

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  display: inline-block;
  background: red;
  width: 50px;
  height: 50px;
  margin-top: 50%;
  margin-left: 50%;
}

在这个例子中:

  • 父级 div 的大小为 6x4
  • margin-topmargin-left 分别为 50%

其结果是,子元素被定位在离父级元素的上边距和左边距3个单位的地方(父级宽度的1/2)。

top/bottom/left/right

topbottom基于包含块的height来计算,leftright 基于包含块的width来计算。

来个例子:

image.png

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  position: relative;
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  position: absolute;
  background: red;
  width: 16.67%;
  height: 25%;
  top: 50%;
  left: 50%;
}

在这个事例中:

  • 父级 div 的大小为 6x4
  • 子元素有 position: absolutetopleft 分别为 50%

最终结果,子 div 被定位在离父 div 的顶部边缘 2 个单位的位置(父 div 高度的 1/2),并被定位在离父 div 的左侧边缘 3 个单位的位置(父 div 宽度的 1/2)。

transform: translate()

一个用于动画/过渡的不可思议的属性,它也支持百分比值。然而,这个属性并不指其包含的块,而是指其自身。

来个例子:

image.png

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  background: red;
  width: 100px;
  height: 50px;
  transform: translate(50%, 50%);
}

在这个事例中:

  • 父级 div 的大小为 6x4
  • div 的大小为 2x1,使用 transform: translate(50%, 50%)

最后结果,子 div 被定位在离父 div 的顶部边缘 0.5 个单位的位置(自身高度的 1/2),并被定位在离父 div 的左侧边缘 1 个单位的位置(自身宽度的 1/2)。

background-size

background-size 属性将百分比单元的复杂性提升到一个新的水平

此属性的百分比值指的是背景定位区域,类似于包含块,但添加了以下 3 个因素:

  • 只有内容的块(content-box)
  • 带有内容和 padding 的块 (padding-box
  • 带有内容、paddingborder 的块(border-box)

这三个值是由 background-origin 给出,具体看 MDN :https://developer.mozilla.org...

来个例子:

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  background-image: url(https://d2fltix0v2e0sb.cloudfront.net/dev-rainbow.png);
  background-size: 50% 50%;
  background-repeat: no-repeat;
  background-color: red;
  width: 50%;
  height: 50%;
}

image.png

在这个例子中:

  • div 的大小为 6x4
  • div 的大小为 3x2,没有 padding,没有 border
  • 这里使用了一个DEV logo(比例为 1:1 )作为子 div 的背景图像,背景大小属性设置为 50% 50%

其结果是,背景图像被拉伸为 1.5 x 1 的大小。

background-position

background-size 类似,background-position 属性的百分比也依赖于背景定位区域。

在这个例子中:

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  background: #eaeaea;
  width: 300px;
  height: 200px;
}

.child {
  background-image: url(https://d2fltix0v2e0sb.cloudfront.net/dev-rainbow.png);
  background-size: 50% 50%;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  background-color: red;
  width: 50%;
  height: 50%;
}

在本例中,使用了与前面相同的图像和布局。当我们改变background-position的值时,可以看到一些变化:

  • 如果没有任何值(默认值为0 0),背景图像将位于左上角。
  • 使用 background-position: 0 50%,背景图片被定位在左边中间。
  • 使用 background-position: 50% 50%,背景图片被定位在中心。
  • 使用 background-position: 100% 100%,背景图片被定位在右下方。

注意: background-position: 0 50% 是下面的缩写

  • background-position-x: 0
  • background-position-y: 50%

显然,这个属性的百分比背后有一些计算,而不仅仅是图像的顶部和左侧边缘与孩子的距离。通过一些研究和测试,似乎 background-position 属性在产生一个实际值之前依赖于以下计算。

offset X = (容器的宽度-图像的宽度) * background-position-x
offset Y = (容器的高度-图像的高度) * background-position-y

在这种情况下:

  • 容器作为子 div
  • 图像的宽度/高度是 background-size 的结果。

font-size

对于 font-size ,百分比值仅指向它的直接父块。

来个例子:

<div class="grandparent">
  font-size: 13px
  <div class="parent">
    font-size: 26px
    <div class="child">font-size: 50%
  </div>
</div>

在这个例子中,我使用与第一个例子相同的布局,字体大小分配如下。

  • grandparent 13px
  • parent 26px
  • child 50%

我们可以清楚地看到,child 的字体大小现在与 grandparent 一样,是 parent1/2

线上地址:https://codepen.io/khangnd/pe...

~~ 完,最近一个礼拜都在赶项目,基本都要2点后才能睡,这篇文章是间断整理好的,现在时间 是 9/20 深夜3点,睡了,感谢大家的观看。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://dev.to/khgnd/understa...

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收录,有一线大厂面试完整考点、资料以及我的系列文章。



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK