Tutorials

PIP

Perfect Image Popups in elke browser

Pagina 1

PIP - Inleiding

Perfecte crossbrowser Image Popups

[color=red]Van thumbnail naar the big pic[/color]
Je kent ze wel: thumbnails waar je op kunt klikken waarna een popup verschijnt waar de grote foto precies in past. De popup is gecentreerd en met een klik op de grote foto verdwijnt hij weer. Hoe krijg je dat in alle browsers werkend? Wat moet er gebeuren als JavaScript uit staat? En hoe krijg je het voor elkaar dat je niet zelf de maten van het grote plaatje mee hoeft te geven?

[color=red]Als JavaScript uit staat[/color]
In dat geval moet de bezoeker nog steeds op de thumb kunnen klikken! De enige manier om dat te bereiken is de volgende:

<a href="plaatje.jpg"><img src="plaatje_tn.jpg"></a>

Een ouderwetsche hyperlink met een plaatje erin, dus. Er zijn nog altijd mensen die JavaScript uit hebben staan en die krijgen na een klik op het kleine plaatje gewoon het grote te zien. Met de backbutton kunnen ze terug, allemaal keurig zoals het hoort. Jij blij, bezoeker blij, W3C blij (p.s. natuurlijk niet vergeten een alt en een title tag op te geven voor het plaatje!)

[color=red]JavaScript Popup[/color]
Als JavaScript wél aan staat (9 van de 10 keer) kunnen we gebruik maken van de functie window.open. De syntax staat hieronder:

window.open(URL, name [, features])

Bij 'URL' geven we een lege string op zodat we een blanco venster krijgen. De bedoeling is namelijk dat we de inhoud er straks met JavaScript in gaan schrijven. Bij 'name' geven we voorlopig ook een lege string op, want we schrijven de titel er ook zelf in, later.

Bij 'features' wordt het interessant. Daar kun je een aantal kenmerken opgeven. Voor een overzicht, zie DevGuru. Wat ik wil voor mijn popup zou er ongeveer zo uit zien:

window.open('', '', 'toolbar=no,scrollbars=no,left=300,top=300,width=300,height=300');

Bij left, top, width en height heb ik voorlopig 300 ingevuld, maar die worden later natuurlijk aangepast, afhankelijk van de JPG die erin komt te staan.
Pagina 2

Custom attributen

[color=red]Wat zijn het?[/color]
Een custom attribuut is een attribuut met een naam die je zelf verzint. Standaard-attributen van een <a> tag zijn bijvoorbeeld 'href', of 'target'. Wij verzinnen nu twee custom attributen: 'popup_w' en 'popup_h'. Een hyperlink komt er dan bijvoorbeeld zo uit te zien:

<a href="plaatje.jpg" popup_w="400" popup_h="300"><img src="plaatje_tn.jpg"></a>

Voor het gemak laat ik nog steeds even de alt en de titles weg. Die komen er later bij.

[color=red]Waarom is dat handig?[/color]
Glad you asked! Het plan is als volgt: met JavaScript gaan we op het onclick event van de hyperlink actie ondernemen. We onderbreken het standaardgedrag van de hyperlink met een return false; in de code en we gaan met window.open een popup genereren met de juiste breedte en hoogte. En die kunnen we ophalen via onze custom-attributen. Nu kan het natuurlijk zijn dat we meer dan één thumbnail op onze pagina hebben, dus we maken een class 'popup' aan voor alle hyperlinks op onze pagina die een popup moeten worden. Het voordeel hiervan is dat we met JavaScript de hele pagina door kunnen lopen en alle <a> tags met de class 'popup' kunnen ophalen.

<a class="popup" href="plaatje.jpg" popup_w="400" popup_h="300"><img src="plaatje_tn.jpg"></a>


