Home > Enterprise >  Force (rectangular) image to display as square with side length = variable parent div's width
Force (rectangular) image to display as square with side length = variable parent div's width

Time:01-09

I have a centered flexbox parent div, #con, with % width, which has an image(s)-containing div (.block) sandwiched between two padded text divs (#info and #links). How can I force .block img to be a square with side length equal to #con's width with JS or CSS? .block could contain 1x1=1 images, 2x2=4 images, etc; thus, background-image is not an option. Imitating the solution here only seems to work if I replace con.width() in the JS with a specific value (e.g. 300px, as shown here with this placeholder image), which is unideal.

var con = $("#con");
$(".block").css("height", con.width(), "width", con.width());

body {
    font-size:1rem;
    text-align:center;
    margin:0;
    height:100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow:hidden;
}

#con {
    width:50%;
    max-width:300px;
    display:flex;
    flex-flow:row wrap;
    justify-content:center;
    margin:5rem auto;
    border:1px solid black;
}

.block {width:100%; overflow:hidden; background:black;}
.block img {
    position: relative;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    object-fit: cover;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<div id="con">
<div id="info">...</div>
<div ><img src="https://dbdzm869oupei.cloudfront.net/img/vinylrugs/preview/60150.png"></div>
<div id="links">...</div>
</div>

CodePudding user response:

You don't need JS for this: just use aspect-ratio: 1 to force a square aspect ratio. You might want to add display: block to ensure the <img> is not displayed inline (which is the default) as well. See proof-of-concept below:

body {
  font-size: 1rem;
  text-align: center;
  margin: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

#con {
  width: 50%;
  max-width: 300px;
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  margin: 5rem auto;
  border: 1px solid black;
}

.block {
  width: 100%;
  overflow: hidden;
  background: black;
}

.block img {
  display: block;
  object-fit: cover;
  width: 100%;
  aspect-ratio: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<div id="con">
  <div id="info">...</div>
  <div ><img src="https://dbdzm869oupei.cloudfront.net/img/vinylrugs/preview/60150.png"></div>
  <div id="links">...</div>
</div>

If you want to support browsers that do not have aspect-ratio support, you can use a combination of a pseudo-element padding-bottom hack to set a fixed aspect ratio instead:

body {
  font-size: 1rem;
  text-align: center;
  margin: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

#con {
  width: 50%;
  max-width: 300px;
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  margin: 5rem auto;
  border: 1px solid black;
}

.block {
  width: 100%;
  overflow: hidden;
  background: black;
  position: relative;
}

.block::before {
  width: 100%;
  padding-bottom: 100%;
  content: '';
  display: block;
  
}

.block img {
  display: block;
  object-fit: cover;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<div id="con">
  <div id="info">...</div>
  <div ><img src="https://dbdzm869oupei.cloudfront.net/img/vinylrugs/preview/60150.png"></div>
  <div id="links">...</div>
</div>

  •  Tags:  
  • Related