112 votes

jQuery - Obtenir la largeur d'un élément non visible (Display : None)

Il semble que dans jQuery, lorsqu'un élément n'est pas visible, width() renvoie 0. C'est logique, mais j'ai besoin d'obtenir la largeur d'un tableau afin de définir la largeur du parent avant de montrer le parent.

Comme indiqué ci-dessous, il y a du texte dans le parent, qui fait que le parent est de travers et a l'air désagréable. Je veux que le parent soit seulement aussi large que la table et que le texte soit enveloppé.

<div id="parent">
    Text here ... Can get very long and skew the parent
    <table> ... </table>
    Text here too ... which is why I want to shrink the parent based on the table
</div>

CSS :

#parent
{
    display: none;
}

Javascript :

var tableWidth = $('#parent').children('table').outerWidth();
if (tableWidth > $('#parent').width())
{
    $('#parent').width(tableWidth);
}

tableWidth renvoie toujours 0 puisqu'il n'est pas visible (c'est ce que je pense puisqu'il me donne un nombre lorsqu'il est visible). Existe-t-il un moyen d'obtenir la largeur du tableau sans rendre le parent visible ?

97voto

Tim Banks Points 4053

Voici une astuce que j'ai utilisée. Il s'agit d'ajouter quelques propriétés CSS pour que jQuery pense que l'élément est visible, mais en fait il est toujours caché.

var $table = $("#parent").children("table");
$table.css({ position: "absolute", visibility: "hidden", display: "block" });
var tableWidth = $table.outerWidth();
$table.css({ position: "", visibility: "", display: "" });

C'est une sorte de piratage, mais cela semble fonctionner correctement pour moi.

UPDATE

J'ai depuis écrit un article de blog qui couvre ce sujet. La méthode utilisée ci-dessus peut s'avérer problématique puisque vous réinitialisez les propriétés CSS à des valeurs vides. Que se passe-t-il si elles avaient des valeurs auparavant ? La solution mise à jour utilise la méthode swap() qui se trouve dans le code source de jQuery.

Code de l'article de blog référencé :

//Optional parameter includeMargin is used when calculating outer dimensions  
(function ($) {
$.fn.getHiddenDimensions = function (includeMargin) {
    var $item = this,
    props = { position: 'absolute', visibility: 'hidden', display: 'block' },
    dim = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 },
    $hiddenParents = $item.parents().andSelf().not(':visible'),
    includeMargin = (includeMargin == null) ? false : includeMargin;

    var oldProps = [];
    $hiddenParents.each(function () {
        var old = {};

        for (var name in props) {
            old[name] = this.style[name];
            this.style[name] = props[name];
        }

        oldProps.push(old);
    });

    dim.width = $item.width();
    dim.outerWidth = $item.outerWidth(includeMargin);
    dim.innerWidth = $item.innerWidth();
    dim.height = $item.height();
    dim.innerHeight = $item.innerHeight();
    dim.outerHeight = $item.outerHeight(includeMargin);

    $hiddenParents.each(function (i) {
        var old = oldProps[i];
        for (var name in props) {
            this.style[name] = old[name];
        }
    });

    return dim;
}
}(jQuery));

1 votes

Cela ne va-t-il pas obliger le navigateur à redessiner la page deux fois ? Si c'est le cas, il s'agit d'une solution sous-optimale.

0 votes

@Tim Banks très bien ! J'ai en fait écrit une extension similaire. Ce que j'ai remarqué, c'est un comportement très étrange dans le cas de Firefox width() renvoie 0, aussi bien pour votre plugin que pour le mien. Et en plus de cela, il ne prend jamais en compte le padding. jsfiddle.net/67cgB . J'ai le plus grand mal à trouver ce qu'on pourrait faire d'autre pour le réparer.

0 votes

Comment puis-je utiliser ce hack dans Jquery Accordion pour obtenir les dimensions cachées de l'accordéon ?

41voto

Fábio Paiva Points 157
function realWidth(obj){
    var clone = obj.clone();
    clone.css("visibility","hidden");
    $('body').append(clone);
    var width = clone.outerWidth();
    clone.remove();
    return width;
}
realWidth($("#parent").find("table:first"));

0 votes

