Skip to content

Kaikki WordPressistä, web-kehityksestä — ja paljon muuta

📱 JavaScript: kuinka tunnistaa näytön leveys, @media-kyselyn vastine koodissa

📱 JavaScript: kuinka tunnistaa näytön leveys, @media-kyselyn vastine koodissa

Joskus asettelu on jo valmis, CSS-mediaqueryt ovat paikallaan, mutta sinun täytyy havaita toimintaa tietyssä taitekohdassa suoraan JavaScriptissä. Ponnahdusikkunan näyttäminen vain mobiililaitteilla, ruudukon uudelleenjärjestely ikkunan kokoa muutettaessa, animaation käynnistäminen näytön ollessa "kapea": kaikki tämä edellyttää, että skripti ymmärtää nykyisen ikkunan leveyden.

Ongelmana on, että kehittäjät valitsevat usein vaikean reitin: he lukevat window.innerWidth-arvon, lisäävät kuristuksen resize-tapahtumaan, vertailevat taikalukuja vasten ja päätyvät hauraaseen koodiin, joka elää erillään CSS-taitekohdista. Selainten käytössä on kuitenkin ollut pitkään menetelmä, joka toimii samoilla medialausekkeilla kuin CSS.

Alla on kolme käytännöllistä lähestymistapaa: modernista matchMedia-metodista (toimii kuten @media CSS:ssä) jQuery-varianttiin vanhoja projekteja varten. Mukana on eläviä esimerkkejä, jotka voit kopioida ja ajaa heti.

💡 Pikakatsaus:

  • matchMedia: natiivi metodi, joka ottaa vastaan CSS-medialausekkeen ja kertoo, täsmääkö se tällä hetkellä; ihanteellinen JS-logiikan synkronointiin CSS-taitekohtien kanssa
  • resize + matchMedia: yhdistelmä, joka reagoi selainikkunan muutoksiin; skripti saa tiedon taitekohdan ylityksestä välittömästi ilman innerWidth-arvon jatkuvaa pollausta
  • jQuery-variantti: projekteihin, joissa jQuery on jo sivulla; sama resize, mutta ilman natiivia matchMedia-metodia; vertailu tehdään $(window).width()-metodilla

MatchMedia: ainoa totuus näytön leveydestä

window.innerWidth-ominaisuuden suurin haittapuoli on, ettei se tiedä mitään CSS-taitekohdistasi. Asetat 768px mediaqueryihin, kirjoitat sitten if (window.innerWidth < 768) JavaScriptissä, ja lopulta pyöristys tai vierityspalkki rikkoo synkronoinnin.

window.matchMedia() ratkaisee tämän ongelman radikaalisti: se hyväksyy saman medialausekkeen merkkijonona kuin CSS:n @media-sääntö. Tuloksena on MediaQueryList-olio, jolla on .matches-ominaisuus (true / false). Ei taikalukuja, ei epäsuhtaa asettelun kanssa.

Perussyntaksi:

1const mq = window.matchMedia("(min-width: 768px)");
2
3if (mq.matches) {
4 console.log("Tablet or wider — 768px+");
5} else {
6 console.log("Mobile resolution — less than 768px");
7}

Selain arvioi saman matchMedia("(min-width: 768px)")-kutsun käyttäen samoja sääntöjä kuin @media (min-width: 768px) CSS:ssä. Jos sivupalkki piilotetaan tässä taitekohdassa CSS:ssä, JS "näkee" saman asian ja voi esimerkiksi piilottaa mobiilivalikon.

.matches-ominaisuuden lisäksi MediaQueryList-olio tarjoaa .media-ominaisuuden (alkuperäinen kyselymerkkijono) ja addEventListener-metodin muutosten tilaamiseen. Tämä tarkoittaa, että kun määrittelet taitekohdan konfiguraatiossa, voit käyttää sitä sekä CSS:ssä että JS:ssä monistamatta taikalukuja: poimi vain 768 vakioksi ja lisää se molempiin paikkoihin.

Reagointi ikkunan koon muutokseen ilman kuristusta ja kiertotapoja

"Tämän hetken" tarkistaminen on vasta puoli voittoa. Todellinen taika alkaa, kun skripti saa tiedon taitekohdan ylityksestä sillä hetkellä, kun ikkuna muuttuu.

MediaQueryList-oliolla on change-tapahtuma, joka laukeaa täsmälleen silloin, kun .matches-arvo vaihtuu. Ei jokaisella resize-pikselillä, vaan ainoastaan rajan ylittyessä:

