jQuery: получить высоту скрытого элемента в jQuery

Мне нужно получить высоту элемента, который находится в div, который скрыт. Прямо сейчас я показываю div, получаю высоту и скрываю Родительский div. Это кажется немного глупым. Есть ли лучший способ?

Я использую jQuery 1.4.2:

$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();

15 ответов


вы могли бы сделать что-то подобное, немного суховато, забыть position если он уже абсолютный:

var previousCss  = $("#myDiv").attr("style");

$("#myDiv")
    .css({
        position:   'absolute', // Optional if #myDiv is already absolute
        visibility: 'hidden',
        display:    'block'
    });

optionHeight = $("#myDiv").height();

$("#myDiv").attr("style", previousCss ? previousCss : "");

я столкнулся с той же проблемой с получением скрытой ширины элемента, поэтому я написал этот вызов плагина jQuery и фактический исправить. Вместо использования

$('#some-element').height();

использовать

$('#some-element').actual('height');

даст вам правильное значение для скрытого элемента или элемента имеет скрытый родитель.

полную документацию см. здесь. Существует также демо включают в себя на странице.

надеюсь, что это поможет :)


вы confuising двух стилей CSS, тег тип дисплея и стиль видимость.

Если элемент скрыт, установив стиль видимости css, то вы должны иметь возможность получить высоту независимо от того, является ли элемент видимым или нет, как элемент по-прежнему занимает место на странице.

Если элемент скрыт, изменив стиль отображения css на "нет", то элемент не занимает места на странице, и вам нужно будет дать ему стиль отображения, который заставит элемент отображаться в некотором пространстве, и в этот момент Вы можете получить высоту.


Я на самом деле прибегал к некоторым трюкам, чтобы справиться с этим время от времени. Я разработал виджет прокрутки jQuery, где я столкнулся с проблемой, которую я не знаю заранее, является ли прокручиваемый контент частью скрытой части разметки или нет. Вот что я сделал:--2-->

// try to grab the height of the elem
if (this.element.height() > 0) {
    var scroller_height = this.element.height();
    var scroller_width = this.element.width();

// if height is zero, then we're dealing with a hidden element
} else {
    var copied_elem = this.element.clone()
                      .attr("id", false)
                      .css({visibility:"hidden", display:"block", 
                               position:"absolute"});
    $("body").append(copied_elem);
    var scroller_height = copied_elem.height();
    var scroller_width = copied_elem.width();
    copied_elem.remove();
}

это работает по большей части, но есть очевидная проблема, которая потенциально может возникнуть. Если контент вы не клонирование стиле с CSS, который содержит ссылки на родителя разметки в правила, клонированный контент не будет содержать соответствующего стиля и, вероятно, будет иметь несколько разные измерения. Чтобы обойти это, вы можете убедиться, что к клонируемой разметке применяются правила CSS, которые не включают ссылки на родительскую разметку.

кроме того, это не пришло мне в голову с моим виджетом скроллера, но чтобы получить соответствующую высоту клонированного элемента, вам нужно установить ширину на ту же ширину родительского элемента. В моем случае ширина CSS всегда применялся к фактическому элементу, поэтому мне не пришлось беспокоиться об этом, однако, если элемент не имеет примененной к нему ширины, вам может потребоваться сделать какой-то рекурсивный обход родословной DOM элемента, чтобы найти соответствующую ширину родительского элемента.


основываясь далее на ответе Ника:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});

я обнаружил, что лучше сделать это:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").removeAttr('style');

настройка атрибутов CSS вставит их в строку, которая перезапишет любые другие атрибуты, которые у вас есть в файле CSS. Удалив атрибут style в элементе HTML, все возвращается к норме и по-прежнему скрыто, так как оно было скрыто в первую очередь.


основываясь далее на ответе пользователя Ника и плагине пользователя hitautodestruct на JSBin, я создал аналогичный плагин jQuery, который извлекает ширину и высоту и возвращает объект, содержащий эти значения.

его можно найти здесь: http://jsbin.com/ikogez/3/

обновление

Я полностью переработал этот крошечный плагин, так как оказалось, что предыдущая версия (упомянутая выше) не была действительно использована в реальном жизненная среда, где происходило много манипуляций с DOM.

