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

249

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

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

$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();
mkoryak
источник
42
+1 Ваш пример решения на самом деле лучше, чем любой из ответов, лол.
Тим Сантефорд
9
Я не согласен, Тим. С этим решением есть вероятность, что дисплей может мерцать, потому что вы на самом деле показываете элемент, а затем скрываете его. Несмотря на то, что решение Nicks более запутанное, у него нет никаких шансов на мерцание дисплея, поскольку родительский элемент div никогда не отображается.
Хамфри
Связанный: stackoverflow.com/questions/3632120/…
Ник
5
Гарри, на самом деле ты узнал, что твой код не работает в IE, а не это решение. Иди отлаживай свой код :)
Gavin

Ответы:

181

Вы можете сделать что-то вроде этого, хотя и немного странно, забудьте, 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 : "");
Ник Крейвер
источник
17
Я объединил приведенный выше код в плагин jQ jsbin.com/ihakid/2 . Я также использую класс и проверяю, не скрыты ли родители.
Hitautodestruct
3
+1 Это прекрасно работает. Просто имейте в виду, что родители элемента также должны отображаться. Это меня смутило на несколько минут. Кроме того, если элемент есть position:relative, вы, конечно, захотите установить его после вместо static.
Майкл Миор
6
Когда вы используете этот метод, целевой элемент часто может менять форму. Таким образом, получение высоты и / или ширины div, когда он абсолютно позиционирован, может быть не очень полезным.
Джереми Рикеттс
2
@Gavin - это предотвращает подсчет и любые мерцания для пользователя, поэтому он дешевле и менее навязчив.
Ник Крейвер
2
@hitautodestruct, я изменил ваш плагин запросов, чтобы проверить, что на самом деле скрыт только тот элемент. jsbin.com/ihakid/58
Прасад
96

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

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

использование

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

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

Полную документацию смотрите здесь . На странице также есть демо-версия.

Надеюсь это поможет :)

Бен
источник
3
Да, это помогает! 2015, и это все еще помогает. Вы говорите «старые версии jquery» на Актуальном веб-сайте - однако - это все еще требуется в v2.1.3, по крайней мере, так было в моей ситуации.
LpLrich
Спасибо! Я использовал этот плагин для чтения и установки высоты элементов (это делается динамически), спрятанных изначально в аккордеонах
alds
Потрясающий плагин! Я пытался все, чтобы получить ширину div внутри модального, когда установлено на 100%, и ничего не получалось. установить это за 5 секунд и работал отлично!
Крейг Хауэлл,
@ben Ссылка не работает.
Сачин Прасад
39

Вы confuising двух стилей CSS, в стиль отображения и стиль видимости .

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

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

casperOne
источник
Спасибо за это. моя проблема заключалась в ячейке таблицы, и установка visibilityна hiddenне решала мою проблему, но это дало мне идею установить, position: fixed; top: 100%и это работает как шарм!
Jayen
Теперь я понимаю, почему высота не отображается на дисплее: нет элементов. Большое спасибо за прекрасное объяснение.
FrenkyB
30

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

// 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-элемента элемента, чтобы найти соответствующую ширину родительского элемента.

elliotlarson
источник
Это имеет интересную проблему, хотя. Если элемент уже является блочным элементом, клон получит всю ширину тела (кроме отступов или полей), которая отличается от его размера внутри контейнера.
Meligy
16

Основываясь на ответе пользователя Ника и плагине 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;
};
Робин ван Баален
источник
Ваш код неверен. Вам нужно относится к исходному пункту, который не виден. sizes = {"width": $wrap.width(), "height": $wrap.height()};this
ДжекДжо
@jackJoe Я уже давно использую этот код без проблем. В лучшем случае я бы сказал, что мне нужно $ clone.width () вместо «this». Не $ Wrap, так как я хочу размер элемента внутри Wrap. Wrapper может иметь размер 10000x10000px, в то время как элемент, который я хочу измерить, по-прежнему составляет 30x40px, например.
Робин ван Баален
Даже нацеливание в $wrapпорядке (по крайней мере, в моих тестах). Я попытался с thisи, очевидно, он не поймает размер, потому что thisвсе еще ссылается на скрытый элемент.
ДжекДжо
1
Спасибо @jackJoe Я теперь обновил пример кода.
Робин ван Баален
12

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

$("#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, все возвращается к нормальному состоянию и все еще скрыто, поскольку оно было спрятано в первую очередь.

Григорий Болкенштейн
источник
1
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'}); optionHeight = $("#myDiv").height(); $("#myDiv").css({'position':'','visibility':'', 'display':''});
Аарон,
9
... если у вас уже не было встроенных стилей элемента. Что будет, если вы спрятали элемент с помощью jQuery.
Muhd
4

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

например.

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

Таким образом, высота () все еще доступна.

vaughanos
источник
3

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

пример flexibox введите описание изображения здесь

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

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

$('[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

Soul_Master
источник
Спасибо за Ваш ответ. Это вдохновило меня на использование MutationObservers тоже. Но обратите внимание, что ваша библиотека проверяет только изменения видимости, вызванные изменениями styleатрибута (см. Строку 59 здесь ), тогда как изменения видимости могут быть вызваны также изменениями classатрибута.
Ашраф Сабри
Ты прав. Правильный оператор должен быть e.attributeName! == 'style' && e.attributeName! == 'className'
Soul_Master
2

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

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

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

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

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

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

Prusprus
источник
1

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

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

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

Клетус
источник
1
Мне нужна высота элемента, который оказывается скрытым в то время, когда я хочу его высоту. я строю плагин, и мне нужно собрать некоторые данные, как я его инициирую
создаю инициирую mkoryak
2
Другая причина - центрировать вещи с помощью javascript, который еще может быть не виден
Simon_Weaver
@cletus Если вы просто любопытно пишете комментарии, это очень часто бывает в кодировании внешнего интерфейса, чтобы получить размер скрытого элемента.
Рантиев
1

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

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');
    }
}

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

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

marksyzm
источник
1

Один из обходных путей - создать родительский 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>

Matt
источник
0

Вот скрипт, который я написал для обработки всех методов измерения 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);
eyelidlessness
источник
Ответ без век выглядит идеально для того, что мне нужно, но не работает с jQuery, который я использую: 1.3.2 Это заставляет jQuery бросать this.clone (или что-то очень близкое) не является функцией. У кого-нибудь есть идеи как это исправить?
0

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

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

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

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

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

Лука С.
источник
Возвращаетundefined
Джейк Уилсон
1
Уверен, это работает, только если вы уже отобразили элемент на странице ранее. Для элементов, которые всегда были display='none', это не будет работать.
Скитс