Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use flexbox and maintain a 1:1 aspect ratio even though content is sized differently

There are a lot of questions on SO about maintaining the aspect ratio of an element (with flexbox or without). However, my problem is slightly different as I want to override the aspect ratio of a child image element:

  1. Make sure the image covers the element (object-fit: cover) completely
  2. Make sure the element is 1:1 (i.e. a perfect circle)
  3. Make sure that the overflowing image is hidden

In other words, the image has to behave as if it was the background of an element (I can't use them as background images though) of which the aspect ratio is always 1:1 and responsive.

In the example below everything works fine except that the <a> elements adapt to their image descendant. But I want them to maintain a 1:1 ratio so I get perfect circles. (The middle one of the first row has to be larger than the rest, though.)

The HTML can't change, but I can use modern CSS properties such as object-fit and flexbox. (As long as recent versions of Chrome/Firefox support it.)

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.img-gallery {
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;
}

.img-gallery .row {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;
}

.img-gallery a {
  display: block;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  padding: 3px;
  flex: 1;
  margin: 0 24px;
  transition: padding 200ms;
}

.img-gallery a:hover,
#s_country .img-gallery .row:first-of-type a:nth-child(2):hover {
  padding: 0;
}

.img-gallery a:hover span {
  transform: scale(1.25);
}

.img-gallery .row:first-of-type a:not(:nth-child(2)) {
  width: 30%;
  width: calc((60% - 96px) / 2);
}

.img-gallery .row:first-of-type a:nth-child(2) {
  flex: 2;
  padding: 4px;
}

.img-gallery span {
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  position: relative;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;
}

.img-gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.img-gallery span::before {
  content: "";
  background-image: linear-gradient(60deg, transparent 48%, #ffc5e7 100%);
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 2;
  border-radius: 50%;
  opacity: .72;
}
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/b3/9c/54/b39c54776074d07ee0b567826768730a.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/88/3b/dd/883bddab14168f5f0807fec021002d8d.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

Code illustrating when Terry's code does not work: landscape pictures.

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.img-gallery {
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;
}

.img-gallery .row {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;
}

.img-gallery a {
  display: block;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  padding: 3px;
  flex: 1;
  margin: 0 24px;
  transition: padding 200ms;
}

.img-gallery .row:first-of-type a:not(:nth-child(2)) {
  width: 30%;
  width: calc((60% - 96px) / 2);
}

.img-gallery .row:first-of-type a:nth-child(2) {
  flex: 2;
  padding: 4px;
}

.img-gallery span {
  height: 0;
  display: block;
  border-radius: 50%;
  position: relative;
  padding-bottom: 100%;
  overflow: hidden;
  transition: transform 250ms;
  z-index: 2;
}

.img-gallery img {
  width: 100%;
  object-fit: cover;
  transition: transform 250ms;
}

.img-gallery a:hover img {
  transform: scale(1.25);
}

.img-gallery span::before {
  content: "";
  background-image: linear-gradient(60deg, transparent 48%, #ffc5e7 100%);
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 2;
  border-radius: 50%;
  opacity: .72;
}
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/b3/9c/54/b39c54776074d07ee0b567826768730a.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/13/7c/3d/137c3d3bd9f25aa9d2677136d9336d74.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>
like image 262
Bram Vanroy Avatar asked May 16 '17 18:05

Bram Vanroy


People also ask

How do I fix my flexbox size?

A flexbox item can be set to a fixed width by setting 3 CSS properties — flex-basis, flex-grow & flex-shrink. flex-basis : This property specifies the initial length of the flex item. flex-grow : This property specifies how much the flex item will grow relative to the rest of the flex items.

How do I make my flex item not stretch width?

By default, the child elements of a flexbox container will stretch vertically to fill the height of the container. This can be prevented by using the align-self property on the child element that you do not want to stretch. This Pen is owned by dev on CodePen.

How can you cause a flex item to grow in size?

flex: 1 0 200px; If you have one element that has a flex-basis of 200px, flex-grow of 1, and flex-shrink of 0, this element will be at minimum 200px wide, but it will be allowed to grow if there is extra space. In this case, you can think of the flex-basis as being a minimum width.

What does flex 1 mean flexbox?

If an element has flex: 1 , this means the size of all of the other elements will have the same width as their content, but the element with flex: 1 will have the remaining full space given to it.


1 Answers

To maintain the aspect ratio of responsive elements, you can use the padding technique.
Note that you shouldn't use percentages on padding bottom/top for flex children, see here for more info.
You can make a grid of responsive squares and add border-radius to make them circles.

For the images, the object-fit: cover; property does exactly what you need : keep the image original aspect ratio and covering the element completely.
I changed the first image to a landscape image to show this technique works also with those.

Here is an example of how you can achieve your aim (I stripped some of your CSS out to keep the demo simple) :

*,*::before,*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.img-gallery {
  background: #fafafa;
  padding: 24px;
  min-width: 320px;
  width: 90%;
  margin: 0 auto;
}

.img-gallery .row {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  align-items: center;
}

.img-gallery a {
  display: block;
  position:relative;
  text-decoration: none;
  background-image: linear-gradient(60deg, #004494 0%, #7db9e8 78%, #c2dfed 100%);
  overflow: hidden;
  border-radius: 50%;
  flex: 1;
  margin: 24px;
}
.img-gallery a::before{
  content:'';
  display:block;
  padding-bottom:100%;
}


.img-gallery .row:first-of-type a:not(:nth-child(2)) {
  width: 30%;
  width: calc((60% - 96px) / 2);
}

.img-gallery .row:first-of-type a:nth-child(2) {
  flex: 2;
}

.img-gallery span {
  position:absolute;
  top:3px;left:3px;right:3px;bottom:3px;
  border-radius: 50%;
  overflow: hidden;
  transition: transform 250ms;
}

.img-gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:transform 0.5s;
}
.img-gallery a:hover img{
  transform:scale(1.25);
}
<div class="img-gallery">
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" id="img-1-3"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d6/df/51/d6df512a2f15f517767b4d82d2d97a4c.jpg" id="img-1-4"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/ec/a9/dd/eca9dd106a04cdbee399870252ef711f.jpg" id="img-1-5"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/7d/01/19/7d0119a2fec989e208f288326c7cad0f.jpg" id="img-1-6"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/d8/c3/32/d8c332d09b03673845b2e92a48816233.jpg" id="img-1-7"></span></a>
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/88/3b/dd/883bddab14168f5f0807fec021002d8d.jpg" id="img-1-8"></span></a>
  </div>
  <div class="row">
    <a href="#" title="Show large image"><span><img itemprop="image" src="https://s-media-cache-ak0.pinimg.com/originals/8e/4f/bb/8e4fbb89b155d15521b80d1baf9290d1.jpg" id="img-1-9"></span></a>
  </div>
</div>

Note that you will need to add vendor prefixes for the transition and transform properties depending on the browsers you need to support. See canIuse for transforms and transitions.

like image 158
web-tiki Avatar answered Oct 12 '22 01:10

web-tiki