335

I have a site with many pages and different background pictures, and I display them from CSS like:

body.page-8 {
    background: url("../img/pic.jpg") no-repeat scroll center top #000;
    background-size: cover;
}

However, I want to show different (fullscreen) pictures on one page using <img> elements, and I want them to have the same properties as the above background-image: cover; property (the images cant be displayed from CSS, they must be displayed from the HTML document).

Normally I use:

div.mydiv img {
    width: 100%;
}

Or:

div.mydiv img {
    width: auto;
}

to make the picture full and responsive. However the picture shrinks too much (width: 100%) when the screen gets too narrow, and shows the body's background-color in the bottom screen. The other method, width: auto;, only makes the image full size and does not respond to the screen size.

Is there a way to display the image the same way that background-size: cover does?

Michael
  • 8,362
  • 6
  • 61
  • 88
pat
  • 5,757
  • 5
  • 25
  • 30

14 Answers14

534

Solution #1 - The object-fit property (Lacks IE support)

Just set object-fit: cover; on the img .

body {
  margin: 0;
}
img {
  display: block;
  width: 100vw;
  height: 100vh;
  object-fit: cover; /* or object-fit: contain; */
}
<img src="https://loremflickr.com/1500/1000" alt="A random image from Flickr" />

See MDN - regarding object-fit: cover:

The replaced content is sized to maintain its aspect ratio while filling the element’s entire content box. If the object's aspect ratio does not match the aspect ratio of its box, then the object will be clipped to fit.

And for object-fit: contain:

The replaced content is scaled to maintain its aspect ratio while fitting within the element’s content box. The entire object is made to fill the box, while preserving its aspect ratio, so the object will be "letterboxed" if its aspect ratio does not match the aspect ratio of the box.

Also, see this Codepen demo which compares object-fit: cover applied to an image with background-size: cover applied to a background image


Solution #2 - Replace the img with a background image with css

body {
  margin: 0;
}

img {
  position: fixed;
  width: 0;
  height: 0;
  padding: 50vh 50vw;
  background: url("https://loremflickr.com/1500/1000") no-repeat;
  background-size: cover;
}
<img src="https://via.placeholder.com/1500x1000" alt="A random image from Flickr" />
Andy
  • 4,783
  • 2
  • 26
  • 51
