Как эмулировать background-size: обложку на ‹img›?

Как изменить размер и положение изображения внутри поля таким образом, чтобы оно покрывало все поле, подобно тому, как работает background-size: cover.

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

Я знаю, что мне нужно добавить overflow:hidden в поле, а изображению нужно position: absolute. Но какая формула дает мне правильный новый размер изображения и левое + верхнее положение?


person Alex    schedule 04.11.2013    source источник
comment
@SpYk3HH, это то же самое, что background: 100% 100%, а не background-size: cover   -  person MattDiamant    schedule 05.11.2013
comment
Вы хотите, чтобы изображение также располагалось по центру или оно было достаточно большим? Я смотрю на этот пример, который не центрирует изображение. w3schools.com/cssref/   -  person TreeTree    schedule 05.11.2013
comment
не совсем уверен, что вы хотите, поскольку обложка присуща позиционированию фона. это кажется плохой позой для внутреннего элемента img, но я полагаю, вы могли бы попробовать точную формулу, хотя я сам не уверен, что формула   -  person SpYk3HH    schedule 05.11.2013
comment
@TreeTree: да. моя ошибка тогда. Я думал, что обложка размера фона также будет центрировать изображение: P (может быть, background-position: center тоже требуется?)   -  person Alex    schedule 05.11.2013
comment
Я считаю, что установка его по центру будет работать, только если изображение меньше контейнера. Если ваше изображение в два раза превышает размер контейнера, оно все равно будет расположено в верхнем левом углу.   -  person TreeTree    schedule 05.11.2013


Ответы (15)


это может быть проще

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
    }
});

css

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

Это должно обрабатывать любой размер/ориентацию и не только изменять размер, но и смещать изображения. Все без relative или absolute позиционирования.

сделал скрипку: http://jsfiddle.net/fileever10/W8aLN/

person FiLeVeR10    schedule 04.11.2013
comment
Привет. Я хотел бы использовать этот хороший пример. Но это не работает, когда родительский div скрыт с видимостью css. У кого-нибудь есть решение для этого? - person Mr Rebel; 02.09.2014
comment
@MrRebel Ты имеешь в виду вот так? На jsfiddle.net/filever10/by91rqr5 показано, как работать с одним элементом, но переопределить el, и вы можете повлиять на несколько, т.е. var el = $(this).children('.box'); - person FiLeVeR10; 04.09.2014
comment
HTML-структура выглядит следующим образом: jsfiddle.net/mpkLtn4q (кнопка не работает на этой скрипке из-за новая структура html) - person Mr Rebel; 04.09.2014
comment
@MrRebel Да, кнопка не работает, потому что line 28 также необходимо обновить с $(this).siblings('.box'); до $(this).siblings('ul').children('.box');, это упоминается в комментариях к этой строке... //определить элемент относительно действия. Кнопка — это просто общее представление для выполнения некоторого действия, которое вызвало изменение, вы можете сделать ее $('.nedmnthnguwnt') для возникновения события. jsfiddle.net/filever10/jnrsrcr3 - person FiLeVeR10; 05.09.2014
comment
Мне нравится этот метод, однако мне пришлось поменять местами добавленные и удаленные классы, а также поставить другое условие в операторы if, if (ih›iw || th›tw) и if (nh‹nw || th›tw). - person Mike Kormendy; 28.01.2016
comment
Понравилось :) Обновлено для контейнера любого размера (не только квадратного): jsfiddle.net/W8aLN/265 - person Julia; 02.03.2016
comment
@Юлия Круто! На самом деле это был код с сайта, где мне приходилось делать полноэкранные фоны и обнюхивать соотношение размеров, я упростил его, чтобы просто обрабатывать квадраты для этого ответа. Просто помните, что это решение зависит от размеров изображений, поэтому, если вы запускаете кучу изображений или действительно большие изображения, оно, скорее всего, будет выполнено до того, как изображения будут отрисованы. Из-за этого лучше всего иметь атрибуты высоты и ширины для изображений и использовать их вместо того, чтобы нюхать размер изображения, таким образом, вам не нужно ждать, пока они загрузятся, чтобы получить размер и выполнить. - person FiLeVeR10; 11.03.2016
comment
Ничего себе :) Ну, мне пришлось заново изобрести это для полноэкранных фиксированных фоновых изображений, потому что поведение IE при использовании background-size:cover глючит. И да, я забыл упомянуть, что изображения должны быть загружены в первую очередь, я использовал для этого небольшой плагин, imagesloaded.js - person Julia; 11.03.2016
comment
Вы можете сделать это только с помощью CSS, см. ответы ниже. - person Sandwell; 05.03.2018
comment
@Sandwell Единственное решение css по-прежнему не является универсальным решением, поскольку оно не поддерживается в IE 11. - person FiLeVeR10; 17.07.2018
comment
@FiLeVeR10 это просто минимальная ширина и минимальная высота: 100%, IE поддерживает это. - person Sandwell; 18.07.2018
comment
@Sandwell, единственное решение css, не использует минимальную ширину / минимальную высоту. Он использует object-fit: cover, который не поддерживается в большинстве версий IE. Покажите пример того, что вы имеете в виду. - person FiLeVeR10; 02.10.2018