1const mq = window.matchMedia("(min-width: 500px)");
2
3mq.addEventListener("change", function (e) {
4 if (e.matches) {
5 console.log("Screen expanded to 500px or more");
6 } else {
7 console.log("Screen narrowed to less than 500px");
8 }
9});

Taaksepäin yhteensopivuuden varmistamiseksi vanhempien selainten kanssa voit saavuttaa saman tuloksen yleisen resize-käsittelijän kautta window-oliolla:

1window.addEventListener("resize", function () {
2 if (window.matchMedia("(min-width: 500px)").matches) {
3 console.log("Screen width — at least 500px");
4 } else {
5 console.log("Less than 500px");
6 }
7});
Selaimen konsoli näyttää näytön leveysviestejä koon muuttamisen aikana

Ero on yksinkertainen: change MediaQueryList-oliolla on tapahtumapohjainen lähestymistapa (ei ylimääräisiä kutsuja resize-tapahtuman aikana alueen sisällä), kun taas resize window-oliolla on jokaiselle kehittäjälle tuttu varavaihtoehto.

Leveysalue: kahden taitekohdan välissä

Yleinen tehtävä on "769px - 1024px". matchMedia toimii tässäkin kuten CSS: yhdistä min-width ja max-width yhteen lausekkeeseen:

1window.addEventListener("resize", function () {
2 if (
3 window.matchMedia("(min-width: 769px)").matches &&
4 window.matchMedia("(max-width: 1024px)").matches
5 ) {
6 console.log("Tablet range: 769px – 1024px");
7 } else {
8 console.log("Outside the tablet range");
9 }
10});

Tai yhtenä lausekkeena (selaimet ymmärtävät yhdistettyjä mediaqueryitä aivan kuten CSS:ssä):

1const tablet = window.matchMedia("(min-width: 769px) and (max-width: 1024px)");
2
3tablet.addEventListener("change", function (e) {
4 console.log(e.matches ? "Entered tablet range" : "Left tablet range");
5});

Kumpi variantti valita? change MediaQueryList-oliolla, kun haluat napata tarkan hetken rajan ylityksestä (esimerkiksi DOM-puun uudelleenjärjestelyä varten). resize + matchMedia, kun logiikka on yksinkertaisempaa ja sinun tarvitsee vain "tarkistaa nyt" tilaamatta tulevia siirtymiä.

JQuery-variantti: kun matchMedia ei ole käytettävissä

Jos projekti käyttää jQueryä eivätkä polyfillit ole vaihtoehto, sama tulos saavutetaan vertaamalla $(window).width()-arvoa kynnysarvoon:

1jQuery(document).ready(function ($) {
2 if ($(window).width() > 1000) {
3 console.log("Screen width greater than 1000px");
4 } else {
5 console.log("Screen width 1000px or less");
6 }
7});

Tämä koodi ajetaan kerran sivun latauksen yhteydessä. Seurataksesi ikkunan koon muutosta kääri tarkistus käsittelijään:

1jQuery(document).ready(function ($) {
2 function checkWidth() {
3 if ($(window).width() > 1000) {
4 console.log("Width > 1000px");
5 } else {
6 console.log("Width ≤ 1000px");
7 }
8 }
9
10 checkWidth(); // initial run
11 $(window).on("resize", checkWidth);
12});

Mutta muista: $(window).width() ja matchMedia voivat erota muutamalla pikselillä vierityspalkin vuoksi. matchMedia toimii viewportin kanssa, aivan kuten CSS-säännöt. Siksi suosittelen natiivia metodia kaikkeen uuteen koodiin.

MatchMedia vs innerWidth: lyhyt vertailu

Kriteeri

matchMedia

innerWidth

Synkronointi CSS:n kanssa

Täysi (samat lausekkeet)

Manuaalinen numeroiden säätö

Tapahtuma taitekohdan ylityksessä

change MediaQueryList-oliolla

Vain resize window-oliolla

Vierityspalkin käsittely

Sama kuin CSS (viewport)

Selainriippuvainen

Tumma teema / prefers-reduced-motion-tunnistus

Kyllä (mikä tahansa medialauseke)

Ei

⁉️🤔 Usein kysytyt kysymykset

Kumpi on parempi: matchMedia vai window.innerWidth?

