web-dev-qa-db-fra.com

jQuery - Récupère la largeur d'un élément lorsqu'il n'est pas visible (Affichage: Aucun)

Cela ressemble à jQuery quand un élément n'est pas visible. Width () renvoie 0. Cela a du sens, mais je dois obtenir la largeur d'un tableau pour définir la largeur du parent avant d'afficher le parent.

Comme indiqué ci-dessous, il y a du texte dans le parent qui le rend biaisé et désobligeant. Je veux que le parent soit aussi large que la table et que le texte soit renvoyé à la ligne.

<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 suppose, car il me donne un nombre lorsqu'il est visible). Existe-t-il un moyen d'obtenir la largeur de la table sans rendre le parent visible?

103
Martin

Voici un truc que j'ai utilisé. Cela implique d'ajouter quelques propriétés CSS pour que jQuery pense que l'élément est visible, mais en réalité, il est toujours masqué.

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

C'est un peu un bidouillage, mais cela semble bien fonctionner pour moi.

METTRE &AGRAVE; JOUR

J'ai depuis écrit un blog post qui couvre ce sujet. La méthode utilisée ci-dessus est potentiellement problématique car vous réinitialisez les propriétés CSS à des valeurs vides. Et s'ils avaient des valeurs auparavant? La solution mise à jour utilise la méthode swap () trouvée 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));
91
Tim Banks
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"));
38
Fábio Paiva

D'après la réponse de Roberts, voici ma fonction .Cela fonctionne pour moi si l'élément ou son parent ont été estompés via jQuery, peuvent obtenir des dimensions internes ou externes et renvoyer les valeurs de décalage.

/ edit1: réécrit la fonction. il est maintenant plus petit et peut être appelé directement sur l'objet

/ edit2: la fonction va maintenant insérer le clone juste après l'élément d'origine au lieu du corps, ce qui permettra 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();
8
Marco Kerwitz

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 flexiboxenter 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 donner cette taille d'élément correcte

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

3
Soul_Master

Merci d’avoir posté la fonction realWidth ci-dessus, cela m’a vraiment aidé. Basé sur la fonction "realWidth" ci-dessus, j’ai écrit une réinitialisation CSS (raison 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. J'ai testé cela avec des balises d'image. Le problème était que, lorsque l'image a donné une dimension CSS par largeur (ou max-width), vous n'obtiendrez jamais la dimension réelle de cette image. Peut-être que l'img a "max-width: 100%", la fonction "realWidth" le clone et l'ajoute au corps. Si la taille originale de l'image est plus grande que le corps, vous obtenez alors la taille du corps et non la taille réelle de cette image. 

3
Robert

Si vous avez besoin de la largeur d'un élément masqué et que vous ne pouvez pas le masquer pour une raison quelconque, vous pouvez le cloner, modifier le code CSS afin qu'il s'affiche en dehors de la page, le rendre invisible, puis le mesurer. L'utilisateur n'en sera pas plus prudent s'il est masqué et supprimé par la suite.

Certaines des autres réponses ici ne font que masquer la visibilité, ce qui fonctionne, mais cela prendra un point blanc sur votre page pendant une fraction de seconde.

Exemple:

$itemClone = $('.hidden-item').clone().css({
        'visibility': 'hidden',
        'position': 'absolute',
        'z-index': '-99999',
        'left': '99999999px',
        'top': '0px'
    }).appendTo('body');
var width = $itemClone.width();
$itemClone.remove();
3
rannmann

Une solution, bien que cela ne fonctionne pas dans toutes les situations, consiste à masquer l'élément en définissant l'opacité sur 0. Un élément complètement transparent aura une largeur. 

L'inconvénient est que l'élément prendra toujours de la place, mais ce ne sera pas un problème dans tous les cas. 

Par exemple:

$(img).css("opacity", 0)  //element cannot be seen
width = $(img).width()    //but has width
2
Jake

Avant de prendre la largeur, affichez l'affichage parent, puis prenez la largeur et, enfin, masquez l'affichage parent. Juste comme suivre 

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

Le problème le plus important qui manque à la plupart des solutions ici est que la largeur d'un élément est souvent modifiée par CSS en fonction de sa portée en HTML.

Si je devais déterminer la largeur offset d'un élément en ajoutant un clone à l'élément, les styles ne s'appliquant que dans sa portée actuelle, la largeur serait erronée.

par exemple:

// css

.module-container .my-elem { bordure: noir uni 60 pixels; }

maintenant, lorsque j'essaie de déterminer la largeur de mon-elem dans le contexte du corps, celui-ci disparaîtra de 120 pixels. Vous pouvez également cloner le conteneur de modules, mais votre JS ne devrait pas avoir à connaître ces détails.

Je ne l'ai pas testée, mais la solution de Soul_Master semble être la seule à pouvoir fonctionner correctement. Mais malheureusement, en regardant l’implémentation, son utilisation sera coûteuse et ses performances réduites (la plupart des solutions présentées ici le sont également).

Si possible, utilisez plutôt visibilité: masqué. Cela rendra toujours l'élément, vous permettant de calculer la largeur sans prise de tête.

1
Code Novitiate

En plus de la réponse postée par Tim Banks , qui a suivi pour résoudre mon problème, j'ai dû modifier une chose simple.

Quelqu'un d'autre pourrait avoir le même problème; Je travaille avec un menu déroulant Bootstrap dans un menu déroulant. Mais le texte peut être plus large que le contenu actuel à ce stade (et il n'y a pas beaucoup de bons moyens pour le résoudre par css).

J'ai utilisé: 

$table.css({ position: "absolute", visibility: "hidden", display: "table" });

au lieu de cela, qui définit le conteneur sur une table dont la largeur est toujours proportionnelle si le contenu est plus large.

0
Mathijs Segers
jQuery(".megamenu li.level0 .dropdown-container .sub-column ul .level1").on("mouseover", function () {
    var sum = 0;
    jQuery(this).find('ul li.level2').each(function(){
    sum -= jQuery(this).height();
    jQuery(this).parent('ul').css('margin-top', sum / 1.8);
    console.log(sum);
    });
});

En survol, nous pouvons calculer la hauteur de l'élément de la liste. 

0
rajashekar

Comme il a été dit précédemment, la méthode cloner et attacher ailleurs ne garantit pas les mêmes résultats car le style peut être différent.

Ci-dessous, mon approche. Il monte les parents à la recherche du parent responsable de la dissimulation, puis l’a masqué temporairement pour calculer la largeur, la hauteur, etc. nécessaires.

    var width = parseInt($image.width(), 10);
    var height = parseInt($image.height(), 10);

    if (width === 0) {

        if ($image.css("display") === "none") {

            $image.css("display", "block");
            width = parseInt($image.width(), 10);
            height = parseInt($image.height(), 10);
            $image.css("display", "none");
        }
        else {

            $image.parents().each(function () {

                var $parent = $(this);
                if ($parent.css("display") === "none") {

                    $parent.css("display", "block");
                    width = parseInt($image.width(), 10);
                    height = parseInt($image.height(), 10);
                    $parent.css("display", "none");
                }
            });
        }
    }
0
Ibraheem