1

I am working on a responsive gallery layout in which all images should cover the dimensions of their container. In order to remain the aspect ratio of each image I thought I could use the rather new CSS property object-fit.

The implemented solution uses the flexbox module to enforce equal heights on each column of the gallery. The cells in each column are stretched to fit in sum the height of their parent. The actual height of each cell is determined by the flexbox module using flex: 1 0 auto and is not necessarily the same.

Here is my problem: The images contained in each cell should now match the dimensions of their container (using object-fit: cover; width: 100%; height: 100%). In Firefox and Internet Explorer (using an object-fit polyfill) these styles result in the expected layout, but not in webkit browsers like Chrome or Safari. In these browsers the dimensions of each cells are correct, but not the dimensions of the images.

I could not find a related bug report nor find a flexible solution to my problem. I hope someone can help me out, as I am currently running out of ideas.

Tested in the latest versions of Chrome, Safari, Firefox and in IE 10 and 11

// Object Fit Polyfill
// @see <https://github.com/bfred-it/object-fit-images>
objectFitImages();
/* Reset */

body {
  font: 100%/26px Lato, sans-serif;
  padding: 5%;
}

figure {
  margin: 0;
}

blockquote {
  margin-left: 0;  
}

img {
  vertical-align: middle;
  max-width: 100%;
  height: auto;
  font-style: italic;
}

/* Gallery */

.c-gallery {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-flow: wrap row;
      -ms-flex-flow: wrap row;
          flex-flow: wrap row;
  -webkit-box-pack: justify;
  -webkit-justify-content: space-between;
      -ms-flex-pack: justify;
          justify-content: space-between;
}

  .c-gallery__column {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-flow: wrap column;
        -ms-flex-flow: wrap column;
            flex-flow: wrap column;
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 33%;
        -ms-flex: 1 0 33%;
            flex: 1 0 33%;
  }

  .c-gallery__item {
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 auto;
        -ms-flex: 1 0 auto;
            flex: 1 0 auto;
  }

    .c-gallery__item img {
      width: 100%;
      height: 100%;
      -o-object-fit: cover;
         object-fit: cover;
    }
<div class="c-gallery">
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x1080" alt="Product A" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <div class="c-gallery__item">
      <figure>
        <blockquote>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officiis architecto voluptatum numquam totam quos neque incidunt!</p>
        </blockquote>
        <figcaption>
          <cite>John Doe</cite>
        </figcaption>
      </figure>
    </div>
    <figure class="c-gallery__item">
      <img src="http://placehold.it/640x720" alt="John Doe" />
    </figure>
  </div>
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product B" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product C" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product D" /></a>
    </figure>
  </div>
</div>
<script src="http://bfred-it.github.io/object-fit-images/dist/ofi.browser.js"></script>

In case you prefer CodePen, I created a demo of what I am working on:

