如何在<img>标签上模拟background-size: cover?

69

如何调整并重定位盒子内的图像,使其覆盖整个盒子,类似于background-size: cover的工作方式。

<div class="box" style="width: 100px; height: 100px;">
  <img src="pic.jpg" width="413" height="325">
</div>

我知道我需要在盒子中添加overflow:hidden,并且图像需要position:absolute。但是,有什么公式可以让我得到正确的图像新尺寸以及左侧和顶部位置吗?


$('.box').each(function(i) { $(this).children('img:first').height($(this).height()).width($(this).width()).css({ position: 'absolute', top: 0, left: 0 }); }) - SpYk3HH
@SpYk3HH 这与 background-size: cover 不同,而是相同的 background: 100% 100% - MattDiamant
你想要图片也居中还是只是足够大?我正在看这个示例,它不会将图像居中。http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=cover - TreeTree
不太确定你想要什么,因为覆盖是固有的背景定位。这似乎对于内部img元素来说有点不好的姿势,但我想你可以尝试一个精确的公式,虽然我自己也不确定那个公式。 - SpYk3HH
@TreeTree:是的,那是我的错误。我以为背景大小覆盖也会居中图片 :P (也许还需要背景位置:中心?) - Alex
我认为将其设置为居中只有在图像比容器小的情况下才起作用。如果您的图像是容器大小的两倍,它仍将定位到左上角。 - TreeTree
15个回答

175

值得一提的是:现在可以仅使用CSS完成以下功能...

新的CSS属性object-fit(目前浏览器支持情况)

只需在img上设置object-fit: cover;

甚至不需要将img包裹在一个div中!

演示

img {
  width: 100px;
  height: 100px;
}
.object-fit {
  display: block;
  object-fit: cover;
}
.original {
  width: auto;
  height: auto;
  display: block;
}
<img src="http://lorempixel.com/413/325/food" width="413" height="325">
<p>Img 'squashed' - not good</p>
<img class="object-fit" src="http://lorempixel.com/413/325/food" width="413" height="325">
<p>object-fit: cover -
   The whole image is scaled down or expanded till it fills the box completely, the aspect ratio is maintained. This normally results in only part of the image being visible. </p>
<img class="original" src="http://lorempixel.com/413/325/food" width="413" height="325">
<p>Original ing</p>

您可以在这篇WebPlatform文章中了解有关这个新属性的更多信息。

此外,这是上述文章中展示object-fit属性所有值的演示版


25
不太明白为什么没有支持IE11的情况下,这个问题还能获得这么多的投票。 - Ricky Boyce
8
当然,我愿意这么做,但我被迫把IE当作一个亲爱的父亲般对待。 - Ricky Boyce
@Toskan 这不是被接受的答案,因为它缺乏IE支持。IE很糟糕,但如果它在IE中完全不支持,则它不是完全兼容的解决方案。仍有许多组织仍然停留在IE上,这很不幸,但仍使其成为基本兼容性标准的要求。使用正在逐渐减少,我希望IE不会成为未来的因素,因为就像这种情况一样。 - FiLeVeR10
5
你可以在那些已经过时的浏览器中使用polyfill,链接为https://github.com/bfred-it/object-fit-images。 - Jair Reina
1
IE11的使用率每个月都在下降...这个答案将成为被接受的答案。 - Markus Siebeneicher
@RickyBoyce 很多人都忽略IE,因为它以其异常而闻名。 - Mohammed Shareef C

57

使用img标签模拟background-size:cover的纯CSS解决方案,浏览器支持非常好(IE8+):

.container {

  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;

  overflow: hidden;

}

.container img {

  position: absolute;
  top: 50%;
  left: 50%;

  width: auto;
  height: auto;

  max-height: none;
  max-width: none;

  min-height: 100%;
  min-width: 100%;

  transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);

}
<div class="container">
  <img src="//lorempixel.com/400/200/sports/1/" />
</div>


1
很棒的解决方案!但是它在IE8上无法工作。这只适用于IE9+。更多信息请参见:http://caniuse.com/#feat=transforms2d - Junaid Bhura
当我使用你的解决方案时,图像只是被拉伸以适应容器。我做错了什么吗? - bumbleshoot
1
@torjinx 看起来这个解决方案只能扩展较小的图像,无法缩小比容器大得多的图像。 - bendman
这应该是被接受的答案!简单易用,在任何地方都得到支持,而且正好做了它应该做的事情。谢谢! - vedsil

10

这可能更容易

jQuery

