Gunnar Bittersmann: Ankerlink scrollt nach oben

Beitrag lesen

@@TooLate

<a href="#"> ist ein Link zum Seitenanfang. Wenn kein Link zum Seitenanfang gemeint ist, dann ist <a href="#"> falsch.

<a href="#"> ist meist ein Zeichen dafür, dass das a-Element falsch ist, weil gar kein Link zu einer anderen Stelle auf der Seite bzw. zu einer anderen Ressource gesetzt werden soll. Deshalb muss in diesen Fällen nicht a, sondern button verwendet werden.

Bei dir liegt der Fall anders: du willst eine andere Ressource verlinken – nämlich das Bild:

<a href="02-Bild.jpg"><img src="KleinesBildchen-02.jpg" alt="Bild 2"/></a>

Und schon funtioniert die Anzeige des großen Bildes auch ohne JavaScript. Allerdings nicht im dafür vorgesehenen Bereich auf der Seite. Dieses Feature packen wir obendrauf – progressive enhancement.

Die Vorschaubilder kommen in eine Liste:

<ul id="gallery-items">
	<li><a href="01-Bild.jpg"><img src="KleinesBildchen-01.jpg" alt="Bild 1"/></a></li>
	<li><a href="02-Bild.jpg"><img src="KleinesBildchen-02.jpg" alt="Bild 2"/></a></li>
</ul>

Bullets und Abstände weg mit CSS:

#gallery-items
{
	list-style: none;
	margin-left: 0;
	padding-left: 0;
}

#gallery-items li
{
	display: inline;
}

(oder Flexbox verwenden)

Für alle a-Elemente dieser Liste werden nun die Eventhandler registriert – aber nicht inline mit onclick-Attributen im HTML, sondern im Script:

document.querySelectorAll('#gallery-items a').forEach(aElement => {
	aElement.addEventListener('click', event => {
		event.preventDefault();
		// … und großes Bild anzeigen
	});
});

event.preventDefault() unterdrückt die Standardaktion, d.h. das Aufrufen des Links. Anstelle von // … und großes Bild anzeigen kommt natürlich noch der Code, der das große Bild auf der Seite austauscht.

Wenn das auch in Browsern laufen soll, die noch keine Pfeilfuntionen kennen, kann man dafür auch schreiben:

document.querySelectorAll('#gallery-items a').forEach(function (aElement) {
	aElement.addEventListener('click', function (event) {
		event.preventDefault();
		// … und großes Bild anzeigen
	});
});

Wenn das auch in Browsern laufen soll, die querySelectorAll() und forEach() noch nicht kennen … – vergiss es. Auch diese Browser werden ja unterstützt. Das große Bild wird eben ohne JavaScript angezeigt – progressive enhancement.

Damit kein Fehler geworfen wird, das Ganze in eine feature detection gepackt:

if (document.querySelectorAll && NodeList.prototype.forEach && EventTarget.prototype.addEventListener)
{
	document.querySelectorAll('#gallery-items a').forEach(function (aElement) {
		aElement.addEventListener('click', function (event) {
			event.preventDefault();
			// … und großes Bild anzeigen
		});
	});
}

Eventhandler für jedes a-Element zu registrieren wäre eine Möglichkeit, aber nicht die beste. Besser ist es, einen Eventhandler für ein übergeordnetes Element (die Liste „gallery-items“ bietet sich an) zu registrieren und darin abzufragen, ob der Click durch ein a-Element ausgelöst wurde – event delegation.

Dazu ändern wir document.querySelectorAll('#gallery-items a') in document.querySelector('#gallery-items'):

document.querySelector('#gallery-items').addEventListener('click', event => {
	if (event.target.tagName === 'A')
	{
		event.preventDefault();
		// … und großes Bild anzeigen
	}
});

bzw. mit function und feature detection:

if (document.querySelector && EventTarget.prototype.addEventListener)
{
	document.querySelector('#gallery-items').addEventListener('click', function (event) {
		if (event.target.tagName === 'A')
		{
			event.preventDefault();
			// … und großes Bild anzeigen
		}
	});
}

wobei querySelector() und addEventListener ab IE 9 unterstützt werden, man sich die feature detection also hier vielleicht auch schenken kann.


Jetzt fehlt „nur noch“ der Code für „… und großes Bild anzeigen“.

Du hattest mit document.getElementById('main_view').innerHTML= '<img src=\'02-Bild.jpg\' width=\'500\' height=\'281\' alt=\'Grosses-Bild-02\' /><br /><br />' zum einen immer wieder erneut das Element „main_view“ im DOM gesucht, zum anderen immer wieder ein neues Bild ins „main_view“ gehängt – beides ungünstig.

Ersteres vermeidest du, indem du einmalig das Element im DOM suchst und die Referenz darauf in einer Variablen speicherst – und zwar außerhalb des Eventhandlers:

const mainViewElement = document.getElementById('main_view');

document.querySelector('#gallery-items').addEventListener('click', event => {
	if (event.target.tagName === 'A')
	{
		event.preventDefault();
		// … in mainViewElement großes Bild anzeigen
	}
});

oder auch hier mit querySelector():

const mainViewElement = document.querySelector('#main_view');

Für ältere Browser mit var statt const:

var mainViewElement = document.querySelector('#main_view');

Zweiteres vermeidest du, indem du nicht immer wieder ein neues img-Element reintust, sondern beim bestehenden einfach den Wert des src-Attributs änderst.

Dann sollte das img-Element keine Breiten- und Höhenangaben haben:

<div id="main-view">
	<img src="01-Bild.jpg" alt="Bild 1"/>
</div>

(Aus dem _, der aus verschiedenen Gründen ungünstig ist, hab ich mal ein - gemacht.)

Damit die Bilder in den Container passen, kommt ins Stylesheet sowas wie:

#main-view img
{
	max-width: 100%;
	max-height: 100%;
}

Nun brauchen wir gar nicht die Referenz auf „main_view“/„main-view“, sondern auf das img-Element darin:

const mainViewImgElement = document.querySelector('#main-view img');

bzw. mit var.

Im Eventhandler übernimmst du für src den Wert aus href des jeweils geclickten Links:

const mainViewImgElement = document.querySelector('#main-view img');

document.querySelector('#gallery-items').addEventListener('click', event => {
	if (event.target.tagName === 'A')
	{
		event.preventDefault();
		
		mainViewImgElement.src = event.target.href;
	}
});

Fehlt noch der Alternativtext. Den holen wir aus dem Vorschaubild:

const mainViewImgElement = document.querySelector('#main-view img');

document.querySelector('#gallery-items').addEventListener('click', event => {
	if (event.target.tagName === 'A')
	{
		event.preventDefault();
		
		mainViewImgElement.src = event.target.href;
		mainViewImgElement.alt = event.target.firstChild.alt;
	}
});

Bzw. für ältere Browser:

var mainViewImgElement = document.querySelector('#main-view img');

document.querySelector('#gallery-items').addEventListener('click', function (event) {
	if (event.target.tagName === 'A')
	{
		event.preventDefault();
		
		mainViewImgElement.src = event.target.href;
		mainViewImgElement.alt = event.target.firstChild.alt;
	}
});

Alles ungetestet.

LLAP 🖖

--
“When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory