How to put a responsive Object fit cover, on the image Card from the Boostrap 4?

Susi picture Susi · Sep 12, 2018 · Viewed 14.3k times · Source

This css took out the responsive layout of the Cards from the Boostrap 4. How can i put a object-fit: cover; on the image of the Card, and have the responsive layout from the Bootstrap 4?

Without object-fit: cover;:

enter image description here

With object-fit: cover;:

enter image description here

I could change the width of the imagen on the id #imgUNcover, but it will not solve the problem in different resulution screens.

Edit:

enter image description here

Answer

Magnus picture Magnus · Sep 13, 2018

Susi, I am going to go out on a limb here and just guess what you are looking for. Do let me know if you need another outcome, and I will adjust the answer


In order for image to resize with the size of its containing block you place a percentage value on the height or the width. Please find a code example below.

Some Interesting Notes (in case you want to dive a bit deeper):

  • You do not have to set both height and width, on the image element
  • It is good practice to do so, but it is not necessary
  • The reason is that the computed value of the dimension which is not set, defaults to auto. That in turn, results in a used value for that property equalling: used value of other dimension / intrinsic image ratio
  • In practice, that means the height or width you did not set will shift, so that the element's content box will be of such as size that the aspect ratio of the content box would be identical to the intrinsic aspect ratio of the image
  • As a result of this, changing object-fit will have no effect, except if you put it to none (none: Image would keep its intrinsic dimensions, while its content box remains what you set it to)
  • In this case we want to use % value(s), to enable resizing when the size of the card changes (responsiveness)
  • We must then make sure the container block has that particular dimension set
  • If it was not set (auto by default), its size would be equal to that of its content
  • That would lead to an unsolvable circular reference: The child wants to be a percentage of its parent's size, and the parent's size tries to be equal to its child(ren)
  • In that case, the percentage you set on the content box would default to auto
  • Which means it would act like it was not set at all
  • If no height/width is set, content box's used values for height/width is set equal to intrinsic height/width of image
  • Thus, content box will most likely be large (unless image is small), and overflow its container (see overflow property)
  • Finally, object-fit only applies if intrinsic aspect ratio of image is different than the dimensions (height/width) you set on the element's content box

Closing remarks:

  • Pheeew, a lot of notes, but hopefully that is helpful to you in terms of explaining how height / width of inline replaced elements work
  • The CSS2.1 spec for height / width of various elements can be found here: 10 Visual formatting model details
  • MDN article of object-fit can be found here: MDN object-fit

Code:

#imgUNcover {
  width: 100%;
  object-fit: contain;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<div class="col-12 col-md-6 col-lg-3 mb-3 mb-md-3">
  <div class="card">
    <div class="img-container">
      <a href="#"><img src="https://www.dailydot.com/wp-content/uploads/2018/05/crush.jpg" class="btn btn-outline-danger btn-sm" alt="blabla" class="card-img-top" id="imgUNcover"></a>
    </div>
    <div class="card-body">
      <a href="#" class="card-title cardTitleLink">
        <h1 class="cardTitleUN">
          Some title
        </h1>
      </a>
      <p class="card-text text-muted">
        foo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foofoo foo
      </p>
      <a href="#">Continue Lendo</a>
    </div>
  </div>

</div>

Finally, a pen so you can easily try resizing the browser (to check that it is responsive): https://codepen.io/magnusriga/pen/xazZzg?editors=1100


UPDATE (added functionality as requested in comment):

To make sure all images are same height, you set a specific height on the cards, then distribute that across the image area (top section) and body section of the card using flexbox's flex-basis property. To avoid that the flex items grow outside their flex container, just use overflow: auto, which tells the block box to add scrollbars if necessary.

The tedious part of modifying Bootstrap functionality, is that there are a lot more factors to check vs just building it from scratch yourself. And many times you have to put in !important to overrule their descriptors.

New code:

.card {
  height: 400px;
}

.img-container {
  flex: 1 0 30% !important;
  // max-height: 30% !important; // <-- Alternative
  overflow: hidden;
}

.card-body {
  flex: 1 0 60% !important;
  // max-height: 60% !important; // <-- Alternative, though still need to control overflow
  overflow: auto;
}

#imgUNcover {
  width: 100%;
  height: 100%;
  object-position: 50% top;
  object-fit: cover;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<div class="container">
  <div class="row">

    <div class="col-12 col-md-6 col-lg-3 mb-3 mb-md-3">
      <div class="card">
        <div class="img-container">
          <a href="#"><img src="https://qph.fs.quoracdn.net/main-qimg-fdaa32b9bffc30131e56956e4bc1e9e4.webp" class="btn btn-outline-danger btn-sm" alt="blabla" class="card-img-top" id="imgUNcover"></a>
        </div>
        <div class="card-body">
          <a href="#" class="card-title cardTitleLink">
            <h1 class="cardTitleUN">
              Some title
            </h1>
          </a>
          <p class="card-text text-muted">blabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalbla
          </p>
          <a href="#">Continue Lendo</a>
        </div>
      </div>
    </div>

    <div class="col-12 col-md-6 col-lg-3 mb-3 mb-md-3">
      <div class="card">
        <div class="img-container">
          <a href="#"><img src="https://www.dailydot.com/wp-content/uploads/2018/05/crush.jpg" class="btn btn-outline-danger btn-sm" alt="blabla" class="card-img-top" id="imgUNcover"></a>
        </div>
        <div class="card-body">
          <a href="#" class="card-title cardTitleLink">
            <h1 class="cardTitleUN">
              Some title
            </h1>
          </a>
          <p class="card-text text-muted">blabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalblablabalbla
          </p>
          <a href="#">Continue Lendo</a>
        </div>
      </div>
    </div>

  </div>
</div>

And the pen: https://codepen.io/magnusriga/pen/VGdxJy?editors=1100

Use the object-position and object-fit properties, to tweak how image is placed inside its block box.


Final Edit:

Here is an updated pen with some improvements to scrollbar etc.: https://codepen.io/magnusriga/pen/VGdxJy