Jak reagovat na měnící se prostředí pomocí matchMedia

Přes Vánoce jsem byl u rodičů. Kromě celodenního jídla a hraní deskových her jsem se pokusil přečíst dvě knihy, které jsem si přinesl.

Jednou z knih byl ODPOVĚDNÝ RESPONZIVNÍ DESIGN od Scotta Jehla. Nedávno vyšla a je to opravdu dobré čtení. Ještě jsem ji nedočetl, ale baví mě a určitě je v TOP5 žebříčku mých oblíbených knih o responzivním webdesignu.

Ve světě responzivního webdesignu se neustále zabýváme mediálními dotazy, abychom našim návštěvníkům poskytli nejlepší možný zážitek v závislosti na jejich zařízení a prostředí. Obvykle to znamená, že weboví vývojáři se zabývají rozměry obrazovky v rámci mediálních dotazů a to je každým dnem bláznivější a užitečnější.

Pokud vás zajímá, co může přijít v budoucnu, specifikace pro Media Queries Level 4 je docela zajímavá – podívejte se na specifikaci pro úroveň osvětlení.;)

Mediální dotazy se většinou používají uvnitř souborů CSS k přizpůsobení stylu konkrétnímu zařízení, které návštěvník používá. To dává naprostý smysl, ale responzivní web design by neměl být jen o tom, „aby to vypadalo pěkně“.

Mělo by se také jednat pouze o používání a inicializaci potřebných komponent.

Ve své poslední práci jsem hodně spolupracoval s Foundation. A opravdu se mi to líbilo. Bloková mřížka je úžasná! A také implementace Off-canvas je podle mého názoru docela pěkná.

Jediná věc, která mi vždy vadila na implementacích ve slavných frameworkech jako Bootstrap a Foundation, je to, že skripty a moduly používané pro menší zařízení se spouštějí i na větších zařízeních a naopak.

Bez ohledu na to, zda jsou moduly a jejich funkce potřebné nebo ne, daný kód se provede a všechny obslužné rutiny událostí jsou stále svázány. Tyto obslužné rutiny událostí se v mnoha případech nespustí, protože dané prvky DOM spojené s funkcí jsou v několika kombinacích prostředí skryty pomocí CSS.

Když se podíváte na navigační řešení pro menší zařízení v obou projektech, uvidíte, že moduly JavaScriptu, které zaručují dobrou zkušenost na menších zařízeních, jsou inicializovány a obslužné rutiny událostí jsou bezdůvodně vázány – bez ohledu na to, zda jsou potřeba. Toto je jednoduché plýtvání CPU a není to vůbec potřeba.

Hodně se diskutuje o tom, co nabídnout zákazníkovi, pokud jde o detekci funkcí a vlastní sestavení, ale ne každý projekt má dostatek času a zdrojů na implementaci komplikovaných systémů sestavení.

Proto jsem začal dané moduly inicializovat pouze v případě potřeby. Vlastní sestavení Modernizru je obvykle součástí mých projektů, takže praktický Modernizr.mq Funkce se většinou používá k tomu, aby se neinicializovaly věci, které vůbec nejsou potřeba.

// only initialize the off-canvas 
// navigation for smaller devices
if ( Modernizr.mq( '(max-width: 50em)' ) ) {
  // initialize Foundation's offcanvas
  $document.foundation( 'offcanvas' );
}

Modernizr.mq - jak to funguje?

Pojďme se podívat, jak tato funkce funguje. Funkce je definována v mq.js a testMediaQuery.js.

// -> testMediaQuery.js
define(['injectElementWithStyles'], function( injectElementWithStyles ) {
  // adapted from matchMedia polyfill
  // by Scott Jehl and Paul Irish
  // gist.github.com/786768
  var testMediaQuery = (function () {
    var matchMedia = window.matchMedia || window.msMatchMedia;
    if ( matchMedia ) {
      return function ( mq ) {
        var mql = matchMedia(mq);
        return mql && mql.matches || false;
      };
    }

    return function ( mq ) {
      var bool = false;

      injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function( node ) {
        bool = (window.getComputedStyle ?
                window.getComputedStyle(node, null) :
                node.currentStyle)['position'] == 'absolute';
      });

      return bool;
    };
  })();

  return testMediaQuery;
});

