There are two major use cases for images in HTML:
background-image
- not treated as content, they are rendered within the bounds of the element, without setting its size
- regular images:
<img>
s - they are treated as content and, among others, they set the size of their parent (when not taken out of the flow, using position
), which is what you seem to want.
The simplest way to make the element have the exact height to display the image without being cropped is by actually using the background image as an <img>
:
<div class="card card-tall" style="background-image:url(./img/portfolio/poster1.jpg)" >
<img src="./img/portfolio/poster1.jpg">
</div>
... combined with this CSS:
.card-tall img {
display: inline-block;
width: 100%;
height: auto;
visibility: hidden;
}
Now the image will be there, setting the card's ratio, but what you'll see is still the background-image
, because <img>
s visibility is hidden
- not rendered.
Also note this doesn't add any extra weight to the page. Since the resource is exactly the same, when it loads for background-image
it also loads for <img>
.
If you only want this behavior on a particular responsiveness interval, wrap the above CSS into the appropriate @media
query.
To avoid custom CSS, apply these classes to the <img>
:
<img src="./img/portfolio/poster1.jpg"
class="d-inline-block w-100 h-auto invisible">
The disadvantage is that each (like most Bootstrap utility classes) comes with !important
. For responsiveness, if you don't want the images displayed on md
and above, use d-md-none
class (it's an example, change it to what you need, if: d-sm-none
, d-lg-none
...).
Side note: you could also add the images programmatically, using this jQuery script:
$(function() {
$('.card-tall').each(function() {
$(this).append($('<img />', {
class: 'd-inline-block w-100 h-auto invisible',
src: $(this).css('backgroundImage').replace('url("', '').replace('")', '')
}))
})
})
See it working:
$(function() {
$('.card-tall').each(function() {
$(this).append($('<img />', {
class: 'd-inline-block w-100 h-auto invisible',
src: $(this).css('backgroundImage').replace('url("', '').replace('")', '')
}))
})
})
.card-tall {
background-size: contain;
background-repeat: none;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<div class="container">
<div class="row">
<div class="col-sm-4">
<div class="card card-tall" style="background-image:url(https://picsum.photos/200/200)"></div>
</div>
<div class="col-sm-4">
<div class="card card-tall" style="background-image:url(https://picsum.photos/200/300)"></div>
</div>
<div class="col-sm-4">
<div class="card card-tall" style="background-image:url(https://picsum.photos/300/200)"></div>
</div>
</div>
</div>
Add d-md-none
to the list of classes if you only want the <img>
s to kick in on sm
and below.