jQuery: ottieni l'altezza dell'elemento nascosto in jQuery


249

Ho bisogno di ottenere l'altezza di un elemento che si trova all'interno di un div nascosto. In questo momento mostro il div, ottengo l'altezza e nascondo il div genitore. Sembra un po 'sciocco. C'è un modo migliore?

Sto usando jQuery 1.4.2:

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

42
+1 La tua soluzione di esempio è in realtà migliore di una qualsiasi delle risposte lol.
Tim Santeford,

9
Non sono d'accordo Tim. Con questa soluzione c'è la possibilità che il display sfarfallio perché stai effettivamente mostrando l'oggetto e poi nascondendolo. Anche se la soluzione di Nicks è più complicata, non ha alcuna possibilità di sfarfallare il display poiché il div parent non viene mai mostrato.
Humphrey,



5
Harry, in realtà quello che hai scoperto è che il tuo codice non funziona in IE, non questa soluzione. Esegui il debug del tuo codice :)
Gavin,

Risposte:


181

Potresti fare qualcosa del genere, un po 'confuso, dimentica positionse è già assoluto:

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
Ho consolidato il codice sopra in un plugin jQ jsbin.com/ihakid/2 . Uso anche una classe e controllo se anche i genitori sono nascosti.
Hitautodestruct,

3
+1 Funziona benissimo. Tieni presente che devono essere visualizzati anche i genitori dell'elemento. Questo mi ha confuso per alcuni minuti. Inoltre, se l'elemento è position:relative, ti consigliamo ovviamente di impostarlo dopo anziché static.
Michael Mior,

6
Quando si utilizza questo metodo, l'elemento target può spesso cambiare forma. Quindi ottenere l'altezza e / o la larghezza del div quando è assolutamente posizionato potrebbe non essere molto utile.
Jeremy Ricketts,

2
@Gavin questo impedisce un calcolo del riflusso e qualsiasi sfarfallio per l'utente, quindi è più economico e meno invadente.
Nick Craver

2
@hitautodestruct, ho modificato il tuo plug-in di query per verificare che solo l'elemento sia effettivamente nascosto. jsbin.com/ihakid/58
Prasad,

96

Ho riscontrato lo stesso problema con l'ottenimento della larghezza dell'elemento nascosto, quindi ho scritto questo plugin chiamato jQuery Actual per risolverlo. Invece di usare

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

uso

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

ti darà il giusto valore per l'elemento nascosto o l'elemento ha un genitore nascosto.

Documentazione completa, consultare qui . C'è anche una demo inclusa nella pagina.

Spero che questo aiuto :)


3
Sì aiuta! 2015 e aiuta ancora. Dici "versioni precedenti di jquery" sul sito web effettivo - tuttavia - è ancora richiesto nella v2.1.3, almeno era nella mia situazione.
LpLrich

Grazie! Ho usato questo plugin per leggere e impostare l'altezza degli elementi (questo viene fatto in modo dinamico) nascosti inizialmente all'interno delle fisarmoniche
alds

Plugin fantastico! Ho provato di tutto per ottenere la larghezza di un div all'interno di un modale quando impostato al 100% e niente ha funzionato. installalo in 5 secondi e ha funzionato perfettamente!
Craig Howell,

@ben Il collegamento è interrotto.
Sachin Prasad,

39

Stai configurando due stili CSS, lo stile di visualizzazione e lo stile di visibilità .

Se l'elemento è nascosto impostando lo stile css di visibilità, dovresti essere in grado di ottenere l'altezza indipendentemente dal fatto che l'elemento sia visibile o meno poiché l'elemento occupa ancora spazio sulla pagina .

Se l'elemento è nascosto modificando lo stile di visualizzazione css in "none", allora l'elemento non occupa spazio sulla pagina e dovrai dargli uno stile di visualizzazione che causerà il rendering dell'elemento in uno spazio, a quale punto, puoi ottenere l'altezza.


grazie per questo. il mio problema riguardava una cella di tabella e l'impostazione visibilityper hiddennon risolvere il mio problema, ma mi ha dato l'idea di impostare position: fixed; top: 100%e funziona come un fascino!
Jayen,

Ora capisco perché l'altezza non viene visualizzata con display: nessuno degli elementi. Grazie mille per la meravigliosa spiegazione.
FrenkyB,

30

A volte ho fatto ricorso a un po 'di trucchi per affrontarlo. Ho sviluppato un widget della barra di scorrimento jQuery in cui ho riscontrato il problema che non so in anticipo se il contenuto scorrevole fa parte o meno di un markup nascosto. Ecco cosa ho fatto:

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

