wake-up-neo.net

Warum ist die Fensterbreite kleiner als die in Medienabfragen festgelegte Breite des Ansichtsfensters?

Ich bin ziemlich verwirrt und bin mir immer noch nicht sicher, wie ich das in richtigen Worten erklären soll. Bisher habe ich meine Medienanfragen mit Breakpoint verwendet und eingerichtet. Eine verwendete Breakpoint-Variable sieht beispielsweise so aus: 

$menustatictofixed: min-width 900px;

$ breakpoint-to-ems ist auf true gesetzt. Ich habe die Seite mit allen ihren Breakpoint-Variablen basierend auf den Pixelwerten des folgenden jQuery-Snippets ausgelegt:

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

Alles sah ordentlich und sauber aus. In den letzten ein bis zwei Tagen hatte ich jedoch Probleme, die letzten Haltepunkte für ein Muster festzulegen und das Verhalten vorhersehbar zu machen. Irgendwie sind die Dinge, die anscheinend sauber und gut zu sein schienen, was ich jetzt logischerweise höchst bezweifle, tatsächlich unangemessen und irgendwie ein Chaos. Wenn Sie einen Blick auf das folgende screenshot werfen, unterscheidet sich die Breite des Fensters (in Chrome) von der Breite des jQuery-Snippets mit window.width. Es ist auch kein Unterschied, ob ich window.width durch window.innerWidth ersetzen würde, um eventuell Bildlaufleisten auszuschließen. Die richtigen Ergebnisse erhalten Sie nur, wenn Sie der Gleichung 15 Pixel hinzufügen: 

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

Ist das einzige Problem in der gesamten Gleichung, dass window.width die falsche Wahl der Funktion ist und es besser wäre, z. document.documentElement.clientWidth oder etwas anderes oder ...? Und wofür stehen die 15 Pixel, für die das Problem oben etwas hackig gelöst wurde? Viele Grüße Ralf

24
rpk

Die Antwort sind Bildlaufleisten und die Lösung ist schwierig.

Medienanfragen sind interessant. Sie verhalten sich im gesamten Browser nicht genau gleich, was bedeutet, dass die Verwendung manchmal nicht so einfach ist. In -webkit/-blink unter OS X und IE10 unter Win8 werden beispielsweise Bildlaufleisten auf der Seite eingeblendet. In -moz werden Bildlaufleisten jedoch nicht auf der Seite eingeblendet. Der beste Weg, um den "sichtbaren Bereich" der Seite zu erhalten, ist die folgende Zeile von Vanilla JavaScript (vorausgesetzt, Sie haben ein gültiges HTML-Dokument):

document.body.parentNode.clientWidth

Suchen Sie das body -Element, suchen Sie das übergeordnete Element (das in einem gültigen Dokument das html -Element ist) und suchen Sie die Breite nach dem Rendern. Dadurch erhalten Sie die Breite, die Sie sehen möchten. Es ist auch eine nutzlose Breite .

Warum, fragen Sie sich vielleicht, ist die tatsächliche Clientbreite unbrauchbar? Das liegt nicht daran, dass es von Browser zu Browser unterschiedlich ist, sondern daran, dass dies der Fall ist. Dies liegt daran, dass die width Medienabfragen nicht wirklich getestet werden! Was width Media Queries Test ist window.innerWidth, was Sie im Wesentlichen jetzt verwenden.

Was ist die Lösung für dieses Problem? Nun, ich würde sagen, die Lösung besteht darin, inhaltsbasierte Medienabfragen anstelle von gerätebasierten Medienabfragen zu verwenden und mit einem gewissen Wackelraum in Ihren Abfragen einverstanden zu sein (insbesondere, wenn dieser Wackelraum ungefähr 15px beträgt). Wenn Sie dies noch nicht getan haben, lesen Sie die Artikel Vexing Viewports und A Pixel Identity Crisis , um eine Vorstellung davon zu erhalten, warum ein möglicher 15px in Ihren MQ-Definitionen schimmert ist nicht das Schlimmste auf der Welt (es gibt wahrscheinlich größere Fische zum Braten).

