dangelsaurus
dangelsaurus

Reputation: 7562

Swiper Responsive images with Text on top of image

I'm using Swiper to create some image sliders, and I'm trying to enclose the sliders within 2 flexbox containers such that my images are responsive.

I'd like to add some text on top of the images, aligned with the upper left corner of the image, and this is where everything goes wrong.

I believe I'm dealing with Flexbox "problem" very similar to Why don't flex items shrink past content size? in which case the parent DIV is keeping the width of the original image. The problem is the fixes in the post don't appear to work once I wrap the image in <div class="img-wrapper">. In fact I've spent quite a bit of time researching, and nothing quite seems to get it working the way I want.

This question is a fork of CSS object-fit: contain; is keeping original image width in layout

NOTE: Open the below code snippet in a new window to see the issue.

enter image description here

var swiper = new Swiper('.swiper-container', {
  slidesPerView: 1,
  spaceBetween: 50,
  // init: false,
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});
img {
  object-fit: contain;
  min-width: 0;
  height: 100%;
  max-width: 100%;
}

.img-num {
  float: left;
  position: absolute;
  padding-left: 10px;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, serif;
}


.img-wrapper {
  border-style: solid;
  border-width: thin;
  height: 100%;
  object-fit: contain;
  min-width: 0;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: #eee;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #000;
  margin: 0;
  padding: 0;
}

.page {
  height: 100%;
  display: flex;
}

