在 <video> 或者 <img> 上模拟 background-size: cover 效果

198

如何在像<video>或<img>这样的HTML元素上模拟background-size:cover的功能?

我希望它能像这样工作

background-size: cover;
background-position: center center;

1
好的,我从未使用过background-size: cover; 但我在网上查看了它,所以你想要的是一种全屏图像/视频,当窗口大小调整时可以自适应缩放? - Lennart
1
是的,但是cover有一些微妙之处。请参阅链接上的“背景大小 101”。 - ivvi
1
如果窗口比图像更高,它将在垂直轴上的某个地方留下空白空间。在这种情况下,图像应该溢出到两侧,并且其高度应与窗口相同。当窗口比图像更宽时,相反的情况应该发生。 - ivvi
所以简单来说,如果图像高度小于浏览器高度,则使图像适合浏览器,使其具有浏览器的高度。 - Lennart
记录一下:你要找的是视频元素上的CSS 'object-fit'属性。它支持不太好。 - commonpike
显示剩余3条评论
20个回答

211

这是一件让我苦恼了一段时间的事情,但我找到了一个绝佳的解决方案,它不使用任何脚本,并且可以用5行CSS(如果计算选择器和括号,则为9行)实现视频的完美覆盖模拟。 除了CSS3兼容性之外,它没有任何不能完美工作的边缘情况

你可以在这里看到一个示例(已存档)

Timothy的解决方案存在问题,就是它无法正确处理缩放。如果周围元素比视频文件小,它不会缩小。即使您给视频标记一个微小的初始大小,如16像素乘以9像素,auto最终还是会强制将其调整为其本机文件大小的最小值。在此页面上当前得票最高的解决方案中,我无法让视频文件进行缩放,从而导致了严重的缩放效果。

但是,如果您知道视频的纵横比,例如16:9,则可以执行以下操作:

.parent-element-to-video {
    overflow: hidden;
}
video {
    height: 100%;
    width: 177.77777778vh; /* 100 * 16 / 9 */
    min-width: 100%;
    min-height: 56.25vw; /* 100 * 9 / 16 */
}
如果视频的父元素被设置为覆盖整个页面(例如position: fixed; width: 100%; height: 100vh;),那么视频也会被覆盖。
如果您希望视频也居中显示,您可以使用确定的居中方法:
/* merge with above css */
.parent-element-to-video {
    position: relative; /* or absolute or fixed */
}
video {
    position: absolute;
    left: 50%; /* % of surrounding element */
    top: 50%;
    transform: translate(-50%, -50%); /* % of current element */
}

当然,vwvhtransform是CSS3的一部分,因此如果你需要与旧浏览器兼容,你将需要使用脚本。


7
这是最佳答案。无 JavaScript,纯 CSS,可以正确缩放并居中。 - mark.monteiro
9
啊,是的,伙计。这就是2016年的答案。忽略其他一切。 - Josh Burson
1
@insidesin:发一个 JSFiddle? - M-Pixel
非常好的解决方案!但是如果我不知道宽高比呢?对于未知的宽高比,真的需要使用JS吗? - Jabel Márquez
8
2020年最佳解决方案是object-fit: cover,正如Daniël de Wit的答案所述。 - Brett Donald
显示剩余11条评论

168

18
这是一个非常强有力的声明,如果浏览器采用它,将会结束很多网站缩放方面的困扰。 - Mike Kormendy
1
这正是我正在寻找的! - Peter_Fretter
3
对于那些还不支持它的浏览器,有一个 polyfill 可以使用: https://github.com/anselmh/object-fit - creimers
12
必须同样应用 height: 100%; width: 100%;。谢谢这个现代的回答。 - Jossef Harush Kadouri
1
这应该是2021年的最佳答案!谢谢。 - Ramtin Soltani
显示剩余5条评论

141

jsFiddle

使用背景覆盖对于图像来说很好,宽度为100%也是如此。这些方式并不适用于 <video> 元素,并且这些答案过于复杂。你不需要 jQuery 或 JavaScript 来实现全屏视频背景。

请注意,我的代码不能完全覆盖视频作为封面图那样的背景,但它会使视频按比例缩放并覆盖整个背景。多余的视频将溢出页面边缘,具体取决于你将视频锚定在哪里。

答案非常简单。

只需要使用此 HTML5 视频代码或类似代码即可:(在全屏模式下测试)

html, body {
  width: 100%; 
  height:100%; 
  overflow:hidden;
}

#vid{
  position: absolute;
  top: 50%; 
  left: 50%;
  -webkit-transform: translateX(-50%) translateY(-50%);
  transform: translateX(-50%) translateY(-50%);
  min-width: 100%; 
  min-height: 100%; 
  width: auto; 
  height: auto;
  z-index: -1000; 
  overflow: hidden;
}
<video id="vid" video autobuffer autoplay>
  <source id="mp4" src="http://grochtdreis.de/fuer-jsfiddle/video/sintel_trailer-480.mp4" type="video/mp4">
