web-dev-qa-db-fra.com

Pourquoi la largeur de window.width est-elle inférieure à la largeur de fenêtre définie dans les requêtes sur les supports

Je suis assez perplexe et je ne sais toujours pas comment expliquer cela avec des mots appropriés. Jusqu'à présent, j'ai utilisé et configuré mes requêtes multimédia avec Breakpoint. Une variable de point d'arrêt utilisée ressemble à, par exemple: 

$menustatictofixed: min-width 900px;

$ breakpoint-to-ems est défini sur true. J'ai aménagé la page avec toutes ses variables de point d'arrêt en fonction des valeurs en pixels de l'extrait de code jQuery suivant:

$('body').append('<div style="position: fixed; bottom: 0; right: 0; display: inline-block; font-weight: bold; padding: 5px 7px; border-radius: 5px 0 0 0; background: green; color: white; z-index: 9999;">Viewport width <span id="width"></span> px</div>');
var viewportWidth = $(window).width()
$('#width').text(viewportWidth);
$(window).resize(function() {
  var viewportWidth = $(window).width();
    $('#width').text(viewportWidth);
});

Tout avait l'air correct et propre. Mais au cours des deux ou trois derniers jours, j'ai eu des problèmes pour configurer les derniers points d'arrêt d'un modèle et pour que les choses se comportent de manière prévisible. D'une manière ou d'une autre, les choses qui semblaient s'additionner étaient propres et bonnes au départ, ce dont je doute fort logiquement, sont en fait inappropriées et en quelque sorte en désordre. Parce que si vous jetez un coup d'oeil au screenshot suivant, la largeur de la fenêtre (sous Chrome) diffère de celle de l'extrait de code jQuery utilisant window.width. Il n'y a pas non plus de différence si je remplacerais window.width par window.innerWidth pour éliminer éventuellement les barres de défilement. La seule façon de recevoir des résultats corrects est d’ajouter 15 pixels à l’équation: 

var viewportWidth = $(window).width() + 15;

Le seul problème qui se pose dans toute l'équation est que window.width est le mauvais choix de fonction et il serait préférable de choisir, par exemple. document.documentElement.clientWidth ou autre chose ou ...? Et pour ce que les 15 pixels sont debout pour qui résolu le problème ci-dessus d'une manière un peu hacky? Cordialement Ralf

24
rpk

La réponse est des barres de défilement, et la solution est délicate.

Les requêtes des médias sont intéressantes. Ils ne se comportent pas exactement de la même façon sur tous les navigateurs, ce qui signifie que leur utilisation peut parfois être moins facile. Dans -webkit/-blink sous OS X et IE10 sous Win8, par exemple, les barres de défilement sont superposées sur la page. Dans -moz, cependant, les barres de défilement sont pas superposées sur la page. Le meilleur moyen d'obtenir la "zone visible" de la page est la ligne suivante de JavaScript Vanilla (en supposant que vous ayez un document HTML valide):

document.body.parentNode.clientWidth

Ce que cela va faire est de trouver l'élément body, de trouver son parent (qui dans un document valide sera l'élément html), puis de trouver sa largeur après le rendu. Cela vous donnera la largeur que vous souhaitez voir. C'est aussi une largeur inutile d'avoir.

Pourquoi, vous demandez-vous, est-il inutile d'avoir la largeur réelle du client? Ce n'est pas parce que cela varie d'un navigateur à l'autre, parce que c'est le cas. C'est parce que ce n'est pas ce que testent les requêtes sur les médias width! Ce que width médias demande le test estwindow.innerWidth, ce que vous utilisez essentiellement.

Alors, quelle est la solution à ce problème? Eh bien, je dirais que la solution consiste à utiliser des requêtes multimédias basées sur le contenu plutôt que des requêtes multimédias basées sur un périphérique et à laisser une certaine marge de manœuvre dans vos requêtes (surtout si cette marge est d'environ 15px). Si vous ne l’avez pas déjà fait, lisez les articles Vexing Viewports et Une crise d’identité de pixels afin d’obtenir une idée de la raison pour laquelle un miroitement 15px potentiel dans vos définitions MQ n’est pas la pire des choses. dans le monde (il y a probablement de plus gros poissons à frire).

En conclusion, continuez donc à utiliser $breakpoint-to-ems: true et choisissez vos requêtes multimédia en fonction du moment où le contenu passe à window.innerWidth, car il s’agit du seul moyen sain de gérer les problèmes impliquant plusieurs navigateurs. D'un coup d'œil rapide à divers problèmes, il semble que la plupart des navigateurs et des systèmes d'exploitation se déplacent vers une barre de défilement superposée (à partir de Firefox 24 chaque navigateur OS X en aura un, l'interface utilisateur Unity d'Ubuntu les a introduits ), donc, dans un souci de convivialité future, je vous conseillerais de ne pas vous soucier du décalage de la barre de défilement et d’accepter les sites légèrement différents d’un navigateur à l’autre. Rappelez-vous, comme le dit si éloquemment Ethan Marcotte:

Le Web est un média intrinsèquement instable

24
Snugug

Voici ce qui a fonctionné pour moi: Les requêtes de média CSS et la largeur de la fenêtre JavaScript ne correspondent pas .

Au lieu d'utiliser $(window).width(); qui inclut des barres de défilement, obtenez la largeur intérieure de la manière suivante:

function viewport() {
    var e = window, a = 'inner';
    if (!('innerWidth' in window )) {
        a = 'client';
        e = document.documentElement || document.body;
    }
    return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}

var vpWidth = viewport().width; // This should match your media query
47
Justin

C’est à cause du scrollbar's 

La solution la plus correcte que j'ai trouvée consiste à utiliser des requêtes de support pour transmettre la taille de la fenêtre à Javascript. Vous devez suivre ces étapes:

  • Ajouter un élément caché à votre page,
  • Utilisez des requêtes multimédias pour modifier la propriété max-width de cet élément,
  • Relisez la propriété max-width de cet élément via Javascript.

Par exemple, ajoutez l'élément suivant à votre page:

<div id="currentMedia"></div>

Ensuite, écrivez les règles CSS suivantes:

#currentMedia {
    display: none;
}

