600

Is it possible to set same height as width (ratio 1:1)?

Example

+----------+
| body     |
| 1:3      |
|          |
| +------+ |
| | div  | |
| | 1:1  | |
| +------+ |
|          |
|          |
|          |
|          |
|          |
+----------+

CSS

div {
  width: 80%;
  height: same-as-width
}
web-tiki
  • 99,765
  • 32
  • 217
  • 249
Thomas Norman
  • 6,003
  • 3
  • 15
  • 4
  • 15
    After Nathan's solution, there is a solution by ❝Kristijan❞ that is even more simpler. Without dummy-elements. – Ideogram Sep 13 '13 at 08:40

9 Answers9

794

[Update: Although I discovered this trick independently, I’ve since learned that Thierry Koblentz beat me to it. You can find his 2009 article on A List Apart. Credit where credit is due.]

I know this is an old question, but I encountered a similar problem that I did solve only with CSS. Here is my blog post that discusses the solution. Included in the post is a live example. Code is reposted below.

#container {
  display: inline-block;
  position: relative;
  width: 50%;
}

#dummy {
  margin-top: 75%;
  /* 4:3 aspect ratio */
}

#element {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: silver/* show me! */
}
<div id="container">
  <div id="dummy"></div>
  <div id="element">
    some text
  </div>
</div>
Robert Synoradzki
  • 1,766
  • 14
  • 20
Nathan Ryan
  • 12,893
  • 4
  • 26
  • 37
  • 34
    It works because margin/padding-top/bottom, when specified as a percentage, is determined according to the *width* of the containing element. Essentially, you have a situation where "vertical" properties can be sized with respect to a "horizontal" property. This isn't an exploit or a hack, because this is how the CSS specification is defined. – Nathan Ryan Dec 26 '12 at 18:25
  • 148
    This can be improved by using the `:before` pseudo-element. `#container:before{content:"";display:block;margin-top:100%;}` – Connor Peet Mar 09 '13 at 01:34
  • 56
    Here's a fiddle for the pseudo-element solution: http://jsfiddle.net/B8FU8/2441/ – Ernests Karlsons Apr 09 '13 at 10:38
  • ☹️ when used with an image it cuts the excess like `overflow:hidden`. – Jose Manuel Abarca Rodríguez Dec 22 '22 at 16:03
  • Thank you, thank you, thank you, thank you!!! – Shmack Jul 22 '23 at 23:47
545

There is a way using CSS!

If you set your width depending on the parent container you can set the height to 0 and set padding-bottom to the percentage which will be calculated depending on the current width:

.some_element {
    position: relative;
    width: 20%;
    height: 0;
    padding-bottom: 20%;
}

This works well in all major browsers.

JSFiddle: https://jsfiddle.net/ayb9nzj3/

Kevin Ghadyani
  • 6,829
  • 6
  • 44
  • 62
Kristijan
  • 5,827
  • 1
  • 13
  • 21
264

Best method now : the aspect-ratio property

div {
  aspect-ratio : 1 / 1;
  width:50%;
  border:1px solid red;
}
<div>Aspect ratio : 1 / 1</div>

This is the most simple and flexible solution. It directly specifies a fixed width to height (or height to width) aspect ratio for an element. This means you can also specify an aspect ratio according to the elements height.
It doesn't rely on the parent width (like the padding technique) or the viewport size (like the following vw unit technique) it relies on the element's own width or height More info on MDN. That is what make it so powerfull compared to other workarounds.

This is a modern property (2021). All modern browsers support it, see caniuse for precise browser support.


Other method with vw:

You can use vw units for a responsive height/width according to the viewport width.

vw : 1/100th of the width of the viewport. (Source MDN)

You can also look into vh, vmin and vmax units to se apsect ratio according to other viewport sizes (see here)

div{
    width:20vw;
    height:60vw; /* <-- 3 x width */
    background:gold;
}

div > div{
    width:15vw;
    height:15vw; /* <-- same as width */
    background:red;
}
<div>
  1:3 aspect ratio
  <div>1:1 aspect ratio</div>