</video>

最小高度和最小宽度将使视频保持视频的纵横比,通常为普通分辨率下任何正常浏览器的纵横比。任何多余的视频都会溢出页面的一侧。


2
这比其他答案简单得多,对我来说很有效。只需设置 min-widthmin-height 即可解决问题。 - Ryan Burney
31
这个解决方案没有像“cover”一样使视频居中。 - weotch
1
+10 分给你...我无法为你的回答点赞够多...非常感谢您发布这个...对我有用的技巧是底部/右侧: 0。 - carrabino
23
这并不会缩小视频(我没有尝试放大),如果浏览器窗口很小,而视频很大,这将导致许多问题。所以基本上它只处理background-size: cover 的"bleed"(溢出)部分,而不是缩放部分。 - Kevin Newman
4
使用目前的技术来说,这应该是可接受的答案:CSS 解决方案比 JavaScript 更可取。即使它需要您正确设置 parentNode。要居中视频,请使用以下代码:position: absolute; left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%); - Sjeiti
显示剩余8条评论

44

以下是我是如何做到的。一个可用的示例在这个 jsFiddle中。

var min_w = 300; // minimum video width allowed
var vid_w_orig;  // original video dimensions
var vid_h_orig;

jQuery(function() { // runs after DOM has loaded

  vid_w_orig = parseInt(jQuery('video').attr('width'));
  vid_h_orig = parseInt(jQuery('video').attr('height'));
  $('#debug').append("<p>DOM loaded</p>");

  jQuery(window).resize(function () { resizeToCover(); });
  jQuery(window).trigger('resize');
});

function resizeToCover() {
  // set the video viewport to the window size
  jQuery('#video-viewport').width(jQuery(window).width());
  jQuery('#video-viewport').height(jQuery(window).height());

  // use largest scale factor of horizontal/vertical
  var scale_h = jQuery(window).width() / vid_w_orig;
  var scale_v = jQuery(window).height() / vid_h_orig;
  var scale = scale_h > scale_v ? scale_h : scale_v;

  // don't allow scaled width < minimum video width
  if (scale * vid_w_orig < min_w) {scale = min_w / vid_w_orig;};

  // now scale the video
  jQuery('video').width(scale * vid_w_orig);
  jQuery('video').height(scale * vid_h_orig);
  // and center it by scrolling the video viewport
  jQuery('#video-viewport').scrollLeft((jQuery('video').width() - jQuery(window).width()) / 2);
  jQuery('#video-viewport').scrollTop((jQuery('video').height() - jQuery(window).height()) / 2);

  // debug output
  jQuery('#debug').html("<p>win_w: " + jQuery(window).width() + "</p>");
  jQuery('#debug').append("<p>win_h: " + jQuery(window).height() + "</p>");
  jQuery('#debug').append("<p>viewport_w: " + jQuery('#video-viewport').width() + "</p>");
  jQuery('#debug').append("<p>viewport_h: " + jQuery('#video-viewport').height() + "</p>");
  jQuery('#debug').append("<p>video_w: " + jQuery('video').width() + "</p>");
  jQuery('#debug').append("<p>video_h: " + jQuery('video').height() + "</p>");
  jQuery('#debug').append("<p>vid_w_orig: " + vid_w_orig + "</p>");
  jQuery('#debug').append("<p>vid_h_orig: " + vid_h_orig + "</p>");
  jQuery('#debug').append("<p>scale: " + scale + "</p>");
};
#video-viewport {
  position: absolute;
  top: 0;
  overflow: hidden;
  z-index: -1; /* for accessing the video by click */
}

#debug {
  position: absolute;
  top: 0;
  z-index: 100;
  color: #fff;
  font-size: 12pt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="video-viewport">
  <video autoplay controls preload width="640" height="360">
    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"type="video/mp4" />
    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.webm"type="video/webm" />
    <source src="http://www.quirksmode.org/html5/videos/big_buck_bunny.ogv"type="video/webm" />
  </video>
</div>

<div id="debug"></div>