Danield
  • 121,619
  • 37
  • 226
  • 255
  • 4
    At the time of this comment, object-fit is not yet supported by any version of Internet Explorer (even Edge). It is however [under consideration](https://dev.windows.com/en-us/microsoft-edge/platform/status/objectfitandobjectposition). – Mike Kormendy Jan 26 '16 at 17:01
  • 4
    object-fit is still is not supported in IE. I would stay away if on production site and you care about IE users. – Travis Michael Heller Aug 04 '16 at 16:19
  • 2
    You can also add polyfill for #1 for IE and old Safari: https://github.com/bfred-it/object-fit-images – Valera Tumash Apr 01 '17 at 21:22
  • 1
    Careful with the second solution. Best not to rely on vh on mobile browsers: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html – sudokai Dec 02 '17 at 18:53
  • Why is IE always late to the party – John R Perry Jan 28 '18 at 21:18
  • What about `background-attachment / position ` ? – RoCkDevstack Apr 14 '18 at 16:13
  • 2
    @RoCk you can find stuff like that on caniuse: https://caniuse.com/#search=background-att :) P.S. I think we can all rest assured that IE will never gain support for this feature and since there is no polyfill either, we're screwed or stuck with JS / CSS hacks until MS decides it is time to (finally) "murder" IE by removing it from Windows. – SidOfc Aug 07 '18 at 19:15
  • Check [my answer](https://stackoverflow.com/questions/11670874/is-there-an-equivalent-to-background-size-cover-and-contain-for-image-elements/51985450#answer-51985450) for an IE compatible solution. – Thiago Barcala Aug 23 '18 at 13:04
  • With `object-fit` (Solution #1) being pretty well supported with `img` across modern browsers, including Edge since v16 in Oct '17, that's our method of choice. Using it, we've found adding `max-width: 100%; max-height: 100%;` to the `img` element helps contain it to its container. – rambillo Sep 02 '19 at 16:54
  • super awsomeness :) – krupesh Anadkat Sep 23 '20 at 16:39
  • Dude, thank you so much! Damn! I thought that there was no work around for this! Cheers! Again big thank you for your answer! – Grinnex. May 25 '21 at 20:10
  • Let's say I will choose the method 2, How do I get the img src of the HTML img tag inside the css file? – Normal May 12 '22 at 21:54
33

Assuming you can arrange to have a container element you wish to fill, this appears to work, but feels a bit hackish. In essence, I just use min/max-width/height on a larger area and then scale that area back into the original dimensions.

.container {
  width: 800px;
  height: 300px;
  border: 1px solid black;
  overflow:hidden;
  position:relative;
}
.container.contain img {
  position: absolute;
  left:-10000%; right: -10000%; 
  top: -10000%; bottom: -10000%;
  margin: auto auto;
  max-width: 10%;
  max-height: 10%;
  -webkit-transform:scale(10);
  transform: scale(10);
}
.container.cover img {
  position: absolute;
  left:-10000%; right: -10000%; 
  top: -10000%; bottom: -10000%;
  margin: auto auto;
  min-width: 1000%;
  min-height: 1000%;
  -webkit-transform:scale(0.1);
  transform: scale(0.1);
}
<h1>contain</h1>
  <div class="container contain">
    <img 
       src="https://www.google.de/logos/doodles/2014/european-parliament-election-2014-day-4-5483168891142144-hp.jpg" 
       />
    <!-- 366x200 -->
  </div>
  <h1>cover</h1>
  <div class="container cover">
    <img 
       src="https://www.google.de/logos/doodles/2014/european-parliament-election-2014-day-4-5483168891142144-hp.jpg" 
       />
    <!-- 366x200 -->
  </div>
Ulrich Schwarz
  • 7,598
  • 1
  • 36
  • 48
33

There is actually quite a simple css solution which even works on IE8:

.container {
  position: relative;
  overflow: hidden;
  /* Width and height can be anything. */
  width: 50vw;
  height: 50vh;
}

img {
  position: absolute;
  /* Position the image in the middle of its container. */
  top: -9999px;
  right: -9999px;
  bottom: -9999px;
  left: -9999px;
  margin: auto;
  /* The following values determine the exact image behaviour. */
  /* You can simulate background-size: cover/contain/etc.
     by changing between min/max/standard width/height values.
     These values simulate background-size: cover
  */
  min-width: 100%;
  min-height: 100%;
}
<div class="container">
    <img src="http://placehold.it/200x200" alt="" />
</div>
Simon
  • 7,182
  • 2
  • 26
  • 42
  • 9
    This doesn't replicate the behaviour of cover, but instead crops a centered section from the src img. See http://jsfiddle.net/sjt71j99/4/ -- the first img is your crop, the next is via background-size: cover, i.e. what we want, the third is the original img. I found for landscape imgs replace min-height & min-width with max-height: 100%; for portrait use max-width: 100%. Would be nice if there were one solution that worked for either landscape or portrait. Any ideas? This is the best cross-browser solution I've seen so far. – terraling Jul 20 '15 at 17:12
  • 1
    You're right, it doesn't do the exact same thing, I tried some stuff but it seems you actually can't get it to replicate cover 100%, it works as long as the image is smaller than the container on one dimension though. – Simon Oct 26 '16 at 09:59
  • @terraling, I know it is an old comment, but check my [answer](https://stackoverflow.com/questions/11670874/is-there-an-equivalent-to-background-size-cover-and-contain-for-image-elements/51985450#answer-51985450). It uses transform to position the img in the center. – Thiago Barcala Aug 23 '18 at 12:35
23

I found a simple solution to emulate both cover and contain, which is pure CSS, and works for containers with dynamic dimensions, and also doesn't make any restriction on the image ratio.

Note that if you don't need to support IE, or Edge before 16, then you better use object-fit.

background-size: cover

.img-container {
  position: relative;
  overflow: hidden;
}

.background-image {
  position: absolute;
  min-width: 1000%;
  min-height: 1000%;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%) scale(0.1);
  z-index: -1;
}
<div class="img-container">
  <img class="background-image" src="https://picsum.photos/1024/768/?random">
  <p style="padding: 20px; color: white; text-shadow: 0 0 10px black">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
</div>

The 1000% is used here in case the image natural size is bigger than the size it is being displayed. For example, if the image is 500x500, but the container is only 200x200. With this solution, the image will be resized to 2000x2000 (due to min-width/min-height), then scaled down to 200x200 (due to transform: scale(0.1)).

The x10 factor can be replaced by x100 or x1000, but it is usually not ideal to have a 2000x2000 image being rendered on a 20x20 div. :)

background-size: contain

Following the same principle, you can also use it to emulate background-size: contain:

.img-container {
  position: relative;
  overflow: hidden;
  z-index: 0;
}

.background-image {
  position: absolute;
  max-width: 10%;
  max-height: 10%;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%) scale(10);
  z-index: -1;
}
<div style="background-color: black">
  <div class="img-container">
    <img class="background-image" src="https://picsum.photos/1024/768/?random">
    <p style="padding: 20px; color: white; text-shadow: 0 0 10px black">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
  </div>
