JavaScript - Match Height: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 3: Zeile 3:
  
 
Etwas ausgereifter als Equal Heights aber auch etwas größer. Allerdings sehr zuverlässig.
 
Etwas ausgereifter als Equal Heights aber auch etwas größer. Allerdings sehr zuverlässig.
 +
=== Source ===
 +
<syntaxhighlight lang="javascript">
 +
/**
 +
* jquery-match-height master by @liabru
 +
* http://brm.io/jquery-match-height/
 +
* License: MIT
 +
*/
  
 +
;(function(factory) { // eslint-disable-line no-extra-semi
 +
    'use strict';
 +
    if (typeof define === 'function' && define.amd) {
 +
        // AMD
 +
        define(['jquery'], factory);
 +
    } else if (typeof module !== 'undefined' && module.exports) {
 +
        // CommonJS
 +
        module.exports = factory(require('jquery'));
 +
    } else {
 +
        // Global
 +
        factory(jQuery);
 +
    }
 +
})(function($) {
 +
    /*
 +
    *  internal
 +
    */
  
 +
    var _previousResizeWidth = -1,
 +
        _updateTimeout = -1;
 +
 +
    /*
 +
    *  _parse
 +
    *  value parse utility function
 +
    */
 +
 +
    var _parse = function(value) {
 +
        // parse value and convert NaN to 0
 +
        return parseFloat(value) || 0;
 +
    };
 +
 +
    /*
 +
    *  _rows
 +
    *  utility function returns array of jQuery selections representing each row
 +
    *  (as displayed after float wrapping applied by browser)
 +
    */
 +
 +
    var _rows = function(elements) {
 +
        var tolerance = 1,
 +
            $elements = $(elements),
 +
            lastTop = null,
 +
            rows = [];
 +
 +
        // group elements by their top position
 +
        $elements.each(function(){
 +
            var $that = $(this),
 +
                top = $that.offset().top - _parse($that.css('margin-top')),
 +
                lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
 +
 +
            if (lastRow === null) {
 +
                // first item on the row, so just push it
 +
                rows.push($that);
 +
            } else {
 +
                // if the row top is the same, add to the row group
 +
                if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
 +
                    rows[rows.length - 1] = lastRow.add($that);
 +
                } else {
 +
                    // otherwise start a new row group
 +
                    rows.push($that);
 +
                }
 +
            }
 +
 +
            // keep track of the last row top
 +
            lastTop = top;
 +
        });
 +
 +
        return rows;
 +
    };
 +
 +
    /*
 +
    *  _parseOptions
 +
    *  handle plugin options
 +
    */
 +
 +
    var _parseOptions = function(options) {
 +
        var opts = {
 +
            byRow: true,
 +
            property: 'height',
 +
            target: null,
 +
            remove: false
 +
        };
 +
 +
        if (typeof options === 'object') {
 +
            return $.extend(opts, options);
 +
        }
 +
 +
        if (typeof options === 'boolean') {
 +
            opts.byRow = options;
 +
        } else if (options === 'remove') {
 +
            opts.remove = true;
 +
        }
 +
 +
        return opts;
 +
    };
 +
 +
    /*
 +
    *  matchHeight
 +
    *  plugin definition
 +
    */
 +
 +
    var matchHeight = $.fn.matchHeight = function(options) {
 +
        var opts = _parseOptions(options);
 +
 +
        // handle remove
 +
        if (opts.remove) {
 +
            var that = this;
 +
 +
            // remove fixed height from all selected elements
 +
            this.css(opts.property, '');
 +
 +
            // remove selected elements from all groups
 +
            $.each(matchHeight._groups, function(key, group) {
 +
                group.elements = group.elements.not(that);
 +
            });
 +
 +
            // TODO: cleanup empty groups
 +
 +
            return this;
 +
        }
 +
 +
        if (this.length <= 1 && !opts.target) {
 +
            return this;
 +
        }
 +
 +
        // keep track of this group so we can re-apply later on load and resize events
 +
        matchHeight._groups.push({
 +
            elements: this,
 +
            options: opts
 +
        });
 +
 +
        // match each element's height to the tallest element in the selection
 +
        matchHeight._apply(this, opts);
 +
 +
        return this;
 +
    };
 +
 +
    /*
 +
    *  plugin global options
 +
    */
 +
 +
    matchHeight.version = 'master';
 +
    matchHeight._groups = [];
 +
    matchHeight._throttle = 80;
 +
    matchHeight._maintainScroll = false;
 +
    matchHeight._beforeUpdate = null;
 +
    matchHeight._afterUpdate = null;
 +
    matchHeight._rows = _rows;
 +
    matchHeight._parse = _parse;
 +
    matchHeight._parseOptions = _parseOptions;
 +
 +
    /*
 +
    *  matchHeight._apply
 +
    *  apply matchHeight to given elements
 +
    */
 +
 +
    matchHeight._apply = function(elements, options) {
 +
        var opts = _parseOptions(options),
 +
            $elements = $(elements),
 +
            rows = [$elements];
 +
 +
        // take note of scroll position
 +
        var scrollTop = $(window).scrollTop(),
 +
            htmlHeight = $('html').outerHeight(true);
 +
 +
        // get hidden parents
 +
        var $hiddenParents = $elements.parents().filter(':hidden');
 +
 +
        // cache the original inline style
 +
        $hiddenParents.each(function() {
 +
            var $that = $(this);
 +
            $that.data('style-cache', $that.attr('style'));
 +
        });
 +
 +
        // temporarily must force hidden parents visible
 +
        $hiddenParents.css('display', 'block');
 +
 +
        // get rows if using byRow, otherwise assume one row
 +
        if (opts.byRow && !opts.target) {
 +
 +
            // must first force an arbitrary equal height so floating elements break evenly
 +
            $elements.each(function() {
 +
                var $that = $(this),
 +
                    display = $that.css('display');
 +
 +
                // temporarily force a usable display value
 +
                if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
 +
                    display = 'block';
 +
                }
 +
 +
                // cache the original inline style
 +
                $that.data('style-cache', $that.attr('style'));
 +
 +
                $that.css({
 +
                    'display': display,
 +
                    'padding-top': '0',
 +
                    'padding-bottom': '0',
 +
                    'margin-top': '0',
 +
                    'margin-bottom': '0',
 +
                    'border-top-width': '0',
 +
                    'border-bottom-width': '0',
 +
                    'height': '100px',
 +
                    'overflow': 'hidden'
 +
                });
 +
            });
 +
 +
            // get the array of rows (based on element top position)
 +
            rows = _rows($elements);
 +
 +
            // revert original inline styles
 +
            $elements.each(function() {
 +
                var $that = $(this);
 +
                $that.attr('style', $that.data('style-cache') || '');
 +
            });
 +
        }
 +
 +
        $.each(rows, function(key, row) {
 +
            var $row = $(row),
 +
                targetHeight = 0;
 +
 +
            if (!opts.target) {
 +
                // skip apply to rows with only one item
 +
                if (opts.byRow && $row.length <= 1) {
 +
                    $row.css(opts.property, '');
 +
                    return;
 +
                }
 +
 +
                // iterate the row and find the max height
 +
                $row.each(function(){
 +
                    var $that = $(this),
 +
                        style = $that.attr('style'),
 +
                        display = $that.css('display');
 +
 +
                    // temporarily force a usable display value
 +
                    if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
 +
                        display = 'block';
 +
                    }
 +
 +
                    // ensure we get the correct actual height (and not a previously set height value)
 +
                    var css = { 'display': display };
 +
                    css[opts.property] = '';
 +
                    $that.css(css);
 +
 +
                    // find the max height (including padding, but not margin)
 +
                    if ($that.outerHeight(false) > targetHeight) {
 +
                        targetHeight = $that.outerHeight(false);
 +
                    }
 +
 +
                    // revert styles
 +
                    if (style) {
 +
                        $that.attr('style', style);
 +
                    } else {
 +
                        $that.css('display', '');
 +
                    }
 +
                });
 +
            } else {
 +
                // if target set, use the height of the target element
 +
                targetHeight = opts.target.outerHeight(false);
 +
            }
 +
 +
            // iterate the row and apply the height to all elements
 +
            $row.each(function(){
 +
                var $that = $(this),
 +
                    verticalPadding = 0;
 +
 +
                // don't apply to a target
 +
                if (opts.target && $that.is(opts.target)) {
 +
                    return;
 +
                }
 +
 +
                // handle padding and border correctly (required when not using border-box)
 +
                if ($that.css('box-sizing') !== 'border-box') {
 +
                    verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
 +
                    verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
 +
                }
 +
 +
                // set the height (accounting for padding and border)
 +
                $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
 +
            });
 +
        });
 +
 +
        // revert hidden parents
 +
        $hiddenParents.each(function() {
 +
            var $that = $(this);
 +
            $that.attr('style', $that.data('style-cache') || null);
 +
        });
 +
 +
        // restore scroll position if enabled
 +
        if (matchHeight._maintainScroll) {
 +
            $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
 +
        }
 +
 +
        return this;
 +
    };
 +
 +
    /*
 +
    *  matchHeight._applyDataApi
 +
    *  applies matchHeight to all elements with a data-match-height attribute
 +
    */
 +
 +
    matchHeight._applyDataApi = function() {
 +
        var groups = {};
 +
 +
        // generate groups by their groupId set by elements using data-match-height
 +
        $('[data-match-height], [data-mh]').each(function() {
 +
            var $this = $(this),
 +
                groupId = $this.attr('data-mh') || $this.attr('data-match-height');
 +
 +
            if (groupId in groups) {
 +
                groups[groupId] = groups[groupId].add($this);
 +
            } else {
 +
                groups[groupId] = $this;
 +
            }
 +
        });
 +
 +
        // apply matchHeight to each group
 +
        $.each(groups, function() {
 +
            this.matchHeight(true);
 +
        });
 +
    };
 +
 +
    /*
 +
    *  matchHeight._update
 +
    *  updates matchHeight on all current groups with their correct options
 +
    */
 +
 +
    var _update = function(event) {
 +
        if (matchHeight._beforeUpdate) {
 +
            matchHeight._beforeUpdate(event, matchHeight._groups);
 +
        }
 +
 +
        $.each(matchHeight._groups, function() {
 +
            matchHeight._apply(this.elements, this.options);
 +
        });
 +
 +
        if (matchHeight._afterUpdate) {
 +
            matchHeight._afterUpdate(event, matchHeight._groups);
 +
        }
 +
    };
 +
 +
    matchHeight._update = function(throttle, event) {
 +
        // prevent update if fired from a resize event
 +
        // where the viewport width hasn't actually changed
 +
        // fixes an event looping bug in IE8
 +
        if (event && event.type === 'resize') {
 +
            var windowWidth = $(window).width();
 +
            if (windowWidth === _previousResizeWidth) {
 +
                return;
 +
            }
 +
            _previousResizeWidth = windowWidth;
 +
        }
 +
 +
        // throttle updates
 +
        if (!throttle) {
 +
            _update(event);
 +
        } else if (_updateTimeout === -1) {
 +
            _updateTimeout = setTimeout(function() {
 +
                _update(event);
 +
                _updateTimeout = -1;
 +
            }, matchHeight._throttle);
 +
        }
 +
    };
 +
 +
    /*
 +
    *  bind events
 +
    */
 +
 +
    // apply on DOM ready event
 +
    $(matchHeight._applyDataApi);
 +
 +
    // use on or bind where supported
 +
    var on = $.fn.on ? 'on' : 'bind';
 +
 +
    // update heights on load and resize events
 +
    $(window)[on]('load', function(event) {
 +
        matchHeight._update(false, event);
 +
    });
 +
 +
    // throttled update heights on resize events
 +
    $(window)[on]('resize orientationchange', function(event) {
 +
        matchHeight._update(true, event);
 +
    });
 +
 +
});
 +