.main-container {
  flex: 1 1 0;
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.half-containers {
  flex: 0 1 50%;
  overflow: auto;
  box-sizing: border-box;
  border: 0.5px solid red;
  display: flex;
}

.page-header {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.page-footer {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  font-size: 18px;
  background: #fff;
  /* Center slide text vertically */
  display: -webkit-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  -webkit-justify-content: center;
  justify-content: center;
  -webkit-box-align: center;
  -ms-flex-align: center;
  -webkit-align-items: center;
  align-items: center;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css" rel="stylesheet" />
<div class="page">
  <div class="main-container">
    <div class="page-header">
      This is a header
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">1</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">2</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">3</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">4</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-footer">
      This is a footer
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>

Upvotes: 3

Views: 6061

Answers (1)

Temani Afif
Temani Afif

Reputation: 274024

First, the use of object-fit is useless when applied to a div and not to the image1. Even the use of it within the image in this case is useless because the image is not getting distorted. object-fit only apply when the ratio is lost in order to bring it back again.

So you will have the same issue without:

var swiper = new Swiper('.swiper-container', {
  slidesPerView: 1,
  spaceBetween: 50,
  // init: false,
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});
img {
  height: 100%;
  max-width: 100%;
}

.img-num {
  float: left;
  position: absolute;
  padding-left: 10px;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, serif;
}


.img-wrapper {
  border-style: solid;
  border-width: thin;
  height: 100%;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: #eee;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #000;
  margin: 0;
  padding: 0;
}

.page {
  height: 100%;
  display: flex;
}

.main-container {
  flex: 1 1 0;
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.half-containers {
  flex: 0 1 50%;
  overflow: auto;
  box-sizing: border-box;
  border: 0.5px solid red;
  display: flex;
}

.page-header {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.page-footer {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  font-size: 18px;
  background: #fff;
  /* Center slide text vertically */
  display: flex;
  justify-content: center;
  align-items: center;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css" rel="stylesheet" />
<div class="page">
  <div class="main-container">
    <div class="page-header">
      This is a header
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">1</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">2</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">3</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">4</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-footer">
      This is a footer
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>

Now the issue you are facing is that the image wrapper is first sized considerd the image width then the image is getting resized inside that wrapper. It's somehow complex but if you remove height:100% from the image you will have this:

var swiper = new Swiper('.swiper-container', {
  slidesPerView: 1,
  spaceBetween: 50,
  // init: false,
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});
img {
  /*height: 100%;*/
  max-width: 100%;
}

.img-num {
  float: left;
  position: absolute;
  padding-left: 10px;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, serif;
}


.img-wrapper {
  border-style: solid;
  border-width: thin;
  height: 100%;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: #eee;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #000;
  margin: 0;
  padding: 0;
}

.page {
  height: 100%;
  display: flex;
}

.main-container {
  flex: 1 1 0;
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.half-containers {
  flex: 0 1 50%;
  overflow: auto;
  box-sizing: border-box;
  border: 0.5px solid red;
  display: flex;
}

.page-header {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.page-footer {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  font-size: 18px;
  background: #fff;
  /* Center slide text vertically */
  display: flex;
  justify-content: center;
  align-items: center;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css" rel="stylesheet" />
<div class="page">
  <div class="main-container">
    <div class="page-header">
      This is a header
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">1</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">2</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">3</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">4</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-footer">
      This is a footer
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>

This is actually what you want considering the width but the height is big thus the image is overflowing. By adding height:100% you will decrease the height and also the width because the image will try to keep its ratio. Of course, the wrapper will not get resized again because will have a cycle thus it will stuck at that size.

An easy fix is to simply make the image wrapper position: absolute;. its height is already defined as 100% and its width will shrink to fit the image width. No need to adjust top/left because it's already centred without the use of absolute thus it will be kept centred:

var swiper = new Swiper('.swiper-container', {
  slidesPerView: 1,
  spaceBetween: 50,
  // init: false,
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});
img {
  height: 100%;
  max-width: 100%;
}

.img-num {
  top:0;
  left:0;
  position: absolute;
  padding-left: 10px;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, serif;
}


.img-wrapper {
  border-style: solid;
  border-width: thin;
  height: 100%;
  position: absolute;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: #eee;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #000;
  margin: 0;
  padding: 0;
}

.page {
  height: 100%;
  display: flex;
}

.main-container {
  flex: 1 1 0;
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.half-containers {
  flex: 0 1 50%;
  overflow: auto;
  box-sizing: border-box;
  border: 0.5px solid red;
  display: flex;
}

.page-header {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.page-footer {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  font-size: 18px;
  background: #fff;
  /* Center slide text vertically */
  display: flex;
  justify-content: center;
  align-items: center;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css" rel="stylesheet" />
<div class="page">
  <div class="main-container">
    <div class="page-header">
      This is a header
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">1</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">2</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">3</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">4</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-footer">
      This is a footer
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>


1The object-fit property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.ref

A div is not a replaced element. Replaced elements are element like canvas, img, iframe, etc (https://html.spec.whatwg.org/multipage/rendering.html#replaced-elements)

UPDATE

The above seems to work only on Chrome so I would consider a small JS hack to rectify the width of the element on the other browsers:

var swiper = new Swiper('.swiper-container', {
  slidesPerView: 1,
  spaceBetween: 50,
  // init: false,
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
});
$('.img-wrapper').each(function() {
  $(this).width($(this).find('img').width())
})
$( window ).resize(function() {
  $('.img-wrapper').each(function() {
    $(this).css('width','100%').width($(this).find('img').width())
  })
});
img {
  height: 100%;
  max-width: 100%;
  object-fit:cover;
}

.img-num {
  top:0;
  left:0;
  position: absolute;
  padding-left: 10px;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, serif;
}


.img-wrapper {
  border-style: solid;
  border-width: thin;
  height: 100%;
  position: absolute;
  max-width:100%;
}

html,
body {
  margin: 0;
  height: 100%;
}

body {
  background: #eee;
  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #000;
  margin: 0;
  padding: 0;
}

.page {
  height: 100%;
  display: flex;
}

.main-container {
  flex: 1 1 0;
  display: flex;
  min-width: 0;
  flex-direction: column;
}

.half-containers {
  flex: 0 1 50%;
  overflow: auto;
  box-sizing: border-box;
  border: 0.5px solid red;
  display: flex;
}

.page-header {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.page-footer {
  flex: 0 0 auto;
  background-color: #dcdcdc;
}

.swiper-container {
  width: 100%;
  height: 100%;
}

.swiper-slide {
  text-align: center;
  font-size: 18px;
  background: #fff;
  /* Center slide text vertically */
  display: flex;
  justify-content: center;
  align-items: center;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />

<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css" rel="stylesheet" />
<div class="page">
  <div class="main-container">
    <div class="page-header">
      This is a header
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">1</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">2</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="half-containers">
      <!-- Swiper -->
      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">3</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
          <div class="swiper-slide">
            <div class="img-wrapper">
              <div class="img-num">4</div>
              <img src='https://i.imgur.com/mSPw98T.jpg' />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="page-footer">
      This is a footer
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>

Upvotes: 4

Related Questions