</div>
Thiago Barcala
  • 6,463
  • 2
  • 20
  • 23
  • The scale trick is given already here [https://stackoverflow.com/a/28771894/2827823](https://stackoverflow.com/a/28771894/2827823), so I can't see the point in posting yet one more, and so is `transform` in many of the answers – Asons Aug 23 '18 at 19:56
  • If you want to expand with an explanation, update that answer instead, as there is no need for 2 with the same solution – Asons Aug 23 '18 at 19:59
  • 3
    Thank you for your comment @LGSon. I hadn't seen that answer before, but I still think my answer has its value here. The approach is pretty much the same, but in my opinion mine is presented in a slightly cleaner way. Many other answer here present the same solution, and all of them are incomplete (except for the one you linked). So if my answer shouldn't be here, so shouldn't the other ones. – Thiago Barcala Aug 24 '18 at 07:23
  • 1
    I found it shrink the image in Chrome mobile browser on Android (tested on LG G3 and Samsung S9), I didn't test it with Chrome on iOS, Firefox mobile on Android displayed it correctly. – Jecko Mar 05 '20 at 15:12
11

No, you can't get it quite like background-size:cover but..

This approach is pretty damn close: it uses JavaScript to determine if the image is landscape or portrait, and applies styles accordingly.

JS

 $('.myImages img').load(function(){
        var height = $(this).height();
        var width = $(this).width();
        console.log('widthandheight:',width,height);
        if(width>height){
            $(this).addClass('wide-img');
        }else{
            $(this).addClass('tall-img');
        }
    });

CSS

.tall-img{
    margin-top:-50%;
    width:100%;
}
.wide-img{
    margin-left:-50%;
    height:100%;
}

http://jsfiddle.net/b3PbT/

Adam Azad
  • 11,171
  • 5
  • 29
  • 70
actual_kangaroo
  • 5,971
  • 2
  • 31
  • 45
4

What you could do is use the 'style' attribute to add the background image to the element, that way you will still be calling the image in the HTML but you will still be able to use the background-size: cover css behaviour:

HTML:

    <div class="image-div" style="background-image:url(yourimage.jpg)">
    </div>

CSS:

    .image-div{
    background-size: cover;
    }

This is how I add the background-size: cover behaviour to elements that I need to dynamically load into HTML. You can then use awesome css classes like background-position: center. boom

Charlie Tupman
  • 519
  • 6
  • 11
  • 1
    Mostly separation of concerns, but here are a few others: http://programmers.stackexchange.com/a/271338 – Daan Sep 01 '16 at 09:35
3

I needed to emulate background-size: contain, but couldn't use object-fit due to the lack of support. My images had containers with defined dimensions and this ended up working for me:

.image-container {
  height: 200px;
  width: 200px;
  overflow: hidden;
  background-color: rebeccapurple;
  border: 1px solid yellow;
  position: relative;
}

.image {
  max-height: 100%;
  max-width: 100%;
  margin: auto;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}
<!-- wide -->
<div class="image-container">
  <img class="image" src="http://placehold.it/300x100">
</div>

<!-- tall -->
<div class="image-container">
  <img class="image" src="http://placehold.it/100x300">
</div>
Gus
  • 61
  • 1
2

With CSS you can simulate object-fit: [cover|contain];. It's use transform and [max|min]-[width|height]. It's not perfect. That not work in one case: if the image is wider and shorter than the container.

.img-ctr{
  background: red;/*visible only in contain mode*/
  border: 1px solid black;
  height: 300px;
  width: 600px;
  overflow: hidden;
  position: relative;
  display: block;
}
.img{
  display: block;

  /*contain:*/
  /*max-height: 100%;
  max-width: 100%;*/
  /*--*/

  /*cover (not work for images wider and shorter than the container):*/
  min-height: 100%;
  width: 100%;
  /*--*/

  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
<p>Large square:
<span class="img-ctr"><img class="img" src="http://placehold.it/1000x1000"></span>
</p>
<p>Small square:
<span class="img-ctr"><img class="img" src="http://placehold.it/100x100"></span>
</p>
<p>Large landscape:
<span class="img-ctr"><img class="img" src="http://placehold.it/2000x1000"></span>
</p>
<p>Small landscape:
<span class="img-ctr"><img class="img" src="http://placehold.it/200x100"></span>
</p>
<p>Large portrait:
<span class="img-ctr"><img class="img" src="http://placehold.it/1000x2000"></span>
</p>
<p>Small portrait:
<span class="img-ctr"><img class="img" src="http://placehold.it/100x200"></span>
</p>
<p>Ultra thin portrait:
<span class="img-ctr"><img class="img" src="http://placehold.it/200x1000"></span>
</p>
<p>Ultra wide landscape (images wider and shorter than the container):
<span class="img-ctr"><img class="img" src="http://placehold.it/1000x200"></span>
</p>
mems
  • 1,224
  • 1
  • 19
  • 27
2

We can take ZOOM approach. We can assume that max 30% (or more upto 100%) can be the zooming effect if aspect image height OR width is less than the desired height OR width. We can hide the rest not needed area with overflow: hidden.

.image-container {
  width: 200px;
  height: 150px;
  overflow: hidden;
}
.stage-image-gallery a img {
  max-height: 130%;
  max-width: 130%;
  position: relative;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
}

This will adjust images with different width OR height.

Rehmat
  • 2,121
  • 2
  • 24
  • 28
1

Try setting both min-height and min-width, with display:block:

img {
    display:block;
    min-height:100%;
    min-width:100%;
}

(fiddle)

Provided your image's containing element is position:relative or position:absolute, the image will cover the container. However, it will not be centred.

You can easily centre the image if you know whether it will overflow horizontally (set margin-left:-50%) or vertically (set margin-top:-50%). It may be possible to use CSS media queries (and some mathematics) to figure that out.

Jeremy
  • 2,642
  • 18
  • 36
0

im not allowed to 'add a comment' so doing this , but yea what Eru Penkman did is pretty much spot on , to get it like background cover all you need to do is change

.tall-img{
    margin-top:-50%;
    width:100%;
}
.wide-img{
    margin-left:-50%;
    height:100%;
}

TO

.wide-img{
    margin-left:-42%;
    height:100%;
}
.tall-img{
    margin-top:-42%;
    width:100%;
}
Asim Ramay
  • 13
  • 3
0

I know this is old, however many solutions I see above have an issue with the image/video being too large for the container so not actually acting like background-size cover. However, I decided to make "utility classes" so that it would work for images and videos. You simply give the container the class .media-cover-wrapper and the media item itself the class .media-cover

Then you have the following jQuery:

function adjustDimensions(item, minW, minH, maxW, maxH) {
  item.css({
  minWidth: minW,
  minHeight: minH,
  maxWidth: maxW,
  maxHeight: maxH
  });
} // end function adjustDimensions

function mediaCoverBounds() {
  var mediaCover = $('.media-cover');

  mediaCover.each(function() {
   adjustDimensions($(this), '', '', '', '');
   var mediaWrapper = $(this).parent();
   var mediaWrapperWidth = mediaWrapper.width();
   var mediaWrapperHeight = mediaWrapper.height();
   var mediaCoverWidth = $(this).width();
   var mediaCoverHeight = $(this).height();
   var maxCoverWidth;
   var maxCoverHeight;

   if (mediaCoverWidth > mediaWrapperWidth && mediaCoverHeight > mediaWrapperHeight) {

     if (mediaWrapperHeight/mediaWrapperWidth > mediaCoverHeight/mediaCoverWidth) {
       maxCoverWidth = '';
       maxCoverHeight = '100%';
     } else {
       maxCoverWidth = '100%';
       maxCoverHeight = '';
     } // end if

     adjustDimensions($(this), '', '', maxCoverWidth, maxCoverHeight);
   } else {
     adjustDimensions($(this), '100%', '100%', '', '');
   } // end if
 }); // end mediaCover.each
} // end function mediaCoverBounds

When calling it make sure to take care of page resizing:

mediaCoverBounds();

$(window).on('resize', function(){
  mediaCoverBounds();
});

Then the following CSS:

.media-cover-wrapper {
  position: relative;
  overflow: hidden;
}

.media-cover-wrapper .media-cover {
  position: absolute;
  z-index: -1;
  top: 50%;
  left: 50%;
  -ms-transform: translate(-50%, -50%);
  -moz-transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

Yeah it may require jQuery but it responds quite well and acts exactly like background-size: cover and you can use it on image and/or videos to get that extra SEO value.

Secular12
  • 53
  • 4
-1

For IE6 you also need to include the second line - width: 100%;

.mydiv img {
    max-width: 100%;
    width: 100%;
}
 
фымышонок
  • 1,362
  • 16
  • 22
-2
background:url('/image/url/') right top scroll; 
background-size: auto 100%; 
min-height:100%;

encountered same exact symptops. above worked for me.