matchMedia on aina parempi, kun logiikka on sidottu CSS-taitekohtiin. Se käyttää samoja sääntöjä kuin @media, eliminoiden yhden tai kahden pikselin erot vierityspalkin tai zoomin vuoksi. innerWidth on sopiva vain, kun tarvitset tarkan numeerisen arvon (esimerkiksi laskeaksesi, montako elementtiä mahtuu), et tietoa "näyttö leveämpi kuin N pikseliä".

Toimiiko matchMedia vanhemmissa selaimissa?

Kyllä, tuki on laaja: kaikki modernit selaimet mukaan lukien mobiili, sekä Internet Explorer 10+. IE9 ja sitä vanhemmat jäävät jälkeen; niille joudut käyttämään window.innerWidth-arvoa tai tämän artikkelin jQuery-varianttia. Käytännössä IE9:n osuus vuonna 2026 lähestyy nollaa.

Voiko matchMedia tarkistaa muutakin kuin leveyttä?

Kyllä, metodi hyväksyy minkä tahansa kelvollisen CSS-medialausekkeen. Esimerkiksi: (orientation: portrait) laitteen orientaatiolle; (prefers-color-scheme: dark) käyttöjärjestelmän tummalle teemalle; (prefers-reduced-motion: reduce) animaatioiden poistopyynnölle. Se toimii aivan kuten CSS:ssä: window.matchMedia("(prefers-color-scheme: dark)").matches palauttaa true, jos käyttäjällä on tumma teema käytössä.

Täytyykö change-käsittelijä poistaa sivulta poistuttaessa?

Modernissa koodissa ei. Selain tyhjentää muistin automaattisesti sivun purkamisen yhteydessä. SPA-sovelluksissa (React, Vue), joissa komponentti liitetään ja irrotetaan ilman sivun uudelleenlatausta, sinun on tallennettava viite käsittelijään ja poistettava se removeEventListener-metodilla componentWillUnmount / onUnmounted-kohdassa; muuten saat muistivuotoja ja toistuvia laukaisuja "kuolleissa" komponenteissa.

Miksi $(window).width() ja matchMedia näyttävät joskus eri leveyksiä?

Koska ne mittaavat eri asioita. matchMedia toimii viewportin leveydellä (CSS-näyttöalue), samalla jota mediaqueryt käyttävät. $(window).width() / window.innerWidth sisältää pystysuoran vierityspalkin leveyden, jos sellainen on näkyvissä. Ero on yleensä 15-17 px, juuri vierityspalkin leveys. Tästä johtuu sääntö: jos sitot logiikan CSS-taitekohtiin, käytä matchMedia-metodia; jos tarvitset "todellisen" ikkunan leveyden pikseleinä, käytä innerWidth-arvoa.

Mitä siis käyttää: lopullinen johtopäätös

Uuteen koodiin vastaus on selvä: window.matchMedia(). Se elää samassa sopimuksessa kuin CSS:si, ei vaadi manuaalista numeroiden säätöä jokaiselle taitekohdalle ja tarjoaa tapahtumamallin "se vaihtui, tiedät sen" jatkuvan leveyden pollauksen sijaan.

Tyypillinen skenaario, jossa ero näkyy välittömästi: rakennat tuotekorttia, joka näyttää neljän kuvan gallerian työpöydällä, mutta pyyhkäistävän yksittäisen kuvan mobiilissa. CSS:ssä sinulla on @media (max-width: 768px), joka muuttaa asettelua. JS:ssä kirjoitat if (window.innerWidth <= 768) sijaan matchMedia("(max-width: 768px)"), ja selain takaa, että JS-ehto laukeaa täsmälleen silloin, kun asettelu muuttuu. Ei "melkein toiminut" -tilanteita, ei bugeja 767px kohdalla vierityspalkin takia.

Jätä jQuery-lähestymistapa $(window).width()-metodilla vanhojen projektien ylläpitoon: se toimii, mutta pakottaa monistamaan taitekohdat koodissa ja poikkeaa hiljaisesti CSS:stä vierityspalkin leveyden verran.

Ja jos haluat nähdä kaiken yllä kuvatun toiminnassa, tässä on 10 minuutin tutoriaali, jossa matchMedia selitetään kutsusta tapahtumamalliin:

Kokeile korvata lähin if (innerWidth < 768) lausekkeella matchMedia("(min-width: 768px)"), niin tunnet välittömästi, kuinka paljon puhtaammaksi koodi muuttuu.