[color=red]Unobtrusive JavaScript[/color]
Net zoals je inhoud (HTML) en opmaak (CSS) gescheiden hoort te houden, hoor je inhoud en gedrag (bijv. JavaScript) ook gescheiden te houden. Het komt de overzichtelijkheid en de onderhoudbaarheid van je pagina's ten goede. We maken dus een apart JS bestand aan en includen dat in de <head> sectie van onze pagina. Het is een goede gewoonte om dat te doen vóór de CSS includes. Je ondervangt daarmee namelijk meteen een bug in Internet Explorer die FOUC heet. Noem je bestand bijvoorbeeld image_popup.js en voeg het op de volgende manier toe:

<script type="text/javascript" src="image_popup.js"></script>
Pagina 3

image_popups.js

[color=red]document.getElementsByTagName[/color]
Met de JavaScript-functie getElementsByTagName kun je alle tags van een bepaald type uit een pagina halen en in een array stoppen. Dat doen we in ons voorbeeld dus voor de <a> tag. We moeten er echter wel zeker van zijn dat de hele pagina is geladen voordat we getElementsByTagName kunnen uitvoeren. Daarvoor gebruiken we het window.onload event. We beginnen image_popups.js dus met:

window.onload = init;
function init () {
	var x = document.getElementsByTagName ('a');
	var n = x.length;
}

Zodra de pagina geladen is wordt de functie init () uitgevoerd. Die stopt alle <a> tags in een array x. De lengte van x zetten we alvast in n. Omdat niet alle hyperlinks op een pagina de class 'popup' hoeven te hebben gaan we de array x doorlopen met een for-lus. Als een hyperlink de class 'popup' heeft, koppelen we een functie aan het onclick-event van die hyperlink:

for (i = 0; i < n; i++) {
	if (x[i].className == 'popup') {
		x[i].onclick = function () {
			return open_picture_win (this);
		}
	}
}

De functie krijgt de naam 'open_picture_win' en krijgt als argument het keyword 'this' mee, wat betekent dat we naar het huidige object uit de array x verwijzen. Omdat we het hele object als argument meegeven, hebben we straks binnen de functie 'open_picture_win' ook de beschikking over onze custom-attributen popup_w en popup_h. De 'return' die ervoor staat is om het standaardgedrag van de hyperlink te onderbreken.

De code die we tot nu toe hebben ziet er dus als volgt uit:

window.onload = init;

function init () {
	var x = document.getElementsByTagName ('a');
	var n = x.length;
	
	for (i = 0; i < n; i++) {
		if (x[i].className == 'popup') {
			x[i].onclick = function () {
				return open_picture_win (this);
			}
		}
	}
}
Pagina 4

open_picture_win

[color=red]The fun part[/color]
De functie open_picture_win is behoorlijk uitgebreid. Wat we er achtereenvolgens in doen is dit:

1. We declareren wat variabelen voor de titel, de HTML-inhoud, de settings van het window voor window.open en 'left' en 'top' voor de positie van het window op het scherm
2. Daarna halen we de breedte (popup_w) en de hoogte (popup_h) uit het object met getAttribute ()
3. Vervolgens sleutelen we de HTML string in elkaar die we in het popup-window gaan schrijven.
4. Dan zorgen we dat de settings voor window.open kloppen, dus de breedte, de hoogte, en de x- en de y-positie van het popup venster.
5. We kijken ook of er al niet een popup venster geopend is. Zoja, dan sluiten we die voordat we een nieuw venster openen.
6. Hierna openen we het popup-venster met de goede settings, we schrijven de HTML-string er naartoe, we geven het popup-venster de focus, we sluiten het schrijven naar het popup-venster met document.close en we zetten een return false; aan het eind van de functie om het standaard-gedrag van de hyperlink te onderbreken.

Okee, genoeg gepraat. Hier is de hele functie:

var picture_window;

