$ (okno) .width () nie to samo co zapytanie multimedialne

186

Używam Twitter Bootstrap w projekcie. Oprócz domyślnych stylów ładowania początkowego dodałem także własne

//My styles
@media (max-width: 767px)
{
    //CSS here
}

Używam również jQuery do zmiany kolejności niektórych elementów na stronie, gdy szerokość rzutni jest mniejsza niż 767px.

$(document).load($(window).bind("resize", checkPosition));

function checkPosition()
{
    if($(window).width() < 767)
    {
        $("#body-container .main-content").remove().insertBefore($("#body-container .left-sidebar"));
    } else {
        $("#body-container .main-content").remove().insertAfter($("#body-container .left-sidebar"));
    }
}

Problem, który mam, polega na tym, że szerokość obliczona przez $(window).width()i szerokość obliczona przez CSS nie wydają się takie same. Kiedy $(window).width()zwraca 767, css oblicza szerokość rzutni jako 751, więc wydaje się, że jest 16px inna.

Czy ktoś wie, co to powoduje i jak mogę rozwiązać problem? Ludzie zasugerowali, że szerokość paska przewijania nie jest brana pod uwagę, a używanie $(window).innerWidth() < 751jest właściwą drogą. Jednak idealnie chcę znaleźć rozwiązanie, które oblicza szerokość paska przewijania i jest zgodne z moim zapytaniem o media (np. Gdy oba warunki sprawdzają się w stosunku do wartości 767). Ponieważ na pewno nie wszystkie przeglądarki będą miały szerokość paska przewijania 16 pikseli?

Bydło
źródło
1
Spróbuj czegoś, jeśli ($ ('html').
Width
@Vaibs_Cool Dzięki za sugestię, ale wciąż otrzymuję ten sam wynik
Pattle
Odpowiedz i tu [wprowadź opis linku tutaj] [1] [1]: stackoverflow.com/questions/11309859/…
Rantiev
Czy „document.documentElement.clientWidth” (zamiast „$ (window) .width ()”) działa tak, jak chcesz, aby działało? Edycja: Mój błąd, właśnie zobaczyłem odpowiedź Vaibs_Cool.
joshhunt

Odpowiedzi:

293

Jeśli nie musisz obsługiwać IE9, możesz po prostu użyć window.matchMedia()( dokumentacja MDN ).

function checkPosition() {
    if (window.matchMedia('(max-width: 767px)').matches) {
        //...
    } else {
        //...
    }
}

window.matchMediajest w pełni zgodny z zapytaniami o media CSS, a obsługa przeglądarki jest całkiem dobra: http://caniuse.com/#feat=matchmedia

AKTUALIZACJA:

Jeśli musisz obsługiwać więcej przeglądarek, możesz użyć metody mq Modernizra , obsługuje ona wszystkie przeglądarki, które rozumieją zapytania o media w CSS.

if (Modernizr.mq('(max-width: 767px)')) {
    //...
} else {
    //...
}
ausi
źródło
8
Jeśli możesz sobie pozwolić na korzystanie z biblioteki Modernizr, jest to najlepsza dostępna odpowiedź.
richsinn
1
To rozwiązanie jest lepsze: stackoverflow.com/a/19292035/1136132 (drugi kod). Tylko JS.
joseantgv
@joseantgv Moje rozwiązanie jest również tylko js. Czy możesz wyjaśnić, dlaczego rozwiązanie, z którym się połączyłeś, jest lepsze?
ausi
2
@edwardm Modernizr.mqzwraca tylko wartość logiczną, więc musisz wywołać ją samodzielnie w module onresizeobsługi zdarzeń.
ausi
2
@Bernig window.matchMediajest zalecanym sposobem, ponieważ nie wywoła reflow , w zależności od tego, jak często wywołać funkcję może to spowodować problemy z wydajnością. Jeśli nie chcesz bezpośrednio korzystać z Modernizra, możesz skopiować kod źródłowy z src / mq.js i src / injectElementWithStyles.js .
ausi
175

Sprawdź regułę CSS, która zmienia zapytanie dotyczące mediów. Gwarantuje to, że zawsze będzie działać.

http://www.fourfront.us/blog/jquery-window-width-and-media-queries

HTML:

<body>
    ...
    <div id="mobile-indicator"></div>
</body>

JavaScript:

function isMobileWidth() {
    return $('#mobile-indicator').is(':visible');
}

CSS:

#mobile-indicator {
    display: none;
}