Что бы это ни стоило: теперь это можно сделать только с помощью CSS с...

Новое свойство CSS object-fit (Текущая поддержка браузеров)

Просто установите object-fit: cover; на img

Вам даже не нужно заворачивать img в div!

FIDDLE

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>

Вы можете узнать больше об этом новом свойстве в этой статье о веб-платформе.

Кроме того, вот скрипка из статьи выше, которая демонстрирует все значения свойства object-fit.

person Danield    schedule 06.10.2014
comment
Я не знаю, как это получает так много голосов без поддержки IE11. - person Ricky Boyce; 13.08.2015
comment
Конечно знаю, но вынужден относиться к IE как к любящему отцу. - person Ricky Boyce; 17.10.2015
comment
@Toskan Это не принятый ответ из-за отсутствия поддержки IE. IE отстой и все такое, но если он в нем совсем не поддерживается; тогда это не полностью совместимое решение. Многие организации по-прежнему придерживаются IE, что, к сожалению, делает его обязательным требованием для базовых стандартов совместимости. Тем не менее, использование останавливается, и я надеюсь, что IE не будет фактором в будущем из-за ситуаций, подобных этой. - person FiLeVeR10; 22.12.2017
comment
Вы всегда можете использовать полифилл для этих устаревших браузеров github.com/bfred-it/object- подходящие изображения - person Jair Reina; 11.09.2018
comment
Статистика использования IE11 снижается каждый месяц... этот ответ должен стать принятым. - person Markus Siebeneicher; 01.04.2020
comment
@RickyBoyce многие люди просто пренебрегают IE, так как он известен своей аномалией - person Mohammed Shareef C; 10.11.2020

Достаточно близкое, чистое CSS-решение для имитации обложки размера фона с использованием тега img с очень хорошей поддержкой браузера (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>

person Vlatko    schedule 03.03.2016
comment
Отличное решение! За исключением того, что это не работает в IE8. Это работает в IE9+. Подробнее здесь: caniuse.com/#feat=transforms2d - person Junaid Bhura; 25.07.2016
comment
Когда я использую ваше решение, изображение просто растягивается, чтобы соответствовать контейнеру. Я делаю что-то неправильно? - person torjinx; 26.08.2017
comment
@torjinx Кажется, это решение расширяет только изображения меньшего размера, оно не сжимает изображения, которые намного больше контейнера. - person bendman; 16.07.2018
comment
Это должен быть принятый ответ! Простой, поддерживается везде и делает именно то, что должен. Благодарю вас! - person vedsil; 14.12.2020

Кроме того, для чего это стоит, тот же эффект может быть получен вместо установки «ширины» и «высоты» (их установка может сломать этот подход, кстати):

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

or

min-width: (your desired percent of viewport width)vw; min-height: (your desired percent of viewport height)vh;

с

overflow: hidden;

на родителя

:)

person SirRodge    schedule 25.07.2015
comment
Это лаконичное и отличное решение! - person budkin; 04.01.2019

Идея состоит в том, чтобы сделать дополнительную обертку для изображения:

<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/

person Paulius Kripaitis    schedule 06.01.2017
comment
Кажется, не работает для всех случаев в вашем примере. Например, изображение размером 3000x2010 выходит далеко за пределы своего контейнера. - person Jake Wilson; 01.03.2017

Из https://developer.mozilla.org/en-US/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/

