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();

42
+1あなたの例のソリューションは、実際の答えよりも優れています(笑)。
Tim Santeford、

9
私はティムに同意しません。このソリューションでは、実際にアイテムを表示してから非表示にしているため、表示がちらつく可能性があります。Nicksソリューションの方が複雑ですが、親divが表示されないため、表示がちらつく可能性はありません。
ハンフリー、



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 2011

3
+1これはうまくいきます。要素の親も表示する必要があることに注意してください。これは私を数分間混乱させました。また、要素がのposition:relative場合は、もちろんの代わりにそれを設定する必要がありstaticます。
Michael Mior

6
この方法を使用すると、ターゲット要素の形状が変化することがよくあります。したがって、divが絶対位置にあるときにdivの高さや幅を取得することは、あまり役に立たない場合があります。
ジェレミーリケッツ

2
@Gavinを使用すると、リフローの計算とユーザーのちらつきを防止できるため、コストが低く、煩わしさが軽減されます。
Nick Craver

2
@hitautodestruct、この要素のみが実際に非表示になっていることを確認するようにクエリプラグインを変更しました。 jsbin.com/ihakid/58
Prasad

96

隠し要素の幅を取得する際に同じ問題に遭遇したので、このプラグインを修正するためにjQuery Actualを呼び出すこのプラグインを書きました。使用する代わりに

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

使用する

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

非表示の要素に適切な値を与えるか、要素に非表示の親があります。

完全なドキュメントはこちらをご覧ください。このページにはデモも含まれています。

この助けを願っています:)


3
はい、役立ちます!2015年もそれは役立ちます。実際のWebサイトで「古いバージョンのjquery」と言っていますが、v2.1.3ではまだ必要です。少なくとも、私の場合はそうでした。
LpLrich 2015年

ありがとう!私はこのプラグインを使用して、最初はアコーディオン内に隠されている要素の高さ(これは動的に行われます)を読み取って設定しました
alds

素晴らしいプラグイン!100%に設定したときに、モーダル内のdivの幅を取得するためにすべてを試しましたが、何も機能しませんでした。これを5秒で設定し、完全に機能しました。
クレイグハウエル

@benリンクが壊れています。
Sachin Prasad

39

表示スタイル表示スタイルという2つのCSSスタイルを混乱させています

可視性のcssスタイルを設定して要素を非表示にした場合、要素がページ上でスペースを取るため、要素が表示されているかどうかに関係なく高さを取得できるはずです

要素が表示cssスタイルを「なし」に変更することによって非表示になっている場合、要素はページ上のスペースを取らないので、要素をあるスペースにレンダリングする表示スタイルを指定する必要があります。どのポイント、あなたは高さを得ることができます。


これをありがとう。私の問題はテーブルセルに関係していて、に設定visibilityhiddenても問題は解決しませんでしたが、設定するというアイデアが得られposition: fixed; top: 100%、魅力のように機能しました!
Jayen

これで高さがdisplay:none要素で表示されない理由がわかりました。素晴らしい説明をありがとうございました。
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祖先をたどって、適切な親要素の幅を見つけます。


これには興味深い問題があります。要素がすでにブロック要素である場合、クローンはボディ全体の幅(ボディのパディングまたはマージンを除く)を取得します。これは、コンテナー内のサイズとは異なります。
Meligy

16

JSBinでのユーザーNickの回答とユーザーhitautodestructのプラグインにさらに基づいて、幅と高さの両方を取得し、これらの値を含むオブジェクトを返す同様の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

@jackJoe私はかなり前からこのコードを問題なく使用しています。せいぜい、「これ」の代わりに$ clone.width()が必要だと思います。ラップ内の要素のサイズが必要なので、$ wrapではありません。たとえば、ラッパーは10000x10000pxですが、測定したい要素はまだ30x40pxです。
ロビンファンバーレン

$wrap(少なくとも私のテストでは)をターゲットにすることも可能です。私は試してみましたがthisthisまだ隠された要素を参照しているため、サイズをキャッチしません。
jackJoe

1
@jackJoeに感謝コード例を更新しました。
Robin van Baalen

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ファイルにある他の属性が上書きされます。HTML要素のスタイル属性を削除すると、最初は非表示だったので、すべてが通常に戻り、非表示になります。


1
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'}); optionHeight = $("#myDiv").height(); $("#myDiv").css({'position':'','visibility':'', 'display':''});
アーロン

9
...要素のインラインスタイルが既にない場合。これは、jQueryで要素を非表示にした場合に当てはまります。
Muhd、2011年

