This is because padding
and margin
in %
gets calculated from width
, not height
as you desire.
From the spec for padding
Unlike margin properties, values for padding values cannot be negative. Like margin properties, percentage values for padding properties refer to the width of the generated box's containing block.
And from the spec for margin
The percentage is calculated with respect to the width of the generated box's containing block. Note that this is true for 'margin-top' and 'margin-bottom' as well. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
This is also how you can create aspect-ratio locked divs in HTML since you can calculate height
from width
using padding-top
with a percentage value.
A solution for you would be to use CSS calc, it has good browser support and fixes your issue in quite a simple manner. The only downside here is that it doesn't calculate the padding-top
in %
but you simply cannot calculate padding-top
in %
from the height
of the element unless you use javascript.
If you don't absolutely require the padding-top: 2%;
I would suggest the below solution.
Your CSS would look like this
ul.list li {
height: calc(10% - 8px);
padding-top: 8px;
}
This would give all ul.list li
items a height of 10% - 8px
and that 8px
is then also used as value for padding-top
which would basically make a perfect 10%
again.
You can write your selectors in a different style too, I used ul.list li
here as the main selector to just select all li
elements but you have :nth-child(odd)
and :nth-child(even)
selectors.
You wrote duplicate properties on these selectors while the only difference is their background
property.
I would strongly recommend to avoid duplication as much as possible as you'll definitely forget to change both properties sometimes, instead change your CSS to something like this:
/*shared properties in a general selector*/
ul.list li {
width: inherit;
height: calc(10% - 8px);
padding-top: 8px;
background: grey;
}
/*if rule is not applied, use ul.list instead of just ul*/
ul li:nth-child(even) {
background: red;
}
This even removes the need for ul li:nth-child(odd)
since this can also be part of the shared styling and then be overwritten by the more specific ul li:nth-child(even)
selector.
Another way
Another way of doing this instead of relying on %
values is to use either em
or rem
values - they work by scaling based on font size.
More reading
Basically, rem
is always relative to the root element
which is the <html>
element.
Setting a font-size on the <html>
element will define the value of 1rem
in CSS, if no font-size
is set then the browser default (usually 16px
will be used).
html {
font-size: 16px; /*1rem is now 16px*/
}
When you define the font-size
like above with a value of 16px
then 0.5rem
will equal 8px
- why is this interesting? It's scaleable! But by different means.
When you now apply a media query and change the font-size
to something bigger or smaller, everything using rem
will scale proportionally (you'd have to set font-size
of the <html>
element ofcourse.)
Now em
is a bit different, it's relative to it's own font-size
but since this get's inherited from it's parent element automatically (if font-size
is set in em
or %
that is) it's basically relative to the parent.
If we take the last CSS example
html {
font-size: 16px; /* 1rem = 16px, 1em = 16px */
}
body > div { /*every direct div of body tag*/
font-size: 0.5em; /*8px*/
font-size: 0.5rem; /*8px*/
}
body > div > div { /*every second level nested div*/
font-size: 0.5em; /*4px*/
font-size: 0.5rem; /*8px*/
}
Basically, since em
is sort-of relative to it's parent size the font-size decreases more when you scale in em
- this is potentially dangerous since if you change your structure and add a container that slightly reduces font-size on most of the page this could have a bigger effect than you think.
With that out of the way, technically em
and rem
are the best ways to scale padding
and margin
on elements according to the font-size
property.
An example for your container could look like this:
ul.list li {
height: 8%;
padding-top: 0.5rem; /*if font-size is 16px, this will be 8px*/
}
In terms of scalability this will work when you change the font-size to something else on a mobile device for instance.
It doesn't provide a solution to your question but it does provide an answer and your best alternative when talking about scalability, I hope this helps you in your quest for that :)
box-sizing
. Anyway, you are aware of the pitfalls withpadding-top
in percentages? – Rubyeruch