person MattDiamant    schedule 04.11.2013
comment
это также центрирует изображение, как background-size: cover? - person FiLeVeR10; 05.11.2013
comment
background-size: cover не центрирует изображение. Если вы посмотрите на мой jsfiddle, вы увидите, что я включил background-size: cover сравнительных изображений, чтобы показать, что эта функция создает идентичное воспроизведение. - person MattDiamant; 05.11.2013
comment
вы совершенно правы, но похоже, что первоначальный вопрос хотел, чтобы это произошло, иначе он не запросил бы размер и позиционирования. - person FiLeVeR10; 05.11.2013
comment
Отличный ответ, мне нравится, что вы следовали фактической спецификации. - person Daniel Dewhurst; 13.04.2017

Вот мой подход:

//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'
});

FIDDLE

person matewka    schedule 04.11.2013
comment
Мне нравится это решение, потому что оно меньше печатает. Хотя он будет вычислять и устанавливать размеры дважды для изображения, если они неверны при первом размере. - person FiLeVeR10; 04.09.2014

Вот чистая функция 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
        } );
    } );
} );
person Gavin    schedule 06.10.2017

При чтении принятого ответа мне кажется, что мы просто проверяем, является ли изображение «портретным» или «пейзажным»:

   if (ih>iw) {//if portrait

В случае с ОП все верно. Но другие могут иметь дело с прямоугольниками и должны учитывать соотношение сторон контейнера и «дочернего» изображения:

    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;
    }
person Ideogram    schedule 27.08.2014
comment
если бы родитель не был квадратом, это определенно имело бы значение, но если бы он был квадратом, это не имело бы значения. - person FiLeVeR10; 04.09.2014

Это чистое решение css. Вы можете определить оболочку с помощью:

div.cover {
  position: fixed; 
  top: -50%; 
  left: -50%; 
  width: 200%; 
  height: 200%;
}

и изображение:

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

person Ruben Rizzi    schedule 20.06.2015
comment
Это работает только в том случае, если изображение меньше, чем его контейнер (в данном случае .box). Это заставит изображение увеличиваться, чтобы соответствовать его контейнеру, но не заставит его сжиматься, чтобы соответствовать его контейнеру. - person Hal Carleton; 30.06.2015
comment
Конечно, это не идеальное решение, но, пожалуй, единственное, в котором не используется javascript. Возможно, вы сможете решить эту проблему, используя очень маленькое изображение svg. - person Ruben Rizzi; 01.07.2015

Вы можете использовать этот стиль для тега изображения :"object-fit:cover;" Эта ссылка поможет вам также https://css-tricks.com/almanac/properties/o/object-fit/

person Mohamed Mamdouh    schedule 12.01.2017

Если вы хотите, чтобы изображение располагалось по центру поля без изменения размера изображения, просто используйте этот код:

.box {
    width: 100px;
    height: 100px;
    overflow: hidden;
    position: relative;
}
.box img {
    width: 413px;
    height: 325px;
    position: absolute;
    left: 50%;
    top: 50%;
}

Если вы хотите изменить размер изображения по размеру, используйте следующий код:

.box {
    width: 100px;
    height: 100px;
}
.box img {
    width: 100%;
    height: auto;
}

Этот код оставит пустое пространство, если ширина изображения превышает его высоту. Если ни один из них не работает, вы можете просто установить изображение в качестве фона и использовать background-size: cover;.

person zsaat14    schedule 04.11.2013
comment
что произойдет, если изображение является пейзажем? - person FiLeVeR10; 05.11.2013
comment
Первый фрагмент кода будет подобен взгляду на картинку через маленькое отверстие, поэтому, пока картинка больше коробки, она будет заполнена. Для второго бита кода горизонтальное изображение оставит пространство под ним (и выше, в зависимости от вашего заполнения). Чтобы избежать этого, вы можете добавить второе изображение и удалить все отступы и поля. - person zsaat14; 05.11.2013

Для всех, кто сталкивается с этим ответом, как я сегодня, в поисках решения, которое будет работать с альбомными, портретными, прямоугольными, квадратными и т. д. изображениями и произвольными размерами контейнеров, я включил свой собственный код ниже.

Это также будет работать быстро, вам просто нужно будет запускать его снова всякий раз, когда размер окна изменяется.