$('.box').each(function() {
    //set size
    var th = $(this).height(),//box height
        tw = $(this).width(),//box width
        im = $(this).children('img'),//image
        ih = im.height(),//inital image height
        iw = im.width();//initial image width
    if (ih>iw) {//if portrait
        im.addClass('ww').removeClass('wh');//set width 100%
    } else {//if landscape
        im.addClass('wh').removeClass('ww');//set height 100%
    }
    //set offset
    var nh = im.height(),//new image height
        nw = im.width(),//new image width
        hd = (nh-th)/2,//half dif img/box height
        wd = (nw-tw)/2;//half dif img/box width
    if (nh<nw) {//if portrait
        im.css({marginLeft: '-'+wd+'px', marginTop: 0});//offset left
    } else {//if landscape
        im.css({marginTop: '-'+hd+'px', marginLeft: 0});//offset top
    }
});

层叠样式表

.box{height:100px;width:100px;overflow:hidden}
.wh{height:100%!important}
.ww{width:100%!important}

这应该适用于任何大小或方向的图片,并且不仅可以调整大小,还可以进行偏移。而且不需要使用 relativeabsolute 定位。

制作了一个演示: http://jsfiddle.net/filever10/W8aLN/


嗨。我想使用这个好的例子。但是当父级div使用css可见性隐藏时,它不起作用。有人有解决办法吗? - Mr Rebel
1
@MrRebel,是的,按钮不起作用,因为line 28也需要更新,从$(this).siblings('.box');更改为$(this).siblings('ul').children('.box');,在该行的注释中确实提到了这一点... “//define the element in relation to the action”。按钮只是执行触发更改的某些操作的一般表示形式,您可以将其设置为$('.nedmnthnguwnt')以使事件发生。http://jsfiddle.net/filever10/jnrsrcr3/ - FiLeVeR10
2
我喜欢这种方法,但是我不得不交换添加和删除的类,并在if语句中加入另一个条件,即(if (ih>iw || th>tw)和if (nh<nw || th>tw))。 - Mike Kormendy
2
喜欢它 :) 更新了任何大小的容器(不仅限于正方形):http://jsfiddle.net/W8aLN/265/ - Julia
1
哇 :) 好吧,我不得不重新发明这个全屏固定背景图像,因为在使用background-size:cover时IE的行为是有缺陷的。是的,我忘了提到图片应该先加载,我使用了一个小插件imagesloaded.js来解决这个问题。 - Julia
显示剩余7条评论

6

顺便提一下,可以通过以下方式实现相同的效果,而不是设置"width"和"height"(设置它们可能会破坏这种方法):

min-width: 100%; min-height: 100%;

或者

min-width:(您期望的视口宽度百分比)vw; min-height:(您期望的视口高度百分比)vh;

在父元素上添加

overflow: hidden;

:)


1
这是一个简洁而优秀的解决方案! - budkin

3
这个想法是为图像添加额外的包装器:

<div class="wrap">
  <div class="inner">
    <img src="http://placehold.it/350x150">
  </div>
</div>

使用如下CSS:

.wrap {
  position: relative;
  width: 100%;
  height: 200px;
  background: rgba(255, 0, 0, 0.3);
  overflow: hidden;
}

.inner {
  position: absolute;
  min-width: 100%;
  height: 100%;
  left: 50%;
  -moz-transform: translateX(-50%);
  -o-transform: translateX(-50%);
  -ms-transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
}