Sale truc sympa ! !! Assurez-vous que le clone a les bonnes propriétés css (ex. si la taille de la police de l'élément original est 15, vous devez utiliser clone.css("visibility", "hidden").css("font-size", "15px") ; )

18 votes

Je tiens à préciser que cela ne fonctionnera pas si votre élément a hérité de sa largeur d'un parent. Il héritera simplement de la largeur du corps, ce qui est incorrect.

3 votes

J'ai modifié clone.css("visibility","hidden"); a clone.css({"visibility":"hidden", "display":"table"}); ce qui résout le problème signalé par @Dean

8voto

denoir Points 318

Sur la base de la réponse de Roberts, voici ma fonction. Elle fonctionne si l'élément ou son parent ont été masqués par jQuery, peut obtenir les dimensions intérieures ou extérieures et renvoie également les valeurs de décalage.

/edit1 : réécriture de la fonction. Elle est maintenant plus petite et peut être appelée directement sur l'objet.

/edit2 : la fonction insère désormais le clone juste après l'élément original au lieu du corps, ce qui permet au clone de conserver les dimensions héritées.

$.fn.getRealDimensions = function (outer) {
    var $this = $(this);
    if ($this.length == 0) {
        return false;
    }
    var $clone = $this.clone()
        .show()
        .css('visibility','hidden')
        .insertAfter($this);        
    var result = {
        width:      (outer) ? $clone.outerWidth() : $clone.innerWidth(), 
        height:     (outer) ? $clone.outerHeight() : $clone.innerHeight(), 
        offsetTop:  $clone.offset().top, 
        offsetLeft: $clone.offset().left
    };
    $clone.remove();
    return result;
}

var dimensions = $('.hidden').getRealDimensions();

0 votes

Version YUI pour ceux qui en ont besoin : gist.github.com/samueljseay/13c2e69508563b2f0458

0 votes

L'offsetTop est-il correct pour l'article étant donné qu'il s'agit du clone et non de l'article "réel" ? Devriez-vous utiliser $this.offset().top ? Je suis également curieux de savoir à quoi sert le haut/gauche ? Je n'utilise que la "largeur" mais je me demande si je ne devrais pas me préoccuper de ces décalages pour une raison quelconque.

3voto

Robert Points 249

Merci d'avoir publié la fonction "realWidth" ci-dessus, cela m'a vraiment aidé. Sur la base de la fonction "realWidth" ci-dessus, j'ai écrit une réinitialisation CSS (la raison est décrite ci-dessous).

function getUnvisibleDimensions(obj) {
    if ($(obj).length == 0) {
        return false;
    }

    var clone = obj.clone();
    clone.css({
        visibility:'hidden',
        width : '',
        height: '',
        maxWidth : '',
        maxHeight: ''
    });
    $('body').append(clone);
    var width = clone.outerWidth(),
        height = clone.outerHeight();
    clone.remove();
    return {w:width, h:height};
}

"realWidth" obtient la largeur d'une balise existante. Je l'ai testé avec des balises d'image. Le problème est que, lorsque l'image a une dimension CSS par largeur (ou max-width), vous n'obtiendrez jamais la dimension réelle de cette image. Peut-être, l'img a "max-width : 100%", la fonction "realWidth" le clone et l'ajoute au corps. Si la taille originale de l'image est supérieure à celle du corps, vous obtenez la taille du corps et non la taille réelle de l'image.

3voto

Soul_Master Points 3224

J'essaie de trouver une fonction fonctionnelle pour les éléments cachés, mais je me rends compte que les CSS sont beaucoup plus complexes que ce que l'on pense. Il y a beaucoup de nouvelles techniques de mise en page en CSS3 qui pourraient ne pas fonctionner pour toutes les réponses précédentes comme la boîte flexible, la grille, la colonne ou même l'élément à l'intérieur d'un élément parent complexe.

exemple de flexibox enter image description here

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

Malheureusement, JavaScript ne fournit pas d'événement direct pour notifier quand un élément est affiché ou caché. Cependant, je crée une fonction basée sur l'API DOM Attribute Modified qui exécutera une 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, veuillez consulter le site GitHub de mon projet.

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

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

4 votes

CSS est beaucoup plus complexe que ce que l'on pense C'est tellement vrai

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X