Conceptually, CSS rules are applied to the elements of a document in the order they appear in the HTML, i.e., in a pre-order traversal of the DOM tree. Historically, this was so that the CSS could be applied as the document was being loaded, but even with dynamic HTML and dynamic CSS, there are performance advantages to being able to apply the CSS in a single pass.
This is why CSS has no selectors for "an A followed by a B" or "an A which contains a B", whereas it's possible to say "an A preceded by a B" or "an A contained inside a B", because in the latter cases, A precedes B in a pre-order traversal.
Vertical centering is difficult because at the time the CSS for the child element (the element to be centered) is processed, the heights of the parent and child elements (the two values required to compute the top offset of the child element) are not known, as they both depend on elements which have not yet been processed.
The dependence on the height of the parent element is overcome by absolute positioning:
top: 50%. This effectively defers calculation of the vertical offset until after the height of the parent element is known.
Similarly, CSS3 transforms can account for the height of the child:
transform: translateY(-50%). Prior to CSS3, it was common to use negative
margin-top instead, but that required setting a fixed height on the child element.