.inner img {
  position: absolute;
  min-height: 100%;
  min-width: 100%;
  top: 50%;
  left: 50%;
  -moz-transform: translate(-50%, -50%);
  -o-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

这是一个工作示例:https://jsfiddle.net/kr60jroe/

2
在您的示例中,似乎并不适用于所有情况。例如,3000x2010像素的图像超出了其容器的边界。 - Jake Wilson

2
这里有一个干净的JavaScript函数来实现此功能,以下是其实现示例:
function backgroundCover(elementSizes, containerSizes) {
    var elementRatio = elementSizes.width / elementSizes.height,
        containerRatio = containerSizes.width / containerSizes.height;
        width = null,
        height = null;
    if (containerRatio > elementRatio) {
        width = Math.ceil( containerSizes.width );
        height = Math.ceil( containerSizes.width / elementRatio );
    } else {
        width = Math.ceil( containerSizes.height * elementRatio );
        height = Math.ceil( containerSizes.height );
    }
    return { width, height };
}

以下是一个实现的例子: HTML
<!-- Make sure the img has width and height attributes. The original image's width and height need to be set in order to calculate the scale ratio. -->
<div class="photo"><img src="photo.jpg" width="400" height="300"></div>

CSS

.photo {
    position: relative;
    overflow: hidden;
    width: 200px;
    padding-bottom: 75%; /* CSS technique to give this element a 4:3 ratio. */
}
.photo img {
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -moz-transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}

JavaScript

$( window ).on( 'resize', function() {
    $( '.cover-photo' ).each( function() {
        var img = $( 'img', this ),
            imgWidth = img.attr( 'width' ),
            imgHeight = img.attr( 'height' ),
            containerWidth = $( this ).width(),
            containerHeight = $( this ).height(),
            newSizes = backgroundCover( { width: imgWidth, height: imgHeight }, { width: containerWidth, height: containerHeight } );
        img.css( {
            width: newSizes.width,
            height: newSizes.height
        } );
    } );
} );

2

来自https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-size:

cover
    This keyword specifies that the background image should be scaled to be as small as possible while ensuring both its dimensions are greater than or equal to the corresponding dimensions of the background positioning area.

因此,您要么考虑将width: 100%height: 100%设置为创建父div中的重叠。 因此,我们可以使用以下逻辑:

var makeBackgroundCover = function (div) {
    $(div + " img").css("height", "100%");
    if ($(div + " img").width() < $(div).width()) {
        $(div + " img").css({
            "height": "auto",
            "width": "100%"
        });
    }
}

以下示例演示了此函数在水平和垂直图像上的工作方式。 http://jsfiddle.net/2r5Cb/

1
这个代码也会像 background-size: cover 一样居中图片吗? - FiLeVeR10
"background-size: cover" 不会使图像居中。如果您查看我的jsfiddle,您将看到我已经包含了 "background-size: cover" 比较图像,以显示此功能创建了相同的复制品。 - MattDiamant
1
你完全正确,但似乎原问题希望发生这种情况,否则它不会要求大小和位置。 - FiLeVeR10
很棒的答案,我喜欢你遵循了实际规范。 - Daniel Dewhurst

2

这是我的方法:

//collect the nodes
var parent = $('.box');
var img = $('image', box);

//remove width and height attributes
img.removeAttr('width');
img.removeAttr('height');

//set initial width
img.attr('width', parent.width());

//if it's not enough, increase the width according to the height difference
if (img.height() < parent.height()) {
    img.css('width', img.width() * parent.height() / img.height());
}

//position the image in the center
img.css({
    left: parseInt((img.width() - parent.width())/-2) + 'px',
    top: parseInt((img.height() - parent.height())/-2) + 'px'
});

演示代码


我喜欢这个解决方案,因为它输入的内容较少。尽管如果第一次调整大小不正确,它会计算并设置图像的尺寸两次 - FiLeVeR10

1
这是一个纯CSS解决方案。您可以使用以下定义包装器:
div.cover {
  position: fixed; 
  top: -50%; 
  left: -50%; 
  width: 200%; 
  height: 200%;
}

and the img:

img.cover {
  position: absolute; 
  top: 0; 
  left: 0; 
  right: 0; 
  bottom: 0; 
  margin: auto; 
  min-width: 50%;
  min-height: 50%;
  overflow-x: hidden;
}

这里是实时示例:

http://codepen.io/ErwanHesry/pen/JcvCw


只有在图像比其容器(在这种情况下为“ .box”)小的情况下才有效。这将使图像增长以适应其容器,但不会使其缩小以适应其容器。 - hal
1
当然这不是一个完美的解决方案,但它可能是唯一不使用Javascript的解决方案。也许您可以通过使用非常小的SVG图像来克服问题。 - Ruben Rizzi

1
在阅读被接受的答案时,我发现我们只是测试图像是“纵向”还是“横向”:
   if (ih>iw) {//if portrait

在这种情况下,对于OP来说是正确的。但是其他人可能正在处理矩形,并且应该考虑容器和“子”图像的纵横比:
    var int_container_width  = parseInt( $_container.width()  );
    var int_container_height = parseInt( $_container.height() );
    var num_container_aspect = int_container_width/int_container_height;

    var int_image_width      = parseInt( $_image.width() );
    var int_image_height     = parseInt( $_image.height());
    var num_image_aspect     = int_image_width/int_image_height;

    if ( num_image_aspect > num_container_aspect){
      num_scale = int_container_width/int_image_width * 100;
    } else {
      num_scale = int_container_height/int_image_height * 100;
    }

如果父元素不是正方形,那肯定会有影响,但由于它是正方形,所以没有影响。 - FiLeVeR10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接