</syntaxhighlight>
 +
===Doku===
 +
<pre>
 +
 +
<script src="jquery.matchHeight.js" type="text/javascript"></script>
 +
You can also install using the package managers Bower and NPM.
 +
 +
bower install matchheight
 +
npm install jquery-match-height
 +
Usage
 +
 +
$(function() {
 +
$('.item').matchHeight(options);
 +
});
 +
Where options is an optional parameter.
 +
See below for a description of the available options and defaults.
 +
 +
The above example will set all selected elements with the class item to the height of the tallest.
 +
If the items are on multiple rows, the items of each row will be set to the tallest of that row (see byRow option).
 +
 +
Call this on the DOM ready event (the plugin will automatically update on window load).
 +
See the included test.html for many working examples.
 +
 +
Also see the Data API below for a simple, alternative inline usage.
 +
 +
Options
 +
 +
The default options are:
 +
 +
{
 +
    byRow: true,
 +
    property: 'height',
 +
    target: null,
 +
    remove: false
 +
}
 +
Where:
 +
 +
byRow is true or false to enable row detection
 +
property 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 height
 +
remove is true or false to remove previous bindings instead of applying new ones
 +
Data API
 +
 +
Use the data attribute data-mh="group-name" where group-name is an arbitrary string to identify which elements should be considered as a group.
 +
 +
