Vývojářský blog Tomáše Hercega

Tisk článku Tisk článku

Dokonale promyšlené HTML: iframe a automatická výška

[Zpět na blog]

Datum: 28. 9. 2011 18:27       Autor: Tomáš Herceg       Zobrazeno: 969x

Kategorie: Javascript, HTML+CSS


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?

Řešení pomocí vnořených iframe

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. 


> Na začátek

 

Hodnocení:

Hlasů: 6
Zvolte své hodnocení

Tomáš Herceg

Jsem hlavním softwarovým architektem ve společnosti Riganti. Mám dlouholeté zkušenosti s technologiemi ASP.NET, Silverlight, WPF a XNA. Působím též jako lektor ve společnosti Gopas a již třetím rokem jsem držitelem ocenění Microsoft Most Valuable Professional.

Podpořte vznik dalších článků
RSS Feed RSS Feed

Diskuse

1 

Zajímavé

Datum: 28.9.2011 19:02
Autor: neregistrovaný (92.62.224.12)
Hodnocení autora: není
Příspěvků: 0
Toto je velice zajimavé řešení, mě by to asi nenapadlo, je pravda, že toto je opravdu hodně špatně řešeno a člověk by prostě tak nějak očekával, že takováto věc již bude v základu, ale ne prostě není, člověk pak musí zdlouhavě googlit různé paskvily a když pak tlačí čas, tak je to dost o nervy, bohužel :-(
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Pěkné řešení!

Datum: 28.9.2011 21:34
Autor: neregistrovaný (91.217.52.182)
Hodnocení autora: není
Příspěvků: 0
Pěkné řešení. Může se výška obsahu a tedy i iframu měnit dynamicky? Nebo se nastavuje jednou po načtení stránky?
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Pěkné řešení!

Datum: 28.9.2011 21:41
Autor: Dušan Janošík
Hodnocení autora: 0
Příspěvků: 15
Hmm, blbá otázka. Samozřejmě jen po načtení stránky. Už jsem doufal, že snad někdo našel řešení. Předchozí příspěvek jsem psal já.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Pěkné řešení!

Datum: 28.9.2011 22:25
Autor: Alexander Clarai
Hodnocení autora: 98
Příspěvků: 98
Ten javascriptový kód se dá vyvolat kdykoliv, klidně by se to mohlo měnit každou sekundu například.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Pěkné řešení!

Datum: 28.9.2011 23:03
Autor: Tomáš Herceg
Hodnocení autora: 1685
Příspěvků: 3558
Teoreticky by šlo ve vnější stránce chytat událost, kdy se změnila velikost okna (žádné ptaní se každou sekundu, to je největší pitomost - pokud to jde udělat událostí, tak nikdy timer).
Jakmile tato událost nastane, tak prvnímu iframu změnit URL, ale jen fragment v URL (např. přidat znak, přičíst jedničku nebo tak něco). Vnitřní stránka by se navěsila na událost hashchange a při jejím vyvolání by se změřila a změnila adresu zase ve vnořeném iframu, který to tím skriptem už zpropaguje do první stránky.
Ale nezkoušel jsem to, takže nevím, jestli to funguje. Naštěstí to nepotřebuju.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Pěkné řešení!

Datum: 29.9.2011 12:40
Autor: Alexander Clarai
Hodnocení autora: 98
Příspěvků: 98
Ano samozřejmě, ta sekunda byl pouze příklad pro ilustraci, že je možné ten kód nechat proběhnout opravdu při každém vývojářově rozmaru :) Mimochodem HashChange nemá zase tak širokou podporu a běžně se časovačem řeší, pokud jej browser nepodporuje, ale jak říkám, tím směrem jsem nemířil.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: Pěkné řešení!

Datum: 28.9.2011 23:06
Autor: Dušan Janošík
Hodnocení autora: 0
Příspěvků: 15
Teoreticky ano, nepochybně. V praxi ale nelze (resp. nevím jak) spolehlivě získat aktuální výšku dokumentu v případě, že došlo k dynamické změně.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...
1 
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.