Это прекрасно работает:

/**
 * getSize plugin
 * This plugin can be used to get the width and height from hidden elements in the DOM.
 * It can be used on a jQuery element and will retun an object containing the width
 * and height of that element.
 *
 * Discussed at StackOverflow:
 * http://stackoverflow.com/a/8839261/1146033
 *
 * @author Robin van Baalen <robin@neverwoods.com>
 * @version 1.1
 * 
 * CHANGELOG
 *  1.0 - Initial release
 *  1.1 - Completely revamped internal logic to be compatible with javascript-intense environments
 *
 * @return {object} The returned object is a native javascript object
 *                  (not jQuery, and therefore not chainable!!) that
 *                  contains the width and height of the given element.
 */
$.fn.getSize = function() {    
    var $wrap = $("<div />").appendTo($("body"));
    $wrap.css({
        "position":   "absolute !important",
        "visibility": "hidden !important",
        "display":    "block !important"
    });

    $clone = $(this).clone().appendTo($wrap);

    sizes = {
        "width": $clone.width(),
        "height": $clone.height()
    };

    $wrap.remove();

    return sizes;
};

вы также можете поместить скрытый div с экрана с отрицательным полем, а не с помощью display:none, как и метод замены отступа текста.

например.

position:absolute;
left:  -2000px;
top: 0;

таким образом, height() по-прежнему доступен.


следуя решению Ника Крейвера, настройка видимости элемента позволяет получить точные размеры. Я использовал это решение очень часто. Однако, чтобы сбросить стили вручную, я пришел, чтобы найти это громоздким, учитывая, что изменение начального позиционирования/отображения элемента в моем css через разработку, я часто забываю обновить соответствующий код javascript. Следующий код не сбрасывает стили за say, но удаляет встроенные стили, добавленные javascript:

$("#myDiv")
.css({
    position:   'absolute',
    visibility: 'hidden',
    display:    'block'
});

optionHeight = $("#myDiv").height();
optionWidth = $("#myDiv").width();

$("#myDiv").attr('style', '');

единственное предположение здесь заключается в том, что не может быть других встроенных стилей, иначе они будут удалены. Преимущество здесь, однако, заключается в том, что стили элемента возвращаются к тому, что они были в таблице стилей css. Как следствие, вы можете записать это как функцию, через которую проходит элемент, и возвращается высота или ширина.

еще одна проблема, которую я нашел в настройке стилей inline через js, заключается в том, что при работе с переходами через css3 вы вынуждены адаптировать вес своих правил стиля, чтобы быть сильнее, чем встроенный стиль, что иногда может расстраивать.


Я пытаюсь найти рабочую функцию для скрытого элемента, но я понимаю, что CSS намного сложнее, чем все думают. В CSS3 есть много новых методов компоновки, которые могут не работать для всех предыдущих ответов, таких как гибкая коробка, сетка, столбец или даже элемент внутри сложного родительского элемента.

пример flexibox enter image description here

Я думаю, что единственным устойчивым и простым решением является рендеринг в реальном времени. В то время браузер должен дать вам это правильный размер элемента.

к сожалению, JavaScript не предоставляет прямого события для уведомления, когда элемент показан или скрыт. Однако я создаю некоторую функцию на основе модифицированного API атрибута DOM, которая будет выполнять функцию обратного вызова при изменении видимости элемента.

$('[selector]').onVisibleChanged(function(e, isVisible)
{
    var realWidth = $('[selector]').width();
    var realHeight = $('[selector]').height();

    // render or adjust something
});

для получения дополнительной информации посетите мой проект GitHub.

https://github.com/Soul-Master/visible.event.js

демо: http://jsbin.com/ETiGIre/7


по определению, элемент имеет высоту, только если он виден.

просто любопытно: зачем вам нужна высота скрытого элемента?

одна эффективно скрыть элемент, поместив его позади (используя z-индекс) какого-то наложения).


var $content = $('.content'),
    contentHeight = $content.height(),
    contentWidth = $content.width(),
    $closestHidden,
    styleAttrValue,
    limit = 20; //failsafe