@media (max-width: 720px) {
    // Make arrows in the carousel disappear...

    #currentMedia {
        max-width: 720px;
    }
}

Ensuite, du côté Javascript, vous pouvez écrire:

if (parseInt(jQuery("#currentMedia").css("max-width"), 10) <= 720) {
    // Code HERE..
}

Et elle sera précise quelle que soit la taille de la barre de défilement, car la valeur provient de la même requête multimédia qui déclenche la disparition du carrousel.

J'ai testé cette solution sur tous les principaux navigateurs récents et elle donne des résultats corrects.

Vous trouverez le grand récapitulatif des propriétés prises en charge sur les navigateurs sur cette page sur quirksmode.org

Votre meilleur choix est probablement de saisir un élément dans la page (en utilisant document.body s'il est pris en charge, ou document.getElementById ou autre), parcourez sa chaîne offsetParent pour rechercher l'élément le plus haut, puis examinez clientWidth et clientHeight de cet élément.

innerWidth documentation 

La méthode .innerWidth() ne s'applique pas aux objets window et document; pour ceux-ci, utilisez plutôt .width().

5
Tushar Gupta

Similaire à la réponse de @ Snugugs mais qui a mieux fonctionné pour mon cas d'utilisation:

CSS (note J'utilise LESS pour que @tabletMin et @desktopMin soient traduits en variables de points d'arrêt que j'ai définies ailleurs: 

    #cssWidth {
        display:none;
        content:'mobile';
    }

    /* Responsive styles (Tablet) */
    @media (min-width: @tabletMin) {
        #cssWidth {
            content:'tablet';
        }
        /* Other tablet CSS... */
    }
    /* Responsive styles (Desktop) */
    @media (min-width: @desktopMin) {
        #cssWidth {
            content:'desktop';
        }
        /* Other Desktop CSS... */
    }

Et puis dans JS:

    getView = function() {
        // If #cssWidth element does not exist, create it and prepend it do body
        if ($('#cssWidth').length === 0) {
            $('body').prepend($(document.createElement('div')).attr('id', 'cssWidth'));
        }
        // Return the value of the elements 'content' property
        return $('#cssWidth').css('content');
    };

La fonction getView () renvoie ensuite la chaîne "mobile", "tablette" ou "bureau" en fonction de la largeur des requêtes media, voir.

Cela pourrait être étendu pour s'adapter à davantage de largeurs de fenêtres, il suffit d'ajouter plus de règles dans le CSS avec d'autres valeurs.

1
Gruffy

Suivez ce lien

function getWindowWidth() {
    var windowWidth = 0;
    if (typeof(window.innerWidth) == 'number') {
        windowWidth = window.innerWidth;
    }
    else {
        if (document.documentElement && document.documentElement.clientWidth) {
            windowWidth = document.documentElement.clientWidth;
        }
        else {
            if (document.body && document.body.clientWidth) {
                windowWidth = document.body.clientWidth;
            }
        }
    }
    return windowWidth;
}
0
Amidou Zabre

La réponse de @Snugug donne une très bonne explication de la raison pour laquelle cela se produit, et @TusharGupta a également une bonne solution qui référence la largeur de mediaquery détectée à javascript. La solution ci-dessous fonctionne de manière inverse en utilisant une largeur détectée par javascript pour déclencher des modifications de mise en page.

Au cas où vous auriez besoin de synchroniser les médias avec la détection de la largeur de pixel javascript, une solution au problème consiste à déclencher des modifications de mise en page CSS basées sur les classes que vous ajoutez avec javascript.

Ainsi, au lieu d’écrire des requêtes multimédia, écrivez les déclarations imbriquées dans une classe, par exemple:

html.myMobileBP { ... }

Et dans votre javascript/jQuery, ajoutez cette classe comme:

if ($(window).width() < myMobileBPPixelSize) {
    $("html").addClass("myMobileBP");
}

Pour aller encore plus loin, vous pouvez envisager le manque de prise en charge de javascript. Définissez les médias qui sont en outre encapsulés dans une classe html.no-js, puis supprimez avec javascript la classe .no-js et appliquez la solution ci-dessus consistant à ajouter des points d'arrêt via des classes javascript.

0
kontur