Schopnost detekovat stav zařízení v kteroukoli chvíli je důležitá z mnoha důvodů, a proto je důležité, aby CSS a JavaScript webové aplikace byly vzájemně synchronizované. Při práci na redesignu Mozilla Developer Networks jsem zjistil, že naše četné dotazy na média, i když byly užitečné, někdy zanechaly JavaScript v nevědomosti o stavu zařízení. Prohlíží si uživatel web na obrazovce počítače, tabletu nebo telefonu? Jednoduché z pohledu CSS, ale CSS přímo nekomunikuje s JavaScriptem. Vytvořil jsem systém založený na dotazech na média a z-index
který mi může sdělit, v jakém mediálním dotazu si uživatel stránky v kteroukoli chvíli prohlíží, takže mohu provádět úpravy dynamických funkcí, kdykoli budu chtít!
CSS
Prvním krokem je vytvoření mediálních dotazů důležitých pro vaši aplikaci a cíle. Pro příklad vytvoříme tři nové dotazy na média (nezahrnující výchozí „vše“), které budou obsahovat čtyři stavy:desktop (výchozí, nevyžaduje dotaz na média), „malá plocha“, tablet, a telefon. Pro každý z těchto stavů nastavíme jiný z-index
na prvku, který použijeme k detekci stavu. Prvek bude umístěn mimo obrazovku, takže nebude vidět; pamatujte, že jediným účelem je držet z-index
hodnotu, kterou můžeme načíst pomocí JavaScriptu:
/* default state */ .state-indicator { position: absolute; top: -999em; left: -999em; z-index: 1; } /* small desktop */ @media all and (max-width: 1200px) { .state-indicator { z-index: 2; } } /* tablet */ @media all and (max-width: 1024px) { .state-indicator { z-index: 3; } } /* mobile phone */ @media all and (max-width: 768px) { .state-indicator { z-index: 4; } }
Každé z těchto čísel z-indexu bude v našem kódu JavaScript indikovat, že jsme v dané době v dané velikosti zařízení. Nepokoušíme se odhalit, že uživatel dává dané zařízení, protože uživatel může mít jednoduše okno plochy v úzkém stavu, ale poskytuje nám informace o ploše obrazovky kvůli rozvržení naší webové aplikace.
JavaScript
Pravděpodobně budete chtít znát velikost obrazovky na DomContentLoaded
ale protože se na to můžete chtít kdykoli zeptat (protože uživatel může změnit velikost svého okna), budeme vyžadovat, aby byla funkce zavolána, aby získala stav, kdykoli bude požadován:
// Create the state-indicator element var indicator = document.createElement('div'); indicator.className = 'state-indicator'; document.body.appendChild(indicator); // Create a method which returns device state function getDeviceState() { return parseInt(window.getComputedStyle(indicator).getPropertyValue('z-index'), 10); }
Řekněme tedy, že chcete tento systém použít k určení, zda se má widget zpočátku zobrazit nebo skrýt:
if(getDeviceState() < 3) { // If desktop or small desktop // Show the widget.... }
Někdo by mohl namítnout, že spoléhání se na tyto číselné klávesy může být matoucí nebo obtížně udržovatelné, takže byste k tomu mohli použít objekt:
function getDeviceState() { var index = parseInt(window.getComputedStyle(indicator).getPropertyValue('z-index'), 10); var states = { 2: 'small-desktop', 3: 'tablet', 4: 'phone' }; return states[index] || 'desktop'; }
V tomto případě byste mohli vytvořit více podmínek pro angličtinu:
if(getDeviceState() == 'tablet') { // Do whatever }
Možná lepší možností je použití obsahu pseudoprvků s CSS a JavaScriptem:
.state-indicator { position: absolute; top: -999em; left: -999em; } .state-indicator:before { content: 'desktop'; } /* small desktop */ @media all and (max-width: 1200px) { .state-indicator:before { content: 'small-desktop'; } } /* tablet */ @media all and (max-width: 1024px) { .state-indicator:before { content: 'tablet'; } } /* mobile phone */ @media all and (max-width: 768px) { .state-indicator:before { content: 'mobile'; } }
Tento klíč lze poté získat pomocí tohoto JavaScriptu:
var state = window.getComputedStyle( document.querySelector('.state-indicator'), ':before' ).getPropertyValue('content')
Je také na vás, jak tento kód uspořádáte. Pokud máte jeden globální objekt, kam připínáte metody a vlastnosti (jako window.config
nebo window.app
globální nebo podobné), můžete na to připnout metodu. Dávám přednost použití modulů formátu AMD, ale každému svému. Můžete jej přidat jako plugin do jQuery
nebo kteroukoli knihovnu JavaScript, kterou používáte. Bez ohledu na to, jak implementujete, nyní máte spolehlivou a snadno použitelnou detekci stavu zařízení na straně klienta díky mediálním dotazům!
Další úsilí
Víme, že ke změně velikosti obrazovky dochází, ať už jde o ruční změnu velikosti okna na ploše nebo prostřednictvím změny orientace na mobilních zařízeních, takže můžeme chtít, aby nějaký typ systému událostí oznámil tyto změny, když k nim dojde. Je to tak jednoduché, jak byste očekávali:
var lastDeviceState = getDeviceState(); window.addEventListener('resize', debounce(function() { var state = getDeviceState(); if(state != lastDeviceState) { // Save the new state as current lastDeviceState = state; // Announce the state change, either by a custom DOM event or via JS pub/sub // Since I'm in love with pub/sub, I'll assume we have a pub/sub lib available publish('/device-state/change', [state]); } }, 20)); // Usage subscribe('/device-state/change', function(state) { if(state == 3) { // or "tablet", if you used the object } });
Všimněte si, že jsem použil funkci debouncing k omezení rychlosti, kterou resize
metoda je spuštěna - to je neuvěřitelně důležité pro výkon. Zda použijete události typu pub/sub nebo vlastní DOM, je na vás, ale jde o to, že vytvoření posluchače změny stavu je snadné!
Miluji tento systém správy velikosti a stavu zařízení. Někteří budou poukazovat na matchMedia
jako možnost, ale problém s tím je potřeba mít dotazy na média jak v CSS, tak v JavaScriptu, a protože dotazy na média mohou být složité, zdá se to spíše jako noční můra údržby než pouhé použití z-index
kódy. Lidé by se mohli hádat, než by se dalo použít window.innerWidth
měření, ale to se jednoduše pokouší převést dotazy na média na podmínky JS a to je také noční můra. Na tom je také hezké, že můžete použít stejný typ systému pro jakýkoli typ znaku dotazu na média, jako je kontrola portrait
nebo landscape
orientace.
V každém případě to vyzkoušejte a dejte mi vědět, co si myslíte!