function open_picture_win (obj) {
	var title = "Klik op de foto om het venster te sluiten"
	var htmlString;
	var settings;
	var left;
	var top;

	var width, height;
	width = (obj.getAttribute('popup_w')) ? (obj.getAttribute('popup_w')) : (800);
	height = (obj.getAttribute('popup_h')) ? (obj.getAttribute('popup_h')) : (600);
	
	htmlString = '<html><head><title>' + title + '<\/title>';
	htmlString += "<style>* {border: 0; margin: 0; padding: 0;} body {background-color: black; overflow: hidden; }<\/style><\/head><body style=\"cursor: pointer\" leftmargin=\"0\" topmargin=\"0\" bgcolor=\"#555555\">";
	htmlString += "<img title=\"Klik om te sluiten\" onclick=\"window.close()\" src=\"";
	htmlString += obj.href;
	htmlString += "\"><\/body><\/html>";
	left = (screen.availWidth - width) / 2;
	top = (screen.availHeight - height) / 2;
	settings = '"toolbar=no, scrollbars=no, left=' + left + ',top=' + top + ',width=' + width + ', height=' + height + '"';

	if (picture_window && !picture_window.closed) {
		picture_window.close();
	}

	picture_window = window.open ('', '', settings);
	picture_window.document.write (htmlString);
	picture_window.focus();
	picture_window.document.close ();
	
	return false;
}
Pagina 5

PHP to the rescue

[color=red]Automatiseren met PHP[/color]
Op zich hebben we nu een werkende situatie. Het enige vervelende is dat we met de hand de breedte en de hoogte moeten invullen voor het grote plaatje waar de hyperlink naar verwijst. Het zou ideaal zijn als ook dit niet nodig was. Gelukkig kunnen we met behulp van PHP de afmetingen van plaatjes opvragen.

Hiervoor gebruiken we de volgende functie:
<?php
function set_thumb ($thumbfile, $alt_tekst = 'Klik op het plaatje voor een vergroting') {
$bigpic = str_replace ('_tn.jpg', '.jpg', $thumbfile);
list ($width, $height) = getimagesize ($bigpic);
list ($width_tn, $height_tn) = getimagesize ($thumbfile);
echo "\n";
echo '<a class="popup" href="' . $bigpic . '" popup_w="' . $width . '" popup_h="' . $height . '">';
echo '<img src="' . $thumbfile . '" width="' . $width_tn . '" height="' . $height_tn . '" class="thumb" alt="' . $alt_tekst . '" title="' . $alt_tekst . '">';
echo '</a>';
}
?>
We vervangen '_tn.jpg' door '.jpg' waarmee we de bestandsnaam van het grote plaatje verkrijgen. Daarna vragen we de breedte en de hoogte van het grote en het kleine plaatje op met getimagesize. Dan kunnen we de hyperlink echoeën met alle juiste waarden erin. We roepen de functie als volgt aan (eventueel kun je een tweede argument opgeven voor de alt/title tekst):
<?php
set_thumb ('plaatje1_tn.jpg');
set_thumb ('plaatje2_tn.jpg');
set_thumb ('plaatje3_tn.jpg', 'Click for the bigger pic!');
?>
Het mooie van deze opzet is, dat we een hele directory zouden kunnen uitlezen. Elk JPG bestand met de string '_tn.jpg' pikken we er dan uit, zodat we een hele reeks thumbs automatisch op een pagina kunnen plaatsen. Een andere uitbreiding op deze tut zou zijn, dat het popupvenster scrollbalken krijgt zodra het plaatje te groot wordt. Voorlopig laat ik het hierbij. Ik hoop dat je er iets aan hebt en als er vragen zijn, hoor ik het graag.

Deze tutorial is getest in Internet Explorer 6, FF 1.5 en Opera 9.01 voor Windows, en in Safari, FireFox 1.5.0.6 en Opera 9.0 voor de Mac.

Deze tutorial staat ook op mijn eigen site met op de laatste pagina een link naar het hele script en een werkend voorbeeld.

p.s. Custom-attributen hebben één (groot) nadeel; ze valideren niet. De enige oplossing die ik daar voor weet, is je eigen DTD (doctype declaration) schrijven. Kijk op de site van Peter Paul Koch voor een artikel over custom attributen

Reacties

0
Nog geen reacties.