Every web developer will face someday, the awesome task of work with columns in a layout with different content. I mean, we always see awesome templates that we found in snippets and demos on the internet and they simply look awesome simetric (however only with the same content):
But when we use the template and we just put some dynamic content, generated by some server side language:
It doesn't look so symmetrical at all, isn't ?.
You will be asking to yourself, why not simply use CSS for this task ? Well, the answer is pretty simple, making robust, responsive equal height columns for arbitrary content is difficult or almost impossible to do with CSS alone (at least without hacks or trickery, in a backwards compatible way, yeah we are talking about you IE9). This task should be accomplished using Javascript (or with jQuery), however, note that you should probably ensure that your layout is still usable for the user (remember that may be someone with javascript disabled).
If you decide to make a little script to achieve what you want, you may be thinking in something similar to:
Note: don't use the following snippet as it is too basic, it is just an example of the explanation of how the logic could work.
(function( $ ) {
// the sameHeight functions makes all the selected elements of the same height
$.fn.sameHeight = function() {
var selector = this;
var heights = [];
// Save the heights of every element into an array
selector.each(function(){
var height = $(this).height();
heights.push(height);
});
// Get the biggest height
var maxHeight = Math.max.apply(null, heights);
// Show in the console to verify
console.log(heights,maxHeight);
// Set the maxHeight to every selected element
selector.each(function(){
$(this).height(maxHeight);
});
};
}( jQuery ));
That should create the sameHeight method as a jQuery plugin, so we can use it like:
$('.my-selector').sameHeight();
$(window).resize(function(){
// Do it when the window resizes too
$('.my-selector').sameHeight();
});
But we don't recommend you to do it by yourself or using the previous snippet, it will take a lot of time making tests, instead we recommend you to use a library for this, as shown in the following area.
Implementation
Too many things to care about if you want to do it by yourself and a lot of tests to execute if you want to be sure that your own implementation really works. Don't reinvent the wheel and use a library to make it easy, functional and correct. In this case, we recommend you to use jquery.matchheight to achieve your goal. There are a lot of jQuery plugins that promise a completely script to make that your divs will be of the same height in every browser, however most of them fail, not because the user uses an old browser, but they don't implement their algorithm to the elements when the windows resizes, because you're using floating elements within a row or other kind of events like the modification of the DOM.
MatchHeight will make the height of all the selected elements exactly equal by using a simple selector and an initialization function. You can see a demo of MatchHeight in this page or visit directly the repository in Github to get a copy of the library. The main features of MatchHeight are:
- it matches the heights for groups of elements automatically.
- use the maximum height or define a specific target element.
- anywhere on the page and anywhere in the DOM.
- responsive (updates on window resize event).
- row aware (handles floating elements and wrapping).
- accounts for
box-sizing
and mixedpadding
,margin
,border
values. - handles images and other media (updates after loading).
- supports hidden or none-visible elements (e.g. those inside tab controls).
- throttled to balance performance and smoothness.
- easily removed when needed.
- maintain scroll position.
- data attributes API.
- callback events.
- tested in IE8+, Chrome, Firefox, Chrome Android.
To get started, get a copy of the match-height library in the Github repository or add the project as a dependency in NPM:
npm install jquery-match-height
Or with Bower:
bower install matchheight
Finally, include the library with a script tag in your document (note that jQuery needs to be included before):
<script src="jquery.matchHeight.js" type="text/javascript"></script>
And then you will be able to use the matchHeight library. You can use MatchHeight with either jQuery or using the data attributes API:
jQuery initialization
For our markup, we are using bootstrap:
<div class="row">
<div class="col-md-4 article" style="background-color:yellow;">
<h2>Article Title</h2>
<p>Hello <br> This has <br> a different height</p>
</div>
<div class="col-md-4 article" style="background-color:blue;">
<h2>Article Title</h2>
<p>Hello <br><br><br>This is not what it <br>looks like</p>
</div>
<div class="col-md-4 article" style="background-color:violet;">
<h2>Article Title</h2>
<p>Hello<br><br><br><br><br><br><br><br><br><br><br>a different height</p>
</div>
</div>
3 columns with a different height, in order to make them all of the same height, initialize matchHeight with jQuery (selecting the 3 elements with the article class):
$(".article").matchHeight();
And you don't have to worry about if your elements have the same height anymore, as matchHeight
will take care of all automatically. The matchHeight
method, can receive as first parameter an object with 4 properties:
$(".article").matchHeight({
byRow: true,
property: 'height',
target: null,
remove: false
});
byRow
istrue
orfalse
to enable row detectionproperty
is the CSS property name to set (e.g.'height'
or'min-height'
)target
is an optional element to use instead of the element with maximum heightremove
istrue
orfalse
to remove previous bindings instead of applying new ones
Data attributes API
You can initialize automatically the library using data attributes, e.g data-mh="group-name"
where group-name is an arbitrary string to identify which elements should be considered as a group (a kind of group id).
<div class="row">
<div class="col-md-4" style="background-color:yellow;" data-mh="article-group">
<h2>Article Title</h2>
<p>Hello <br> This has <br> a different height</p>
</div>
<div class="col-md-4" style="background-color:blue;" data-mh="article-group">
<h2>Article Title</h2>
<p>Hello <br><br><br>This is not what it <br>looks like</p>
</div>
<div class="col-md-4" style="background-color:violet;" data-mh="article-group">
<h2>Article Title</h2>
<p>Hello<br><br><br><br><br><br><br><br><br><br><br>a different height</p>
</div>
</div>
<div class="row">
<div class="col-md-4" style="background-color:yellow;" data-mh="blog-group">
<h2>Blog Title</h2>
<p>Hello <br> This has <br> a different height</p>
</div>
<div class="col-md-4" style="background-color:blue;" data-mh="blog-group">
<h2>Blog Title</h2>
<p>Hello <br><br><br>This is not what it <br>looks like</p>
</div>
<div class="col-md-4" style="background-color:violet;" data-mh="blog-group">
<h2>Blog Title</h2>
<p>Hello<br><br><br><br><br><br><br><br><br><br><br>a different height</p>
</div>
</div>
All elements with the same group name will be set to the same height when the page is loaded, regardless of their position in the DOM, without any extra code required.
Note that byRow
will be enabled when using the data API, if you don't want this (or require other options) then use the alternative method (with jQuery).
With the usage of any of the previous mentioned methods, you should see a simetric layout with your columns using jQuery:
Helper methods
If you want to work with this library and you want to know it thoroughly, then there are a couple of method worth to mention:
Trigger update event
If you've already initialized matchHeight in elements, and for some reason you need to update the adjust method,for example if you've modified some content, you can do it using:
$.fn.matchHeight._update()
Callbacks events
Since matchHeight automatically handles updating the layout after certain window events, you can supply functions as global callbacks if you need to be notified:
$.fn.matchHeight._beforeUpdate = function(event, groups) {
// do something before any updates are applied
}
$.fn.matchHeight._afterUpdate = function(event, groups) {
// do something after all updates are applied
}
If you need more information, please visit the advanced usage in the Github repository here.
Happy coding !