Alex Eguia's Codeblog

gem blurred_image_tag

1 Mar 2017

Sometimes it is mandatory to insert an image in a fixed width/height wrapper, either for aesthetic reasons, a fixed-dimension container, or other circumstances. The problem of creating elements with a fixed width and height is that the content needs to be processed to fit the measurements, possibly flattenning the images.

There are solutions both from the server side and from the client side to find out where the images “overflows”, and to be able to adapt the style in each case, but many of these solutions require a load time. A close-to-perfect solution can be one based on pure CSS as explained on the article Forcing image aspect ratio via CSS.

To keep the Rails’ DRY[1] motto, I have developed a Ruby on Rails gem defining a new method called blurred_image_tag that prints an image fitting it to its parent container’s width/height without being flattened. Its usage and params are the same as the native image_tag method.

Example of the blurred_image_tag gem usage with portrait and landscape images within a forced dimension div.

The main difference with the native method is that it creates a double <img> tag on the HTML: the first one to paint the blurred background, and the second one to print the image itself. This way, and using the CSS filter function, we can create fixed width/height image containers that neither flatten nor cut them by any side, with a blurred and semi-opaque background generated by the same image. Also, regarding the loading time, the same image is being referred twice, therefore the loading time will be the same as printing just one image since the cache of the web browser will reuse it.

To get the most out of this gem, or to collaborate with it, you can see the code and documentation in Github.

Rubygemsblurred_image_tag

Githubblurred_image_tag


[1] Don’t Repeat Yourself https://en.wikibooks.org/wiki/Ruby_on_Rails/Getting_Started/Don%C2%B4t_repeat_yourself

Forcing image aspect ratio via CSS

24 Feb 2017

Imagine we want to show a list of images:

1
2
3
4
5
<div class="image-container">
  <div><img src="http://dummyimage.com/200x200" /></div>
  <div><img src="http://dummyimage.com/200x200" /></div>
  <div><img src="http://dummyimage.com/200x200" /></div>
</div>

These will be well aligned if we use some CSS and flex:

1
2
3
4
5
6
7
8
9
.image-container {
  display: flex;
  flex-direction: row;
}

.image-container > div {
  margin: 0 10px;
  width: 100%; /* Flex takes care of this */
}

This code is acceptable for images that have the same aspect ratio, this is, the same ratio between its width and height (200x200px in the example above). If we change the images’ dimensions the result will be different:

1
2
3
4
5
<div class="image-container">
  <div><img src="http://dummyimage.com/300x200" /></div>
  <div><img src="http://dummyimage.com/200x300" /></div>
  <div><img src="http://dummyimage.com/300x400" /></div>
</div>

There are various solutions to this problem:

  • Resize every image by hand.
  • Implement a server-based image resizing algorythm (what about the processing time?).
  • Use just CSS and the padding-top technique as seen in sitepoint.com.
  • Use just CSS to force images to keep their aspect ratio (cleaner solution that the padding-top one IMO).

To keep the aspect ratio, we need images to have a <div> parent with position: relative, which is the one that will be in charge of having the necessary space so that the photo is embedded inside. A great use for this is in card elements, where the image container is preset with a fixed width/height or responsive measurements. Inside this <div> will be the image tag with position: absolute, being centered with the top, bottom, left, and right properties set to 0 and margin: auto, making the properties max-width and max-height the ones that define the width and height of the image. Basically we are forcing the image to “grow” from the center of its parent until one of the limits is reached (width, height, or both).

Let’s see it in action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.image-container {
  display: flex;
  flex-direction: row;
}

.image-container > div {
  margin: 0 10px;
  width: 100%;
  height: 180px; /* We have set a 180px height as an example */
  background: white; /* We have set a white background to see the image container width/height */
  position: relative;
}

.image-container > div > img {
  position: absolute;
  display: block;
  max-width: 100%;
  max-height: 100%;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
}

We can see that the aspect ratio of the images are being kept, and they automatically place themselves in the optimum position without being wider or longer than their parent element, neither lengthen, flatten, or lose viewing areas, and remarking that it is a solution where the size of the main container doesn’t matter, so it can be used for any responsive view.

View the demo code on JSFiddle.