Let's say you want to display elements (like little cards), and you want them to display like this :
In a nutshell : always fill full width of the container, wrapping, keeping a minimum fixed size, and of course fill the rows with the maximum cards possible.
Consequently, we can already say that:
- Fixed width are not an option because it will not fill the full width of the container
- Width in percent won't work because you can't add more tiles to the same line without making an extra media query (can be very boring and this is not scalable at all if you want one day to change the content and the minimum width of the cards)
My first though was about flexbox, it ended up like that :
You can see a jsfiddle here to see the code.
We can notice the first line is perfect ! However, if independently of how many lines there are, if the last line doesn't have the same number of elements than the others, it will not display well. (ie stick to the left).
It is normal considering how flex-grow works. But then how to create the effect ?
My solution was to create a custom directive (I work with Angular), it works pretty well (my first images are displayed like that thanks to it.
Here is the directive code :
(function () {
'use strict';
angular.module('app')
.directive('flexGrowConsistent', function ($window, $document) {
var directive = {};
directive.restrict = 'A';
directive.link = function (scope, elements, attrs) {
$document.ready(onResize);
function onResize() {
//container width
var cw = elements[0].parentElement.offsetWidth;
// first element width
var w = elements[0].parentElement.firstElementChild.offsetWidth;
if (isWrapped(w, cw, scope.$index)) {
elements.css({
maxWidth: w + 'px'
});
}
}
/*
Tell if an element is wrapped given element width, container width and index
Take care of the incertainty from javascript with the -0.5
*/
function isWrapped(w, cw, index) {
return ((w - 0.5) * (index + 1) > cw) && index > 0;
}
function cleanUp() {
angular.element($window).off('resize', onResize);
}
angular.element($window).on('resize', onResize);
scope.$on('$destroy', cleanUp);
};
return directive;
}
);
})();
My question is : is there a way to do this with pure CSS ?. I really dislike to use Javascript for a pure display purpose.
If you have propositions to improve the directive, they are welcome as well.