Ankerlink scrollt nach oben
bearbeitet von
@@TooLate
`<a href="#">`{:.language-html} ist ein Link zum Seitenanfang. Wenn kein Link zum Seitenanfang gemeint ist, dann ist `<a href="#">`{:.language-html} falsch.
`<a href="#">`{:.language-html} 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:
~~~HTML
<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*{:@en}.
Die Vorschaubilder kommen in eine Liste:
~~~HTML
<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:
~~~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:
~~~JavaScript
document.querySelectorAll('#gallery-items a').forEach(aElement => {
aElement.addEventListener('click', event => {
event.preventDefault();
// … und großes Bild anzeigen
});
});
~~~
`event.preventDefault()`{:.language-js} unterdrückt die Standardaktion, d.h. das Aufrufen des Links. Anstelle von `// … und großes Bild anzeigen`{:.language-js} kommt natürlich noch der Code, der das große Bild auf der Seite austauscht.
Wenn das auch in Browser laufen soll, die noch keine Pfeilfuntionen kennen, kann man dafür auch schreiben:
~~~JavaScript
document.querySelectorAll('#gallery-items a').forEach(function (aElement) {
aElement.addEventListener('click', function (event) {
event.preventDefault();
// … und großes Bild anzeigen
});
});
~~~
Wenn das auch in Browser laufen soll, die `querySelectorAll()`{:.language-js} und `forEach()`{:.language-js} noch nicht kennen … – vergiss es. Auch diese Browser werden ja unterstützt. Das große Bild wird eben ohne JavaScript angezeigt – *progressive enhancement*{:@en}.
Damit kein Fehler geworfen wird, das Ganze in eine *feature detection*{:@en} gepackt:
~~~JavaScript
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.
Dazu ändern wir `document.querySelectorAll('#gallery-items a')`{:.language-js} in `document.querySelector('#gallery-items')`{:.language-js}:
~~~JavaScript
document.querySelector('#gallery-items').addEventListener('click', event => {
if (event.target.tagName === 'A')
{
event.preventDefault();
// … und großes Bild anzeigen
}
});
~~~
bzw. mit `function`{:.language-js} und *feature detection*{:@en}:
~~~JavaScript
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()`{:.language-js} und `addEventListener`{:.language-js} ab IE 9 unterstützt werden, man sich die *feature detection*{:@en} 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 />'`{:.language-js} 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:
~~~JavaScript
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()`{:.language-js}:
~~~JavaScript
const mainViewElement = document.querySelector('#main_view');
~~~
Für ältere Browser mit `var`{:.language-js} statt `const`{:.language-js}:
~~~JavaScript
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:
~~~HTML
<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:
~~~CSS
#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:
~~~JavaScript
const mainViewImgElement = document.querySelector('#main-view img');
~~~
bzw. mit `var`{:.language-js}.
Im Eventhandler übernimmst du für `src` den Wert aus `href` des jeweils geclickten Links:
~~~JavaScript
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:
~~~JavaScript
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:
~~~JavaScript
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](https://twitter.com/thebillygregory/status/552466012713783297)
Ankerlink scrollt nach oben
bearbeitet von
@@TooLate
`<a href="#">`{:.language-html} ist ein Link zum Seitenanfang. Wenn kein Link zum Seitenanfang gemeint ist, dann ist `<a href="#">`{:.language-html} falsch.
`<a href="#">`{:.language-html} 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:
~~~HTML
<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*{:@en}.
Die Vorschaubilder kommen in eine Liste:
~~~HTML
<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:
~~~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:
~~~JavaScript
document.querySelectorAll('#gallery-items a').forEach(aElement => {
aElement.addEventListener('click', event => {
event.preventDefault();
// … und großes Bild anzeigen
});
});
~~~
`event.preventDefault()`{:.language-js} unterdrückt die Standardaktion, d.h. das Aufrufen des Links. Anstelle von `// … und großes Bild anzeigen`{:.language-js} kommt natürlich noch der Code, der das große Bild auf der Seite austauscht.
Wenn auch in Browser laufen soll, die noch keine Pfeilfuntionen kennen, kann man dafür auch schreiben:
~~~JavaScript
document.querySelectorAll('#gallery-items a').forEach(function (aElement) {
aElement.addEventListener('click', function (event) {
event.preventDefault();
// … und großes Bild anzeigen
});
});
~~~
Wenn auch in Browser laufen soll, die `querySelectorAll()`{:.language-js} und `forEach()`{:.language-js} noch nicht kennen … – vergiss es. Auch diese Browser werden ja unterstützt. Das große Bild wird eben ohne JavaScript angezeigt – *progressive enhancement*{:@en}.
Damit kein Fehler geworfen wird, das Ganze in eine *feature detection*{:@en} gepackt:
~~~JavaScript
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.
Dazu ändern wir `document.querySelectorAll('#gallery-items a')`{:.language-js} in `document.querySelector('#gallery-items')`{:.language-js}:
~~~JavaScript
document.querySelector('#gallery-items').addEventListener('click', event => {
if (event.target.tagName === 'A')
{
event.preventDefault();
// … und großes Bild anzeigen
}
});
~~~
bzw. mit `function`{:.language-js} und *feature detection*{:@en}:
~~~JavaScript
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()`{:.language-js} und `addEventListener`{:.language-js} ab IE 9 unterstützt werden, man sich die *feature detection*{:@en} 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 />'`{:.language-js} 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:
~~~JavaScript
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()`{:.language-js}:
~~~JavaScript
const mainViewElement = document.querySelector('#main_view');
~~~
Für ältere Browser mit `var`{:.language-js} statt `const`{:.language-js}:
~~~JavaScript
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:
~~~HTML
<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:
~~~CSS
#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:
~~~JavaScript
const mainViewImgElement = document.querySelector('#main-view img');
~~~
bzw. mit `var`{:.language-js}.
Im Eventhandler übernimmst du für `src` den Wert aus `href` des jeweils geclickten Links:
~~~JavaScript
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:
~~~JavaScript
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:
~~~JavaScript
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](https://twitter.com/thebillygregory/status/552466012713783297)