if (!contentHeight) {
    $closestHidden = $content;
    //if the main element itself isn't hidden then roll through the parents
    if ($closestHidden.css('display') !== 'none') { 
        while ($closestHidden.css('display') !== 'none' && $closestHidden.size() && limit) {
            $closestHidden = $closestHidden.parent().closest(':hidden');
            limit--;
        }
    }
    styleAttrValue = $closestHidden.attr('style');
    $closestHidden.css({
        position:   'absolute',
        visibility: 'hidden',
        display:    'block'
    });
    contentHeight = $content.height();
    contentWidth = $content.width();

    if (styleAttrValue) {
        $closestHidden.attr('style',styleAttrValue);
    } else {
        $closestHidden.removeAttr('style');
    }
}

на самом деле, это объединение ответов Ника, Грегори и Eyelidless, чтобы дать вам использование улучшенного метода Грегори, но использует оба метода в случае, если есть предполагается, что что-то в атрибуте style, который вы хотите вернуть, и ищет родительский элемент.

моя единственная проблема с моим решением заключается в том, что цикл через родителей не совсем эффективен.


один обходной путь-создать родительский div вне элемента, который вы хотите получить высоту, применить высоту " 0 " и скрыть любое переполнение. Затем возьмите высоту дочернего элемента и удалите свойство overflow родительского элемента.

var height = $("#child").height();
// Do something here
$("#parent").append(height).removeClass("overflow-y-hidden");
.overflow-y-hidden {
  height: 0px;
  overflow-y: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="parent" class="overflow-y-hidden">
  <div id="child">
    This is some content I would like to get the height of!
  </div>
</div>

вот сценарий, который я написал для обработки всех методов измерения jQuery для скрытых элементов, даже потомков скрытых родителей. Обратите внимание, что, конечно, есть хит производительности с помощью этого.

// Correctly calculate dimensions of hidden elements
(function($) {
    var originals = {},
        keys = [
            'width',
            'height',
            'innerWidth',
            'innerHeight',
            'outerWidth',
            'outerHeight',
            'offset',
            'scrollTop',
            'scrollLeft'
        ],
        isVisible = function(el) {
            el = $(el);
            el.data('hidden', []);

            var visible = true,
                parents = el.parents(),
                hiddenData = el.data('hidden');

            if(!el.is(':visible')) {
                visible = false;
                hiddenData[hiddenData.length] = el;
            }

            parents.each(function(i, parent) {
                parent = $(parent);
                if(!parent.is(':visible')) {
                    visible = false;
                    hiddenData[hiddenData.length] = parent;
                }
            });
            return visible;
        };

    $.each(keys, function(i, dimension) {
        originals[dimension] = $.fn[dimension];

        $.fn[dimension] = function(size) {
            var el = $(this[0]);

            if(
                (
                    size !== undefined &&
                    !(
                        (dimension == 'outerHeight' || 
                            dimension == 'outerWidth') &&
                        (size === true || size === false)
                    )
                ) ||
                isVisible(el)
            ) {
                return originals[dimension].call(this, size);
            }

            var hiddenData = el.data('hidden'),
                topHidden = hiddenData[hiddenData.length - 1],
                topHiddenClone = topHidden.clone(true),
                topHiddenDescendants = topHidden.find('*').andSelf(),
                topHiddenCloneDescendants = topHiddenClone.find('*').andSelf(),
                elIndex = topHiddenDescendants.index(el[0]),
                clone = topHiddenCloneDescendants[elIndex],
                ret;

            $.each(hiddenData, function(i, hidden) {
                var index = topHiddenDescendants.index(hidden);
                $(topHiddenCloneDescendants[index]).show();
            });
            topHidden.before(topHiddenClone);

            if(dimension == 'outerHeight' || dimension == 'outerWidth') {
                ret = $(clone)[dimension](size ? true : false);
            } else {
                ret = $(clone)[dimension]();
            }

            topHiddenClone.remove();
            return ret;
        };
    });
})(jQuery);

Если вы уже отображали элемент на странице ранее, вы можете просто взять высоту непосредственно из элемента DOM (достижимый в jQuery with .get (0)), так как он установлен даже тогда, когда элемент скрыт:

$('.hidden-element').get(0).height;

то же самое для ширины:

$('.hidden-element').get(0).width;

(спасибо Скитс О'Рейли для исправления)


$('#idOfElement').height();

//, чтобы найти высота