The example below assumes an inline-level element in the normal flow, though the technique can be extended to block-level elements and absolutely positioned elements.
First, the HTML:
The element whose aspect ratio we want to specify has the ID “element”. The element is wrapped by a container that will be used to specify the width. Additionally, the element has a dummy element as a previous sibling that will be used the express the height as a function of the width. Effectively, the dummy element enforces the aspect ratio.
Now, the CSS:
padding-top: 75%; /* 4:3 aspect ratio */
background-color: silver /* show me! */
A working example can be seen here.
Why does this work?
display:inline-blockmakes the container an inline element that declares a new block formatting context.
position:relativegives the container a position box. The position box acts as the containing block of the inner elements. (Note: Using
position:absolutewould give the element a shrink-to-fit box that would act as the containing block of the inner elements.)
width:50%gives the box of the container a width that will be used for the aspect ratio. The width can be specified as a length or as a percentage.
padding-top:75%gives the box of the dummy element a height that is 75% of the aforementioned width, thus defining the aspect ratio. The key here is that a percentage value for
margin-bottom, for that matter) refers to the width of the containing block. Because the container is an inline-level block container, the height of the container is automatically computed as the height of the dummy element, which is based on the width of the container. Voilà, instant aspect ratio using only CSS.
position:absoluteremoves the element from the normal flow inside the container, allowing the dummy element to dictate the sizing of the container.
top/bottom/left/right:0stretches the element to the edges of the container, which are determined by the aspect ratio as per the above. The element will thus receive all user events. Set margin/border/padding to taste.
[Edit: In the explanation of
padding-top above, I swapped
margin from the original version of this post, in response to the excellent catch by Matthew and the follow-up suggestion from ciantic.]
I have tested this on the latest versions of Google Chrome, Firefox, Safari, and Opera as of this writing, with no apparent hangups.