Absolute positioned images are breaking layout

bootstrap

#1

For a equal height two column layout I am using the following html (Bootstrap) structure:

<div class="container main">
	<div class="row row-flex">
		<div class="col-md-4 col-sm-12 sidebar">
			<div class="card">
		            //sidebar content
			</div>		
		</div>
		<div class="col-md-8 col-sm-12 content">
			<div class="card">
		                // main content
			</div>
		</div>
	</div>
</div>

Basically for all pages this works just fine only on the home (index) page I have slideshow using CSS animation. For this to happen I need to use position absolute on the images

.card-img-top {
	margin-bottom: 2rem;	
}
.card-img-top img {
	width: 100%; 
	height: auto !important;
	position:absolute; 
	left:0; 
	right:0;
	opacity:0; 
	animation-name: fade; 
	animation-duration: 12s; 
	animation-iteration-count: infinite;	
}

html

<div class="card-img-top">
	<img src="/images/slideshow/1.jpg"> 
    <img src="/images/slideshow/2.jpg"> 
    <img src="/images/slideshow/3.jpg"> 
    <img src="/images/slideshow/4.jpg"> 
</div>

But this is breaking the layout, in other words the sidebar and the content divs on this page are no longer equal height. Is there a way to avoid using position absolute for the images ? I also don’t want to set a height for the parent!

Thank you in advance


#2

I don’t believe that is true? If you add a background color to .sidebar and to .content you will see that they are full height.

Your right column will of course be the one that dictates the height because as far as the left column is concerned it will be empty because of the absolute elements. Your card elements though will not match the height of the columns unless you see them to display:flex and flex-direction:column

The absolute element of course will just poke out of the sidebar if it is not tall enough and will not have any influence on the right column height.

It is unclear whether you are intending the left images to always match the height of the columns (which will be dictated by the content in the right column)? If you do want a full column image you could do something like this.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
.card-img-top img {
	width: 100%;
	height:100%;
	object-fit:cover;/* won't work in ie11*/
	position:absolute;
	left:0;
	right:0;
	top:0;
	bottom:0;
	opacity:1;
	animation-name: fade;
	animation-duration: 12s;
	animation-iteration-count: infinite;
}
.sidebar{
	background:red;
	position:relative;
	display:flex;
}
.content {
	background:blue;
}
</style>
</head>

<body>
<h1>Testing Only</h1>
<div class="container main">
  <div class="row row-flex">
    <div class="col-md-4 col-sm-12 sidebar">
      <div class="card card-img-top"><img src="images/fixed-01.jpg"> <img src="images/fixed-02.jpg"> <img src="images/fixed-03.jpg"> <img src="images/fixed-04.jpg"> </div>
    </div>
    <div class="col-md-8 col-sm-12 content">
      <div class="card"> main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
        main content<br>
      </div>
    </div>
  </div>
</div>


<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> 
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>

If you only want the images to their natural height then assuming all images are the same height your option would be to place a default image placeholder in the flow to hold the space open and then absolutely place the slider images on top. Or if images are all the same aspect ratio use the padding-top aspect ratio trick to hold the column open and once again absolutely place the slider into place.

It all depends on what you want to achieve but all will involve some sort of mechanism to maintain the flow for the absolutely placed images.

As I said it is unclear how you expect this to work and what the dynamics are supposed to be and what are the variations in the images that you are using?


#3

Hi @PaulOB. Thank you for the reply ans sorry for the late reply. I think I wasn’t clear enough explaining the problem I am having. The slideshow is in the right column and all images have the same width and height. Furthermore has the slideshow text content underneath.

It is indeed the card in the left column whixh is not extending all the way down. I tried your suggestion by giving that card the property display flex but without success. This are the CSS and HTML I vave so far:

CSS:

.main {
	margin-top: 2rem;
	margin-bottom: 2rem;
	position: relative;
	z-index: 2;	
}

.main .row-flex {
    display: flex;
    flex-wrap: wrap;
}

.row-flex .card{
	background-color: RGBA(0, 0, 0, .9) !important;
	color: RGB(255, 255, 255);
}

.sidebar .card {
	display: flex !important;
	flex-direction: column !important;	
}

.card-img-top {
	position: relative !important;	
}