JSFiddle:

http://jsfiddle.net/66c43ao1/

HTML

<div class="test">
    <div class="cover">
        <img src="http://d2ws0xxnnorfdo.cloudfront.net/character/meme/cool-dog.jpg" width="590" height="590"/>
    </div>
</div>

CSS

/* modify the width and height below to demonstrate coverage */
.test {
    height: 300px;
    position: relative;
    width: 500px;
}
/* you will need the below styles */
.cover {
    height: 100%;
    left: 0;
    overflow: hidden;
    position: absolute;
    top: 0;
    width: 100%;
    z-index: 1;
}

JS

$('.cover').each(function() {
    var containerHeight = $(this).height(),
        containerWidth  = $(this).width(),
        image           = $(this).children('img'),
        imageHeight     = image.attr('height'),
        imageWidth      = image.attr('width'),
        newHeight       = imageHeight,
        newWidth        = imageWidth;

    if (imageWidth < containerWidth) {
        // if the image isn't wide enough to cover the space, scale the width
        newWidth        = containerWidth;
        newHeight       = imageHeight * newWidth/imageWidth;
    }
    if (imageHeight < containerHeight) {
        // if the image isn't tall enough to cover the space, scale the height
        newHeight       = containerHeight;
        newWidth        = imageWidth * newHeight/imageHeight;
    }

    var marginLeft      = (newWidth - containerWidth)/2;
    var marginTop       = (newHeight - containerHeight)/2;

    image.css({
        marginLeft  : '-' + marginLeft + 'px',
        marginTop   : '-' + marginTop + 'px',
        height      : newHeight,
        width       : newWidth
    });
});

Конечно, вы можете использовать такие библиотеки, как Backstretch, которые делают то же самое, но я считаю, что это решение лучше подходит для моих целей (без увеличения зависимостей, меньшего веса и т. д.).

person Heath    schedule 21.04.2015

Я создал функцию ниже, которая должна это сделать. Я позаимствовал часть логики из принятого ответа и настроил ее для работы с любым контейнером, создав соотношение для размера изображения: размер контейнера, а затем сравнил, что больше, чтобы определить, какое измерение нужно настроить. Также добавлен аргумент «центр» («истина» центрирует, ложь устанавливает его вверх/влево).

Я использую CSS3 с translateX/Y, но мог бы достаточно легко заставить его работать без него.

Вот код:

var coverImage = function(wrap, center) {

  if (typeof center === 'undefined') {
    center = true;
  }

    var wr = $(wrap),
        wrw = wr.width(),
        wrh = wr.height();

  var im = wr.children('img'),
        imw = im.width(),
        imh = im.height();

  var wratio = wrw / imw;
    var hratio = wrh / imh;

  //Set required CSS
  wr.css({'overflow' : 'hidden'});
  im.css({'position' : 'relative'});


  if (wratio > hratio) {
    im.width(wrw);
    im.css({'height' : 'auto'});

    if (center) {
      im.css({
        'top' : '50%',
        'transform' : 'translateY(-50%)'
      });
    }
  } else {
    im.height(wrh);
    im.css({'width' : 'auto'});

    if (center) {
      im.css({
        'left' : '50%',
        'transform' : 'translateX(-50%)'
      });
    }
  }
}

и проверьте jsfiddle, чтобы увидеть его в действии: https://jsfiddle.net/cameronolivier/57nLjoyq/2/

person Cameron    schedule 14.12.2015

Я сделал что-то, что могло бы работать для эмуляции background-size:cover и background-position:center.

Если вы хотите изменить положение, просто измените стили "сверху" на "слева" изображения.

CSS

.box{
    overflow:hidden;
    position:relative;
}

.box img{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
}

JS

$('.box').each(function() {
     //aspect ratio of container
     var boxRatio = $(this).height() / $(this).width(); 
     //aspect ration of image
     var imageRatio = $(this).children('img').height() / $(this).children('img').width();
     //set width or height 100% depend of difference
     if (imageRatio > boxRatio) {
          $(this).children('img').css({"width":"100%","height":"auto"});                
     } else {
          $(this).children('img').css({"height":"100%","width":"auto" });
     }
});

Эта функция должна быть активирована на события "загрузка" и "изменение размера".

person Santi Nunez    schedule 10.10.2016