24

As discussed here I am trying to get an image to be covered within a div. With just these simple lines I was able to achieve this via background-image:

div{
    width: 172px;
    height: 172px;
    border-style: solid;
    background-image: url('../images/img1.jpg');
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
}

In result the image was centered within the div and was resized so it would fit the width or the height of the div (depending if the image was wide or not). Now I would like to achieve the same result with the image tag within the div.

<div>
  <img src="images/img1.jpg"/>
</div>

Is there any way to get through this with plain CSS?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
PLAYCUBE
  • 795
  • 4
  • 14
  • 24

3 Answers3

70

Use object-fit:cover to not lose ratio.

div {
  border: black solid;
  width: 400px;
  height: 400px;
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover
}
<div>
  <img src="//loremflickr.com/100/100" />
</div>

NOTE: this is not supported in IE


It doesn't work in IE (by the way, it is an outdated browser, so please educate your clients to use at least the upgraded browser EDGE), but there are a few object-fit polyfills out there that will make object-fit work.

Here are a few examples:

Or if you think its an overkill using a polyfill just for that property, here is simple snippet that will make this work in IE.

You can use a simple JS snippet to detect if the object-fit is supported and then replace the img for a svg

//for browsers which doesn't support object-fit (you can use babel to transpile to ES5)

if ('objectFit' in document.documentElement.style === false) {
    document.addEventListener('DOMContentLoaded', () => {
        document.querySelectorAll('img[data-object-fit]').forEach(image => {
            (image.runtimeStyle || image.style).background = `url("${image.src}") no-repeat 50%/${image.currentStyle ? image.currentStyle['object-fit'] : image.getAttribute('data-object-fit')}`
            image.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${image.width}' height='${image.height}'%3E%3C/svg%3E`
        })
    })
}
img {
  display: inline-flex;
  width: 175px;
  height: 175px;
  margin-right: 10px;
  border: 1px solid red
}

/*for browsers which support object fit */

[data-object-fit='cover'] {
  object-fit: cover
}

[data-object-fit='contain'] {
  object-fit: contain
}
<img data-object-fit='cover' src='//picsum.photos/1200/600' />
<img data-object-fit='contain' src='//picsum.photos/1200/600' />
<img src='//picsum.photos/1200/600' />
E_net4
  • 27,810
  • 13
  • 101
  • 139
dippas
  • 58,591
  • 15
  • 114
  • 126
  • I believe what the OP is requesting for is a background image of some sort where you can write over other elements on top of it. – Wax May 20 '17 at 23:07
  • 1
    Wow, worked for me! Thank you very much! I am working a little bit with drag and drop and try to swap images. That's why I switched from background image method to using img tags :) – PLAYCUBE May 20 '17 at 23:09
  • 1
    object-fit: cover works great but the image is still not centered. It starts form the left top. how do you center the image with the object-fit method? – Babulaas Jan 31 '18 at 12:53
  • @Babulaas you probably dont want 'cover' but something else like 'fill'. https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit – AussieJoe Aug 08 '18 at 15:27
7

If you want to recreate the background-size: cover; look without using a CSS background image, you can use the following to achieve the desired result. Keep in mind, however, that there will always need to be a container holding the image.

div {
    position: relative;
    overflow: hidden;
}
img {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    min-width: 100%;
    min-height: 100%;
    height: auto;
    width: auto;
}

Depending on your additional CSS, you might want to use max-width and max-height.

jjcarlson
  • 73
  • 1
  • 5
2

Try this:

div {
    position:relative;
}
img {
    max-height: 100%;
    max-width: 100%;
    margin: auto;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
}

This assumes you have given a size to the div.

Tom_B
  • 307
  • 2
  • 8
  • This one wins because it is cross browser. – Matt Wilson Sep 11 '18 at 23:04
  • Unless I'm mistaken, I think this will stretch and distort the image away from it's native aspect ratio, unlike `background-size: cover`. – Simon East Feb 21 '19 at 03:21
  • That is incorrect, height: 100%; and width: 100%; would distort the image. max-height and max-width maintains the aspect ratio. Give it a try :) – Tom_B Feb 21 '19 at 11:33
  • Sorry, but it stretches the image respectively shrinks it to a smaller size. – elysian-design Mar 14 '19 at 13:31
  • https://www.w3schools.com/css/tryit.asp?filename=tryresponsive_image2 Change the css to img {max-height: 100%;max-width: 100%;} to see how it works, no stretching or distortion occurs – Tom_B Mar 15 '19 at 10:06
  • 2
    this is like background-size: contain and not cover – DRC Mar 25 '19 at 18:15
  • For me the perfect solution was using this answer combined with the object-fit: cover. Maybe had a different setup, but this was stretching the image for me. – matiss.andersons Sep 08 '20 at 08:01