Jak vidíme interně, Modernizr používá matchMedia funkce (pokud je k dispozici), která je definována ve specifikaci modulu zobrazení CSSOM. Pokud matchMedia není podporováno, poskytuje podložku pro dosažení stejné funkčnosti.

window.matchMedia - tak co?

matchMedia poskytuje funkci kontroly mediálních dotazů na straně JavaScriptu. A skvělé na tom je, že je podle caniuse.com skutečně poměrně široce podporován.

Modernizr.mq nám již poskytuje podporu při získávání informací o tom, zda daný mediální dotaz odpovídá či nikoliv. Jedna klíčová věc, na kterou je třeba si dávat pozor, je matchMedia nevrací booleovskou hodnotu, se kterou se má pracovat – místo toho vrací rozhraní MediaQueryList.

Informace, zda se mediální dotaz shoduje, je uložen ve vlastnosti matches .

( function( window, document ) {
  // get MediaQueryList Interface
  var mql = window.matchMedia( '(min-width:20em)' );
  // get a container to do something with it depending 
  // on matching media query
  var container = document.getElementById( 'container' );
  // create new paragraph object
  var paragraph = document.createElement( 'p' );
  
  // set innerHTML depending on matching media query
  paragraph.innerHTML = mql.matches ?
    'Yeah - matching!' : 
    'No - not matching!';
  
  // append element to container
  container.appendChild( paragraph );
} )( window, document );

Už to je skvělé, protože tímto způsobem můžeme snadno vyhodnotit, zda je potřeba konkrétní modul JavaScriptu inicializovat nebo ne. Ale co případ změny prostředí, jako je změna výřezu z režimu na výšku na režim na šířku? To je něco, s čím jsem se už nějakou dobu potýkal – a při čtení knihy Scotta Jehla jsem právě narazil na super elegantní řešení.

Už jsem četl spoustu článků o matchMedia , ale předtím jsem nevěděl, že poskytuje více než jen matches vlastnost.

Vráceno MediaQueryList Interface také poskytuje možnost připojit posluchače k ​​okamžiku, kdykoli se dotaz na média změní z odpovídající na neodpovídající nebo naopak.

( function( window, document ) { 
  // get MediaQueryList Interface
  var mql = window.matchMedia( '(min-width:20em)' );
  // get a container to do something with it depending 
  // on matching media query
  var container = document.getElementById( 'container' );
  // create new paragraph element
  var paragraph = document.createElement( 'p' );
  
  // set innerHTML depending on matching media query
  paragraph.innerHTML = mql.matches ?
    'Yeah - matching!' : 
    'No - not matching!';
  
  // append element to container
  container.appendChild( paragraph );
  
  // attach event listener to changed state
  // of the given media query
  mql.addListener( function( mql ) {
    // create new paragraph element
    var paragraph = document.createElement( 'p' );
    
    // set innerHTHML depending on matching media query
    paragraph.innerHTML = mql.matches ?
      'Yeah - changed to matching!' : 
      'No - changed to not matching!';
    
    // append element to container
    container.appendChild( paragraph );
  } );
} )( window, document );

To je přesně to, co jsem chvíli hledal, poskytuje snadný způsob, jak vylepšit rozhraní při změně prostředí za chodu a od začátku šetřit zdroje.

Pokud si s tím chcete hrát, vytvořil jsem pro vás pero, se kterým si můžete hrát.

A to je pro dnešek vše - doufám, že se vám krátké čtení líbilo. Jakékoli nápady a připomínky jsou více než vítány. :)


No