Ankerlink scrollt nach oben
TooLate
- html
Hallo Forum
Ich habe ein DIV als Hauptanzeigefenster:
<div id="main_view">
<img src="01-Bild.jpg" width="500" height="281" alt="Grosses-Bild-01" />
</div>
Und darunter verschiedene Bildchen in dieser Art und Weise:
<a href="#" onclick="document.getElementById('main_view').innerHTML=
'<img src=\'02-Bild.jpg\' width=\'500\' height=\'281\' alt=\'Grosses-Bild-02\' /><br /><br />'"><img src="KleinesBildchen-02.jpg" /></a>
Das funktioniert auch alles. Bei Klick auf den Link "KleinesBildchen-02.jpg" wird das Grosse Bild im Haupt-DIV ersetzt. Nur wird nach dem Ersetzen des Bildes im Haupt-DIV die Web-Seite ganz nach oben gescrollt.
Bei einem grossen Bildschirm kein Problem, aber bei Mobil-Devices mit entsprechendem kleinen Bildschirm, muss der Client nach jedem Klick auf das Vorschaubildchen wieder herunter scrollen.
Kann der Anker "#" anders gesetzt werden? Oder muss ich die Scrollposition der Webseite auslesen, in einem Cookie speichern und nach dem Bildwechsel an den Ursprungsort zurück scrollen?
CU TooLate
Hallo Forumsleser
Habe eine Seite weiter den Thread von "Thirteen37" gefunden. Demnach wird bei einem Link die Seite stets neu geladen. Also kann es nicht verhindert werden.
Gut, dann suche ich mal nach einer Möglichkeit, die Scrollposition auszulesen (eventuell ist dass ja mit JS realisierbar.
Tschüss TooLate
Hallo,
dein Problem ist der Link. Wenn du drauf klickst, wird die entsprechnde Seite geladen.
Wenn es ein Link bleiben soll, dann verlinke das Bild für Besucher ohne Javascript und beende den Click-Handler mit return false bzw. unterdrücke die Defaultaktion: https://wiki.selfhtml.org/wiki/JavaScript/DOM/Event/preventDefault. Bei der Gelegenheit solltest du dann auch die Eventhandler vom HTML trennen.
Gruß
Jürgen
Hallo Forum
Mit:
<script type="text/javascript">
function getWidth() {
var de = document.documentElement;
var myWidth = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
return myWidth;
}
document.getWidth=getWidth;
function getHeight() {
var de = document.documentElement;
var myHeight = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
return myHeight;
}
document.getHeight=getHeight;
Kann ich die aktuelle Fenstergrösse auslesen. Das klappt.
Mit:
function getScrollXY() {
var scrOfX = 0, scrOfY = 0;
if( typeof( window.pageYOffset ) == 'number' ) {
//Netscape compliant
scrOfY = window.pageYOffset;
scrOfX = window.pageXOffset;
} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
//DOM compliant
scrOfY = document.body.scrollTop;
scrOfX = document.body.scrollLeft;
} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
//IE6 standards compliant mode
scrOfY = document.documentElement.scrollTop;
scrOfX = document.documentElement.scrollLeft;
}
return [ scrOfX, scrOfY ];
}
bekomme ich die gescrollten Werte.
Aber wie rufe ich die Funktion getScrollXY() beim Seitenladen auf? Mein Ziel ist es, dass wenn der Client auf das Bildchen klickt (onclick), die:
Ist das realisierbar?
Gruss TooLate
Hallo
Mit … Kann ich die aktuelle Fenstergrösse auslesen.
… die in vielen Fällen nicht mit der Größe der Anzeigefläche für Webseiten übereinstimmen wird.
Mein Ziel ist es, dass wenn der Client auf das Bildchen klickt (onclick), die:
- Aktuelle (scroll)-Position ermittelt wird.
- Diese als cookie im Browser gespeichert wird.
- Die Seite neu geladen wird.
- Das Cookie mit dem Scrollwert ausgelesen wird.
- An die vorherige Position gescrollt wird.
Ist das realisierbar?
Bestimmt ist es das. Mit der Lösung, die Gunnar dir darbietet, ist es aber unnötig. Zumal dein Weg unnötig kompliziert ist.
Tschö, Auge
@@TooLate
Mein Ziel ist es, dass wenn der Client auf das Bildchen klickt (onclick), die:
- 1.) Aktuelle (scroll)-Position ermittelt wird.
- 2.) Diese als cookie im Browser gespeichert wird.
- 3.) Die Seite neu geladen wird.
- 4.) Das Cookie mit dem Scrollwert ausgelesen wird.
- 5.) An die vorherige Position gescrollt wird.
Nein. Nein. Nein. Nein. Nein. Das ist nicht dein Ziel.
Ist das realisierbar?
Da das nicht sinnvoll ist, stellt sich die Frage nach der Realisierbarkeit gar nicht.
LLAP 🖖
@@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 🖖
Hi Gunnar Bittersmann
Das ist viel Input!!!
Ich teste das mal in Ruhe durch. Damit ich nicht alles haarklein Posten muss, hier mal ein Link auf die betreffende Seite:
Für Testzwecke Seite scrollen und dann auf ein Vorschaubilchen klicken.
Und die anderen Nachrichten werde ich auch beherzigen. Habe es erst jetzt gesehen.
Viel Arbeit!!! OK. Bis später. Habe ja ne Menge Hausaufgaben von Gunnar bekommen…
Gruss TooLate
Nachtrag…
Und natürlich ein dickes Dankeschön für die Tipps - vor allem an Gunnar, der sich richtig Arbeit gemacht hat - Danke!
Gruss TooLate
Hallo Forum
@Gunnar Bittersmann Ich bin gerade beim Testen deiner Vorschläge an dem Punkt deines Posts, wo es heisst:
Für alle a-Elemente dieser Liste werden nun die Eventhandler registriert – aber nicht inline mit onclick-Attributen im HTML, sondern im Script:
Diese beiden EventHandler. Wie ist das gemeint. Nehm ich den Oberen, oder den Unteren mit "functions", oder alle beide?
Gruss TooLate
Hallo Forum
Nachtrag: Vergiss die Frage. Wenn das auch in älteren Browser laufen soll natürlich die "Untere" Version.
JS ist so anders, als Perl und Python. JavaScript ist und bleibt für mich abstrakter Code...
Allerdings bin ich geneigt, das Thema hier ab zu brechen und eventuell doch über die Cookie-Lösung den Browser-Schirm wieder an die zuletzt ausgelesene Position zu scrollen. Mal ehrlich - wäre das nicht einfacher und auch Browser-Übergreifender? (Cookies kann jeder Browser und Scrollen auch)
Ich habe mal einen Link, wo du bisherig gemachtes ersehen kannst:
Gruss TooLate
Hallo Forum
Lösung des Problems wurde gefunden...
<a href="#" onclick="document.getElementById('main_view').innerHTML=
'<img src=\'01-cct-box.jpg\' width=\'500\' height=\'281\' alt=\'Grosses-Bild-01\' /><br /><br />' ;return false;"><img src="small-01-cct-box.jpg" /></a>
...also ein schlichtes ;return false; eingehängt - und gut ist.
Gruss TooLate
@@TooLate
Lösung des Problems wurde gefunden...
<a href="#" onclick="document.getElementById('main_view').innerHTML= '<img src=\'01-cct-box.jpg\' width=\'500\' height=\'281\' alt=\'Grosses-Bild-01\' /><br /><br />' ;return false;"><img src="small-01-cct-box.jpg" /></a>
...also ein schlichtes ;return false; eingehängt - und gut ist.
Dann habe ich wohl mal wieder Perlen vor die Säue geworfen. Schade eigentlich.
LLAP 🖖
Hallo TooLate,
dein Link ist tot...
Aber von deiner Turnübung mit Cookies und Javascript-induziertem Scrolling würde ich Dir abraten. Ein a Tag mit href='#' oder href='#blabla' löst keinen Roundtrip zum Server aus, der Browser positioniert die Anzeige lediglich so, dass die angegebene ID oben auf der Seite steht. Mit Cookies kommst Du deshalb vermutlich nicht so weiter, wie Du es Dir vorstellst.
Was Du vermutlich willst, ist die Garantie, dass nach jeder Bildauswahl das große Bild sichtbar ist. Dafür könnte man <a href='#main_view' ...>
einsetzen. Dann springt das Bildfenster aber auch dann jedesmal an den oberen Rand, wenn es gar nicht nötig ist.
Eigentlich solltest Du den Vorschlag berücksichtigen, mit <button type='button'>
zu arbeiten, und es dem User überlassen, ob er scrollt oder nicht. Ein Eventhandler auf dem Button, nach dem vom Gunnar beschriebenen Vorgehen, tauscht nur das Bild aus und verändert die Scrollposition der HTML Seite nicht. Dein Layout von "großem Bild" und "kleinen Bildern" ist nahezu quadratisch und sollte bei diesem Vorgehen auch auf einem Smartphone im Hochformat gut funktionieren. Im Querformat nicht unbedingt, aber dann hast Du entweder einen Desktop, ein Tablet oder der User hält sein Smartphone quer und rechnet damit, viel vertikal scrollen zu müssen.
Rolf
@@Rolf B
Eigentlich solltest Du den Vorschlag berücksichtigen, mit
<button type='button'>
zu arbeiten
Wer hatte einen solchen unterbreitet?
Ich nicht. Der Vorschlag wäre hier nicht richtig.
LLAP 🖖
Hi Rolf
dein Link ist tot...
Habe ihn als unvollständiges Beispiel wieder reaktiviert. Er stört auf dem Server nicht und darf eine Weile bleiben ☺️
Zum restlichen Thema: Das "return false" arbeitet einwandfrei. Habe es gerade auch am i-Pad ausprobiert - läuft!
Also das funktionierende Beispiel kann man unter... diesem Link ...ansehen
Gruss TooLate
@@TooLate
Ein flüchtiger Blick in die Konsole im Entwicklerwerkzeug deines Browsers verrät dir:
Der Fehler tritt also in Zeile 18 auf:
Gruss TooLate
Du solltest dich TooEarly nennen – denn das ist, wann du das Script ausführst. Es steht im head
der HTML-Datei, also lange bevor es das Element mit der ID „gallery-items“ überhaupt gibt. Deshalb wird kein solches Element gefunden und kein Eventhandler registriert. Was du siehst ist, dass der Fallback funktioniert, nämlich der Link auf das jeweilige große Bild, welches dann im Browserfenster angezeigt wird.
BTW, <script language="JavaScript">
ist unsinnig (und war es schon immer). Verwende <script>
in HTML. Dazu noch den DOCTYPE ändern auf <!DOCTYPE html>
. Und auch gleich die Sprache angeben: <html lang="de">
.
Du willst das Script erst ausführen, wenn das HTML (fast) vollständig geparst und das DOM aufgebaut ist. Zwei Möglichkeiten:
Du notierst das Script ganz unten im body
– nach allem Seiteninhalt.
Du registrierst einen Eventhandler document.addEventListener('DOMContentLoaded', …)
und sorgst damit dafür, dass das Script erst ausgeführt wird, wenn es das Element „gallery-items“ im DOM gibt.
Nee jetzt, oder?
LLAP 🖖
Guten Abend
Vorab: Diese beta-Seite ist nicht auf dem neusten Stand. Ich werde mich gleich mal um diesen Spass kümmern - schließlich will ich am Ende sehen, ob diese ganze Eventhändler-Geschichte auch ohne ";return false;" funktioniert hätte 😉 !
Habe erstmal die offiziellen Pages im W3C getestet und korrigiert - es waren nämlich ein paar Flüchtigkeitsfehler darin enthalten! Der Webauftritt zeigt im Validator jetzt - bis auf eine Stelle - alles in "Grün" an. Die will ich noch korrigieren. Es ist diese Seite.
Wenn man unten, am Seitenende auf W3C-HTML 4.01 klickt, sieht man den Fehler:
Line 326, Column 68: required attribute "ACTION" not specified.
Das mag daher kommen, weil der Code früher für eine Formularabsendung benötigt wurde. Da die aktuellen Seiten ohne serverseitige Scripts sind (kein cgi), findet auch keine Verarbeitung auf dem Server statt. Das Formular wird nur zum Drucken benötigt. Muss ich jetzt ein blindes "action" irgendwo verbauen, um den Fehler weg zu bekommen?
Wäre nett, wenn wir das noch zuvor lösen könnten ☺️
Gruss TooLate
@@TooLate
schließlich will ich am Ende sehen, ob diese ganze Eventhändler-Geschichte auch ohne ";return false;" funktioniert hätte 😉 !
Wie JürgenB schon sagte, erfüllt return false
dieselbe Funktion wie Event.preventDefault()
. Letzteres hat den sprechenden Namen und man erkennt, wozu es dient. Ich würde deshalb immer Event.preventDefault()
verwenden, nicht return false
.
Habe erstmal die offiziellen Pages im W3C getestet und korrigiert - es waren nämlich ein paar Flüchtigkeitsfehler darin enthalten! Der Webauftritt zeigt im Validator jetzt - bis auf eine Stelle - alles in "Grün" an. Die will ich noch korrigieren. Es ist diese Seite.
Wenn man unten, am Seitenende auf W3C-HTML 4.01 klickt, sieht man den Fehler:
Line 326, Column 68: required attribute "ACTION" not specified.
In HTML 4.01 verlangte das form
ein action
-Attribut; wenn das Formular an dieselbe Adresse geschickt werden sollte („Affenformular“): <form action="">
. Beachte die Verganheitsform! HTML 4.01 ist Vergangenheit.
In HTML muss dass action
-Attribut – wenn vorhanden – jetzt einen nicht-leeren URI als Wert haben; ansonsten muss man es weglassen.
Du solltest <DOCTYPE html>
verwenden.
Dann zeigt dir der Validator auch noch andere Fehler – und das sind keine Flüchtigkeitsfehler.
Das mag daher kommen, weil der Code früher für eine Formularabsendung benötigt wurde. Da die aktuellen Seiten ohne serverseitige Scripts sind (kein cgi), findet auch keine Verarbeitung auf dem Server statt. Das Formular wird nur zum Drucken benötigt. Muss ich jetzt ein blindes "action" irgendwo verbauen, um den Fehler weg zu bekommen?
Wenn keine Daten übertragen werden sollen, wozu brauchst du dann ein Formular?
Wozu braucht Gott ein Raumschiff?
LLAP 🖖
Hi Gunnar
Ich habe mal HTML 4.01 gelernt. Und kurz vor der Rente werde ich mich sicherlich nicht noch um orientieren. Die letzte Neuerung war "rounded-corners" mit "border-radius" - also was über neues CSS gestyled werden kann, bin ich bereit mir anzueignen. Mehr aber nicht! hehe…
Im "original" W3C Validator haben die Seiten "Null" Fehler. Der komische "NU"-Validator hat für mich keine Relevanz. Ob jetzt obsolet oder nicht - ich bitte dich.
Soll jetzt mein Nachbar, der Oldtimer sammelt, die Autos wegwerfen, weil die Motoren ineffizient und zu laut sind?
Hier nochmal der Gegenbeweis - Damit Nachleser die Realität verifizieren können:
So, den Rest mit dem Handler Test versuche ich morgen - ist schon spät. Und nochmals vielen Dank an Dich für Deine ausführlichen Posts.
Gruss TooLate
@@TooLate
Ich habe mal HTML 4.01 gelernt.
Ich auch. Und XHTML 1.0. Und ich habe die Spezifikationen geliebt, weil sie einfach zu lesen waren – im Gegensatz zur jetzigen HTML-Spezifikation. Aber das ist Vergangenheit.
Soll jetzt mein Nachbar, der Oldtimer sammelt, die Autos wegwerfen, weil die Motoren ineffizient und zu laut sind?
Nein, aber um von A nach B mit 150 über die Autobahn zu fahren, wird er wohl kaum einen seiner Oldtimer aus der Garage holen – weil die Motoren zu wertvoll sind!
Dass mein Vergleich hinkt, liegt daran, dass er auf deinem Vergleich aufsetzte, der schon hinkte.
Es geht auch nicht darum, was wegzuwerfen, sondern um Neues hinzuzufügen. HTML ist bewusst abwärtskompatibel gehalten – die allermeisten Dinge aus HTML 4.01 funktionieren nach wie vor.
Hier nochmal der Gegenbeweis - Damit Nachleser die Realität verifizieren können:
Baust du deine Seiten für den Validator oder für Menschen? Wenn für Menschen, dann sollten deren Bedürfnisse zählen. Und die bedienst du mit neuem HTML viel besser als mit uraltem HTML 4.01. Bspw. Typen von Eingabefeldern:
für die Anzahl von Produkten, die in den Warenkorb gelegt werden sollen: <input type="number">
Nutzer können mit den Pfeilen am Eingabefeld die Anzahl vergrößen/verringern ohne die Tastatur zu benutzen; Nutzer mit virtueller Tastatur (Mobilgeräte) bekommen eine numerische Tastatur präsentiert, wobei die Zahlentasten nicht so winzig sind wie die Tasten bei der alphanumerischen Tastatur.
für E-Mail-Adressen: <input type="email">
Nutzer mit virtueller Tastatur (Mobilgeräte) bekommen das @ auf die Tastatur, sodass es mit einem Click eingegeben werden kann.
für Datumsangaben: <input type="date">
Es wird ein Datepicker angeboten.
Es macht überhaupt keinen Sinn, von den Möglichkeiten, die Browser bieten, keinen Gebrauch zu machen.
Wenn man HTML schreibt, sollte man das auch angeben: <!DOCTYPE html>
. Der einzige Zweck der DOCTYPE-Angabe ist ja, Browser aus dem Quirks-Modus herauszuholen – und zwar möglichst in den Standard-Modus. <!DOCTYPE html>
tut dies; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
tut das nicht.
LLAP 🖖