4

テキストインデント画像の置換テクニックと同じように、display:noneを使用する代わりに、非表示のdivを画面の外に負のマージンで配置することもできます。

例えば。

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

このように、height()は引き続き使用できます。


3

私は隠し要素の機能を見つけようとしましたが、CSSは誰もが考えるよりもはるかに複雑であることに気づきました。CSS3には、フレキシブルボックス、グリッド、列、複雑な親要素内の要素など、以前のすべての回答では機能しない可能性のある新しいレイアウトテクニックがたくさんあります。

flexiboxの例 ここに画像の説明を入力してください

持続可能でシンプルなソリューションは、リアルタイムレンダリングだけだと思います。その時、ブラウザはあなたにその正しい要素サイズを与えるはずです。

悲しいことに、JavaScriptは要素が表示または非表示になったときに通知する直接イベントを提供しません。ただし、要素の可視性が変更されたときにコールバック関数を実行するDOM属性変更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


ご回答有難うございます。MutationObserversも使用するようになりました。ただし、ライブラリはstyle属性の変更によって引き起こされる可視性の変更のみをチェックすることに注意してください(ここで 59行目を参照)。可視性の変更はclass属性の変更によっても引き起こされる可能性があります。
Ashraf Sabry 2014

あなたが正しい。正しい文はe.attributeName!== 'style' && e.attributeName!== 'className'
Soul_Master

2

Nick Craverのソリューションに従って、要素の可視性を設定すると、要素の正確な寸法を取得できます。私はこのソリューションを非常に頻繁に使用しました。ただし、スタイルを手動でリセットする必要があるため、開発のcssで要素の初期配置/表示を変更すると、関連するJavaScriptコードを更新するのを忘れることが多いため、これが面倒なことに気付きました。次のコードは、スタイルごとのスタイルをリセットしませんが、JavaScriptによって追加されたインラインスタイルを削除します。

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

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

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

ここでの唯一の前提は、他のインラインスタイルはあり得ないということです。そうしないと、それらも削除されます。ただし、ここでの利点は、要素のスタイルがcssスタイルシートにあったものに戻されることです。結果として、これは、要素が渡され、高さまたは幅が返される関数として記述できます。

jsを介してインラインでスタイルを設定する際に私が見つけたもう1つの問題は、css3を介して遷移を処理するときに、スタイルルールの重みをインラインスタイルよりも強くするように強制されるため、苛立たしい場合があります。


1

定義上、要素は表示されている場合にのみ高さを持ちます。

気になるところ:なぜ隠し要素の高さが必要なのですか?

1つの代替方法は、何らかの要素のオーバーレイを(z-indexを使用して)後ろに置くことで、要素を効果的に非表示にすることです。


1
要素の高さが必要なのですが、その高さを求めている間はたまたま非表示になっています。プラグインを作成していて、初期化しながらデータを収集する必要があります
mkoryak

2
もう1つの理由は、まだ表示されていない可能性のあるJavaScriptを使用して物事を
中央に配置する

@cletusコメントを書きたいだけの場合、それは非表示要素のサイズを取得するためのフロントエンドコーディングで非常によくある状況です。
ランティエフ2015

1

私の状況では、高さの値を取得できないようにする隠し要素もありましたが、それは要素自体ではなく、親の1つだったので、プラグインの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');
    }
}

実際、これはニック、グレゴリー、まぶたの反応の融合であり、グレゴリーの改善された方法を使用できますが、スタイル属性に戻す必要があるものがあると思われる場合は両方の方法を利用して探します親要素。

私の解決策の私の唯一の不満は、親を通るループが完全に効率的ではないということです。


1

1つの回避策は、高さを取得する要素の外側に親divを作成し、高さを「0」に適用して、オーバーフローを非表示にすることです。次に、子要素の高さを取得し、親のオーバーフロープロパティを削除します。

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>


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

まぶたのないことによる答えは、私が必要としているものには完璧に見えますが、実行しているjQueryでは機​​能しません。誰でもそれを修正する方法について何かアイデアがありますか?

0

以前にページに要素をすでに表示している場合は、要素が非表示の場合でも設定されるため、DOM要素から直接高さを取得できます(jQueryで.get(0)を使用して到達可能)。

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

幅も同じ:

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

(修正のためにSkeets O'Reillyに感謝)


リターンundefined
ジェイクウィルソン

1
かなり前にページに要素を表示したことがある場合にのみ、これが機能することを確認してください。以前から使用されている要素の場合display='none'、これは機能しません。
スキート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.