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>