为什么这个解决方案被踩了?从所有方面看,它似乎可以解决这个问题。 - Jan
2
这是我为这个问题找到的最佳解决方案。谢谢! - Chaser324
1
如果视频很大而窗口很小,则此方法非常有效,但如果窗口比视频更大且视频需要升级,则对我无效。我将@ Timothy-Ryan-Carpenter(在此处回答)的最小技巧添加到video标记中:video {min-width: 100%; min-height:100%;},它就像魔术般地工作。 - Alexandre DuBreuil
我也发现这种方法很有用,并将其打包为一个简单的jQuery插件,供任何感兴趣的人使用:https://github.com/aMoniker/jquery.videocover - Jim Greenleaf
尽管@AlexandreDuBreuil说过的话,这种方法可以很好地扩展视频(请自行查看:http://fiddle.jshell.net/GCtMm/show/)。这绝对是这里最好的解决方案。可惜相比其他答案,这需要大量JS,但如果您想为视频使用“background-size:cover”,那就是所需的。 - Chuck Le Butt
@JimGreenleaf,你能解释一下你的脚本如何使用吗?我尝试了这样:$("#video_id").videocover(); 但结果并没有达到我想要的效果。视频确实适应了屏幕大小,但是没有被裁剪,留下了背景的暴露区域。 - brett

22

根据Daniel de Wit的答案及其评论,我进行了更多搜索。感谢他提供的解决方案。

解决方案是使用object-fit: cover;,它具有很好的支持(每个现代浏览器都支持它)。如果你确实想支持IE,可以使用类似object-fit-imagesobject-fit的polyfill。

演示:

img {
  float: left;
  width: 100px;
  height: 80px;
  border: 1px solid black;
  margin-right: 1em;
}
.fill {
  object-fit: fill;
}
.contain {
  object-fit: contain;
}
.cover {
  object-fit: cover;
}
.none {
  object-fit: none;
}
.scale-down {
  object-fit: scale-down;
}
<img class="fill" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
<img class="contain" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
<img class="cover" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
<img class="none" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
<img class="scale-down" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>

并且有一个父元素:

div {
  float: left;
  width: 100px;
  height: 80px;
  border: 1px solid black;
  margin-right: 1em;
}
img {
  width: 100%;
  height: 100%;
}
.fill {
  object-fit: fill;
}
.contain {
  object-fit: contain;
}
.cover {
  object-fit: cover;
}
.none {
  object-fit: none;
}
.scale-down {
  object-fit: scale-down;
}
<div>
<img class="fill" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
</div><div>
<img class="contain" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
</div><div>
<img class="cover" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
</div><div>
<img class="none" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
</div><div>
<img class="scale-down" src="http://www.peppercarrot.com/data/wiki/medias/img/chara_carrot.jpg"/>
</div>


1
最佳现代答案。 - Routhinator
1
这是针对现代浏览器的最佳解决方案。使用 object-fit: cover,并将 widthheight 设置为 100%,您可以轻松获得一个比例缩放的 imgvideo,并且居中放大而无需任何麻烦。 - phip

16

其他答案都不错,但它们涉及JavaScript或者无法使视频水平和垂直居中。

您可以使用这个完整的CSS解决方案来创建一个模拟background-size: cover属性的视频背景:

  video {
    position: fixed;           // Make it full screen (fixed)
    right: 0;
    bottom: 0;
    z-index: -1;               // Put on background

    min-width: 100%;           // Expand video
    min-height: 100%;
    width: auto;               // Keep aspect ratio
    height: auto;

    top: 50%;                  // Vertical center offset
    left: 50%;                 // Horizontal center offset

    -webkit-transform: translate(-50%,-50%);
    -moz-transform: translate(-50%,-50%);
    -ms-transform: translate(-50%,-50%);
    transform: translate(-50%,-50%);         // Cover effect: compensate the offset

    background: url(bkg.jpg) no-repeat;      // Background placeholder, not always needed
    background-size: cover;
  }

这对我没用。视频没有缩放到全屏。我能看一下你的HTML代码吗?这只是一个在body标签中的视频标签吗? - matt
真是个好的解决方案。一开始它对我没起作用,但可能是我错过了什么,因为当我复制并粘贴你的CSS时,它就起作用了!谢谢 ;) - rafaelbiten
2
对我来说非常有效。我只是将position:fixed更改为absolute。 - Assaf Katz

13

M-Pixel的解决方案非常出色,它解决了Timothy答案中的缩放问题(视频将会被放大但不会被缩小,所以如果你的视频非常大,你只能看到一个小的放大部分)。然而,该解决方案是基于对视频容器大小的错误假设,即其必须是视口宽度和高度的100%。我发现有一些情况它对我并不起作用,因此我决定自己解决这个问题,并且我相信我想出了终极解决方案

HTML

<div class="parent-container">
    <div class="video-container">
        <video width="1920" height="1080" preload="auto" autoplay loop>
            <source src="video.mp4" type="video/mp4">
        </video>
    </div>
</div>

CSS

