I've been using relatively positioned elements to center things vertically for a while. I never understood, though, why position: relative; top: 50%;
doesn't vertically center the element, or at least center the top edge of the element in it's container div.
position: relative
according to MDN:
lays out all elements as though the element were not positioned, and then adjusts the element's position, without changing layout
The top
keyword:
specifies the amount the element is moved below its normal position.
And a %
value on the top
keyword:
Is a percentage of the containing block's height
So a relatively positioned element with a value of top: 50%
should be moved 50% of the containing blocks height downward, right? Doesn't this mean that the top edge of that element is exactly in the middle of the containing element?
Consider this snippet:
.container {
overflow: hidden;
width: 90%;
height: 90%;
margin: 0 auto;
background-color: #eee;
}
.child {
width: 40%;
height: 40%;
margin: 0 auto;
background-color: #444;
border-top: 5px solid #f00;
}
.top-50-percent {
position: relative;
top: 50%;
}
.contract-and-expand {
animation-name: contract-and-expand;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
@keyframes contract-and-expand {
50% {
height: 0%;
}
}
<html>
<head>
<style>
/* Just initial/basic CSS rules here to make this look better */
@import url("https://necolas.github.io/normalize.css/latest/normalize.css");
* {
box-sizing: border-box;
margin: 0;
}
html, body {
height: 100%;
}
body {
color: #aaa;
}
.center-vertically {
position: relative;
top: 50%;
transform: translateY( -50% );
}
p {
position: absolute; /* Remove paragraphs from flow so they don't interfere */
}
</style>
</head>
<body>
<div class="container center-vertically contract-and-expand">
<p>Container Wrapper</p> <!-- Paragraphs are removed from the flow -->
<div class="child top-50-percent">
</div>
</div>
</body>
</html>
From the snippet it looks like the top edge is centered. Is this always correct? there's this similar fiddle: https://jsfiddle.net/9kyjt8ze/5/ when the height of the viewport is pulled up the top border of the child element no longer looks centered.
I measured this with Inkscape and 2 ( yellow ) vertical blocks the same exact size. It's an optical illusion. The top edge never actually gets off center in that fiddle. Also all of my assumptions appear correct: top:50%
on relatively positioned elements moves the top border of that element down 50% of the container's height. The reason this doesn't perfectly vertically center the element is the top edge is the pivot point when using top: 50%
on relatively positioned elements.