Wykrywanie poziomu powiększenia w przeglądarce.
Gdybym za każdym razem, kiedy źródłem błędnego wyświetlania się strony jest to, że klient ma zwiększony poziom zbliżenia (Ctrl +) dostawał 5 zł miałbym już chyba na parę zgrzewek PEPSI ;-) Przy jednym z ostatnich mini projektów potrzebowałem informacji właśnie o tym - czy osoba odwiedzająca stronę ma ustawiony zoom na wartość inną niż 100%.
Pierwsze próby spełzły na niczym - myślałem, że przy zwiększeniu poziomu zoom-u wymiary obrazków pobierane dynamicznie przez JavaScript będą odzwierciedlał ich nowe proporcje - jednak tak nie jest, podają one wciąż rzeczywiste (ustalone na stronie za pomocą HTML/CSS) wymiary. Okazało się, że jedynym obiektem, który przy zmianie zoom-u potrafi zgłaszać swój nowy wymiar jest Flash. Nie przepadam za Flashem, ale Action Script mam jako-tako opanowany, więc całość zamknęła się w 8 linijkach AS3 i kilku JS. Zacznijmy od Action Script:
stage.scaleMode = "noScale"; #1
import flash.external.ExternalInterface;
import flash.utils.setInterval;
function sendSignal():void {
ExternalInterface.call("flashSize", stage.stageWidth); #5
}
setInterval(sendSignal, 100);
sendSignal();
Wyjaśnię tylko co "trudniejsze" linijki. Pierwsza (#1) informuje nasz obiekt, że w przypadku skalowania strony nie należy skalować zawartości flash - obiekty mają pozostać tej samej wielkości, zmieni się za to wymiar "płótna" (stage). Kolejna (#5) wywołuje poprzez ExternalInterface funkcję flashSize którą definiujemy w naszym HTML jako funkcję JavaScript, przyjmującą jako argument jeden parametr numeryczny - przekazujemy do niej szerokość obiektu flash.
Mając już gotowy Flash, osadzamy go na stronie nadając np. 100px szerokości - domyślnie, pierwsze wywołanie przekaże do funkcji flashSize() właśnie powyższe 100. Przy przeskalowaniu strony (Ctrl +) przekaże już nową wartość, np. 111px - dzięki temu możemy z proporcji (bądź też bez, jeżeli używamy bazowej szerokości 100px) obliczyć procentowy poziom powiększenia i odpowiednio zareagować (zmienić logikę strony, poinformować odwiedzającego).
Próbowałem wywołanie cykliczne (setInterval) zastąpić reakcją na zdarzenie Event.RESIZE, ale zdaje się, że nie jest one sygnalizowane w takiej konfiguracji stąd też setInterval - na szczęście sama funkcja jest na tyle lekka że nie powoduje praktycznie żadnego dodatkowego obciążenia dla CPU.