Skip to content

Kõik WordPressist, veebiarendusest — ja mitte ainult

📱 JavaScript: kuidas tuvastada ekraani laiust, @media päringu vaste koodis

📱 JavaScript: kuidas tuvastada ekraani laiust, @media päringu vaste koodis

Mõnikord on küljendus juba valmis, CSS-i meediapäringud on paigas, kuid sul on vaja tuvastada käitumist kindlal murdepunktil otse JavaScriptis. Hüpikakna kuvamine ainult mobiilseadmetes, ruudustiku ümberpaigutamine akna suuruse muutmisel, animatsiooni käivitamine, kui ekraan on „kitsas": kõik see eeldab, et skript mõistab praegust akna laiust.

Probleem on selles, et arendajad valivad sageli keerulisema tee: nad loevad window.innerWidth väärtust, lisavad resize sündmusele throttlingu, võrdlevad maagiliste numbritega ja jõuavad hapra koodini, mis elab CSS-i murdepunktidest eraldi. Ometi on brauseritel juba ammu olemas meetod, mis töötab samade meediaavaldistega nagu CSS.

Allpool on kolm praktilist lähenemist: alates kaasaegsest matchMedia-st (töötab nagu @media CSS-is) kuni jQuery variandini pärandprojektide jaoks. Koos töötavate näidetega, mida saad kohe kopeerida ja käivitada.

💡 Kiirülevaade:

  • matchMedia: natiivne meetod, mis võtab vastu CSS-i meediaavaldise ja teatab, kas see hetkel kehtib; ideaalne JS-i loogika sünkroonimiseks CSS-i murdepunktidega
  • resize + matchMedia: kombinatsioon, mis reageerib brauseriakna muutustele; skript saab murdepunkti ületamisest koheselt teada, ilma innerWidth väärtust perioodiliselt küsitlemata
  • jQuery variant: projektidele, kus jQuery on juba lehel olemas; sama resize, kuid ilma natiivse matchMedia-ta; võrdlus tehakse $(window).width() abil

MatchMedia: ainus tõeallikas ekraani laiuse kohta

window.innerWidth peamine puudus on see, et see ei tea midagi sinu CSS-i murdepunktidest. Määrad meediapäringutes 768px, seejärel kirjutad JS-is if (window.innerWidth < 768) ja lõpuks lõhub ümardamine või kerimisriba sünkroonimise.

window.matchMedia() lahendab selle probleemi radikaalselt: see võtab vastu sama meediaavaldise sõne nagu CSS-i @media reegel. Tulemuseks on MediaQueryList objekt, millel on .matches omadus (true / false). Ei mingeid maagilisi numbreid, ei mingit lahknevust küljendusega.

Põhisüntaks:

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}

Sama matchMedia("(min-width: 768px)") kutset hindab brauser samade reeglite alusel nagu @media (min-width: 768px) CSS-is. Kui külgriba on sellel murdepunktil CSS-is peidetud, siis JS „näeb" sama asja ja võib näiteks mobiilimenüü peita.

Lisaks .matches omadusele pakub MediaQueryList objekt .media omadust (algne päringusõne) ja addEventListener meetodit muutustele tellimiseks. See tähendab, et kui oled murdepunkti konfiguratsioonis deklareerinud, saad seda kasutada nii CSS-is kui JS-is ilma maagilisi numbreid dubleerimata: lihtsalt eralda 768 konstandiks ja kasuta seda mõlemas kohas.

Reageerimine akna suuruse muutmisele ilma throttlingu ja muude trikkideta

„Kohese" oleku kontrollimine on vaid pool võitu. Tõeline maagia algab siis, kui skript saab murdepunkti ületamisest teada just sel hetkel, kui aken muutub.

MediaQueryList-l on change sündmus, mis käivitub täpselt siis, kui .matches väärtus lülitub. Mitte igal resize pikslil, vaid ainult piiri ületamisel:

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});

Tagasiühilduvuseks vanemate brauseritega saad sama tulemuse saavutada üldise resize töötleja kaudu window-l:

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});
Brauseri konsool kuvab akna suuruse muutmisel ekraani laiuse teateid

Erinevus on lihtne: change MediaQueryList-l on sündmuspõhine lähenemine (ei mingeid lisakutseid resize ajal vahemiku sees), samas kui resize window-l on varuvariant, mis on igale arendajale tuttav.

Laiuse vahemik: kahe murdepunkti vahel

Levinud ülesanne on „769px kuni 1024px." matchMedia töötab ka siin nagu CSS: kombineeri min-width ja max-width ühes avaldises:

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});

Või ühe avaldisena (brauserid mõistavad liitmeediapäringuid täpselt nagu CSS-is):

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});

Millist varianti valida? change MediaQueryList-l, kui on vaja tabada täpset piiriületuse hetke (näiteks DOM-puu ümberstruktureerimiseks). resize + matchMedia, kui loogika on lihtsam ja on vaja lihtsalt „kohe kontrollida", ilma tulevastele üleminekutele tellimata.

JQuery variant: kui matchMedia pole saadaval

Kui projekt kasutab jQueryt ja polüfillid ei tule kõne alla, saavutatakse sama tulemus $(window).width() võrdlemisega läviväärtusega:

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});

