使用JavaScript达成 background-size: cover 的效果

366 words, 2 minutes to read / October 28, 2019

最近有一个项目,领导要求:要让一个视频一屏显示的情况下不能改变宽高比 and 适配各种分辨率 and 兼容到 IE 7。嘶~,有点棘手,对于要兼容到 IE 7 的项目,写 CSS 简直头疼。

不过不是我做(欸嘿),别人也没做出来,我也没站出来(面子最重要),于是领导不得不放低要求,当然这都是后话了。

后来想,如果我来做的话,我会怎么做?对于领导的要求,我脑子里第一个闪过的就是background-size: cover这个玩意儿,但是第一,这个是 CSS 3 的属性,IE 8 就歇菜了,更别说 IE 7 了,第二,这个属性只对图片有用…

那能不能用 js 来模拟呢?

说干就干,当下就开始研究cover属性是怎么工作的,最后结论是:

cover在正常情况下,只是单纯的将图片宽度放到与容器一样宽,在缩放过程中,当图片高度小于容器高度时会根据原始图片的宽高比 (ratio) 来放大图片宽度,使原始图片始终撑满容器。

听起来有点绕,直接上代码:

;(function(w) {
    var kkkover = function () {
        _ = this;
        this.init = function (obj) {
            w.onresize = function () {
                _.resized(obj);
            }
            obj.img.onload = function () {
                obj.ratio = obj.img.clientHeight / obj.img.clientWidth;
                _.calcStyle(obj);
            }
            obj.ratio = obj.img.clientHeight / obj.img.clientWidth;
            _.calcStyle(obj);
        }
        this.calcStyle = function (obj) {
            obj.wrapCell.style.position = 'relative';
            obj.img.style.position = 'absolute';
            obj.img.style.top = '50%';
            obj.img.style.zIndex = '0';
            obj.img.style.left = '50%';
            obj.img.style.width = '100%';
            obj.img.style.marginLeft = -(obj.img.clientWidth / 2) + 'px';
            obj.img.style.marginTop = -(obj.img.clientHeight / 2) + 'px';
            if(obj.img.clientHeight <= obj.wrapCell.clientHeight){
                obj.img.style.maxWidth = 'none';
                obj.img.style.height = obj.wrapCell.clientHeight;
                obj.img.style.width = obj.wrapCell.clientHeight / obj.ratio + 'px';
                obj.img.style.marginTop = -(obj.img.clientHeight / 2) + 'px'
                obj.img.style.marginLeft = -(obj.img.clientWidth / 2) + 'px';
            }
            if(obj.wrapCell.clientWidth > obj.img.clientWidth){
                obj.img.style.width = '100%';
                obj.img.style.height = 'auto';
                obj.img.style.marginLeft = -(obj.img.clientWidth / 2) + 'px';
                obj.img.style.marginTop = -(obj.img.clientHeight / 2) + 'px';
            }
        }
        this.resized = function (obj) {
            _.calcStyle(obj);
        }
    }
    var app = new kkkover();
    var wp = w.prototype || w.__proto__ || w;
    wp.kkkover = app.init;
}(window));

使用的话大概就是这样:

<div id="test">
    <img src="path/to/img" id="test_img">
</div>
kkkover({
    wrapCell: document.getElementById('test'), // 传入容器
    img: document.getElementById('test_img') // 传入容器中的图片
});

可以在这里看一下演示。代码已经测试,可以兼容到 IE 7。

对于视频也是一样的用法,img传视频元素就可以了。