<div data-mh="my-group">My text</div>
 +
<div data-mh="my-group">Some other text</div>
 +
<div data-mh="my-other-group">Even more text</div>
 +
<div data-mh="my-other-group">The last bit of text</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 above.
 +
 +
Advanced Usage
 +
 +
There are some additional functions and properties you should know about:
 +
 +
Manually trigger an update
 +
 +
$.fn.matchHeight._update()
 +
If you need to manually trigger an update of all currently set groups, for example if you've modified some content.
 +
 +
Row detection
 +
 +
You can toggle row detection by setting the byRow option, which defaults to true.
 +
It's also possible to use the row detection function at any time:
 +
 +
$.fn.matchHeight._rows($('.item'));
 +
Which will return an array of element selections for each row, see this thread for more information and an example.
 +
 +
Remove bindings
 +
 +
$('.item').matchHeight({ remove: true });
 +
This will remove all bindings for the selected elements, from all groups.
 +
 +
Custom target element
 +
 +
$(function() {
 +
$('.item').matchHeight({
 +
        target: $('.sidebar')
 +
    });
 +
});
 +
Will set all selected elements to the height of the first item with class sidebar.
 +
 +
Custom property
 +
 +
$('.item').matchHeight({ property: 'min-height' });
 +
This will set the min-height property instead of the height property.
 +
 +
