Jeden náš zákazník má web na objednávání vstupenek do divadel a nedávno potřeboval udělat affiliate program, tedy že někdo si na svůj web dá tlačítko “koupit vstupenky na tuhle show na tento den”, a pokud ho někdo použije, tak majitel toho webu dostane nějakou provizi.
Vzhledem k tomu, že ne každému affiliátovi vyhovuje obyčejné tlačítko koupit, ale rád by od nás použil i obrázek a případně kalendář s výběrem vhodného představení, nabízelo se prakticky jediné řešení – použít iframe.
No a teď přijde ta legrace. Hledal jsem snad všude, ale v HTML neexistuje rozumný způsob, jak iframu říct, aby si velikost určil podle toho, co je uvnitř.
Představoval bych si třeba nějaký atribut “autoheight” nebo něco takového, nebo ještě lépe naprosto přirozené chování, že když nezadáte výšku resp. šířku, zabere to tolik místa, kolik potřebuje anebo kolik má k dispozici (což dělá většina dalších elementů, například tabulka, obrázek, odstavec textu, prostě všechno). Až pokud si někdo výšku řekne, pak to teprve platí.
Jenže ne - pokud výšku a šířku nezadáte, dostane iframe výchozí rozměry 300x150. Jak na ta čísla přišli si dovedu představit naprosto jasně – to se takhle někdo ráno vzbudí, protáhne se a řekne “tak co třeba 300x150”, to je takový užitečný rozměr.
Prostředky samotného HTML to tedy nejde, přichází na řadu javascript. Nemám rád, když musím k layoutu a rozložení prvků na stránce používat skripty, když v jiných technologiích se podobné věci dají dělat deklarativně a snadno. No ale když to jinak nejde… Takže vnitřní stránka si zjistí, kolik pixelů potřebuje, a nějak to předá té vnější, která iframu nastaví požadovanou výšku (šířka je naštěstí vždy pevná, takže tu neřešíme).
Typicky člověk dospěje k něčemu jako window.parent.document.getElementById…
Potíž je, že v našem případě obsahuje iframe stránku, která pochází z jiné domény, než ta, jež tento iframe hostuje. A tu přichází další problém – v prohlížečích není mnoho obecně použitelných způsobů, jak si z jednoho iframu poslat do druhého zprávu. Když si zkusíte sáhnout na objekt document iframu z jiné domény, dostanete po čumáku chybovou hláškou “Access denied”. Nejde ani zavolat javascriptovou funkci, vnější stránka ani není schopná zjistit URL té vnitřní, takže si to nelze předat ani přes fragment v URL ani přes window.name, jak na některých fórech ještě najdete. Možná to ve starších prohlížečích funguje, ale v IE9 třeba ne.
Bezpečnostní důvody, které jsou za tím, celkem chápu, na druhou stranu proč tam už od začátku není nějaká možnost komunikace (se kterou by musely počítat obě strany)? Funkci postMessage přináší HTML5, ale tu ještě mnoho prohlížečů neumí, a je na tom opět vidět, že HTML 5 řeší problémy, které bylo potřeba řešit už před minimálně 5 lety – iframy jsou tu přeci jen dost dlouho.
Nakonec jsem na webu a fórech jedno řešení vyštrachal – vnitřní stránka si uvnitř udělá ještě jeden (neviditelný) iframe, a nastaví mu jako URL nějakou speciální stránku (svou výšku jí předá v URL fragmentu), která musí být na stejné doméně, jako ta vnější. Ta nejvnitřnější pak může komunikovat s tou vnější a velikost iframe elementu nastavit podle toho, co najde v URL.
Jak to tedy vypadá na obrázku?
Pointa je, že nejvnitřnější a vnější rám (tedy červená a modrá) musí být na stejné doméně. Jinak by volání window.parent.document vyhodilo chybu.
Nejvíc mě na tom štve, že tohle celé divadlo by nebylo nutné, kdyby se při návrhu HTML aspoň trochu přemýšlelo a když se iframu rozměry nezadají, uzpůsobilo by ho to podle velikosti obsahu – stejně jako to dělá třeba obrázek nebo tabulka.