web-dev-qa-db-fra.com

jQuery: Obtenir la hauteur d'un élément caché dans jQuery

Je dois obtenir la hauteur d'un élément caché dans une div. En ce moment, je montre le div, prend la hauteur et masque le div parent. Cela semble un peu bête. Y a-t-il un meilleur moyen?

J'utilise jQuery 1.4.2:

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

Vous pouvez faire quelque chose comme ça, un peu hacky cependant, oubliez position si c'est déjà absolu:

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 : "");
177
Nick Craver

J'ai rencontré le même problème pour obtenir la largeur d'élément caché, alors j'ai écrit cet appel de plugin jQuery Actual pour le corriger. À la place d'utiliser

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

utilisation

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

vous donnera la bonne valeur pour l’élément caché ou l’élément a un parent caché.

Une documentation complète s'il vous plaît voir ici . Il y a aussi une démo à inclure dans la page.

J'espère que cette aide :)

92
ben

Vous configurez deux styles CSS, le style d'affichage et le style de visibilité .

Si l'élément est masqué en définissant le style CSS de visibilité, vous devriez pouvoir obtenir la hauteur, que l'élément soit visible ou non, car l'élément prend toujours de la place sur la page. .

Si l'élément est masqué en modifiant le style d'affichage CSS en "aucun", l'élément ne prend pas d'espace sur la page et vous devrez lui attribuer un style d'affichage qui entraînera le rendu de l'élément dans un espace donné. quel point, vous pouvez obtenir la hauteur.

38
casperOne

J'ai en fait eu recours à quelques astuces pour régler ce problème de temps en temps. J'ai développé un widget de barre de défilement jQuery où j'ai rencontré le problème que je ne connaissais pas à l'avance si le contenu défilant faisait partie d'un élément de balisage masqué ou non. Voici ce que j'ai fait:

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

Cela fonctionne pour la plupart, mais il y a un problème évident qui peut potentiellement se poser. Si le contenu que vous clonez est stylé avec CSS qui inclut des références au balisage parent dans leurs règles, le contenu cloné ne contiendra pas le style approprié et aura probablement des mesures légèrement différentes. Pour contourner ce problème, vous pouvez vous assurer que les règles CSS appliquées au balisage que vous clonez ne comprennent pas les références au balisage parent.

En outre, cela ne m'est pas venu avec mon widget de défilement, mais pour obtenir la hauteur appropriée de l'élément cloné, vous devez définir la largeur sur la même largeur que l'élément parent. Dans mon cas, une largeur CSS était toujours appliquée à l'élément réel; je n'avais donc pas à m'en soucier. Cependant, si l'élément n'a pas de largeur, vous devrez peut-être effectuer une sorte de récursif. parcours de l’ascendance DOM de l’élément pour trouver la largeur de l’élément parent approprié.

29
elliotlarson

En me basant davantage sur la réponse de l'utilisateur Nick et sur le plug-in de hitautodestruct de l'utilisateur sur JSBin, j'ai créé un plug-in jQuery similaire qui récupère la largeur et la hauteur et renvoie un objet contenant ces valeurs.

Vous pouvez le trouver ici: http://jsbin.com/ikogez/3/

Mise à jour

J'ai complètement repensé ce minuscule plugin car il s'est avéré que la version précédente (mentionnée ci-dessus) n'était pas vraiment utilisable dans des environnements de la vie réelle où de nombreuses manipulations DOM étaient en cours.

Cela fonctionne parfaitement:

