jQuery: Ruft die Höhe des versteckten Elements in jQuery ab

249

Ich muss die Höhe eines Elements ermitteln, das sich in einem versteckten Div befindet. Im Moment zeige ich das Div, erhalte die Höhe und verstecke das übergeordnete Div. Das scheint ein bisschen albern. Gibt es einen besseren Weg?

Ich verwende jQuery 1.4.2:

$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();
mkoryak
quelle
42
+1 Ihre Beispiellösung ist tatsächlich besser als jede der Antworten lol.
Tim Santeford
9
Ich bin nicht einverstanden, Tim. Bei dieser Lösung besteht die Möglichkeit, dass die Anzeige flackert, weil Sie das Objekt tatsächlich anzeigen und dann ausblenden. Obwohl die Nicks-Lösung komplizierter ist, besteht keine Chance, dass die Anzeige flackert, da das übergeordnete Div niemals angezeigt wird.
Humphrey
Mögliches Duplikat von jQuery - Breite des Elements
abrufen,
Siehe auch
Nick
5
Harry, eigentlich hast du herausgefunden, dass dein Code im IE nicht funktioniert, nicht in dieser Lösung. Debuggen Sie Ihren Code :)
Gavin

Antworten:

181

Sie könnten so etwas tun, ein bisschen hackig, vergessen positionSie , wenn es bereits absolut ist:

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 : "");
Nick Craver
quelle
17
Ich habe den obigen Code in einem jQ-Plugin jsbin.com/ihakid/2 konsolidiert . Ich benutze auch eine Klasse und überprüfe, ob die Eltern auch versteckt sind.
Hitautodestruct
3
+1 Das funktioniert super. Denken Sie daran, dass auch die Eltern des Elements angezeigt werden müssen. Das hatte mich ein paar Minuten verwirrt. Wenn das Element ist position:relative, möchten Sie dies natürlich nachher anstelle von festlegen static.
Michael Mior
6
Wenn Sie diese Methode verwenden, kann das Zielelement häufig seine Form ändern. Daher ist es möglicherweise nicht sehr nützlich, die Höhe und / oder Breite des Div zu ermitteln, wenn es absolut positioniert ist.
Jeremy Ricketts
2
@Gavin Dies verhindert eine Reflow-Berechnung und jegliches Flimmern für den Benutzer, sodass es sowohl billiger als auch weniger aufdringlich ist.
Nick Craver
2
@hitautodestruct, ich habe Ihr Abfrage-Plugin geändert, um zu überprüfen, ob nur das Element tatsächlich ausgeblendet ist. jsbin.com/ihakid/58
Prasad
96

Ich hatte das gleiche Problem beim Abrufen der Breite versteckter Elemente, daher habe ich diesen Plugin-Aufruf jQuery Actual geschrieben , um das Problem zu beheben. Anstatt zu verwenden

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

verwenden

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

gibt Ihnen den richtigen Wert für verstecktes Element oder Element hat ein verstecktes übergeordnetes Element.

Die vollständige Dokumentation finden Sie hier . Es gibt auch eine Demo auf der Seite.

Ich hoffe das hilft :)

ben
quelle
3
Ja es hilft! 2015 und es hilft immer noch. Sie sagen "ältere Versionen von jquery" auf der Actual-Website - es ist jedoch in Version 2.1.3 immer noch erforderlich, zumindest in meiner Situation.
LpLrich
Vielen Dank! Ich habe dieses Plugin verwendet, um die Höhe von Elementen zu lesen und einzustellen (dies geschieht dynamisch), die anfänglich in Akkordeons versteckt waren
alds
Super Plugin! Ich habe alles versucht, um die Breite eines Divs innerhalb eines Modals zu erhalten, wenn es auf 100% eingestellt war, und nichts hat funktioniert. Richten Sie dies in 5 Sekunden ein und es hat perfekt funktioniert!
Craig Howell
@ben Der Link ist defekt.
Sachin Prasad
39

Sie verwechseln zwei CSS-Stile, den Anzeigestil und den Sichtbarkeitsstil .

Wenn das Element durch Festlegen des CSS-Stils für die Sichtbarkeit ausgeblendet wird, sollten Sie in der Lage sein, die Höhe zu ermitteln, unabhängig davon, ob das Element sichtbar ist oder nicht, da das Element noch Platz auf der Seite einnimmt .