Verwenden Sie also abschließend weiterhin $breakpoint-to-ems: true und wählen Sie Ihre Medienabfragen basierend darauf aus, wann der Inhalt zu window.innerWidth wechselt, da dies die einzig vernünftige Möglichkeit ist, browserübergreifende Probleme zu behandeln. Auf den ersten Blick scheinen die meisten Browser und Betriebssysteme auf eine Overlay-Bildlaufleiste umzusteigen (ab Firefox 24 Jeder OS X-Browser hat eine, Ubuntus Unity-Benutzeroberfläche eingeführt) sie ), also in dem Bestreben, zukunftsfreundlich zu sein, würde ich vorschlagen, sich nicht um den Versatz der Bildlaufleiste zu sorgen und Websites zu akzeptieren, die im Browser etwas anders aussehen. Denken Sie daran, wie Ethan Marcotte so beredt formuliert:

Das Web ist ein inhärent instabiles Medium

24
Snugug

Das hat bei mir funktioniert: CSS-Medienabfragen und JavaScript-Fensterbreite stimmen nicht mit überein.

Verwenden Sie anstelle von $(window).width();, die Bildlaufleisten enthält, die innere Breite wie folgt:

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

IT's wegen der scrollbar's 

Die richtigste Lösung, die ich gefunden habe, ist die Verwendung von Medienabfragen, um die tatsächliche Fenstergröße an Javascript zu übergeben. Du musst diesen Schritten folgen:

  • Fügen Sie Ihrer Seite ein verstecktes Element hinzu.
  • Verwenden Sie Medienabfragen, um die max-width-Eigenschaft dieses Elements zu ändern.
  • Lesen Sie die max-width-Eigenschaft dieses Elements über Javascript zurück.

Fügen Sie Ihrer Seite beispielsweise folgendes Element hinzu:

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

Dann schreibe die folgenden CSS-Regeln:

#currentMedia {
    display: none;
}

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

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

Dann können Sie auf der Javascript-Seite Folgendes schreiben:

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

Unabhängig von der Größe der Bildlaufleiste ist dies genau, da der Wert von der gleichen Medienabfrage stammt, die das Verschwinden des Karussells auslöst.

Ich habe diese Lösung mit allen gängigen Browsern getestet und liefert korrekte Ergebnisse.

Sie finden eine große Zusammenfassung, welche Eigenschaften von welchen Browsern unterstützt werden auf dieser Seite auf quirksmode.org

Ihre beste Wette ist wahrscheinlich, ein Element auf der Seite (mit document.body wo unterstützt oder document.getElementById oder was auch immer) zu packen, seine offsetParent-Kette zu durchsuchen, das oberste Element zu finden und dann clientWidth und clientHeight des Elements zu untersuchen.

innerWidth Dokumentation 

Die .innerWidth()-Methode ist nicht auf window- und document-Objekte anwendbar. Verwenden Sie hierfür .width().

5
Tushar Gupta

Ähnlich der Antwort von @ Snugugs, funktionierte für meinen Anwendungsfall jedoch besser:

CSS (Hinweis: Ich verwende LESS so, dass @tabletMin und @desktopMin in Haltepunktvariablen übersetzt werden, die an anderer Stelle festgelegt wurden: 

    #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... */
    }

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

Die Funktion getView () gibt dann die Zeichenfolge 'mobile', 'tablet' oder 'desktop' zurück, abhängig von der Breite der media-Abfragen see.

Dies kann erweitert werden, um mehr Ansichtsfensterbreiten anzupassen. Fügen Sie einfach weitere Regeln im CSS mit anderen Werten hinzu.

1
Gruffy

folgen Sie diesem Link

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

Die Antwort von @Snugug gibt eine wirklich gute Erklärung dafür, warum dies geschieht, und @TusharGupta hat auch eine gute Lösung, die die von Mediaquery erkannte Breite auf Javascript verweist. Die Lösung unten geht anders herum, indem JavaScript-erkannte Breite verwendet wird, um Layoutänderungen auszulösen.

Falls Sie Mediaqueries mit der Javascript-Pixelbreitenerkennung synchronisieren müssen, können Sie das Problem mithilfe von CSS-Layoutänderungen auf der Grundlage von Klassen auslösen, die Sie mit Javascript hinzufügen.

Schreiben Sie also anstelle von Medienanfragen diese Deklarationen, die unter einer Klasse verschachtelt sind, beispielsweise:

html.myMobileBP { ... }

Und füge diese Klasse in deinem Javascript/jQuery hinzu:

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

Um dies noch weiter voranzutreiben, sollten Sie den Mangel an Javascript-Unterstützung in Betracht ziehen. Definieren Sie Medienabfragen, die außerdem in eine html.no-js-Klasse eingeschlossen sind. Entfernen Sie dann mit Javascript die .no-js-Klasse und wenden Sie die obige Lösung an, um Haltepunkte über Javascript-Klassen hinzuzufügen.

0
kontur