</div>

Table to calculate height according to the desired aspect ratio and width of element.

   aspect ratio  |  multiply width by
    -----------------------------------
         1:1      |         1
         1:3      |         3
         4:3      |        0.75
        16:9      |       0.5625

This technique allows you to :

  • insert any content inside the element without using position:absolute;
  • no unecessary HTML markup (only one element)
  • adapt the elements aspect ratio according to the height of the viewport using vh units
  • you can make a responsive square or other aspect ratio that alway fits in viewport according to the height and width of the viewport (see this answer : Responsive square according to width and height of viewport or this demo)

These units are supported by IE9+ see canIuse for more info

web-tiki
  • 99,765
  • 32
  • 217
  • 249
129

It is possible without any Javascript :)

The HTML:

<div class='box'>
    <div class='content'>Aspect ratio of 1:1</div>
</div> 

The CSS:

.box {
    position: relative;
    width:    50%; /* desired width */
}

.box:before {
    content:     "";
    display:     block;
    padding-top: 100%; /* initial ratio of 1:1*/
}

.content {
    position: absolute;
    top:      0;
    left:     0;
    bottom:   0;
    right:    0;
}

/* Other ratios - just apply the desired class to the "box" element */
.ratio2_1:before{
    padding-top: 50%;
}
.ratio1_2:before{
    padding-top: 200%;
}
.ratio4_3:before{
    padding-top: 75%;
}
.ratio16_9:before{
    padding-top: 56.25%;
}
Max S.
  • 1,383
  • 14
  • 25
Sathran
  • 1,288
  • 1
  • 9
  • 7
85

Using jQuery you can achieve this by doing

var cw = $('.child').width();
$('.child').css({'height':cw+'px'});

Check working example at http://jsfiddle.net/n6DAu/1/

chridam
  • 100,957
  • 23
  • 236
  • 235
Hussein
  • 42,480
  • 25
  • 113
  • 143
74

Extremely simple method jsfiddle

HTML

<div id="container">
    <div id="element">
        some text
    </div>
</div>

CSS

#container {
    width: 50%; /* desired width */
}

#element {
    height: 0;
    padding-bottom: 100%;
}
Ninjakannon
  • 3,751
  • 7
  • 53
  • 76
12

Expanding upon the padding top/bottom technique, it is possible to use a pseudo element to set the height of the element. Use float and negative margins to remove the pseudo element from the flow and view.

This allows you to place content inside the box without using an extra div and/or CSS positioning.

.fixed-ar::before {
  content: "";
  float: left;
  width: 1px;
  margin-left: -1px;
}
.fixed-ar::after {
  content: "";
  display: table;
  clear: both;
}


/* proportions */

.fixed-ar-1-1::before {
  padding-top: 100%;
}
.fixed-ar-4-3::before {
  padding-top: 75%;
}
.fixed-ar-16-9::before {
  padding-top: 56.25%;
}


/* demo */

.fixed-ar {
  margin: 1em 0;
  max-width: 400px;
  background: #EEE url(https://lorempixel.com/800/450/food/5/) center no-repeat;
  background-size: contain;
}
<div class="fixed-ar fixed-ar-1-1">1:1 Aspect Ratio</div>
<div class="fixed-ar fixed-ar-4-3">4:3 Aspect Ratio</div>
<div class="fixed-ar fixed-ar-16-9">16:9 Aspect Ratio</div>
Salman A
  • 262,204
  • 82
  • 430
  • 521
5

width: 80vmin; height: 80vmin;

CSS does 80% of the smallest view, height or width

http://caniuse.com/#feat=viewport-units

4

really this belongs as a comment to Nathan's answer, but I'm not allowed to do that yet...
I wanted to maintain the aspect ratio, even if there is too much stuff to fit in the box. His example expands the height, changing the aspect ratio. I found adding

overflow: hidden;
overflow-x: auto;
overflow-y: auto;

to the .element helped. See http://jsfiddle.net/B8FU8/3111/

craq
  • 1,441
  • 2
  • 20
  • 39