Callback 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
 +
}
 +
Where event a jQuery event object (e.g. load, resize, orientationchange) and groups is a reference to $.fn.matchHeight._groups (see below).
 +
 +
Manually apply match height
 +
 +
$.fn.matchHeight._apply(elements, options)
 +
Use the apply function directly if you wish to avoid the automatic update functionality.
 +
 +
Throttling resize updates
 +
 +
$.fn.matchHeight._throttle = 80;
 +
By default, the _update method is throttled to execute at a maximum rate of once every 80ms. Decreasing the above _throttle property will update your layout quicker, appearing smoother during resize, at the expense of performance. If you experience lagging or freezing during resize, you should increase the _throttle property.
 +
 +
Maintain scroll position
 +
 +
$.fn.matchHeight._maintainScroll = true;
 +
Under certain conditions where the size of the page is dynamically changing, such as during resize or when adding new elements, browser bugs cause the page scroll position to change unexpectedly.
 +
 +
If you are observing this behaviour, use the above line to automatically attempt to force scroll position to be maintained (approximately). This is a global setting and by default it is false.
 +
 +
Accessing current group bindings
 +
 +
$.fn.matchHeight._groups
 +
The array that contains all element groups that have had matchHeight applied. Used internally for automatically updating on resize events, but you may modify this array if you need to manually access any groups (e.g. if you're deleting elements).
 +
 +
Tests
 +
 +
Open test/page/test.html in your browser to run unit tests via the jasmine test runner.
 +
 +
If you wish to contribute functionality to this project, you are encouraged to add new tests following the same conventions.
 +
 +
Run gulp test to run unit tests on multiple browsers and multiple resolutions, automatically through selenium.
 +
 +
Run gulp test:cloud to test on even more browsers via a cloud service (you will need to create a file called test/conf/private.conf.js with your cloud credentials that looks like this:
 +
 +
exports.config = {
 +
    user: 'username',
 +
    key: 'key'
 +
};
 +
Cloud browser testing for this project is provided by BrowserStack (which is free for open source).
 +
 +
Known limitations
 +
 +
CSS transitions and animations are not supported
 +
 +
You should ensure that there are no transitions or other animations that will delay the height changes of the elements you are matching, including any transition: all rules. Otherwise the plugin will produce unexpected results, as animations can't be accounted for.
 +
 +
Delayed webfonts may cause incorrect height
 +
 +
Some browsers do not wait for webfonts to load before firing the window load event, so if the font loads too slowly the plugin may produce unexpected results.
 +
 +
If this is a problem, you should call _update once your font has loaded by using something like the webfontloader script.
 +
 +
Content changes require a manual update
 +
 +
If you change the content inside an element that has had matchHeight applied, then you must manually call $.fn.matchHeight._update() afterwards. This will update of all currently set equal heights groups.
 +
 +
Also note that previous matchHeight bindings do not apply to new elements, even if they match the selector used. In this case you must remove the old bindings and add new ones, see this comment.
 +
</pre>
  
 
== jQuery - Equal Heights ==
 
== jQuery - Equal Heights ==

Version vom 28. April 2017, 20:44 Uhr

jQuery - MatchHeight

https://github.com/liabru/jquery-match-height

Etwas ausgereifter als Equal Heights aber auch etwas größer. Allerdings sehr zuverlässig.

Source

/**
* jquery-match-height master by @liabru
* http://brm.io/jquery-match-height/
* License: MIT
*/

;(function(factory) { // eslint-disable-line no-extra-semi
    'use strict';
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof module !== 'undefined' && module.exports) {
        // CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Global
        factory(jQuery);
    }
})(function($) {
    /*
    *  internal
    */

    var _previousResizeWidth = -1,
        _updateTimeout = -1;

    /*
    *  _parse
    *  value parse utility function
    */

    var _parse = function(value) {
        // parse value and convert NaN to 0
        return parseFloat(value) || 0;
    };

    /*
    *  _rows
    *  utility function returns array of jQuery selections representing each row
    *  (as displayed after float wrapping applied by browser)
    */

    var _rows = function(elements) {
        var tolerance = 1,
            $elements = $(elements),
            lastTop = null,
            rows = [];

        // group elements by their top position
        $elements.each(function(){
            var $that = $(this),
                top = $that.offset().top - _parse($that.css('margin-top')),
                lastRow = rows.length > 0 ? rows[rows.length - 1] : null;

            if (lastRow === null) {
                // first item on the row, so just push it
                rows.push($that);
            } else {
                // if the row top is the same, add to the row group
                if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
                    rows[rows.length - 1] = lastRow.add($that);
                } else {
                    // otherwise start a new row group
                    rows.push($that);
                }
            }

            // keep track of the last row top
            lastTop = top;
        });

        return rows;
    };

    /*
    *  _parseOptions
    *  handle plugin options
    */

    var _parseOptions = function(options) {
        var opts = {
            byRow: true,
            property: 'height',
            target: null,
            remove: false
        };

        if (typeof options === 'object') {
            return $.extend(opts, options);
        }

        if (typeof options === 'boolean') {
            opts.byRow = options;
        } else if (options === 'remove') {
            opts.remove = true;
        }

        return opts;
    };

    /*
    *  matchHeight
    *  plugin definition
    */

    var matchHeight = $.fn.matchHeight = function(options) {
        var opts = _parseOptions(options);

        // handle remove
        if (opts.remove) {
            var that = this;

            // remove fixed height from all selected elements
            this.css(opts.property, '');

            // remove selected elements from all groups
            $.each(matchHeight._groups, function(key, group) {
                group.elements = group.elements.not(that);
            });

            // TODO: cleanup empty groups

            return this;
        }

        if (this.length <= 1 && !opts.target) {
            return this;
        }

        // keep track of this group so we can re-apply later on load and resize events
        matchHeight._groups.push({
            elements: this,
            options: opts
        });

        // match each element's height to the tallest element in the selection
        matchHeight._apply(this, opts);

        return this;
    };

    /*
    *  plugin global options
    */

    matchHeight.version = 'master';
    matchHeight._groups = [];
    matchHeight._throttle = 80;
    matchHeight._maintainScroll = false;
    matchHeight._beforeUpdate = null;
    matchHeight._afterUpdate = null;
    matchHeight._rows = _rows;
    matchHeight._parse = _parse;
    matchHeight._parseOptions = _parseOptions;

    /*
    *  matchHeight._apply
    *  apply matchHeight to given elements
    */

    matchHeight._apply = function(elements, options) {
        var opts = _parseOptions(options),
            $elements = $(elements),
            rows = [$elements];

        // take note of scroll position
        var scrollTop = $(window).scrollTop(),
            htmlHeight = $('html').outerHeight(true);

        // get hidden parents
        var $hiddenParents = $elements.parents().filter(':hidden');

        // cache the original inline style
        $hiddenParents.each(function() {
            var $that = $(this);
            $that.data('style-cache', $that.attr('style'));
        });

        // temporarily must force hidden parents visible
        $hiddenParents.css('display', 'block');

        // get rows if using byRow, otherwise assume one row
        if (opts.byRow && !opts.target) {

            // must first force an arbitrary equal height so floating elements break evenly
            $elements.each(function() {
                var $that = $(this),
                    display = $that.css('display');

                // temporarily force a usable display value
                if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
                    display = 'block';
                }

                // cache the original inline style
                $that.data('style-cache', $that.attr('style'));

                $that.css({
                    'display': display,
                    'padding-top': '0',
                    'padding-bottom': '0',
                    'margin-top': '0',
                    'margin-bottom': '0',
                    'border-top-width': '0',
                    'border-bottom-width': '0',
                    'height': '100px',
                    'overflow': 'hidden'
                });
            });

            // get the array of rows (based on element top position)
            rows = _rows($elements);

            // revert original inline styles
            $elements.each(function() {
                var $that = $(this);
                $that.attr('style', $that.data('style-cache') || '');
            });
        }

        $.each(rows, function(key, row) {
            var $row = $(row),
                targetHeight = 0;

            if (!opts.target) {
                // skip apply to rows with only one item
                if (opts.byRow && $row.length <= 1) {
                    $row.css(opts.property, '');
                    return;
                }

                // iterate the row and find the max height
                $row.each(function(){
                    var $that = $(this),
                        style = $that.attr('style'),
                        display = $that.css('display');

                    // temporarily force a usable display value
                    if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
                        display = 'block';
                    }

                    // ensure we get the correct actual height (and not a previously set height value)
                    var css = { 'display': display };
                    css[opts.property] = '';
                    $that.css(css);

                    // find the max height (including padding, but not margin)
                    if ($that.outerHeight(false) > targetHeight) {
                        targetHeight = $that.outerHeight(false);
                    }

                    // revert styles
                    if (style) {
                        $that.attr('style', style);
                    } else {
                        $that.css('display', '');
                    }
                });
            } else {
                // if target set, use the height of the target element
                targetHeight = opts.target.outerHeight(false);
            }

            // iterate the row and apply the height to all elements
            $row.each(function(){
                var $that = $(this),
                    verticalPadding = 0;

                // don't apply to a target
                if (opts.target && $that.is(opts.target)) {
                    return;
                }

                // handle padding and border correctly (required when not using border-box)
                if ($that.css('box-sizing') !== 'border-box') {
                    verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
                    verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
                }

                // set the height (accounting for padding and border)
                $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
            });
        });

        // revert hidden parents
        $hiddenParents.each(function() {
            var $that = $(this);
            $that.attr('style', $that.data('style-cache') || null);
        });

        // restore scroll position if enabled
        if (matchHeight._maintainScroll) {
            $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
        }

        return this;
    };

    /*
    *  matchHeight._applyDataApi
    *  applies matchHeight to all elements with a data-match-height attribute
    */

    matchHeight._applyDataApi = function() {
        var groups = {};

        // generate groups by their groupId set by elements using data-match-height
        $('[data-match-height], [data-mh]').each(function() {
            var $this = $(this),
                groupId = $this.attr('data-mh') || $this.attr('data-match-height');

            if (groupId in groups) {
                groups[groupId] = groups[groupId].add($this);
            } else {
                groups[groupId] = $this;
            }
        });

        // apply matchHeight to each group
        $.each(groups, function() {
            this.matchHeight(true);
        });
    };

    /*
    *  matchHeight._update
    *  updates matchHeight on all current groups with their correct options
    */

    var _update = function(event) {
        if (matchHeight._beforeUpdate) {
            matchHeight._beforeUpdate(event, matchHeight._groups);
        }

        $.each(matchHeight._groups, function() {
            matchHeight._apply(this.elements, this.options);
        });

        if (matchHeight._afterUpdate) {
            matchHeight._afterUpdate(event, matchHeight._groups);
        }
    };

    matchHeight._update = function(throttle, event) {
        // prevent update if fired from a resize event
        // where the viewport width hasn't actually changed
        // fixes an event looping bug in IE8
        if (event && event.type === 'resize') {
            var windowWidth = $(window).width();
            if (windowWidth === _previousResizeWidth) {
                return;
            }
            _previousResizeWidth = windowWidth;
        }

        // throttle updates
        if (!throttle) {
            _update(event);
        } else if (_updateTimeout === -1) {
            _updateTimeout = setTimeout(function() {
                _update(event);
                _updateTimeout = -1;
            }, matchHeight._throttle);
        }
    };

    /*
    *  bind events
    */

    // apply on DOM ready event
    $(matchHeight._applyDataApi);

    // use on or bind where supported
    var on = $.fn.on ? 'on' : 'bind';

    // update heights on load and resize events
    $(window)[on]('load', function(event) {
        matchHeight._update(false, event);
    });

    // throttled update heights on resize events
    $(window)[on]('resize orientationchange', function(event) {
        matchHeight._update(true, event);
    });

});