@media (max-width: 767px) {
    #mobile-indicator {
        display: block;
    }
}
NateS
źródło
9
To bardziej eleganckie rozwiązanie niż hacki JS wspomniane w innych odpowiedziach.
René Roth
3
+1 to jest po prostu sprytne. Podoba mi się, jeśli chcesz zmienić punkty przerwania, wystarczy zmienić css, a nie javascript.
JoeMoe1984
To rozwiązanie działa dobrze i uważam, że jest bardziej eleganckie niż hack javascript zaproponowany w najczęściej głosowanej odpowiedzi.
Andrés Meza-Escallón
2
Jeśli używasz bootstrap, możesz to zrobić bez css, takiego jak<div id="xs-indicator" class="xs-visible">
Čamo,
33

Może to wynikać z scrollbarużycia innerWidthzamiast widthpodobnego

if($(window).innerWidth() <= 751) {
   $("#body-container .main-content").remove()
                                .insertBefore($("#body-container .left-sidebar"));
} else {
   $("#body-container .main-content").remove()
                                .insertAfter($("#body-container .left-sidebar"));
}

Możesz także dostać viewportpodobne

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

Powyższy kod Źródło

Rohan Kumar
źródło
Dzięki. To zadziała, ale czy mimo to mogę użyć jquery, aby uwzględnić szerokość paska przewijania. Po prostu myślę, że szerokość paska przewijania może się zmienić w różnych przeglądarkach?
Pattle 10.10.13
1
Tak, użyj innerWidth()lub możesz użyć go jak $('body').innerWidth();Zobacz to stackoverflow.com/questions/8339377/...
Rohan Kumar
3
Masz na myśli window.innerWidth, a nie obiekt jQuery $ (okno), $ (okno) .width () zwraca go niepoprawnie
EJanuszewski
1
window.innerWidthnie jest zgodny z zapytaniami o media CSS w Safari 8, jeśli paski preferencji są włączone w preferencjach systemowych OSX.
ausi
10

tak, wynika to z paska przewijania. Właściwe źródło odpowiedzi: wprowadź opis linku tutaj

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' ] };
}
Rantiev
źródło
4

Być może lepszą praktyką jest nieokreślanie szerokości dokumentu przez JS, ale jakaś zmiana wprowadzona przez zapytanie css @media. Dzięki tej metodzie możesz być pewien, że funkcja JQuery i zmiana css zachodzą w tym samym czasie.

css:

#isthin {
    display: inline-block;
    content: '';
    width: 1px;
    height: 1px;
    overflow: hidden;
}

@media only screen and (max-width: 990px) {
    #isthin {
        display: none;
    }
}

jquery:

$(window).ready(function(){
    isntMobile = $('#isthin').is(":visible");
    ...
});

$(window).resize(function(){
    isntMobile = $('#isthin').is(":visible");
    ...
});
gramgram
źródło
3

Ostatnio miałem ten sam problem - także z Bootstrap 3.

Ani $ .width () ani $ .innerWidth () nie będzie dla ciebie działać.

Najlepszym rozwiązaniem, jakie wymyśliłem - i jest specjalnie dostosowane do BS3 -
jest sprawdzenie szerokości .containerelementu.

Jak zapewne wiesz, jak .containerdziała ten element,
jest to jedyny element, który da ci bieżącą szerokość ustawioną przez reguły BS css.

To idzie mniej więcej tak

bsContainerWidth = $("body").find('.container').width()
if (bsContainerWidth <= 768)
    console.log("mobile");
else if (bsContainerWidth <= 950)
    console.log("small");
