Bumming off Chris's idea, another option is to use pseudo elements so you don't need to use an absolutely positioned internal element.
<style>
.square {
/* width within the parent.
can be any percentage. */
width: 100%;
}
.square:before {
content: "";
float: left;
/* essentially the aspect ratio. 100% means the
div will remain 100% as tall as it is wide, or
square in other words. */
padding-bottom: 100%;
}
/* this is a clearfix. you can use whatever
clearfix you usually use, add
overflow:hidden to the parent element,
or simply float the parent container. */
.square:after {
content: "";
display: table;
clear: both;
}
</style>
<div class="square">
<h1>Square</h1>
<p>This div will maintain its aspect ratio.</p>
</div>
I've put together a demo here: http://codepen.io/tcmulder/pen/iqnDr
EDIT:
Now, bumming off of Isaac's idea, it's easier in modern browsers to simply use vw units to force aspect ratio (although I wouldn't also use vh as he does or the aspect ratio will change based on window height).
So, this simplifies things:
<style>
.square {
/* width within the parent (could use vw instead of course) */
width: 50%;
/* set aspect ratio */
height: 50vw;
}
</style>
<div class="square">
<h1>Square</h1>
<p>This div will maintain its aspect ratio.</p>
</div>
I've put together a modified demo here: https://codepen.io/tcmulder/pen/MdojRG?editors=1100
You could also set max-height, max-width, and/or min-height, min-width if you don't want it to grow ridiculously big or small, since it's based on the browser's width now and not the container and will grow/shrink indefinitely.
Note you can also scale the content inside the element if you set the font size to a vw measurement and all the innards to em measurements, and here's a demo for that: https://codepen.io/tcmulder/pen/VBJqLV?editors=1100