Doku


<script src="jquery.matchHeight.js" type="text/javascript"></script>
You can also install using the package managers Bower and NPM.

bower install matchheight
npm install jquery-match-height
Usage

$(function() {
	$('.item').matchHeight(options);
});
Where options is an optional parameter.
See below for a description of the available options and defaults.

The above example will set all selected elements with the class item to the height of the tallest.
If the items are on multiple rows, the items of each row will be set to the tallest of that row (see byRow option).

Call this on the DOM ready event (the plugin will automatically update on window load).
See the included test.html for many working examples.

Also see the Data API below for a simple, alternative inline usage.

Options

The default options are:

{
    byRow: true,
    property: 'height',
    target: null,
    remove: false
}
Where:

byRow is true or false to enable row detection
property 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 height
remove is true or false to remove previous bindings instead of applying new ones
Data API

Use the data attribute data-mh="group-name" where group-name is an arbitrary string to identify which elements should be considered as a group.

<div data-mh="my-group">My text</div>
<div data-mh="my-group">Some other text</div>
<div data-mh="my-other-group">Even more text</div>
<div data-mh="my-other-group">The last bit of text</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 above.

Advanced Usage

There are some additional functions and properties you should know about:

Manually trigger an update

$.fn.matchHeight._update()
If you need to manually trigger an update of all currently set groups, for example if you've modified some content.