else if (bsContainerWidth <= 1170)
    console.log("medium");
else
    console.log("large");
użytkownik3041539
źródło
3

Posługiwać się

window.innerWidth

To rozwiązało mój problem

użytkownik4451021
źródło
3

Oto alternatywa dla wspomnianych wcześniej metod, które polegają na zmianie czegoś za pomocą CSS i odczytaniu go za pomocą Javascript. Ta metoda nie wymaga window.matchMediaani Modernizr. Nie potrzebuje również dodatkowego elementu HTML. Działa przy użyciu pseudoelementu HTML do „przechowywania” informacji o punkcie przerwania:

body:after {
  visibility: hidden;
  height: 0;
  font-size: 0;
}

@media (min-width: 20em) {
  body:after {
    content: "mobile";
  }
}

@media (min-width: 48em) {
  body:after {
    content: "tablet";
  }
}

@media (min-width: 64em) {
  body:after {
    content: "desktop";
  }
}

Użyłem bodyjako przykładu, możesz użyć do tego dowolnego elementu HTML. Możesz dodać dowolny ciąg lub liczbę do contentpseudoelementu. Nie musi być „mobilny” i tak dalej.

Teraz możemy odczytać te informacje ze Javascript w następujący sposób:

var breakpoint = window.getComputedStyle(document.querySelector('body'), ':after').getPropertyValue('content').replace(/"/g,'');

if (breakpoint === 'mobile') {
    doSomething();
}

W ten sposób zawsze jesteśmy pewni, że informacje o punkcie przerwania są poprawne, ponieważ pochodzą bezpośrednio z CSS i nie musimy mieć problemów z uzyskaniem odpowiedniej szerokości ekranu za pomocą Javascript.

dschenk
źródło
Nie musisz używać querySelector()lub getPropertyValue(). Możesz także szukać pojedynczego cudzysłowu w wyrażeniu regularnym (ponieważ nie jest spójne). To: window.getComputedStyle(document.body, ':after').content.replace(/"|'/g, ''). Aby uczynić to nieco tańszym, możesz owinąć go podkreślnikiem / lodash ._debounce()z ~ 100ms oczekiwaniem. Wreszcie, dołączenie atrybutów do <html> udostępnia dane wyjściowe dla innych rzeczy, takich jak klauzule wyłączania podpowiedzi szukające surowych flag / danych poza zmiennymi. Przykład: gist.github.com/dhaupin/f01cd87873092f4fe2fb8d802f9514b1
dhaupin
2

JavaScript zapewnia więcej niż jedną metodę sprawdzania szerokości rzutni. Jak zauważyłeś, innerWidth nie obejmuje szerokości paska narzędzi, a szerokości paska narzędzi będą się różnić w zależności od systemu. Istnieje również opcja outerWidth , która obejmie szerokość paska narzędzi. W Mozilla JavaScript API stanowi:

Window.outerWidth pobiera szerokość zewnętrznej strony okna przeglądarki. Reprezentuje szerokość całego okna przeglądarki, w tym paska bocznego (jeśli jest rozwinięty), chromowania okna i zmiany rozmiaru ramek / uchwytów.

Stan javascript jest taki, że nie można polegać na określonym znaczeniu outerWidth w każdej przeglądarce na każdej platformie.

outerWidthnie jest dobrze obsługiwany w starszych przeglądarkach mobilnych , ale cieszy się obsługą głównych przeglądarek stacjonarnych i większości nowszych przeglądarek smartfonów.

Jak wskazał ausi, matchMediabyłby to świetny wybór, ponieważ CSS jest lepiej ustandaryzowany (matchMedia używa JS do odczytu wartości rzutni wykrytych przez CSS). Ale nawet przy przyjętych standardach nadal istnieją opóźnione przeglądarki, które je ignorują (IE <10 w tym przypadku, co sprawia, że ​​matchMedia nie jest bardzo przydatna przynajmniej do śmierci XP).

W skrócie , jeśli rozwijają się tylko dla przeglądarek desktopowych i nowszych przeglądarek mobilnych, outerWidth powinno dać to, czego szukasz, z pewnych zastrzeżeń .

fzzylogic
źródło
1

Oto mniej zaangażowany sposób radzenia sobie z zapytaniami medialnymi. Obsługa wielu przeglądarek jest nieco ograniczona, ponieważ nie obsługuje mobilnego IE.

     if (window.matchMedia('(max-width: 694px)').matches)
    {
        //do desired changes
    }

Zobacz dokumentację Mozilla więcej szczegółów.

użytkownik2128205
źródło
1

Spróbuj tego

getData(){
    if(window.innerWidth <= 768) {
      alert('mobile view')
      return;
    }

   //else function will work

    let body= {
      "key" : 'keyValue'
    }
    this.dataService.getData(body).subscribe(
      (data: any) => {
        this.myData = data
      }
    )
}
DINESH Adhikari
źródło
0

Obejście, które zawsze działa i jest zsynchronizowane z zapytaniami o media CSS.

Dodaj div do ciała

<body>
    ...
    <div class='check-media'></div>
    ...
</body>

Dodaj styl i zmień je, wprowadzając określone zapytanie o media

.check-media{
    display:none;
    width:0;
}
@media screen and (max-width: 768px) {
    .check-media{
         width:768px;
    }
    ...
}

Następnie w JS sprawdź styl, który zmieniasz, wprowadzając zapytanie o media

if($('.check-media').width() == 768){
    console.log('You are in (max-width: 768px)');
}else{
    console.log('You are out of (max-width: 768px)');
}

Ogólnie rzecz biorąc, możesz sprawdzić dowolny styl, który jest zmieniany, wprowadzając określone zapytanie o media.

Arsen Pyuskyulyan
źródło
0

Najlepszym rozwiązaniem dla różnych przeglądarek jest użycie Modernizr.mq

link: https://modernizr.com/docs/#mq

Modernizr.mq pozwala programowo sprawdzić, czy bieżący stan okna przeglądarki odpowiada zapytaniu medialnemu.

var query = Modernizr.mq('(min-width: 900px)');
if (query) {
   // the browser window is larger than 900px
}

Uwaga Przeglądarka nie obsługuje zapytań o media (np. Stara IE) mq zawsze zwróci false.

Sanjib Debnath
źródło
0
if(window.matchMedia('(max-width: 768px)').matches)
    {
        $(".article-item").text(function(i, text) {

            if (text.length >= 150) {
                text = text.substring(0, 250);
                var lastIndex = text.lastIndexOf(" ");     
                text = text.substring(0, lastIndex) + '...'; 
            }

            $(this).text(text);

        });

    }
Adam Colton
źródło
0

Co robię ;

<body>
<script>
function getWidth(){
return Math.max(document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth);
}
var aWidth=getWidth();
</script>
...

i wywołać zmienną aWidth gdziekolwiek później.

Musisz umieścić getWidth () w treści dokumentu, aby upewnić się, że szerokość paska przewijania jest policzona, w przeciwnym razie szerokość paska przewijania odjęta od getWidth ().

burkul
źródło
-1

Implementacja suwaka slick i wyświetla różne liczby slajdów w bloku w zależności od rozdzielczości (jQuery)

   if(window.matchMedia('(max-width: 768px)').matches) {
      $('.view-id-hot_products .view-content').slick({
        infinite: true,
        slidesToShow: 3,
        slidesToScroll: 3,
        dots: true,
      });
    }

    if(window.matchMedia('(max-width: 1024px)').matches) {
      $('.view-id-hot_products .view-content').slick({
        infinite: true,
        slidesToShow: 4,
        slidesToScroll: 4,
        dots: true,
      });
    }
Vitalii
źródło
-2

Spróbuj tego

if (document.documentElement.clientWidth < 767) {
   // scripts
}

Aby uzyskać więcej informacji, kliknij tutaj

Vaibs_Cool
źródło
Dzięki, to wciąż ma ten sam wynik
Pattle