Funziona per la maggior parte, ma c'è un ovvio problema che può potenzialmente sorgere. Se il contenuto che stai clonando è in stile CSS che include riferimenti al markup genitore nelle loro regole, il contenuto clonato non conterrà lo stile appropriato e probabilmente avrà misure leggermente diverse. Per ovviare a questo, puoi assicurarti che al markup che stai clonando siano applicate regole CSS che non includano riferimenti al markup genitore.

Inoltre, questo non mi è venuto in mente con il mio widget scroller, ma per ottenere l'altezza appropriata dell'elemento clonato, dovrai impostare la larghezza sulla stessa larghezza dell'elemento genitore. Nel mio caso, una larghezza CSS veniva sempre applicata all'elemento reale, quindi non dovevo preoccuparmene, tuttavia, se all'elemento non è stata applicata una larghezza, potrebbe essere necessario eseguire una sorta di ricorsivo attraversamento dell'antenato DOM dell'elemento per trovare la larghezza dell'elemento padre appropriata.


Questo ha un problema interessante però. Se l'elemento è già un elemento a blocchi, il clone prenderà l'intera larghezza del corpo (tranne l'imbottitura o il margine del corpo), che è diverso dalla sua dimensione all'interno di un contenitore.
Meligy

16

Sviluppando ulteriormente la risposta dell'utente Nick e il plugin dell'utente hitautodestruct su JSBin, ho creato un plug-in jQuery simile che recupera sia la larghezza che l'altezza e restituisce un oggetto contenente questi valori.

Può essere trovato qui: http://jsbin.com/ikogez/3/

Aggiornare

Ho completamente ridisegnato questo piccolo plug-in in quanto si è scoperto che la versione precedente (menzionata sopra) non era realmente utilizzabile in ambienti di vita reale in cui si stava verificando molta manipolazione del DOM.

Funziona perfettamente:

/**
 * 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;
};

il tuo codice non è corretto. È necessario sizes = {"width": $wrap.width(), "height": $wrap.height()};il thisriferimento all'articolo originale, che non è visibile.
jackJoe,

@jackJoe Sto usando questo codice da un po 'di tempo senza problemi. Nella migliore delle ipotesi direi che ho bisogno di $ clone.width () invece di 'this'. Non $ wrap poiché voglio la dimensione dell'elemento all'interno dell'involucro. Il wrapper potrebbe essere 10000x10000px mentre l'elemento che voglio misurare è ancora 30x40px per esempio.
Robin van Baalen,

Anche il targeting $wrapè ok (almeno nei miei test). Ho provato con thise ovviamente non avrebbe preso la dimensione perché thissi riferisce ancora all'elemento nascosto.
jackJoe,

1
Grazie @jackJoe Ho ora aggiornato l'esempio di codice.
Robin van Baalen,

12

Sviluppando ulteriormente la risposta di Nick:

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

Ho scoperto che è meglio fare questo:

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

L'impostazione degli attributi CSS li inserirà in linea, sovrascrivendo tutti gli altri attributi presenti nel file CSS. Rimuovendo l'attributo di stile sull'elemento HTML, tutto è tornato alla normalità e ancora nascosto, poiché era nascosto in primo luogo.


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

9
... a meno che tu non abbia già avuto stili in linea sull'elemento. Quale sarebbe il caso se nascondessi l'elemento con jQuery.
Muhd,

4

Puoi anche posizionare il div nascosto sullo schermo con un margine negativo anziché utilizzare la visualizzazione: nessuna, proprio come una tecnica di sostituzione dell'immagine del rientro del testo.

per esempio.

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

In questo modo l'altezza () è ancora disponibile.


3

Cerco di trovare una funzione funzionante per l'elemento nascosto ma mi rendo conto che il CSS è molto complesso di quanto tutti pensino. Ci sono molte nuove tecniche di layout in CSS3 che potrebbero non funzionare per tutte le risposte precedenti come box flessibile, griglia, colonna o persino elemento all'interno di un elemento genitore complesso.

esempio di flexibox inserisci qui la descrizione dell'immagine

Penso che l'unica soluzione sostenibile e semplice sia il rendering in tempo reale . A quel tempo, il browser dovrebbe fornire la dimensione dell'elemento corretta .

Purtroppo, JavaScript non fornisce alcun evento diretto per avvisare quando l'elemento viene mostrato o nascosto. Tuttavia, creo alcune funzioni basate sull'API modificata dell'attributo DOM che eseguirà la funzione di richiamata quando viene modificata la visibilità dell'elemento.

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

    // render or adjust something
});

Per ulteriori informazioni, visitare il mio progetto GitHub.

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

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


Grazie per la tua risposta. Mi ha ispirato a usare anche MutationObservers. Tuttavia, tieni presente che la tua libreria verifica solo i cambiamenti di visibilità causati da stylecambiamenti di attributo (vedi la riga 59 qui ), mentre i cambiamenti di visibilità possono essere causati anche da cambiamenti classnell'attributo.
Ashraf Sabry,

Hai ragione. L'istruzione corretta dovrebbe essere e.attributeName! == 'style' && e.attributeName! == 'className'
Soul_Master

2

Seguendo la soluzione di Nick Craver, l'impostazione della visibilità dell'elemento consente di ottenere dimensioni precise. Ho usato questa soluzione molto spesso. Tuttavia, dovendo ripristinare manualmente gli stili, sono arrivato a trovare questo ingombrante, dato che modificando il posizionamento / visualizzazione iniziale dell'elemento nel mio CSS attraverso lo sviluppo, spesso dimentico di aggiornare il relativo codice javascript. Il seguente codice non reimposta gli stili per dire, ma rimuove gli stili in linea aggiunti da javascript:

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

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

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

L'unico presupposto qui è che non ci possono essere altri stili in linea, altrimenti verranno rimossi. Il vantaggio qui, tuttavia, è che gli stili dell'elemento vengono riportati a quello che erano nel foglio di stile CSS. Di conseguenza, è possibile scrivere questo come una funzione in cui viene passato un elemento e viene restituita un'altezza o una larghezza.

Un altro problema che ho riscontrato nell'impostare gli stili in linea tramite js è che quando si ha a che fare con le transizioni tramite css3, si diventa costretti ad adattare i pesi delle proprie regole di stile per essere più forti di uno stile in linea, che a volte può essere frustrante.


1

Per definizione, un elemento ha altezza solo se è visibile.

Solo curioso: perché hai bisogno dell'altezza di un elemento nascosto?

Un'alternativa è nascondere efficacemente un elemento mettendolo dietro (usando z-index) una sovrapposizione di qualche tipo).


1
ho bisogno di un'altezza di un elemento, che sembra essere nascosta nel momento in cui voglio la sua altezza. sto costruendo un plugin e ho bisogno di raccogliere alcuni dati mentre lo
avvio

2
un altro motivo è per centrare le cose con javascript che potrebbero non essere ancora visibili
Simon_Weaver

@cletus Se sei solo curioso di scrivere commenti, questa è spesso una situazione nella codifica frontend per ottenere la dimensione di un elemento nascosto.
Rantiev,

1

Nella mia circostanza avevo anche un elemento nascosto che mi impediva di ottenere il valore dell'altezza, ma non era l'elemento stesso ma piuttosto uno dei suoi genitori ... quindi ho appena controllato un mio plugin per vedere se è nascosto, altrimenti trova l'elemento nascosto più vicino. Ecco un esempio:

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

In realtà, questa è una fusione delle risposte di Nick, Gregory e Eyelidlessness per darti l'uso del metodo migliorato di Gregory, ma utilizza entrambi i metodi nel caso in cui si supponga che ci sia qualcosa nell'attributo di stile che vuoi rimandare, e cerca un elemento genitore.

La mia unica lamentela con la mia soluzione è che il circuito attraverso i genitori non è del tutto efficiente.


1

Una soluzione alternativa consiste nel creare un div parent all'esterno dell'elemento di cui si desidera ottenere l'altezza, applicare un'altezza di '0' e nascondere eventuali overflow. Quindi, prendi l'altezza dell'elemento figlio e rimuovi la proprietà di overflow del genitore.

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

Ecco una sceneggiatura che ho scritto per gestire tutti i metodi di dimensione di jQuery per elementi nascosti, anche discendenti di genitori nascosti. Si noti che, ovviamente, c'è un colpo di prestazioni usando questo.

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

La risposta per mancanza di palpebra sembra perfetta per ciò di cui ho bisogno, ma non funziona con il jQuery che sto correndo: 1.3.2 Fa sì che jQuery lanci un this.clone (o qualcosa di molto vicino) non è una funzione. Qualcuno ha qualche idea su come risolverlo?

0

Se hai già visualizzato l'elemento sulla pagina in precedenza, puoi semplicemente prendere l'altezza direttamente dall'elemento DOM (raggiungibile in jQuery con .get (0)), poiché è impostato anche quando l'elemento è nascosto:

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

lo stesso per la larghezza:

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

(grazie a Skeets O'Reilly per la correzione)


Restituisceundefined
Jake Wilson,

1
Abbastanza sicuro che questo funziona solo se hai già visualizzato l'elemento sulla pagina in precedenza. Per gli elementi che sono sempre stati display='none', questo non funzionerà.
Skeets
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.