Row detection

You can toggle row detection by setting the byRow option, which defaults to true.
It's also possible to use the row detection function at any time:

$.fn.matchHeight._rows($('.item'));
Which will return an array of element selections for each row, see this thread for more information and an example.

Remove bindings

$('.item').matchHeight({ remove: true });
This will remove all bindings for the selected elements, from all groups.

Custom target element

$(function() {
	$('.item').matchHeight({
        target: $('.sidebar')
    });
});
Will set all selected elements to the height of the first item with class sidebar.

Custom property

$('.item').matchHeight({ property: 'min-height' });
This will set the min-height property instead of the height property.

Callback 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
}
Where event a jQuery event object (e.g. load, resize, orientationchange) and groups is a reference to $.fn.matchHeight._groups (see below).

Manually apply match height

$.fn.matchHeight._apply(elements, options)
Use the apply function directly if you wish to avoid the automatic update functionality.

Throttling resize updates

$.fn.matchHeight._throttle = 80;
By default, the _update method is throttled to execute at a maximum rate of once every 80ms. Decreasing the above _throttle property will update your layout quicker, appearing smoother during resize, at the expense of performance. If you experience lagging or freezing during resize, you should increase the _throttle property.

Maintain scroll position

$.fn.matchHeight._maintainScroll = true;
Under certain conditions where the size of the page is dynamically changing, such as during resize or when adding new elements, browser bugs cause the page scroll position to change unexpectedly.

