Page Visibility API: Kouká na mě vůbec někdo?

Možná znáte výrok: „Vesmír existuje, jen když se na něj někdo dívá“. Mottem dnes popisované novinky – Page Visibility API – by mohla být parafráze tohoto výroku, nějak takto: „Stránka pracuje, jen když si ji někdo prohlíží“. Jak to celé funguje a jaký to má praktický význam? Ukážeme si v článku.
Seriál: Webdesignérův průvodce po HTML5 (21 dílů)
- Webdesignérův průvodce po HTML5 – díl nultý 25. 5. 2010
- Webdesignérův průvodce po HTML5 – nová sémantika 1. 6. 2010
- Webdesignérův průvodce po HTML5 – nová sémantika II 8. 6. 2010
- Webdesignérův průvodce po HTML5 – pohyblivé obrázky 15. 6. 2010
- Webdesignérův průvodce po HTML5 – používáme pohyblivé obrázky 22. 6. 2010
- Webdesignérův průvodce po HTML5 – taháme data od návštěvníka 29. 6. 2010
- HTML5 Audio: rádio ve vašich stránkách 13. 7. 2010
- Webdesignérův průvodce po HTML5: Microdata 20. 7. 2010
- AppCache: webové aplikace i bez připojení 27. 7. 2010
- Webdesignérův průvodce po HTML5: WebStorage 3. 8. 2010
- Webdesignérův průvodce po HTML5: Multithreading s WebWorkers 10. 8. 2010
- Webdesignérův průvodce po HTML5: Databáze v prohlížečích 17. 8. 2010
- Webdesignérův průvodce po HTML5: Shrnutí a rozhrnutí 24. 8. 2010
- HTML5: ukládáme si data k elementům 6. 12. 2010
- Webdesignérův průvodce po HTML5: Táhni a srůstej 5. 1. 2011
- HTML5: První krůčky s FileSystem API 15. 2. 2011
- Mobilizujeme web v HTML5 4. 4. 2011
- Single Page Apps a řešení problémů s historií 1. 6. 2011
- Page Visibility API: Kouká na mě vůbec někdo? 10. 8. 2011
- Práce se soubory v prohlížeči, díl 1 15. 8. 2011
- Práce se soubory v prohlížeči, díl 2 5. 9. 2011
Nálepky:
Novinka, dostupná zatím v prohlížeči Chrome od verze 13 umožňuje obsloužit programem změny ve viditelnosti stránky. Page Visibility API umožňuje programátorovi zjistit, jestli je stránka právě viditelná nebo ne. K tomu umožňuje na změny viditelnosti reagovat.
Prohlížeče dnes už celkem běžně nabízejí prohlížení v panelech. Jednotlivé otevřené stránky, respektive skripty v nich spuštěné, běží nezávisle na sobě, a především běží nejen na stránce, na kterou se uživatel právě dívá v aktivním panelu, ale i na ostatních. Pokud máte v panelech otevřené stránky, které se pravidelně aktualizují, kde běží nějaké náročné skripty, bujné animace či se přehrává video, představuje to poměrně velkou zátěž, která navíc běží „do zdi“. Zcela zbytečně se zatěžuje procesor, a u mobilních zařízení bude jistě mít nemalý vliv na výdrž baterie.
Implementace v Chrome
Page Visibility API je, jak jsme si už říkali, implementován v Chrome od verze 13 a jeho implementace je „vendor-prefixed“, viz http://code.google.com/chrome/whitepapers/pagevisibility.html. Funkce si proto popíšeme v podobě, v jaké jsou dostupné v prohlížeči Chrome, tedy s prefixem „webkit“, a mějme, prosím, na paměti, že po jejich rozšíření přijde sjednocení na „neprefixové“ verzi – použijte tedy nějaký „shim“, kterým si tyto funkce zpřístupníte v „normovaném“ tvaru.
Page Visibility API přidává dva atributy objektu document
– atribut hidden
a atribut visibilityState
. V implementaci Chrome jsou dostupné jako document.webkitHidden
a document.webkitVisibilityState
.
webkitHidden
je boolovská hodnota, která je true v případě, že stránka není vidět – tedy v případech, kdy je prohlížeč minimalizován, kdy je počítač zamknutý, kdy je stránka v panelu, který je na pozadí, dokonce i v případě, kdy je prohlížeč minimalizován a zobrazuje se jen jeho náhled. Hodnotu „False“ bude mít tehdy, když bude stránka zobrazená na popředí.
Na místě je podotknout, že v ostatních prohlížečích bude hodnota „undefined“, která je vyhodnocena jako „false“. Před prací s tímto atributem je rozumné udělat kontrolu pomocí if (typeof document.webkitHidden === "undefined")
…
Předchozí atribut určuje, jestli stránku někdo může sledovat (jestli je viditelná), nebo zda je někde skrytá. Další atribut, document.webkitVisibilityState
vrací řetězec, který udává přesněji stav, v jakém se stránka nachází:
- hidden
- Stránka je skrytá, není vidět, nezobrazuje se atd.
- visible
- Stránka je viditelná
- prerender
- Stránka byla vykreslena do cache, ještě ale není zobrazená
- preview
- Stránka se zobrazuje pouze v systémovém náhledu (např. při najetí kurzorem myši na minimalizovaný prohlížeč v panelu / docku) – tuto hodnotu Chrome zatím neimplementuje
Hodnoty „prerender“ a „preview“ nemusí prohlížeče poskytovat. Preferovaný způsob rozhodování, zda je stránka vidět nebo není, je podle atributu hidden (webkitHidden).
Vidí mě někdo?
Informace o viditelnosti samy o sobě nejsou až tak užitečné. Proto Page Visibility API nabízí i novou událost – visibilitychange
(v implementaci Chrome jako „ webkitvisibilitychange
“). Jak už název napovídá, tato událost je vyvolána ve chvíli, kdy se změní stav viditelnosti. Událost můžeme skriptem odchytit a zareagovat na ni.
Co si s touto informací skript má počít? Můžete např. snížit frekvenci periodického dotazování serveru a načítání novinek – když je stránka s chatem na pozadí nebo minimalizovaná, jistě není zapotřebí ji obnovovat co deset sekund, delší interval postačí. V případě, že se přehrává na stránce video, můžete jej „zapauzovat“ – viz pěkné demo od Sama Duttona. Pusťte si jej (v Chrome 13+, samosebou) a sledujte, co se bude dít, když si přepnete do jiného panelu, když prohlížeč minimalizujete atd.
Pro zajímavost – zdrojový kód výše odkázaného příkladu:
var videoElement = document.getElementById("videoElement"); // if the page is hidden, pause the video // if the page is shown, play the video function handleVisibilityChange() { if (document.webkitHidden) { videoElement.pause(); } else { videoElement.play(); } } // warn if the browser doesn't support document.webkitHidden if (typeof document.webkitHidden === "undefined") { alert("This demo requires a browser such as Google Chrome 13 that supports the Page Visibility API."); } // avoid errors from browsers that don't support addEventListener if (typeof document.addEventListener !== "undefined") { // handle page visibility change // see https://developer.mozilla.org/en/API/PageVisibility/Page_Visibility_API document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false); // revert to existing favicon for site when the page is closed // otherwise the favicon will remain as paused.png window.addEventListener("unload", function(){ favicon.change('/favicon.ico'); }, false); // when the video pauses, set the favicon videoElement.addEventListener("pause", function(){ favicon.change('images/paused.png'); }, false); // when the video plays, set the favicon videoElement.addEventListener("play", function(){ favicon.change('images/playing.png'); }, false); // set the document (tab) title from the current video time videoElement.addEventListener("timeupdate", function(){ document.title = Math.floor(videoElement.currentTime) + " second(s)"; }, false); }
Využití najde v budoucnu toto API v nejrůznějších webových aplikacích, kde pomůže „snížit odběr“ ve chvílích, kdy budou aplikace minimalizované či „vypnuté“. Určitě naleznete další případy, v nichž má smysl, aby skript ve chvílích, kdy stránku nikdo nesleduje, takříkajíc „ubral plyn“.
Odkazy ke čtení
- http://www.w3.org/TR/2011/WD-page-visibility-20110602/
- http://code.google.com/intl/cs/chrome/whitepapers/pagevisibility.html
- http://updates.html5rocks.com/2011/06/Page-Visibility-API-Have-I-got-your-attention
- http://functionsource.com/post/page-visibility-in-action
- https://github.com/evilmartians/visibility.js
Je někde uveden důvod, proč se příslušné API váže k objektu document, když dle mého prvního odhadu by vedlo na objekt window? (příznávám, jsem líný to hledat ;-))
http://ie.microsoft.com/testdrive/Performance/PageVisibility/Default.html
Tak snad uživatel není hlupák, ne?
Třeba jen u videa poslouchám zvuk a u toho pracuju. Nebo přeskakuju nepřetočitelné reklamy a mezitím si něco čtu. Nebo mám nějaký jiný důvod na stránku zrovna nekoukat.
Implementace tohoto nesmyslu povede jen k tomu, že se na onvisibilitychange navěsí reklamní kódy a jakmile přepnu na nějaký tab, tak všechny reklamy začnou skákat a volat „klikni sem“ :)
Někteří uživatelé bohužel hlupáci jsou. :-) A naopak někteří programátoři naštěstí nejsou hlupáci.
– Jsem si jistý že tvůrci přehrávačů budou s touto novinkou nakládat velmi citlivě.
– Ad druhá připomínka: ale vždyť to se v určité míře děje/může dít už dnes :-)
Velmi bych ocenil pokud by se automaticky deaktivovaly FLASHové bannery které zrovna nejsou viditelné (šetřilo by to výkon = baterku)
To ma FLASH od verzie 10:
http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-8000.html#WS4a4606c864353c0a-dcb49ee124a2e6df51-8000
Vzpomněl jsem si na ten typ útoků, kdy se stránka po nějaké prodlevě (kdy na ni uživatel už pravděpodobně nekouká) promění ve falešnou přihlašovací stránku třeba na Google.
Tohle API je docela dobrý pomocník, dá se to vůbec nějak ošetřit?
Záleží, co myslíte tím ošetřením. Jak je zřejmé, toto API pouze zjednodušuje tvorbu takovýchto stránek, ale i bez něj by si šlo poradit (mousemove, keydown, keyup, blur, focus, …).
Blokovat tato API by bylo zřejmě neefektivní. Uživatel se prostě musí podívat, kam to heslo zadává. Před časem jsem dával na bugzillu Mozilly návrh UI (včetně primitivních kreseb), které by tomu mohlo pomoci, ale nesetkal jsem se s odezvou. Každopádně, cesta IMHO vede tudy.
A může tomu pomoci do jisté míry i App Tab – pokud se o to pokusí neapptabová stránka, uživateli to bude divné, čímž se může okruh stránek s potenciálem útočit zmenšit.
Hodnota
undefined
se vyhodnocuje jakofalse
. Stejně jako několik dalších hodnot.Porovnání výsledku
typeof
s řetězcem"undefined"
je třeba jen u běžných proměnných (kde přímý přístup na rozdíl od vlastností objektu vyvolá chybu).Ano mas pravdu, ale v kontexte veci autor asi chcel povedat, ze ked dam test:
if (document.webkitHidden) {} else {}
napr. v Mozille, tak spusti false vetvu „if“, cize okno je podla tohto prikazu viditelne.
Spustí se větev
else
. A to je podle mě naprosto v pořádku – když se nemohu spolehnout na to, že je okno skryté, tak se chovám, jako kdyby bylo vidět.False opraveno, díky.
Ve starších prohlížečích se pro podobnou funkci dá použít kombinace událostí
window.onblur
awindow.onfocus
. Já to v Admineru používám pro zobrazení ikony, pokud probíhá práce. Někde jsem to také viděl použité pro zastavení časového odpočítávadla – to mi přijde chytré, i když protivné.Přesně to mě taky napadlo, když jsem to četl. Jde asi o nějaké vylepšení těchto dvou událostí, je možné, že některé prohlížeče blurem reagovat třeba u zamčení počítače, ale i tak je to IMHO schopno postihnout zajímavé procento případů. (BTW, pokud nechávám počítač zamknutý a neuspaný, tak mě ta nepatrná úspora energie nebo lepší responsivnes nevytrhne…)
Podle mě
onblur
nastane i v případě, kdy focus ztratí celé okno (ale je stále vidět). Kdežtovisibilitychange
jen v případě, kdy stránka skutečně zmizí (nejčastěji asi přepnutím na jiný panel, ale třeba i minimalizací okna).Ale to jen tak hádám, specifikaci jsem nečetl, ani jsem to nezkoušel – takhle bych to navrhl já.
Máš pravdu, je to tak. A aby toho nebolo málo, niektoré prehliadače ešte podporujú dvojicu udalostí DOMFocusIn/DOMFocusOut (ako focus/blur, len prebubláva), iné zasa focusin/focusout (tiež prebubláva, len nefunguje na window).
To je fakt. Já mám ve zvyku si okna maximalizovat a nejlépe jim ještě odstranit „dekoraci“ (ty rámečky, tutilek apod.), takže jsem si neuvědomil, že by neaktivní okno mohlo být viditelné.