.parent-container {
  /* any width or height */
  position: relative;
  overflow: hidden;
}
.video-container {
  width: 100%;
  min-height: 100%;
  position: absolute;
  left: 0px;
  /* center vertically */
  top: 50%;
  -moz-transform: translate(0%, -50%);
  -ms-transform: translate(0%, -50%);
  -webkit-transform: translate(0%, -50%);
  transform: translate(0%, -50%);
}
.video-container::before {
  content: "";
  display: block;
  height: 0px;
  padding-bottom: 56.25%; /* 100% * 9 / 16 */
}
.video-container video {
  width: auto;
  height: 100%;
  position: absolute;
  top: 0px;
  /* center horizontally */
  left: 50%;
  -moz-transform: translate(-50%, 0%);
  -ms-transform: translate(-50%, 0%);
  -webkit-transform: translate(-50%, 0%);
  transform: translate(-50%, 0%);
}

它还基于视频的比例,因此如果您的视频比例不是16/9,则需要更改填充底部的百分比。除此之外,它能够直接使用。已在IE9+,Safari 9.0.1,Chrome 46和Firefox 41中进行测试。

编辑(2016年3月17日)

自从我发布了这个答案后,我编写了一个小型CSS模块,在<video>元素上模拟了background-size: coverbackground-size: containhttp://codepen.io/benface/pen/NNdBMj

它支持不同的视频对齐方式(类似于background-position)。同时请注意,contain实现并不完美。与background-size: contain不同,如果容器的宽度和高度更大,它不会将视频缩放到其实际大小,但我认为在某些情况下仍然有用。我还添加了特殊的fill-widthfill-height类,您可以将它们与contain一起使用,以获得containcover的特殊组合...尝试一下,随时可以改进它!


这不会将视频缩放到超出正常分辨率以适应100%的宽度/高度,因此它无法复制“覆盖”功能。 - jetlej
@jetlej,这里可以。你在测试哪个浏览器?你看了我的CodePen吗? - benface
1
它在Edge上作为备用方案很好用。干杯 - MrThunder
@MrThunder,如果您将此作为备选方案,那么您主要使用什么解决方案? - benface
1
@benoitr007 我在Firefox和Chrome中使用了object-fit: cover,而你使用Modernizr来解决IE的问题。 - MrThunder

8

4
CSS和少量js可以使视频覆盖背景并水平居中。
CSS:
video#bgvid {
    position: absolute;
    bottom: 0px; 
    left: 50%; 
    min-width: 100%; 
    min-height: 100%; 
    width: auto; 
    height: auto; 
    z-index: -1; 
    overflow: hidden;
}

JS:(将this与窗口大小调整绑定并分别调用一次)

$('#bgvid').css({
    marginLeft : '-' + ($('#bgvid').width()/2) + 'px'
})

3
在我们漫长的评论部分之后,我认为这就是您要寻找的,它基于jQuery: HTML:
<img width="100%" id="img" src="http://uploads8.wikipaintings.org/images/william-adolphe-bouguereau/self-portrait-presented-to-m-sage-1886.jpg">

JS:

<script type="text/javascript">
window.onload = function(){
       var img = document.getElementById('img')
       if(img.clientHeight<$(window).height()){
            img.style.height=$(window).height()+"px";
       }
       if(img.clientWidth<$(window).width()){
            img.style.width=$(window).width()+"px";
       } 
}
​</script>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

CSS:

body{
    overflow: hidden;
}

以上代码使用浏览器的宽度和高度。如果您在div内完成此操作,则需要更改为以下内容:

对于Div:

HTML:

<div style="width:100px; max-height: 100px;" id="div">
     <img width="100%" id="img" src="http://uploads8.wikipaintings.org/images/william-adolphe-bouguereau/self-portrait-presented-to-m-sage-1886.jpg">
</div>

JS:

<script type="text/javascript">
window.onload = function(){
       var img = document.getElementById('img')
       if(img.clientHeight<$('#div').height()){
            img.style.height=$('#div').height()+"px";
       }
       if(img.clientWidth<$('#div').width()){
            img.style.width=$('#div').width()+"px";
       } 
}
​</script>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
div{
   overflow: hidden;
}

我还要声明一下,我只在Google Chrome中测试过这个... 这里是一个jsfiddle: http://jsfiddle.net/ADCKk/


当我改变结果框架的大小或浏览器大小时,jsfiddle似乎没有任何反应。我在Chrome中尝试过这个。 - ivvi
我已经更新了它,但是如果你把宽度减小太多,它会突然跳动,还存在一些小问题... http://jsfiddle.net/ADCKk/1/ - Lennart
好的,抱歉但我一点头绪也没有,我尝试了很多东西,我觉得我已经把自己搞糊涂了,我不确定这是否可能...上面的脚本只有在刷新页面时才能工作,要使其在调整窗口大小时工作,您需要在js中使用window.resize事件,但我无法让它工作,也许您可以用这些信息 :) 无论如何祝你好运 - Lennart

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