If you are observing this behaviour, use the above line to automatically attempt to force scroll position to be maintained (approximately). This is a global setting and by default it is false.

Accessing current group bindings

$.fn.matchHeight._groups
The array that contains all element groups that have had matchHeight applied. Used internally for automatically updating on resize events, but you may modify this array if you need to manually access any groups (e.g. if you're deleting elements).

Tests

Open test/page/test.html in your browser to run unit tests via the jasmine test runner.

If you wish to contribute functionality to this project, you are encouraged to add new tests following the same conventions.

Run gulp test to run unit tests on multiple browsers and multiple resolutions, automatically through selenium.

Run gulp test:cloud to test on even more browsers via a cloud service (you will need to create a file called test/conf/private.conf.js with your cloud credentials that looks like this:

exports.config = {
    user: 'username',
    key: 'key'
};
Cloud browser testing for this project is provided by BrowserStack (which is free for open source).

Known limitations

CSS transitions and animations are not supported

You should ensure that there are no transitions or other animations that will delay the height changes of the elements you are matching, including any transition: all rules. Otherwise the plugin will produce unexpected results, as animations can't be accounted for.

Delayed webfonts may cause incorrect height

Some browsers do not wait for webfonts to load before firing the window load event, so if the font loads too slowly the plugin may produce unexpected results.

If this is a problem, you should call _update once your font has loaded by using something like the webfontloader script.

Content changes require a manual update

If you change the content inside an element that has had matchHeight applied, then you must manually call $.fn.matchHeight._update() afterwards. This will update of all currently set equal heights groups.

Also note that previous matchHeight bindings do not apply to new elements, even if they match the selector used. In this case you must remove the old bindings and add new ones, see this comment.

jQuery - Equal Heights

/* 
 /* * @Copyright (c) 2013 James Stoddern - info@jamesstoddern.net  
 * web:jamesstoddern.net  
 *  
 * Permission is hereby granted, free of charge, to any person  
 * obtaining a copy of this software and associated documentation  
 * files (the "Software"), to deal in the Software without  
 * restriction, including without limitation the rights to use,  
 * copy, modify, merge, publish, distribute, sublicense, and/or sell  
 * copies of the Software, and to permit persons to whom the  
 * Software is furnished to do so, subject to the following  
 * conditions:  
 * The above copyright notice and this permission notice shall be  
 * included in all copies or substantial portions of the Software.  
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES  
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,  
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  
 * OTHER DEALINGS IN THE SOFTWARE.  
 *  
 * How to use it:  
 *  
 * If you have a series of floated columns, which you wish to make the same height, give them all the same  
 * class, and then run the plugin. It will determine the tallest div, and equalise the height of the rest  
 *  
 * $('.selector').equalHeights();  
 *  
 *  
 */
 
(function( $ ) {
    $.fn.equalHeights = function() {
        var tallestElement = 0;
        var startRow = 0;
        var elements = new Array();
        var $currentElement;
        var topPosition = 0;
 
        this.each(function() {
 
            $currentElement = $(this);
            topPostion = $currentElement.position().top;
 
            if (startRow != topPostion) {
                for (currentDiv = 0 ; currentDiv < elements.length ; currentDiv++) {
                    elements[currentDiv].height(tallestElement);
                }
 
                elements.length = 0;
                startRow = topPostion;
                tallestElement = $currentElement.height();
                elements.push($currentElement);
 
            } else {
                elements.push($currentElement);
                tallestElement = (tallestElement < $currentElement.height()) ? ($currentElement.height()) : (tallestElement);
 
            }
 
            for (currentDiv = 0 ; currentDiv < elements.length ; currentDiv++) {
                elements[currentDiv].height(tallestElement);
            }
 
        });
 
    };
}) ( jQuery );