与不同情况下的其他单位相比,百分比如何真正起作用 [英] How percentage truly works compared to other units in different situations

查看:31
本文介绍了与不同情况下的其他单位相比,百分比如何真正起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以基本上我最近一直在试验 CSS,我遇到了一些对我来说看起来很新的东西.我通常在设置元素的填充时使用 em 或 px 等单位,但这次我尝试使用百分比,令我惊讶的是它的工作方式与其他单位非常不同.

所以我设置了三种不同的情况:

body {边距:0;}.容器 {显示:弹性;背景颜色:浅蓝色;对齐内容:间隔;边距:30px 0;}.柔性 {显示:弹性;}.container a {颜色:#000;填充:50px;背景颜色:rgba(0, 0, 0, 0.3)}.container.two {背景颜色:浅绿色;}.container.two a {填充:30%;}.container.三{背景颜色:米色;}.container.three a {填充:30%;}

<div class="flex"><a href="#">项目 1</a><a href="#">项目 2</a>

<div class="flex"><a href="#">项目 1</a><a href="#">项目 2</a>

<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

<div class="第三个容器"><div><a href="#">项目 9</a><a href="#">项目 10</a>

<div><a href="#">项目 11</a><a href="#">项目 12</a>

在每种情况下,我都有一个导航栏,导航栏两侧各有 2 个项目.我使用像素和百分比为项目设置填充.导航栏本身是弹性容器.在前两种情况下,物品的容器是弹性容器,但第三种不是.

  1. 使用像素(连同 flexbox):当使用像素和 flexbox 时,我觉得一切都很正常.

  2. 使用百分比(连同 flexbox):所以这就是事情开始变得奇怪的地方.项目被推出导航栏.

  3. 使用百分比(不使用 flexbox):在这里,项目没有被推到导航栏,而是在它们的直接父级内部增长,最终它们开始以更高的百分比值包装.

当我从导航栏中删除 flex 时,一切都变得更奇怪了.

我只想知道在处理 flexbox 时,为什么百分比的行为与其他单位不同.我从来没有用百分比来做这样的事情,所以这对我来说很新.我好奇.我怀疑这与 flexbox 有关,而不是直接与百分比单位有关.

这是相同的复制品:

https://jsfiddle.net/sLnvzrmb/

解决方案

您同时面临着很多事情的组合.

首先,与 padding 一起使用的百分比会将父元素宽度视为参考(而不是元素本身)

<块引用>

百分比是根据生成的框的包含块的宽度计算的,即使对于padding-top"和padding-bottom"ref

在我们的例子中,包含块是父元素.

其次,在行内元素上应用内边距和在块元素上应用内边距是不一样的.内联元素的顶部和底部填充不会影响布局,但您会有一种重叠:

<块引用>

内联、非替换框的垂直填充、边框和边距从内容区域的顶部和底部开始,与行高"无关.但是在计算线框的高度时只使用line-height".ref

第三,在使用 flexbox 时,你必须考虑默认的 nowrap 行为 ref 以及 flex 项目被阻塞的事实(即使它们的显示设置为内联)

<块引用>

flex item 的显示值被屏蔽了.. 参考


现在,如果我们考虑使用 flexbox 的第一种情况.项目被阻塞,并且百分比将考虑父宽度作为参考,但是您有一个复杂的循环行为案例,因为父(也是一个弹性项目)的宽度基于其内容.我知道消化所有这些信息并不容易,所以这里有一个分步说明来理解:

.container {显示:弹性;背景颜色:浅蓝色;对齐内容:间隔;}.柔性 {显示:弹性;边框:2px 纯红色;}.container a {颜色:#000;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

仔细观察我添加的红色边框,以及它在两种情况下的宽度如何相同.诀窍是浏览器将首先忽略填充(因为它是一个百分比值)来计算父宽度,然后使用该宽度来查找填充的值,并且逻辑上会出现溢出.溢出等于您所拥有的填充(正好是宽度的 30%*4).由于默认的 nowrap 行为,元素不会换行,但您可以禁用此功能:

.container {显示:弹性;背景颜色:浅蓝色;对齐内容:间隔;}.柔性 {显示:弹性;边框:2px 纯红色;弹性包裹:包裹;}.container a {颜色:#000;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

现在,如果您从父项中删除 display:flex,您将不再拥有 flex 项,现在您处理内联元素并获得以下内容

.container {显示:弹性;背景颜色:浅蓝色;对齐内容:间隔;}.柔性 {边框:2px 纯红色;}.container a {颜色:#000;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

与以前相同的逻辑,首先定义宽度,然后用作参考,但您不会溢出,因为内联元素将换行到下一行,并且行之间会有重叠,因为 padding-top/bottom 没有't 适用于内联元素.

添加 inline-block 看看区别

.container {显示:弹性;背景颜色:浅蓝色;对齐内容:间隔;}.柔性 {边框:2px 纯红色;}.container a {颜色:#000;显示:内联块;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

最后,如果你从导航栏中移除 flexbox,作为 flex item 的父元素现在是一个块元素,它的宽度不再基于它的内容,但它现在默认为全宽,你有

.container {背景颜色:浅蓝色;对齐内容:间隔;宽度:100px;}.柔性 {边框:2px 纯红色;}.container a {颜色:#000;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

更大的宽度<div class="容器二" style="width:300px"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

全屏宽度<div class="container2" style="width:auto"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

所以我们的父元素是全宽的,padding:30% 是基于这个宽度的.想象一下它会有多大,因为每个元素都有 60% 的填充(左 + 右),所以总共 120%.并且我们的元素是内联元素,因此顶部和底部将不适用,只会重叠

使用 inline-block 并禁用overalp,现在顶部和底部是布局的一部分:

.container {背景颜色:浅蓝色;对齐内容:间隔;宽度:100px;}.柔性 {边框:2px 纯红色;}.container a {颜色:#000;显示:内联块;背景颜色:rgba(0, 0, 0, 0.3)}.container.two a {填充:30%;}

填充前<div class="容器"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

填充后<div class="容器二"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

更大的宽度<div class="容器二" style="width:300px"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

全屏宽度<div class="container2" style="width:auto"><div class="flex"><a href="#">项目 5</a><a href="#">项目 6</a>

<div class="flex"><a href="#">项目 7</a><a href="#">项目 8</a>

so basically I've been experimenting with CSS recently and I came across something which looked seemed new to me. I usually use units such as em, or px when setting the padding of an element but this time I tried using percentages and to my surprise it worked very differently than the other units.

So I set up three different situations:

body {
  margin: 0;
}
.container {
  display: flex;
  background-color: lightblue;
  justify-content: space-between;
  margin: 30px 0;
}
.flex {
   display: flex;
}
.container a {
  color: #000;
  padding: 50px;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two {
  background-color: lightgreen;
}
.container.two a {
  padding: 30%;
}
.container.three {
  background-color: beige;
}
.container.three a {
  padding: 30%;
}

<div class="container">
  <div class="flex">
    <a href="#">Item 1</a>
    <a href="#">Item 2</a>
  </div>
  <div class="flex">
    <a href="#">Item 1</a>
    <a href="#">Item 2</a>
  </div>
</div>
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
<div class="container three">
  <div>
    <a href="#">Item 9</a>
    <a href="#">Item 10</a>
  </div>
  <div>
    <a href="#">Item 11</a>
    <a href="#">Item 12</a>
  </div>
</div>

In each situation I have a navbar with 2 items on either side of the navbar. I use pixels and percentage to set a padding to the items. The navbars itself are flex containers. In the first two cases the container of the items were flex containers but the 3rd one was not.

  1. Using pixel (along with flexbox): When using pixel along with flexbox everything seemed normal to me.

  2. Using percentages (along with flexbox): So this is where things started to get weird. The items get pushed out of the navbar.

  3. Using percentages (without flexbox): Here, the items did not get pushed of the navbar but instead just grew inside their direct parent and eventually they started wrapped at higher percentage values.

When I remove flex from the navbars everything gets weirder.

I just wanna know why percentage acts differently than the other units when dealing with flexboxes. I've never used percentages to do such a thing so this is very new to me. I am curious. I'm suspecting this has something to do with flexbox and not the percentage unit directly.

Here is a reproduction of the same:

https://jsfiddle.net/sLnvzrmb/

解决方案

You are facing the combination of a lot of things at once.

First, percentange used with padding will consider the parent element width as reference (and not the element itself)

The percentage is calculated with respect to the width of the generated box's containing block, even for 'padding-top' and 'padding-bottom' ref

The containing block is the parent element in our cases.

Second, applying padding on inline element is not the same as applying it to block element. top and bottom padding on inline element will not affect the layout but you will have a kind of overlap:

The vertical padding, border and margin of an inline, non-replaced box start at the top and bottom of the content area, and has nothing to do with the 'line-height'. But only the 'line-height' is used when calculating the height of the line box. ref

Third, when using flexbox you have to consider the default nowrap behavior ref and the fact the flex item get blockified (even if their dispaly is set to inline)

The display value of a flex item is blockified .. ref


Now, if we consider the first case using flexbox. The items are blockified and percentage will consider the parent width as reference BUT you have a complex case of cyclic behavior because the parent (that is also a flex items) has its width based on its content. I know it's not easy to digest all these information so here is a step-by-step illustration to understand:

.container {
  display: flex;
  background-color: lightblue;
  justify-content: space-between;
}
.flex {
   display: flex;
   border:2px solid red;
}
.container a {
  color: #000;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

Look closely at the red border I am adding and how its width is the same in both situations. The trick is that the browser will first ignore the padding (because it's a percentage value) to calculate the parent width and later will use that width to find the value of padding and you will logically have an overflow. An overflow equal to the padding you are having (30%*4 of the width exactly). The elements will not wrap due to the default nowrap behavior but you can disable this:

.container {
  display: flex;
  background-color: lightblue;
  justify-content: space-between;
}
.flex {
   display: flex;
   border:2px solid red;
   flex-wrap:wrap;
}
.container a {
  color: #000;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

Now if you remove display:flex from the parent, you no more have flex item and now you deal with inline elements and you get the following

.container {
  display: flex;
  background-color: lightblue;
  justify-content: space-between;
}
.flex {
   border:2px solid red;
}
.container a {
  color: #000;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

Same logic as before, the width is first defined and later used as reference but you will not have overflow because inline element will wrap to the next line AND you will have the overlap between the lines because padding-top/bottom doesn't apply to inline elements.

add inline-block and see the difference

.container {
  display: flex;
  background-color: lightblue;
  justify-content: space-between;
}
.flex {
   border:2px solid red;
}
.container a {
  color: #000;
  display:inline-block;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

Finally, if you remove flexbox from the navbar, the parent element that was a flex item is now a block element and its width is no more based on its content but it's now full width by default and you have

.container {
  background-color: lightblue;
  justify-content: space-between;
  width:100px;
}
.flex {
   border:2px solid red;
}
.container a {
  color: #000;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

bigger width
<div class="container two" style="width:300px">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

full width
<div class="container two" style="width:auto">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

So our parent element is full width, the padding:30% is based on that width. Imagine how big it will be since each element is having 60% of padding (left + right) so a total of 120%. and our elements are inline elements so the top and bottom will not apply and will simply overlap

Use inline-block and you disable the overalp and now top and bottom are part of the layout:

.container {
  background-color: lightblue;
  justify-content: space-between;
  width:100px;
}
.flex {
   border:2px solid red;
}
.container a {
  color: #000;
  display:inline-block;
  background-color: rgba(0, 0, 0, 0.3)
}
.container.two a {
  padding: 30%;
}

Before padding
<div class="container">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>
After padding
<div class="container two">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

bigger width
<div class="container two" style="width:300px">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

full width
<div class="container two" style="width:auto">
  <div class="flex">
    <a href="#">Item 5</a>
    <a href="#">Item 6</a>
  </div>
  <div class="flex">
    <a href="#">Item 7</a>
    <a href="#">Item 8</a>
  </div>
</div>

这篇关于与不同情况下的其他单位相比,百分比如何真正起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