/**
 * 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;
};
12
Robin van Baalen

Bâtir plus loin sur la réponse de Nick:

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

J'ai trouvé qu'il vaut mieux faire ceci:

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

La définition d'attributs CSS les insérera en ligne, ce qui écrasera tous les autres attributs de votre fichier CSS. En supprimant l'attribut style de l'élément HTML, tout est revenu à la normale et est toujours masqué, puisqu'il était masqué en premier lieu.

12

Vous pouvez également positionner la division masquée sur l'écran avec une marge négative plutôt que d'utiliser l'affichage: aucune, à la manière d'une technique de remplacement d'image avec retrait.

par exemple.

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

Ainsi, la hauteur () est toujours disponible.

4
vaughanos

Suivant la solution de Nick Craver, le réglage de la visibilité de l'élément lui permet d'obtenir des dimensions précises. J'ai utilisé cette solution très très souvent. Cependant, comme je devais réinitialiser les styles manuellement, je trouvais cela fastidieux, étant donné que la modification du positionnement/affichage initial de l'élément dans mon css au cours du développement, j'oubliais souvent de mettre à jour le code javascript associé. Le code suivant ne réinitialise pas les styles en tant que tel, mais supprime les styles en ligne ajoutés par javascript:

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

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

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

La seule hypothèse ici est qu'il ne peut y avoir d'autres styles inline, sinon ils seront également supprimés. L'avantage ici, cependant, est que les styles de l'élément sont ramenés à ce qu'ils étaient dans la feuille de style css. En conséquence, vous pouvez écrire ceci en tant que fonction dans laquelle un élément est passé et une hauteur ou une largeur est renvoyée.

Un autre problème que j’ai constaté lors de la définition des styles en ligne via js est que, lorsqu’il s’agit de transitions via css3, vous devez adapter le poids de vos règles de style pour qu’il soit plus puissant qu’un style en ligne, ce qui peut parfois être frustrant.

2
Prusprus

J'essaie de trouver une fonction de travail pour l'élément caché, mais je me rends compte que CSS est beaucoup plus complexe que tout le monde le pense. De nombreuses nouvelles techniques de mise en forme dans CSS3 pourraient ne pas fonctionner pour toutes les réponses précédentes, telles que les zones flexibles, les grilles, les colonnes ou même les éléments à l'intérieur d'un élément parent complexe.

exemple flexibox  enter image description here

Je pense que la seule solution durable et simple est le rendu en temps réel . À ce moment-là, le navigateur devrait vous indiquer que la taille correcte de l'élément .

Malheureusement, JavaScript ne fournit aucun événement direct à notifier lorsque l'élément est affiché ou masqué. Cependant, je crée une fonction basée sur l'API DOM Attribute Modified qui exécutera la fonction de rappel lorsque la visibilité de l'élément est modifiée.

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

    // render or adjust something
});

Pour plus d'informations, s'il vous plaît visitez mon projet GitHub.

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

démo: http://jsbin.com/ETiGIre/7

2
Soul_Master

Par définition, un élément n'a de hauteur que s'il est visible.

Juste curieux: pourquoi avez-vous besoin de la hauteur d'un élément caché?

Une alternative consiste à effectivement masquer un élément en le plaçant derrière (en utilisant z-index) une superposition quelconque).

1
cletus

Une solution de contournement consiste à créer un div parent en dehors de l'élément dont vous souhaitez obtenir la hauteur, appliquez une hauteur de "0" et masquez tout débordement. Ensuite, prenez la hauteur de l'élément enfant et supprimez la propriété de débordement du parent.

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>
1
Matt

Dans mon cas, j’avais aussi un élément caché qui m’empêchait d’obtenir la valeur height, mais ce n’était pas l’élément lui-même, mais plutôt l’un de ses parents ... alors j’ai juste placé un chèque pour l’un de mes plugins pour voir si caché, sinon trouvez l'élément caché le plus proche. Voici un exemple:

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

En fait, il s’agit d’une fusion des réponses de Nick, Gregory et Eyelidlessness pour vous donner l’utilisation de la méthode améliorée de Gregory, mais utilise les deux méthodes dans le cas où il est supposé y avoir quelque chose dans l’attribut de style que vous souhaitez reporter et que vous recherchez. un élément parent.

Mon seul reproche, c'est que la boucle entre les parents ne soit pas totalement efficace.

1
marksyzm

Si vous avez déjà affiché l'élément sur la page, vous pouvez simplement prendre la hauteur directement de l'élément DOM (accessible dans jQuery avec .get (0)), car il est défini même lorsque l'élément est masqué:

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

idem pour la largeur:

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

(merci à Skeets O'Reilly pour la correction)

0
Luca C.

Voici un script que j'ai écrit pour gérer toutes les méthodes de dimension de jQuery pour les éléments cachés, même les descendants de parents cachés. Notez que, bien sûr, cela a un impact négatif sur les performances.

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