Daniel
  • 53
  • 9
  • possible guidance: http://stackoverflow.com/q/37127384/3597276 – Michael Benjamin Jun 23 '16 at 13:44
  • Doesn't `object-fit` work with fixed dimensions? So make it `max-width` and `max-height`, maybe. I don't know for sure since you are using a poly. – zer00ne Jun 23 '16 at 14:19
  • Flexbox prefixes are no longer needed- [CanIUse](http://caniuse.com/#feat=flexbox) There's a lot of antiquated flexbox properties...maybe simplify to most current flexbox syntax? Once again, I'm uncertain what is required...I do not trust polies. – zer00ne Jun 23 '16 at 14:27
  • @Michael_B The images need to be wrapped in anchor links, as they will link to product pages. I already tried to make these `display: flex; flex-flow: nowrap column; flex: 1 0 100%;` as well to ensure that they match the height of the figure, but that does not change anything. – Daniel Jun 23 '16 at 14:37
  • @zer00ne The vendor prefixes are required for IE 10/11. The polyfill is used primarily for IE as well. Could you elaborate a bit further what you mean by "Doesn't object-fit work with fixed dimensions"? – Daniel Jun 23 '16 at 14:41
  • A possible fix seems to be to position the anchor links absolutely, which does not make sense to me. According to my understanding this should force all cells to collapse as the anchor tags and the contained images are taken out of the document flow. But the opposite seems to be the case... http://codepen.io/dweidner/pen/qNqzEb. Does anyone have an idea what is going on? This component is driving me crazy... – Daniel Jun 23 '16 at 15:03
  • The previously suggested workaround does only work, as long as the columns are lined up on a single row. As soon as one column switches to a separate row the gallery items collapse as expected due to the absolutely positioned anchor elements. Strange... I am close to giving up on this. – Daniel Jun 23 '16 at 15:11
  • @Daniel Calm down take a deep breath. I haven't tested this demo in IE I ran out of time. Please review it and I'll be back later on. Perhaps you might need the poly on the flexbox layout, hopefully you won't. – zer00ne Jun 23 '16 at 17:10

2 Answers2

0

Changes

  • Removed object-fit poly
  • Cleaned up flexbox properties to modern standards
  • Removed all img, images from sites like placeholder host images that have fixed dimensions so they do not stretch.
  • Used background shorthand on each <figure> with the following properties:
    • background-image
    • background-repeat
    • background-position
  • Used background-size: cover on each figure which has the same effect as object-fit: cover. For details on background scaling see this article
  • Set the flex-items' dimensions of each flex-column with this pattern:
    • min-width: Xvw;
    • max-width: Xem;
    • min-width: Yvh;
    • max-height: Yem;
    • vw and vh are viewport units.
    • em measurements are based on the dimensions observed from the original <img>
  • flex-wrap: [row/column] [wrap/nowrap] is the proper syntax
    • You need nowrap in this grid layout. If for some reason the flexboxes' limits are exceeded, wrap would distort the layout with boxes stacked under each other. For current details on flexbox, read this article
  • Placed the <a>nchors within the <figure> and set a <div> within the anchor to spread it from edge to edge within the <figure>. It's ugly and there's probably a better way. See the source and look for .space classes for the details.

SUPPORT

Flexbox

IE sux, it's buggy so keep it simple.

background-size

Fully supported unless your clients use opera-mini(less than .1% of users?)

This demo seems very compatible overall, so no polies needed hopefully. It isn't perfect, but I figure you can adjust the rest yourself with the lengths, margins, etc.

CODEPEN

Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Thank you for your time and effort. I think your solution requires some further tweaks (e.g. currently there is a gap on the left of the first column and a mismatch in the height of the third column). Nonetheless I would like to keep the images within the DOM, for SEO and accessibility reasons. The wrong order in the `flex-flow` statement is a good hint. Furthermore your solution using background images spawned another idea: Visually hide the images and apply images as background (http://codepen.io/dweidner/full/dXNXNO/). Obviously this results in a mismatch of the click-surface of the images. – Daniel Jun 24 '16 at 09:29
  • @Daniel that's not a bad idea, you could make the `` 1x1px if it doesn't muckup SEO. – zer00ne Jun 24 '16 at 10:28
0

I found a solution that is working for me. The problem seems to be the missing dimensions on the anchor elements. While I tried to absolutely position the links to force them to cover their container, I should have tried more thoroughly to style them as flexbox-container as well. My solution includes the following additions:

  1. Force the anchor elements to act as flexbox-container as well, just like the gallery items do.
  2. Force each gallery item to use 100% of the height of its parent column. The flex-module will calculate the actual height used for the element and allow the item to grow or shrink as required (flex: 1 1 auto).
  3. Each image element is stretched to cover the dimensions of their container using the flex-module (using flex: 1 1 auto;). The object-fit statement will ensure the aspect-ratio is maintained.
  4. A new css class allows the blockquote-container to use just as much space as required by the contents (flex-shrink: 0; flex-grow: 0; height: auto;).

The resulting layout, was exactly what I was looking for – at least in Chrome, Firefox and IE10+. Unfortunately in Safari the result is a bit different. In Safari the blockquote-element and its contents determines the height of the entire gallery. The resulting height of each column is as a consequence divided between each child, resulting in small thumbnail images. I assume the reason is, that there is no element with a explicit height and percentage based height do not work here (wondering why it does for other browsers though). A fix which is working for my use-case was to apply a min-height on the gallery container.

Here the current solution:

// Object Fit Polyfill
// @see <https://github.com/bfred-it/object-fit-images>
objectFitImages();
/* #Base:Reset */

body {
  font: 100%/26px Lato, sans-serif;
  padding: 5%;
}

figure {
  margin: 0;
}

blockquote {
  margin-left: 0;  
}

img {
  vertical-align: middle;
  max-width: 100%;
  height: auto;
  font-style: italic;
}

/* #Component:Gallery */

.c-gallery {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  min-height: 100vh; /* Prevents collapsing items in Safari */
  max-height: 1080px;
}

  .c-gallery__column {
    display: flex;
    flex-flow: column nowrap;
    flex: 1 1 auto;
    width: 33.33333%;
  }

  .c-gallery__item,
  .c-gallery__item > a {
    display: flex;
    flex-flow: column nowrap;
    flex: 1 1 auto;
    height: 100%;
  }

  .c-gallery__item--fit-content {
    flex-grow: 0;
    flex-shrink: 0;
    height: auto;
  }

    .c-gallery__item img {
      flex: 1 1 auto;
      width: 100%;
      max-width: none;
      height: 100%;
      object-fit: cover;
    }
<div class="c-gallery">
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x1080" alt="Product A" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <div class="c-gallery__item c-gallery__item--fit-content">
      <figure>
        <blockquote>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officiis architecto voluptatum numquam totam quos neque incidunt!</p>
        </blockquote>
        <figcaption>
          <cite>John Doe</cite>
        </figcaption>
      </figure>
    </div>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x720" alt="John Doe" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product B" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product C" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product D" /></a>
    </figure>
  </div>
</div>
<script src="http://bfred-it.github.io/object-fit-images/dist/ofi.browser.js"></script>

You can see a fork of the original demo again on CodePen

NOTE: I left out the vendor-prefixes in my answer, running the snippet may as a consequence result in a broken layout if you are browsing with a browser that does not support flexbox.

Daniel
  • 53
  • 9