Wenn das Element durch Ändern des Anzeige-CSS-Stils in "Keine" ausgeblendet wird, nimmt das Element keinen Platz auf der Seite ein, und Sie müssen ihm einen Anzeigestil zuweisen, der bewirkt, dass das Element in einem bestimmten Bereich bei gerendert wird An welchem ​​Punkt können Sie die Höhe ermitteln.

casperOne
quelle
Danke dafür. Mein Problem bestand in einer Tabellenzelle, und das Einstellen visibilityauf hiddenlöste mein Problem nicht, aber es brachte mich auf die Idee, es einzustellen, position: fixed; top: 100%und es funktioniert wie ein Zauber!
Jayen
Jetzt verstehe ich, warum die Höhe nicht mit der Anzeige angezeigt wird: keine Elemente. Vielen Dank für die wundervolle Erklärung.
FrenkyB
30

Ich habe tatsächlich manchmal auf ein paar Tricks zurückgegriffen, um damit umzugehen. Ich habe ein jQuery-Bildlaufleisten-Widget entwickelt, bei dem ich auf das Problem gestoßen bin, dass ich nicht im Voraus weiß, ob der scrollbare Inhalt Teil eines versteckten Markups ist oder nicht. Folgendes habe ich getan:

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

Dies funktioniert größtenteils, aber es gibt ein offensichtliches Problem, das möglicherweise auftreten kann. Wenn der Inhalt, den Sie klonen, mit CSS gestaltet ist, dessen Regeln Verweise auf übergeordnetes Markup enthalten, enthält der geklonte Inhalt nicht das entsprechende Design und weist wahrscheinlich leicht unterschiedliche Maße auf. Um dies zu umgehen, können Sie sicherstellen, dass auf das Markup, das Sie klonen, CSS-Regeln angewendet werden, die keine Verweise auf das übergeordnete Markup enthalten.

Dies ist mir bei meinem Scroller-Widget auch nicht aufgefallen. Um jedoch die entsprechende Höhe des geklonten Elements zu erhalten, müssen Sie die Breite auf die gleiche Breite des übergeordneten Elements einstellen. In meinem Fall wurde immer eine CSS-Breite auf das eigentliche Element angewendet, sodass ich mir darüber keine Gedanken machen musste. Wenn auf das Element jedoch keine Breite angewendet wird, müssen Sie möglicherweise eine Art Rekursiv ausführen Durchlaufen der DOM-Abstammung des Elements, um die Breite des entsprechenden übergeordneten Elements zu ermitteln.

Elliotlarson
quelle
Dies hat jedoch ein interessantes Problem. Wenn das Element bereits ein Blockelement ist, nimmt der Klon die gesamte Körperbreite (außer Körperpolsterung oder Rand) an, die sich von der Größe in einem Container unterscheidet.
Meligy
16

Aufbauend auf der Antwort von Benutzer Nick und dem Plugin von Benutzer hitautodestruct in JSBin habe ich ein ähnliches jQuery-Plugin erstellt, das sowohl Breite als auch Höhe abruft und ein Objekt zurückgibt, das diese Werte enthält.

Es kann hier gefunden werden: http://jsbin.com/ikogez/3/

Aktualisieren

Ich habe dieses winzige kleine Plugin komplett neu gestaltet, da sich herausstellte, dass die vorherige Version (oben erwähnt) in realen Umgebungen, in denen viele DOM-Manipulationen stattfanden, nicht wirklich verwendbar war.

Das funktioniert perfekt:

