19

I want to achieve the following for an <img> element in HTML, using only CSS:

width: calc(100% - 20px)
height: calc(width * 0.5625) /*16:9 aspect ratio*/

There are similair examples all over the internet regarding <div> elements and their background. But in the case of <img> elements, changing the padding does not work

Similair example: Maintain the aspect ratio of a div with CSS

Edit, using jQuery one can achieve the above with:

$(".myImage/s").outerHeight($(".myImage/s").outerWidth() * 0.5625);
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Alexander
  • 921
  • 3
  • 12
  • 31
  • i think you can do it without javascript http://stackoverflow.com/questions/17672010/set-the-height-of-a-div-to-be-half-of-whatever-the-width-is – melbx Oct 15 '16 at 17:46
  • Why do you want that? ... Asking because the img is sized by the image, in the div case it is not, and if you want to do that with an image, use a div – Asons Oct 15 '16 at 17:47
  • @LGSon Are you recommending using a div as a container and nesting the img inside of it, or just using the div and setting the image as the background? – Alexander Oct 15 '16 at 17:57
  • It depends, what I tried to say initally was, if you force an `img` to do that the image it holds will be distorted, but if the image already has the wanted ratio, just set either its height or width and it will always keep its ratio. If you want it to be cropped at a certain ratio, use a `div` and its `background-image` property – Asons Oct 15 '16 at 18:06

5 Answers5

26

CSS has a built-in property called aspect-ratio just assign it to the element after height or width has been defined. CSS-tricks has an example and I made a code snippet below.

div{
  width:50vw;
  border: 2px solid black;
  border-radius: 15px;
  margin:5px;
  aspect-ratio: 16/9;
 }
<div>
</div>
SamsonTheBrave
  • 527
  • 4
  • 10
  • 1
    As of iOS 15 this is now officially supported. See the chart from Mozilla https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio – SamsonTheBrave Jan 20 '22 at 17:55
  • This should be the accepted answer. I've spent hours hunting for a solution that works for me (`div`s as direct children of a flexbox, each containing an image of the same aspect ratio, but refuse to be as tall as the image they contain). All the answers I found across SO were hacky or not helpful. This one worked right out of the box, no hacks, and is compatible across all browsers. – Karthik Sivasubramaniam Sep 08 '22 at 20:32
15

Use viewport-width (vw) for defining width in the height property:

width: calc(100% - 20px)
height: calc((100vw - 20px) * 0.5625) /*16:9 aspect ratio*/

The viewport is the visible area of the web page.

Its full size is 100vw * 100vh, where vw and wh are the viewports size units.

Thus one "vw" is equal to 1% of the web page's currently visible width.

More can be found at: Viewport units: vw, vh, vmin, vmax

HelpingHand
  • 1,045
  • 11
  • 26
  • Was about to comment about this; are you sure that you can use the vw in the height property? Never tried it before, assumed it just would not work – vladdobra Oct 15 '16 at 17:54
  • Yeah, viewport-width and viewport-height are just variables which are defined for use. They may not be accurate depending on usage of meta tags for device-width and other things... – HelpingHand Oct 15 '16 at 17:57
  • @HelpingHand it works! It's my first time using viewport units, so I added a brief explanation of the units to your answer, for future novice readers – Alexander Oct 15 '16 at 18:22
  • @HelpingHand What if my widht is set to a fixed (example) 500px, is there anything I could use instead of viewport in this case? – Alexander Oct 15 '16 at 18:23
  • @Alexander Yes... 500px... Plus, if you are manipulating the viewport-width manually, `100vw` will still equal 500px. – HelpingHand Oct 15 '16 at 18:26
  • @HelpingHand sorry, wasn't clear enough. Let's say the img is within a div, that is within another div and so on. Consequently I don't know, whether the width is 499, 500, or 501px. Only thing I do know is, I can't fiddle with any of the div's sizes. Can I still achieve something similair to "height = width * 0.56" for the image? – Alexander Oct 15 '16 at 18:30
  • @Alexander I'm not proficient in this aspect of CSS as it is still experimental, but I believe you are looking for [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables), where you would set the calculated width into a variable and use that variable in your height calculation. – HelpingHand Oct 15 '16 at 18:32
10

the proposed solutions so far use vw which only work if you want the image to fill the entire page.

but there is a much cleaner solution that keep the image aspect ratio 9/16 in all size containers.

HTML:

...
<div class="image image-9-16"> <!-- replace image and image-9-16 with any name you like -->
    <img src="..." />
</div>
...

CSS:

.image {
    position: relative;
    display: block;
    width: calc(100% - 20px);
    max-width: calc(100% - 20px);
    height: auto;
    max-height: 100%;
    padding: 0;
    margin: 0;
    overflow: hidden;
}

.image::before {
    display: block;
    content: "";
}

.image, .image img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.image-9-16::before {
    padding-top: 56.25%;
}

and that'll work no matter the width of the container holding the image with no need to place the image as a background-image... and now you can even add more aspect ratios if you want...

.image-1-1::before {
    padding-top: 100%;
}

.image-3-4::before {
    padding-top: 75%;
}

.image-9-21::before {
    padding-top: 42.857143%;
}
...
thothlike
  • 145
  • 1
  • 9
1

This worked for me using the actual ratio… then I needed a max dimension, so make sure you set them before setting the height:

position: relative;
margin: 0 auto;
width: 100vw;
max-width: 1080px;
max-height: 1920px;
height: calc(100vw * (16/9));
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
Joe Berry
  • 26
  • 5
0

you can use vw (viewport width) to do that:

width: calc(100vw - 20px);
height: calc((100vw - 20px) * 0.5625); /*16:9 aspect ratio*/

You can also use the padding-bottom method if you place the image as a background for the div.

https://jsfiddle.net/m11L9kjb/1/

hector22x
  • 104
  • 6
  • oh,.. sorry, you answered just while i was creating the jsfidle. Was not copy paste. I added something else, but will be glad to delete my answer if you think it's copy paste, but it's not. @HelpingHand – hector22x Oct 15 '16 at 18:16
  • @hector22x What if my widht is set to a fixed (example) 500px, is there anything I could use instead of viewport in this case? ___ PS: HelpingHand beat you to the answer, so his is marked as correct. Voted your answer up for the help ;) – Alexander Oct 15 '16 at 18:25
  • @Alexander if your widht is fixed then you can use that fixed value instead of '100vw'. If not, then I don't get your question. And yes, he was faster than me, so it's ok. – hector22x Oct 15 '16 at 18:32
  • @hector22x thanks for the reply. What I wanted to say was, what would one do, if the "img" is nested inside of other elements, whos widths are unknown. I posted the same question to the above answer, please feel free to reply with possible suggestions – Alexander Oct 15 '16 at 18:52
  • @Alexander Ah, I get it. Then I will go with the div option, placing the image as background. That is my preferred option by the way because it gives you more control over the image (for example, you can force the it to fill the container while keeping the aspect ration of the original image). You may also wrap the img tag inside the div (`padding-bottom: 56%; position: relative`) with styles `position: absolute; width: 100%; height:100%`. – hector22x Oct 15 '16 at 19:25
  • I still can't comment on other's answers, but I was checking the above one, about CSS Variables if you check the link it says that it's an experimental feature and the compatibility table doesn't look good.Additionally, for things like size I would prefer to have it as responsive as posible (using dinamic units, like %), but that's a personal opinion. – hector22x Oct 15 '16 at 19:45
  • I agree, using a div either as a container, or as the element, whos background is the image gives you more control and would be the preffered way to go in the future. Thanks for the help – Alexander Oct 16 '16 at 08:43