.card-img-top img {
	width: 100% !important;
	height: auto !important;
	position: absolute;
	top: 0;
	left: 0;	
}

HTML

<div class="container main">
	<div class="row row-flex">
		<div class="col-md-4 col-sm-12 sidebar">
			<div class="card">
				<div class="card-body">
					<h2>Laatste nieuws</h2>
					// news content
				</div>
			</div>		
		</div>
		<div class="col-md-8 col-sm-12 content">
			<div class="card">
				<div class="card-img-top">
					<img src="/images/slideshow/1.jpg">
					<img src="/images/slideshow/2.jpg"> 
					<img src="/images/slideshow/3.jpg"> 
					<img src="/images/slideshow/4.jpg"> 
					<img src="/images/slideshow/5.jpg"> 		
				</div>
				<div class="card-body">
					// body content
				</div>
			</div>
		</div>
	</div>
</div>

Whis is giving me the following result:

I’m not sure what I’m doing wrong?


#4

The code I gave you was working and you could have tested it and followed procedures for the change in columns :slight_smile:

You have made it more awkward by adding extra wrappers and not removing the ones shown in my demo.

Here is another example with the images in the right column now.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
.container{margin-bottom:3rem}
h1{text-align:center;}
.card-img-top img {
	width: 100%;
	height:100%;
	flex:1 0 100%;
	object-fit:cover;/* won't work in ie11*/
	position:absolute;
	left:0;
	right:0;
	top:0;
	bottom:0;
	opacity:1;
	animation-name: fade;
	animation-duration: 12s;
	animation-iteration-count: infinite;
}
.content .card-img-top{flex:1 0 0%;	min-height:300px;/* adjust to suit*/}
.content {
	position:relative;
	display:flex;
	flex-direction:column;
	flex-wrap:wrap;
}
.sidebar {	
	display:flex;
}
.card-body {
	background:green
}
.content .card-body{background:#000;color:#fff;flex:0;}
.sidebar .card {flex:1 0 100%}
</style>
</head>

<body>
<h1>Testing</h1>
<div class="container main">
  <div class="row row-flex">
    <div class="col-md-4 col-sm-12 sidebar">
      <div class="card">
        <div class="card-body">
          <h2>Laatste nieuws</h2>
          // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content  </div>
      </div>
    </div>
    <div class="col-md-8 col-sm-12 content">
      <div class="card card-img-top"> <img src="images/fixed-01.jpg"> </div>
      <div class="card-body"> body content </div>
    </div>
  </div>
</div>

<div class="container main">
  <div class="row row-flex">
    <div class="col-md-4 col-sm-12 sidebar">
      <div class="card">
        <div class="card-body">
          <h2>Laatste nieuws</h2>
          // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content   // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content  // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content  // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content  // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content  // news content <br> // news content  <br>  // news content    // news content <br> // news content  <br>  // news content </div>
      </div>
    </div>
    <div class="col-md-8 col-sm-12 content">
      <div class="card card-img-top"> <img src="images/fixed-01.jpg"> </div>
      <div class="card-body"> body content </div>
    </div>
  </div>
</div>



<div class="container main">
  <div class="row row-flex">
    <div class="col-md-4 col-sm-12 sidebar">
      <div class="card">
        <div class="card-body">
          <h2>Laatste nieuws</h2>
          // news content  <br>  // news content  </div>
      </div>
    </div>
    <div class="col-md-8 col-sm-12 content">
      <div class="card card-img-top"> <img src="images/fixed-01.jpg"> </div>
      <div class="card-body"> body content </div>
    </div>
  </div>
</div>




<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> 
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>

The output from above looks like this:

The same caveats apply as before as object-fit is not supported in IE11 yet.

It’s hard to debug without seeing the working page as your slideshow script may also have something to say about it :slight_smile:

You have to remember that only the flex children match their heights and as soon as you add inner elements the inner elements have their own height unless you construct more flex boxes in a column format. It can be very tricky to get inner nested elements to match the height of a distant flex item sibling.

The basics are in this demo.


#5

Hi @PaulOB. Thanks again for the reply. Fair enough. That is where I went wrong indeed. In div content you combined the card div with card-img-top where I had card-img-top as nested div. It is working great now :ok_hand:. Again thanks a lot for the input.