142

Let's say I've got a div that has a width of 50% of the body. How do I make its height equal to that value? So that when the browser window is 1000px wide, the div's height and width are both 500px.

TylerH
  • 20,799
  • 66
  • 75
  • 101
HankSmackHood
  • 4,673
  • 7
  • 29
  • 30
  • it can't be done in straight css. the js solution is simple though. – Ben Lee Apr 08 '12 at 12:40
  • 7
    It can actually be done with CSS alone. See Fadi's answer. – Adam Waite Feb 11 '13 at 22:58
  • Another approach, which also works for setting the width in terms of the height (unlike the padding approach), can be found [here](http://stackoverflow.com/questions/6148012/setting-element-width-based-on-height-via-css) – Kevin Wheeler Jul 11 '15 at 01:11
  • This is not a duplicate of the linked question. This question specifically asks about basing the square on height, not width - a much different problem. – Sandy Gifford Dec 01 '16 at 20:59
  • **Pure JS approach**: `el=document.getElementById('id_div')` `el.style.height=el.offsetWidth+"px"` This will give u a perfect square. Make your JS file execute this code when page loads -- `window.onload` – Aseem Apr 26 '19 at 22:11
  • Assuming 100% of the width of the div in question is the same as 100vw, why not just use vw? Is there a good reason? – John Miller Dec 19 '22 at 03:09

4 Answers4

152

This can actually be done with only CSS, but the content inside the div must be absolutely positioned. The key is to use padding as a percentage and the box-sizing: border-box CSS attribute:

div {
  border: 1px solid red;
  width: 40%;
  padding: 40%;
  box-sizing: border-box;
  position: relative;
}
p {
  position: absolute;
  top: 0;
  left: 0;
}
<div>
  <p>Some unnecessary content.</p>
</div>

Adjust percentages to your liking. Here is a JSFiddle

TylerH
  • 20,799
  • 66
  • 75
  • 101
Fadi
  • 1,770
  • 4
  • 13
  • 10
  • 5
    I understand that `width: 40%` is 40% of the parent element, but what is the `padding: 40%` in relation to? – Ryan Mar 05 '13 at 16:49
  • 1
    The padding is what gives the box equal width and height. It 'inflates' the inside of the box with padding. – Fadi Apr 25 '13 at 23:44
  • 3
    Firefox seems to have an issue on that method, but it's simple to fix. If you want a 50% box, you need "padding: 25%;". 25% on each side. – jurihandl Aug 15 '13 at 07:39
  • At least in Chrome, the width value is almost unnecessary. It basically needs to be anything that's not 100% - the actual size of the box is set by the padding. (And Chrome exhibits the same behavior as jurihandl mentioned for Firefox.) – Ben Visness Jun 10 '14 at 15:50
  • @BenjaminVisness You're mostly correct in that the width can be any value, but the value can't be left out or the width will default to 100%. – Fadi Jun 23 '14 at 16:43
  • @Fadi That's why I said it was "almost" unnecessary - the value is irrelevant, but it much be present (and not 100%) in order for this to work. – Ben Visness Jun 23 '14 at 18:49
  • @BenjaminVisness ahh I read almost as "at most" :) Thanks! – Fadi Jun 25 '14 at 15:14
  • This technique was a tremendous help, thank you! – wordman Aug 20 '14 at 21:56
  • I would say that width must not be more than DOUBLE of padding, as if it was, it would be larger than its padding-computed width. checked in chrome – Rayjax Sep 29 '14 at 13:52
  • 97
    I hate how you can do 3D transforms, shadows, rounded corners, etc easily in CSS, but to have a square div requires a hack... – Jonathan. Sep 29 '14 at 17:45
  • I vote this as the best answer. I need a 4/3 ratio for photos and wanted a purely CSS solution. Much appreciated. (So I'll tweak the padding for my use. padding: 37.5% 50%;) – Andrew Leyva Oct 10 '14 at 15:06
  • 3
    @Ryan the `padding: 40%` is in relation to the width of the element (including padding-top and padding-bottom). Definitely surprised me, there's a good explanation on [another question](http://stackoverflow.com/a/10441480/1314762). – Don McCurdy Jul 07 '15 at 18:54
  • the problem is the width percentage set is not what we expect du to padding acting on it. For example, I couldn't use this technique for three inline-block divs with 33% width... As @implum suggested, setting padding-top instead of padding works better. – TrtG Nov 04 '15 at 11:03
  • Padding should be 40% 0 0 0 – NicolasBernier Oct 06 '16 at 08:05
  • @Jonathan, yes. Try cetering things vertically :p Flex. – Kevin Parker Dec 03 '19 at 20:05
  • 1
    @DonMcCurdy That is actually incorrect. The `padding: 40%` is in relation to the with of the *containing* element, not the element itself. So if the container is `1000px` wide, and `padding-bottom: 40%` is applied to its direct descendant, the calculated value of padding will be `400px` regardless of the width of the descendant. – Ejaz Apr 29 '20 at 16:05
37

This can be done with a CSS hack (see the other answers), but it can also be done very easily with JavaScript.

Set the div's width to (for example) 50%, use JavaScript to check its width, and then set the height accordingly. Here's a code example using jQuery:

$(function() {
    var div = $('#dynamicheight');
    var width = div.width();
    
    div.css('height', width);
});
#dynamicheight
{
    width: 50%;
    
    /* Just for looks: */
    background-color: cornflowerblue;
    margin: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="dynamicheight"></div>

If you want the box to scale with the browser window on resize, move the code to a function and call it on the window resize event. Here's a demonstration of that too (view example full screen and resize browser window):

$(window).ready(updateHeight);
$(window).resize(updateHeight);

function updateHeight()
{
    var div = $('#dynamicheight');
    var width = div.width();
    
    div.css('height', width);
}
#dynamicheight
{
    width: 50%;
    
    /* Just for looks: */
    background-color: cornflowerblue;
    margin: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="dynamicheight"></div>
Hubro
  • 56,214
  • 69
  • 228
  • 381
  • 31
    You don't need javascript for that. You can do as mentioned below: height: 0px; width: 40%; padding-top: 40%; – Chris Andersson Feb 25 '14 at 08:50
  • As mentioned above using JavaScript is totally unnecessary and presents problems such as FOUC or worse, disabled JS (nothing will happen). Go with the CSS method. – Bill Nov 05 '14 at 14:35
  • 1
    @Billy: "totally unnecessary"? You're forgetting that the CSS method below has some tight restrictions. The Javascript method will work in all scenarios where Javascript is enabled. – Hubro Nov 05 '14 at 14:40
  • @Hubro "tight restrictions"? – Bill Nov 05 '14 at 15:00
  • @Billy: At first glance, the div appears to need a set width and absolutely positioned content. Also, taking a look at the comments, the results appear to vary between browsers – Hubro Nov 05 '14 at 15:06
  • The OP specifically said he wants a div with a set width to have the height reflect that.. The most upvoted answer (which still works without box-sizing: border-box) only uses standard CSS and will work everywhere. No comment on the FF issue though.. :P – Bill Nov 05 '14 at 15:34
15
<div><p>some unnecessary content</p></div>

div{
    border: 1px solid red;
    width: 40%;
    padding: 40%;
    box-sizing: border-box;
    position: relative;
}
p{
    position: absolute;
    top: 0;
    left: 0;
}

For this to work i think you need to define the padding to ex. top? like this:

<div><p>some unnecessary content</p></div>

div{
    border: 1px solid red;
    width: 40%;
    padding-top: 40%;
    box-sizing: border-box;
    position: relative;
}
p{
    position: absolute;
    top: 0;
    left: 0;
}

anyways, thats how i got it to work, since with just padding all arround it would not be a square.

implum
  • 231
  • 2
  • 7
  • Thank you ! The above answer did render a square but it was not 40% width of its parent. – TrtG Nov 04 '15 at 11:08
10

I made a CSS approach to this that is sized by the viewport width, but maxes out at 100% of the viewport height. It doesn't require box-sizing:border-box. If a pseudo element cannot be used, the pseudo-code's CSS can be applied to a child. Demo

.container {
  position: relative;
  max-width:100vh;
  max-height:100%;
  margin:0 auto;
  overflow: hidden;
}
.container:before {
  content: "";
  display: block;
  margin-top: 100%;
}
.child {
  position: absolute;
  top: 0;
  left: 0;
}

Support table for viewport units

I wrote about this approach and others in a CSS-Tricks article on scaling responsive animations that you should check out.

Zach Saucier
  • 24,871
  • 12
  • 85
  • 147