I had been racking my brains over creating a vertical alignment in css using the following
.base{ background-color:green; width:200px; height:200px; overflow:auto; position:relative; } .vert-align{ padding-top:50%; height:50%; }
While this seemed to work for this case, i was surprised that when i increased or decreased the width of my base div, the vertical alignment would snap. I was expecting that when I set the padding-top property, it would take the padding as a percentage of the height of the parent container, which is base in our case, but the above value of 50 percent is calculated as a percentage of the width. :(
Is there a way to set the padding and/or margin as a percentage of the height, without resorting to using JavaScript?
The fix is that yes, vertical padding and margin are relative to width, but top
and bottom
aren't.
So just place a div inside another, and in the inner div, use something like top:50%
(remember position
matters if it still doesn't work)
An answer to a slightly different question: You can use vh
units to pad elements to the center of the viewport:
.centerme {
margin-top: 50vh;
background: red;
}
<div class="centerme">middle</div>
vh
is almost the same as percentages... even worse in some cases. This answer is irrelevant to the question
Here are two options to emulate the needed behavior. Not a general solution, but may help in some cases. The vertical spacing here is calculated on the basis of the size of the outer element, not its parent, but this size itself can be relative to the parent and this way the spacing will be relative too.
<div id="outer">
<div id="inner">
content
</div>
</div>
First option: use pseudo-elements, here vertical and horizontal spacing are relative to the outer. Demo
#outer::before, #outer::after {
display: block;
content: "";
height: 10%;
}
#inner {
height: 80%;
margin-left: 10%;
margin-right: 10%;
}
Moving the horizontal spacing to the outer element makes it relative to the parent of the outer. Demo
#outer {
padding-left: 10%;
padding-right: 10%;
}
Second option: use absolute positioning. Demo
#outer {
position: relative;
}
#inner {
position: absolute;
left: 10%;
right: 10%;
top: 10%;
bottom: 10%;
}
To make the child element positioned absolutely from its parent element you need to set relative position on the parent element AND absolute position on the child element.
Then on the child element 'top' is relative to the height of the parent. So you also need to 'translate' upward the child 50% of its own height.
.base{ background-color: green; width: 200px; height: 200px; overflow: auto; position: relative; } .vert-align { position: absolute; top: 50%; transform: translate(0, -50%); }
There is another a solution using flex box.
.base{ background-color:green; width: 200px; height: 200px; overflow: auto; display: flex; align-items: center; }
You will find advantages/disavantages for both.
This can be achieved with the writing-mode
property. If you set an element's writing-mode
to a vertical writing mode, such as vertical-lr
, its descendants' percentage values for padding and margin, in both dimensions, become relative to height instead of width.
From the spec:
. . . percentages on the margin and padding properties, which are always calculated with respect to the containing block width in CSS2.1, are calculated with respect to the inline size of the containing block in CSS3.
The definition of inline size:
A measurement in the inline dimension: refers to the physical width (horizontal dimension) in horizontal writing modes, and to the physical height (vertical dimension) in vertical writing modes.
Example, with a resizable element, where horizontal margins are relative to width and vertical margins are relative to height.
.resize { width: 400px; height: 200px; resize: both; overflow: hidden; } .outer { height: 100%; background-color: red; } .middle { writing-mode: vertical-lr; margin: 0 10%; width: 80%; height: 100%; background-color: yellow; } .inner { writing-mode: horizontal-tb; margin: 10% 0; width: 100%; height: 80%; background-color: blue; }
Using a vertical writing mode can be particularly useful in circumstances where you want the aspect ratio of an element to remain constant, but want its size to scale in correlation to its height instead of width.
-webkit-
prefix, but according to caniuse it hasn't required the prefix since Safari 11. Did you try it with any browser in which it didn't work?
writing-mode: revert;
on the inside: codepen.io/sollyu/pen/dyJQyze?editors=1100
revert
, but it seems that it just sets the writing-mode
to that of the parent element: … it resets the property to its inherited value if it inherits from its parent or to the default value established by the user agent's stylesheet (or by user styles, if any exist).
Other way to center one line text is:
.parent{
position: relative;
}
.child{
position: absolute;
top: 50%;
line-height: 0;
}
or just
.parent{
overflow: hidden; /* if this ins't here the parent will adopt the 50% margin of the child */
}
.child{
margin-top: 50%;
line-height: 0;
}
A 50% padding wont center your child, it will place it below the center. I think you really want a padding-top of 25%. Maybe you're just running out of space as your content gets taller? Also have you tried setting the margin-top instead of padding-top?
EDIT: Nevermind, the w3schools site says
% Specifies the padding in percent of the width of the containing element
So maybe it always uses width? I'd never noticed.
What you are doing can be acheived using display:table though (at least for modern browsers). The technique is explained here.
line-height
, ie, make the line-height 200px?
This is a very interesting bug. (In my opinion, it is a bug anyway) Nice find!
Regarding how to set it, I would recommend Camilo Martin's answer. But as to why, I'd like to explain this a bit if you guys don't mind.
In the CSS specs I found:
'padding' Percentages: refer to width of containing block
… which is weird, but okay.
So, with a parent width: 210px
and a child padding-top: 50%
, I get a calculated/computed value of padding-top: 96.5px
– which is not the expected 105px
.
That is because in Windows (I'm not sure about other OSs), the size of common scrollbars is per default 17px × 100%
(or 100% × 17px
for horizontal bars). Those 17px
are substracted before calculating the 50%
, hence 50% of 193px = 96.5px
.
Success story sharing
top
works great for resizing based on browser/window height. How aboutt having a div underneath that div? How can youclear
the 2nd div to be under the div that is shifted down by atop:50%
??top: 50%
is not very useful if you need to align the contents by their own center.