/**
 * 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 <[email protected]>
 * @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;
};
Robin van Baalen
quelle
Ihr Code ist nicht korrekt. Sie benötigen sizes = {"width": $wrap.width(), "height": $wrap.height()};die thisVerweise auf das Originalelement, das nicht sichtbar ist.
JackJoe
@jackJoe Ich benutze diesen Code seit einiger Zeit ohne Probleme. Bestenfalls würde ich sagen, ich brauche $ clone.width () anstelle von 'this'. Nicht $ wrap, da ich die Größe des Elements innerhalb des Wraps haben möchte. Der Wrapper kann 10000 x 10000 Pixel groß sein, während das Element, das ich messen möchte, beispielsweise noch 30 x 40 Pixel groß ist.
Robin van Baalen
Auch das Anvisieren $wrapist in Ordnung (zumindest in meinen Tests). Ich habe es mit dem versucht thisund offensichtlich würde es die Größe nicht erfassen, da es sich thisimmer noch auf das versteckte Element bezieht.
JackJoe
1
Danke @jackJoe Ich habe jetzt das Codebeispiel aktualisiert.
Robin van Baalen
12

Aufbauend auf Nicks Antwort:

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

Ich fand es besser, dies zu tun:

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

Durch das Festlegen von CSS-Attributen werden diese inline eingefügt, wodurch alle anderen Attribute in Ihrer CSS-Datei überschrieben werden. Durch Entfernen des style-Attributs im HTML-Element wird alles wieder normal und immer noch ausgeblendet, da es an erster Stelle ausgeblendet wurde.

Gregory Bolkenstijn
quelle
1
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'}); optionHeight = $("#myDiv").height(); $("#myDiv").css({'position':'','visibility':'', 'display':''});
Aaron
9
... es sei denn, Sie hatten bereits Inline-Stile für das Element. Was der Fall wäre, wenn Sie das Element mit jQuery verstecken würden.
Muhd
4

Sie können das ausgeblendete Div auch mit einem negativen Rand vom Bildschirm positionieren, anstatt die Anzeige zu verwenden: keine, ähnlich wie beim Ersetzen von Bildern mit Texteinzug.

z.B.

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

Auf diese Weise ist die Höhe () noch verfügbar.

Vaughanos
quelle
3

Ich versuche, eine funktionierende Funktion für versteckte Elemente zu finden, aber mir ist klar, dass CSS viel komplexer ist, als jeder denkt. Es gibt viele neue Layouttechniken in CSS3, die möglicherweise nicht für alle vorherigen Antworten wie flexible Boxen, Raster, Spalten oder sogar Elemente in komplexen übergeordneten Elementen funktionieren.

Flexibox Beispiel Geben Sie hier die Bildbeschreibung ein

Ich denke, die einzige nachhaltige und einfache Lösung ist das Echtzeit-Rendering . Zu diesem Zeitpunkt sollte der Browser die richtige Elementgröße angeben .

Leider bietet JavaScript kein direktes Ereignis, um zu benachrichtigen, wenn ein Element angezeigt oder ausgeblendet wird. Ich erstelle jedoch eine Funktion basierend auf der DOM Attribute Modified API, die die Rückruffunktion ausführt, wenn die Sichtbarkeit des Elements geändert wird.

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

    // render or adjust something
});

Weitere Informationen finden Sie in meinem Projekt GitHub.

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

Demo: http://jsbin.com/ETiGIre/7

Seelen Meister
quelle
Danke für deine Antwort. Es hat mich dazu inspiriert, auch MutationObservers zu verwenden. Beachten Sie jedoch, dass Ihre Bibliothek nur nach Sichtbarkeitsänderungen sucht, die durch styleAttributänderungen verursacht werden (siehe Zeile 59 hier ), während Sichtbarkeitsänderungen auch durch Änderungen im classAttribut verursacht werden können.
Ashraf Sabry
Du hast recht. Die korrekte Anweisung sollte e.attributeName! == 'style' && e.attributeName! == 'className'
Soul_Master
2

Nach der Lösung von Nick Craver können Sie durch Einstellen der Sichtbarkeit des Elements genaue Abmessungen erhalten. Ich habe diese Lösung sehr sehr oft verwendet. Da ich die Stile jedoch manuell zurücksetzen muss, finde ich dies umständlich, da ich beim Ändern der anfänglichen Positionierung / Anzeige des Elements in meinem CSS durch Entwicklung oft vergesse, den zugehörigen Javascript-Code zu aktualisieren. Der folgende Code setzt die Stile nicht per say zurück, sondern entfernt die durch Javascript hinzugefügten Inline-Stile:

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

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

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

Die einzige Annahme hier ist, dass es keine anderen Inline-Stile geben kann, sonst werden sie auch entfernt. Der Vorteil hierbei ist jedoch, dass die Stile des Elements auf das zurückgesetzt werden, was sie im CSS-Stylesheet waren. Infolgedessen können Sie dies als eine Funktion aufschreiben, bei der ein Element durchlaufen wird und eine Höhe oder Breite zurückgegeben wird.

Ein weiteres Problem beim Festlegen der Stile inline über js ist, dass Sie beim Umgang mit Übergängen über css3 gezwungen sind, die Gewichte Ihrer Stilregeln so anzupassen, dass sie stärker sind als ein Inline-Stil, was manchmal frustrierend sein kann.

Prusprus
quelle
1

Per Definition hat ein Element nur dann eine Höhe, wenn es sichtbar ist.

Nur neugierig: Warum brauchst du die Höhe eines versteckten Elements?

Eine Alternative besteht darin , ein Element effektiv auszublenden, indem es hinter einem Overlay (unter Verwendung des Z-Index) platziert wird.

Cletus
quelle
1
Ich brauche eine Höhe eines Elements, das während der Zeit, in der ich seine Höhe haben möchte, versteckt ist. Ich
baue
2
Ein weiterer Grund ist die Zentrierung von Dingen mit Javascript, die möglicherweise noch nicht sichtbar sind
Simon_Weaver
@cletus Wenn Sie nur neugierig sind, Kommentare zu schreiben, ist dies sehr oft eine Situation bei der Frontend-Codierung, um die Größe eines versteckten Elements zu ermitteln.
Rantiev
1

Unter meinen Umständen hatte ich auch ein verstecktes Element, das mich daran hinderte, den Höhenwert zu erhalten, aber es war nicht das Element selbst, sondern einer seiner Eltern ... also habe ich einfach nach einem meiner Plugins gesucht, um zu sehen, ob es ist versteckt, sonst finde das nächste versteckte Element. Hier ist ein Beispiel:

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

Tatsächlich ist dies eine Zusammenführung der Antworten von Nick, Gregory und Eyelidlessness, um Ihnen die Verwendung der verbesserten Methode von Gregory zu ermöglichen. Sie verwendet jedoch beide Methoden, falls das Stilattribut etwas enthalten soll, das Sie zurücksetzen möchten, und sucht ein übergeordnetes Element.

Mein einziger Kritikpunkt an meiner Lösung ist, dass die Schleife durch die Eltern nicht ganz effizient ist.

marksyzm
quelle
1

Eine Problemumgehung besteht darin, ein übergeordnetes Div außerhalb des Elements zu erstellen, dessen Höhe Sie ermitteln möchten, eine Höhe von '0' anzuwenden und einen Überlauf auszublenden. Nehmen Sie als Nächstes die Höhe des untergeordneten Elements und entfernen Sie die Überlaufeigenschaft des übergeordneten Elements.

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
quelle
0

Hier ist ein Skript, das ich geschrieben habe, um alle Dimensionsmethoden von jQuery für versteckte Elemente zu behandeln, sogar für Nachkommen versteckter Eltern. Beachten Sie, dass dies natürlich zu einem Leistungseinbruch führt.

// 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);
Augenlidlosigkeit
quelle
Die Antwort durch Augenlidlosigkeit sieht perfekt aus für das, was ich brauche, funktioniert aber nicht mit der von mir ausgeführten jQuery: 1.3.2 Es bewirkt, dass jQuery einen this.clone (oder etwas sehr Nahes) auslöst, ist keine Funktion. Hat jemand Ideen, wie man das Problem beheben kann?
0

Wenn Sie das Element bereits zuvor auf der Seite angezeigt haben, können Sie die Höhe einfach direkt aus dem DOM-Element übernehmen (in jQuery mit .get (0) erreichbar), da es auch dann festgelegt wird, wenn das Element ausgeblendet ist:

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

Gleiches gilt für die Breite:

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

(Danke an Skeets O'Reilly für die Korrektur)

Luca C.
quelle
Rückkehrundefined
Jake Wilson
1
Ziemlich sicher, dass dies nur funktioniert, wenn Sie das Element bereits zuvor auf der Seite angezeigt haben. Für Elemente, die schon immer waren display='none', funktioniert dies nicht.
Skeets