Sunday, August 21, 2016

Balanced Responsive Grid

I needed to create a responsive grid of logos and this is what I have done.

Step 1

I started creating a simple html with the img nested in couple of divs. Then I used the old fashioned float left. Is possible to use flex boxes for a better result. The first result was horrible due to the fact that images have all sort of pixel size and ratio.


Step 2

To adjust the things I decided to go with the padding-bottom-trick. Having padding-bottom equal 100% insure that the hight of the div is always square because it relate to the width of the parent div.

The just making the image position absolute and adding some style fix the rest. I used max-width and max height = 75% because I wanted to leave some margin around the logo.


The page is much better but I want to limit the max-size of the logo to a certain value, let's say 200px.

Step 3

So I added some math to the Sass that would generated media queries. I started with logos occupying 100% of the screen, so as soon the screen reach 200px I needed to add a media query that would the logos going in two columns.

The media query is
@media (min-width: 200px) {
  .logo {
    width: 50%;
  }
}
When those two logos reach again the maximum width, the screen will be at 200px * 2 = 400px. Time to add a new media query:
@media (min-width: 400px) {
  .logo {
    width: 33.33333%;
  }
}
And so on. To simplify the list of media queries I first created a mixin like
@mixin mediaQuery($lev)
 @media (min-width: $max-element-size * $lev)
  width: percentage( 1 / ( $lev + 1 ) )
Then I created a loop that generate the media query with the mixin
@while $level < $max-levels
 @include mediaQuery($level)
 $level: $level + 1
Now the page adjust itself beautifully and logos width is never wider than 200 pixels.

This would be the conclusion of the exercise until I noted that some font look larger than other. It is just a feeling because the logo share all the same container. Well, probably not just a feeling but it depends on the shape of the logo and eventually on the area of the logo.


Step 4

So I was thinking to calculate the area of the logo to compensate the size but calculating the are may be not trivial as it depend on the shape of the logo and not just the size of the image. Round logos have less area compare to the squared one.

So I decided to use the aspect ratio to influence the size of the logo. I eventually came out with this formula:
Size of the image (percentage) = minPerc + 
    ((( maxPerc - minPerc ) / ( maxRatio - 1 )) * ( r - 1 ) );
Dove r is the ratio of the image that can go from 1 for squared logos to a very large number for rectangular logos. A logos of size 100px horizontal and 50px vertical would have a ratio of 100/50 = 2. The ratio in this case ignore if the logo is bigger horizontally or vertically. So, to calculate the ration I used this formula:
r = Math.min( Math.max(x,y) / Math.min(x,y), maxRatio );
Where maxRatio is the maximum ratio that I will take in consideration. In my example I use 4 so that all logos that have a side longer more than 4 times the other side will all be treated in similar way.

The calculation of a new percentage of the image require width and height of the logo. These values are available once the image is loaded so it would be reasonable to apply the new percentage on the onload event for each image.

Unfortunately the onload event for image has several issues so I decided to go for a much more inelegant way of just waiting, using timers, for when the sizes are ready. There are probably better solutions than this.

While waiting for the new percentage to kick in, I let the css style to resize logos to an average size. So, in my example I will change the size of images from 90% to 50%, depending on the ratio.

Logos contained in a squared shape with a ratio of 1 will have a percentage of 50%; rectangular logos that have one side 4 times or more longer than the other will have a percentage of 90%. Everything else goes in between these two limit cases.

This is the final result (note how the rectangular logos shrink and the square logo enlarge):