See kood käivitub üks kord lehe laadimisel. Akna suuruse muutumise jälgimiseks mähi kontroll töötlejasse:

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});

Kuid pea meeles: $(window).width() ja matchMedia võivad kerimisriba tõttu mõne piksli võrra erineda. matchMedia töötab vaateaknaga, täpselt nagu CSS-i reeglid. Seetõttu soovitan kogu uue koodi puhul natiivset meetodit.

MatchMedia vs innerWidth: lühike võrdlus

Kriteerium

matchMedia

innerWidth

Sünkroonimine CSS-iga

Täielik (samad avaldised)

Käsitsi numbrite kohandamine

Sündmus murdepunkti ületamisel

change MediaQueryList-l

Ainult resize window-l

Kerimisriba käsitlemine

Sama mis CSS-is (vaateaken)

Brauserist sõltuv

Tume teema / prefers-reduced-motion tuvastamine

Jah (mis tahes meediaavaldis)

Ei

⁉️🤔 Korduma kippuvad küsimused

Kumb on parem: matchMedia või window.innerWidth?

matchMedia on alati parem, kui loogika on seotud CSS-i murdepunktidega. See kasutab samu reegleid nagu @media, välistades ühe-kahepikslised lahknevused kerimisriba või suumi tõttu. innerWidth on asjakohane ainult siis, kui vajad täpset numbrilist väärtust (näiteks arvutamaks, mitu elementi mahub), mitte fakti „ekraan laiem kui N pikslit."

Kas matchMedia töötab vanemates brauserites?

Jah, tugi on laialdane: kõik kaasaegsed brauserid, sealhulgas mobiilseadmetes, ja Internet Explorer 10+. IE9 ja vanemad jäävad kõrvale; nende jaoks pead kasutama window.innerWidth või selle artikli jQuery varianti. Praktikas läheneb IE9 osakaal 2026. aastal nullile.

Kas matchMedia suudab kontrollida enamat kui ainult laiust?

Jah, meetod võtab vastu mis tahes kehtiva CSS-i meediaavaldise. Näiteks: (orientation: portrait) seadme orientatsiooni jaoks; (prefers-color-scheme: dark) tumeda teema jaoks opsüsteemis; (prefers-reduced-motion: reduce) animatsioonide keelamise soovi jaoks. See töötab täpselt nagu CSS-is: window.matchMedia("(prefers-color-scheme: dark)").matches tagastab true, kui kasutajal on tume teema lubatud.

Kas change töötleja tuleb lehelt lahkudes eemaldada?

Kaasaegses koodis ei ole vaja. Brauser vabastab mälu lehe sulgemisel automaatselt. Üheleherakendustes (React, Vue), kus komponent monteeritakse ja eemaldatakse ilma lehte uuesti laadimata, pead salvestama viite töötlejale ja eemaldama selle removeEventListener abil componentWillUnmount / onUnmounted sees; vastasel juhul tekivad mälulekked ja korduvad käivitumised „surnud" komponentidel.

Miks näitavad $(window).width() ja matchMedia mõnikord erinevat laiust?

Sest need mõõdavad erinevaid asju. matchMedia töötab vaateakna laiusega (CSS-i vaateala), sama, mida kasutavad meediapäringud. $(window).width() / window.innerWidth sisaldab vertikaalse kerimisriba laiust, kui see on olemas. Erinevus on tavaliselt 15-17 px, täpselt kerimisriba laius. Siit ka reegel: kui seod loogikat CSS-i murdepunktidega, kasuta matchMedia-t; kui vajad akna „tõelist" laiust pikslites, kasuta innerWidth-i.

Mida siis kasutada: lõplik järeldus

Uue koodi puhul on vastus selge: window.matchMedia(). See elab samas leppes nagu sinu CSS, ei nõua käsitsi numbrite kohandamist iga murdepunkti jaoks ning pakub sündmusmudelit „see lülitus, nüüd tead", mitte pidevat laiuse küsitlemist.

Tüüpiline stsenaarium, kus erinevus on koheselt märgatav: ehitad tootekaarti, mis kuvab lauaarvutis neljast pildist koosnevat galeriid, kuid mobiilis ühte pühitavat pilti. CSS-is on sul @media (max-width: 768px), mis muudab küljendust. JS-is kirjutad if (window.innerWidth <= 768) asemel matchMedia("(max-width: 768px)") ja brauser garanteerib, et JS-i tingimus käivitub täpselt siis, kui küljendus muutub. Ei mingeid „peaaegu töötas" olukordi, ei mingeid vigu 767px juures kerimisriba tõttu.

Jäta jQuery lähenemine $(window).width()-ga vanade projektide hooldamiseks: see töötab, kuid sunnib murdepunkte koodis dubleerima ja lahkneb vaikimisi CSS-ist kerimisriba laiuse võrra.

Ja kui soovid kõike ülalkirjeldatut tegevuses näha, siis siin on 10-minutiline õpetus, kus matchMedia on lahti seletatud alates väljakutsumisest kuni sündmusmudelini:

Proovi asendada lähim if (innerWidth < 768) väärtusega matchMedia("(min-width: 768px)") ja tunned koheselt, kui palju puhtamaks kood muutub.