Undvik onödiga resurser för mobila enheter, ännu en metod

Marcus Olsson,

Tid är fienden, i alla fall på webben. Och mer data är lika med mer tid – och fler sura användare.

Bygger man responsiva webbplatser så vill man skona användaren från att ladda in onödiga resurser som ändå inte kommer att visas. För uppnå detta krävs två steg; dels så måste man upptäcka om det är en mobil enhet som används på din webbplats, och sedan så måste man välja om man ska ladda in det "tunga" innehållet eller inte (oftast är det vissa bilder man vill hoppa över).

Det finns förmodligen hundratals metoder för att upptäcka de mobila enheterna, ett vanligt sätt att kolla av vilken user-agent som används, här ett exempel med Javascript:

1if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
2 // some code..
3}
1if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
2 // some code..
3}

Exempel saxat från stackoverflow.

Men detta är långt ifrån optimalt; kommer det t.ex. ut en ny webbläsare på marknaden, ska man då behöva gå tillbaka till gammal kod? Android – är det en smartphone eller "surfplatta"? iPad – är den i "landscape" eller "portrait"? Det kan bli en hel del Javascript för att se över alla möjliga fall.

Header-bild på marcusolsson.me Exempel på en header-bild här på marcusolsson.me

På den här webbplatsen då använder jag relativt tunga header-bilder som jag inte vill visa på mindre enheter, t.ex. iPhones. Men vill ha kvar dem på surfplattor, t.ex. iPads. Eftersom att jag utvecklade sidan för att vara responsiv, så har jag redan inlagda brytpunkter som jag kan använda tillsammans med Javascript för att upptäcka vad det är för typ av enhet (eller i alla fall skärmstorlek) som är inne på sidan. Men även här finns en rad olika alternativ; man skulle kunna göra något enkelt som det här:

1<div class="header"></div>
1<div class="header"></div>
 
1.header {
2 background: #333 no-repeat center center;
3}
4
5@media only screen and (max-device-width: 568px) and (min-device-width: 320px) {
6 .header {
7 display: none;
8 }
9}
1.header {
2 background: #333 no-repeat center center;
3}
4
5@media only screen and (max-device-width: 568px) and (min-device-width: 320px) {
6 .header {
7 display: none;
8 }
9}
 
1var $header = $('.header');
2if($header.is(':visible') === true) {
3 $header.css('background-image', 'url(/img/header.jpg)';
4}
1var $header = $('.header');
2if($header.is(':visible') === true) {
3 $header.css('background-image', 'url(/img/header.jpg)';
4}

Här så laddar vi alltså in bilder efter att vi har kollat av värdet på header-elementet med Javascript (i det här fallet via jQuery).

Man kan också gå ett steg längre, som jag bland annat har gjort här på marcusolsson.me; förmodligen så använder man inte bara en enda brytpunkt, utan flera. iPads, iPhones, flera storlekar på skärmar m.m. Kanske finns det flera olika bilder som laddas in (eller inte) beroende på enhet eller upplösning? Då kan vi inte längre hålla oss till ett enda element för att kolla emot, is(':visible') är binärt (eller i alla fall boolean) – antingen är det true eller false.

För att komma runt det här, och slippa skapa en rad pseudo-element att kolla emot så gjorde jag följande:

1<div class="js-query-tester"></div>
1<div class="js-query-tester"></div>
 
1.js-query-tester {
2 top: 0px;
3}
4
5@media only screen and (max-device-width: 568px) and (min-device-width: 320px) {
6 .js-query-tester {
7 top: 1px;
8 }
9}
10
11@media only screen and (max-width: 800px) {
12 // För de med liten skärm
13 .js-query-tester {
14 top: 2px;
15 }
16}
1.js-query-tester {
2 top: 0px;
3}
4
5@media only screen and (max-device-width: 568px) and (min-device-width: 320px) {
6 .js-query-tester {
7 top: 1px;
8 }
9}
10
11@media only screen and (max-width: 800px) {
12 // För de med liten skärm
13 .js-query-tester {
14 top: 2px;
15 }
16}

Därefter kan man då utläsa top-attributet från .query-tester och handla där utifrån:

1// Kanske inte optimalt, men fungerar:
2var test = $('.js-query-tester').css('top').replace('px', '');
3if(test == 0) {
4 // "Standard"
5} else if(test == 1) {
6 // iPhones
7} else if(test == 2) {
8 // Mindre skärmar
9}
1// Kanske inte optimalt, men fungerar:
2var test = $('.js-query-tester').css('top').replace('px', '');
3if(test == 0) {
4 // "Standard"
5} else if(test == 1) {
6 // iPhones
7} else if(test == 2) {
8 // Mindre skärmar
9}

Den här metoden ger en ett relativt kompakt sätt att kolla av vilken enhet användaren använder sig av för att bland annat undvika att ladda in onödiga bilder, visa anpassade menyer och liknande (sitter du på en dator, prova att minska och förstora webbläsaren). Helt osemantiska pseudo-element är kanske inte allas favorit, men här kommer man undan med ett enda i alla fall.

Vad tror du om den här metoden? För- och nackdelar? Säg gärna vad du tycker på Twitter.

Uppdaterad 1 nov 2013: Emil Stenström (@EmilStenstrom) pekade mig till den här artikeln där Jeremy Keith provar en rad olika metoder även han.

Han får tipset om att man kan använda CSS-selektorn :after tillsammans med attributet content för att sätta olika värden som går att läsa av med Javascript. Se den här gist:en av Emil Björklund (@ThatEmil) för exempel.

Ett lite snyggare och "renare" sätt måste jag säga.