Hilfe bei JavaScript
Boris Bär
- javascript
Hallo liebe Community!
Ich bin ein absoluter Einsteiger in JavaScript und ich bin eigentlich erstaunt, dass ich überhaupt so weit gekommen bin mit meinem Projekt. Es geht um folgendes, ich habe eine Art interaktives Buch für The Elder Scrolls Online geschrieben bzw. bin ich gerade dabei das Layout dafür zu erstellen.
Hier ist ein Beispiel zu finden: http://www.brsbaer.de/bibliothek/vvardenfell/flugblatt-des-paktes/
Ich habe es geschafft, dass man die Seiten umblättern kann, stehe jetzt allerdings vor zwei kniffligen Problemen.
Bei jeder Seite muss individuell eingetragen werden, nach wievielen Seiten Schluss ist. In diesem Fall nach Seite 3. Ich würde gerne den Pfeil zum Weiterblättern dann komplett verschwinden lassen und durch einen ausgegrauten ersetzen, der nicht mehr anklickbar ist.
Die Seitenzählung. Ich möchte einfach nur die Seite anzeigen lassen, auf der man sich gerade befindet, aber durch document.write(page_number) sieht man zwar die Nummer, allerdings schaltet sie nicht um, da kein richtiger "Trigger" da ist. Ich denke da müsste sich was mit dem event-tag von JavaScript machen lassen, aber ich kenne mich leider da gar nicht aus und meine Experimente sind bisher gescheitert.
Ich wäre für jede Hilfe sehr dankbar!
Gar nicht schlecht für den Anfang 👍
Du könntest als nächstes, die Stelle:
<script>
document.write(page_number)
</script>
durch folgendes HTML ersetzen:
<span id="pageNumber">1</span>
Und dann in deiner if
/else
-Verzweigung das <span>
-Element mit der aktuellen Seitenanzahl aktualisieren:
document.querySelector('#pageNumber').textContent = page_number;
Wow, super! Das hat das Problem mit der Seitenzahl gelöst! Vielen Dank!
Jetzt gilt es nur noch herauszufinden, wie ich das mit der letzten Seite umsetze.
Habe folgendes probiert, klappt aber irgendwie nicht:
document.getElementById("input#next_page").addEventListener('click', function(){
if(pageNumber>=2){
$("input#next_page").hide();
$("img#next_page-disabled").show();
}
else{return false;}
});
Weiß jemand Rat?
Hallo Boris Bär,
Habe folgendes probiert, klappt aber irgendwie nicht:
Du könntest ein paar Fehler beseitigen: https://validator.nu/?doc=http%3A%2F%2Fwww.brsbaer.de%2Fbibliothek%2Fvvardenfell%2Fflugblatt-des-paktes%2F
document.getElementById("input#next_page").addEventListener('click', function(){ if(pageNumber>=2){ $("input#next_page").hide(); $("img#next_page-disabled").show(); } else{return false;} });
IDs müssen dokumentweit eindeutig sein. Die Selektoren sind also überspezifiziert. #next_page
reicht.
Warum mischst du JavaScript mit JQuery?
Was ist, wenn es mehr als 2 Seiten gibt?
Bis demnächst
Matthias
Danke Matthias, habe jetzt das input bei #next_page und #previous_page ausgelassen.
Wie gesagt bin ich eigentlich überhaupt nicht bewandert jenseits von etwas HTML und CSS. Ich versuche, immer mehr dazu zu lernen, aber hauptsächlich ist es Learning by Doing. Mit JQuery bzw. JavaScript habe ich praktisch gestern erst angefangen.
Mit Validierungsprozessen kenne ich mich kaum aus, ich werde mir die Ergebnisse mal ganz genau anschauen und versuche dann, die Fehler zu beheben! Hoffentlich klappt es.
Wo mische ich JQuery und JavaScript? Meine Vermutung: $("#next_page").click(function() ist JQuery und document.addEventListener("DOMContentLoaded", function() ist JavaScript?
Wenn ich zum Beispiel ersteres auch durch addEventListener erstetze, habe ich dann reines JavaScript? Was müsste ich denn dann hier ändern: <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> ?
Die gute Nachricht ist: Ich habe es tatsächlich hingekriegt, dass auf der Website alles so funktioniert wie es soll! Ich habe das Script oben in der HTML-Datei platziert, deshalb hat es nicht geklappt. Jetzt füge ich jeder Seite ein kleines Script am Ende hinzu, das die "Vorherige-Seite"- und "Nächste-Seite"-Inputs reguliert.
Sieht dann folgendermaßen aus und kann dann je nach Anzahl der Seiten umgeschrieben werden:
<script type="text/javascript">
document.getElementById("next_page").addEventListener('click', function(){
if(pageNumber==1) {
$("input#previous_page").show();
$("img#previous_page-disabled").hide();
}
else if(pageNumber>=2){
$("input#next_page").hide();
$("img#next_page-disabled").show();
}
});
document.getElementById("previous_page").addEventListener('click', function(){
if(pageNumber==2){
$("input#previous_page").hide();
$("img#previous_page-disabled").show();
}
else if(pageNumber==3){
$("input#next_page").show();
$("img#next_page-disabled").hide();
}
});
</script>
Ich habe den Code nochmal umgeschrieben, damit er etwas sauberer ist.
JavaScript und JQuery zu vermischen scheints Tragisches zu sein wie ich recherchiert habe. Vor allem wegen der FadeIn-Funktion kann ich nicht darauf verzichen.
In der Index-HTML stehen die Variablen und die allgemeine Funktion zum Umblättern.
Achtung: Das Script sollte ganz am Ende der Seite stehen, unter dem </body>-Tag.
var pageNumber = 1;
var previousPage = document.getElementById("previous_page");
var nextPage = document.getElementById("next_page");
previousPage.addEventListener("click", function(){
if ( pageNumber == 1 ) { return false; }
else if ( pageNumber == 2 ) {
$("input#previous_page").hide();
$("img#previous_page-disabled").show();
$("#text_page_02").hide();
$("#text_page_01").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 3) {
$("#text_page_03").hide();
$("#text_page_02").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 4) {
$("#text_page_04").hide();
$("#text_page_03").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 5) {
$("#text_page_05").hide();
$("#text_page_04").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 6) {
$("#text_page_06").hide();
$("#text_page_05").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 7) {
$("#text_page_07").hide();
$("#text_page_06").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 8) {
$("#text_page_08").hide();
$("#text_page_07").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 9) {
$("#text_page_09").hide();
$("#text_page_08").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 10) {
$("#text_page_10").hide();
$("#text_page_09").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
});
nextPage.addEventListener("click", function(){
if ( pageNumber == 1 ) {
$("input#previous_page").show();
$("img#previous_page-disabled").hide();
$("#text_page_01").hide();
$("#text_page_02").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 2 ) {
$("#text_page_02").hide();
$("#text_page_03").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 3 ) {
$("#text_page_03").hide();
$("#text_page_04").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 4 ) {
$("#text_page_04").hide();
$("#text_page_05").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 5 ) {
$("#text_page_05").hide();
$("#text_page_06").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 6 ) {
$("#text_page_06").hide();
$("#text_page_07").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 7 ) {
$("#text_page_07").hide();
$("#text_page_08").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 8 ) {
$("#text_page_08").hide();
$("#text_page_09").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 9 ) {
$("#text_page_09").hide();
$("#text_page_10").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
else if ( pageNumber == 10 ) {
$("#text_page_10").hide();
$("#text_page_11").fadeIn(600);
pageNumber++;
document.querySelector('#pageNumber').textContent = pageNumber;
}
});
document.addEventListener("DOMContentLoaded", function(){
if ( pageNumber == 1 ) {
$("#previous_page").hide();
$("#previous_page-disabled").show();
}
else { return false; }
});
Ich habe jetzt elf Text-Seiten eingestellt. Natürlich bläht sich das Script mit jeder Seite auf, aber für meine Zwecke benötige ich eigentlich nie mehr als zehn Text-Seiten. Es gibt bestimmt noch eine Möglichkeit, diesen Teil des Codes dynamisch zu machen, damit man nicht für jede Text-Seite einen if-Eintrag benötigt, aber leider ist mir nicht bekannt, wie das geht.
Der EventListener mit der DOMContentLoaded-Bedingung dient dazu, den linken Pfeil immer auszublenden, sobald die Seite geladen wurde.
Da die maximale Seitenzahl ja bei jedem Text variiert, füge ich bei jeder Seite noch diesen kleinen Code-Abschnitt ebenfalls am Ende der Seite ein.
Aber wieder Achtung: Wenn beide Code-Abschnitte sich in demselben HTML-Dokument befinden, dann sollte der kleine Abschnitt vor dem großen stehen.
document.getElementById("next_page").addEventListener("click", function(){
if ( pageNumber >= 2) {
$("input#next_page").hide();
$("img#next_page-disabled").show();
}
else { return false; }
});
document.getElementById("previous_page").addEventListener("click", function(){
if ( pageNumber == 3 ) {
$("input#next_page").show();
$("img#next_page-disabled").hide();
}
else { return false; }
});
Das war’s auch schon! Ich dachte, ich teile meine Lösung mal, falls es jemanden interessiert.
Herzlichen Dank nochmal an Euch beide für die Hilfe!
Aloha ;)
Ich habe jetzt elf Text-Seiten eingestellt. Natürlich bläht sich das Script mit jeder Seite auf, aber für meine Zwecke benötige ich eigentlich nie mehr als zehn Text-Seiten. Es gibt bestimmt noch eine Möglichkeit, diesen Teil des Codes dynamisch zu machen, damit man nicht für jede Text-Seite einen if-Eintrag benötigt, aber leider ist mir nicht bekannt, wie das geht.
Ganz einfach: überall wo in deinem Code zigmal hintereinander das gleiche passiert mit nur marginalen Unterschieden (z.B. in der id) kannst du optimieren. Beispielsweise:
var pageNumber = 1;
var previousPage = document.getElementById("previous_page");
var nextPage = document.getElementById("next_page");
previousPage.addEventListener("click", function(){
if ( pageNumber == 1 ) { return false; } else if ( pageNumber == 2 ) { $("input#previous_page").hide(); $("img#previous_page-disabled").show(); $("#text_page_02").hide(); $("#text_page_01").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 3) { $("#text_page_03").hide(); $("#text_page_02").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 4) { $("#text_page_04").hide(); $("#text_page_03").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 5) { $("#text_page_05").hide(); $("#text_page_04").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 6) { $("#text_page_06").hide(); $("#text_page_05").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 7) { $("#text_page_07").hide(); $("#text_page_06").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 8) { $("#text_page_08").hide(); $("#text_page_07").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 9) { $("#text_page_09").hide(); $("#text_page_08").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; } else if ( pageNumber == 10) { $("#text_page_10").hide(); $("#text_page_09").fadeIn(600); pageNumber--; document.querySelector('#pageNumber').textContent = pageNumber; }
});
wird zu:
var pageNumber = 1;
var previousPage = document.getElementById("previous_page");
var nextPage = document.getElementById("next_page");
var lastPage = 10; // das möchtest du vielleicht auch irgendwann dann dynamisch ermitteln
previousPage.addEventListener("click", function(){
// spezielle Aktion - bleibt einzeln:
if ( pageNumber == 1 ) { return false; }
// spezielle Aktion - bleibt einzeln:
else if ( pageNumber == 2 ) {
$("input#previous_page").hide();
$("img#previous_page-disabled").show();
$("#text_page_02").hide();
$("#text_page_01").fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
// ab hier passiert immer das Gleiche - zusammenfassen:
else if ( pageNumber >= 3 && pageNumber <= lastPage) {
$("#text_page_"+(((pageNumber) < 10)?"0"+pageNumber:pageNumber)).hide();
$("#text_page_"+(((pageNumber-1) < 10)?"0"+(pageNumber-1):(pageNumber-1))).fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
});
Der Block
((pageNumber) < 10)?"0"+pageNumber:pageNumber)
tut nichts anderes als entweder die pageNumber liefern oder, falls sie kleiner als 10 ist, die pageNumber mit führender Null liefern.
Ich würde dir allerdings hier wärmstens empfehlen, das Code Design zu ändern und statt #text_page_01
, ..., #text_page_09
, #text_page_10
, ... ein #text_page_1
, #text_page_2
, ... #text_page_9
, #text_page_10
, ... zu verwenden. Die einzelne führende Null bei Zahlen unter 10 bedeutet nur Zusatzaufwand und schlechte Robustheit (was, wenn du das mal wo verwenden willst, wo es mehr als 99 Seiten gibt?). Wenn du das änderst wird dein Code noch einfacher. Zusätzlich kann man sogar einen Teil der Aktionen bei pageNumber == 2 mit in die Zusammenfassung nehmen:
var pageNumber = 1;
var previousPage = document.getElementById("previous_page");
var nextPage = document.getElementById("next_page");
var lastPage = 10; // das möchtest du vielleicht auch irgendwann dann dynamisch ermitteln
previousPage.addEventListener("click", function(){
// ganz spezielle Aktion - bleibt auf jeden Fall einzeln:
if ( pageNumber == 1 ) { return false; }
// ab hier passiert immer das Gleiche - zusammenfassen:
else if ( pageNumber >= 2 && pageNumber <= lastPage) {
// Spezialaktion für pageNumber == 2
if (pageNumber == 2) {
$("input#previous_page").hide();
$("img#previous_page-disabled").show();
}
$("#text_page_"+pageNumber).hide();
$("#text_page_"+(pageNumber-1)).fadeIn(600);
pageNumber--;
document.querySelector('#pageNumber').textContent = pageNumber;
}
});
Grüße,
RIDER
Hallo Boris Bär,
kann es sein, dass Du beim Basteln doppelten Code produziert hast? Ich finde zwei Stellen, die Click-Handler für next_page und previous_page installieren.
Du solltest deinen Script-Block zunächst einmal kapseln, um den globalen Namensraum freizuhalten. Das gilt mittlerweile als schlechter Stil. Zum Beispiel bietet JQuery die Möglichkeit, einen sogenannten Ready-Handler zu setzen - der wird ausgeführt sobald das HTML der Seite geladen ist und das DOM erzeugt wurde. Das geht so:
$.ready(function() {
// dein Code
});
Du kannst in dieser Ready-Function nun ebenso Event-Handler installieren. UND du kannst Variablen erzeugen, die nur innerhalb dieser Funktion bekannt sind. Wenn Du darin außerdem noch Event-Handler erzeugst, entsteht eine sogenannte Closure, d.h. die Eventhandler-Funktion merkt sich den Laufzeit-Kontext der übergeordneten Ready-Function und hält deine Variable damit am Leben.
Für das Verständnis des folgenden Codes diese Hinweise:
Was jetzt folgt, habe ich im Forum runtergetippt (während Du deine eigene Lösung gepostet hast) und nicht live getestet. Mag also ein paar Dibfeler enthalten. Viel Glück :)
$.ready(function() {
// Aktuelle Seite ist erstmal unbekannt
var pageNumber = -1;
// jQuery matched set für alle Seiten bilden und speichern
var $pages = $(".letter-text");
var changePage = function(newPage) {
// newPage nicht im Bereich -> nichts tun
if (newPage < 1 || newPage > $pages.length) return;
// Seite wechseln
if (pageNumber > 0)
$pages.eq(pageNumber-1).hide();
$pages.eq(newPage-1).fadeIn(600);
pageNumber = newPage;
// Navigationselemente updaten
controlNavigation("previous_page", pageNumber > 1);
controlNavigation("next_page", pageNumber < $pages.length);
};
var controlNavigation = function(id, show) {
if (show) {
$("input#"+id).show();
$("img#"+id+"-disabled").hide();
} else {
$("input#"+id).hide();
$("img#"+id+"-disabled").show();
}
};
// Eventhandler registrieren
$("#next_page").click(function() { changePage(pageNumber+1); });
$("#previous_page").click(function() { changePage(pageNumber-1); });
// Seite 1 aktivieren
changePage(1);
});
Ich glaube, mehr Code als das hier brauchst Du nicht.
Rolf
Hallo Rolf,
kann es sein, dass Du beim Basteln doppelten Code produziert hast? Ich finde zwei Stellen, die Click-Handler für next_page und previous_page installieren.
Ja, ich habe zwei Click-Handler benutzt, den einen für das normale Umblättern, den anderen, um festzulegen, bis zu welcher Seite geblättert werden kann.
$.ready(function()
{ // dein Code
});
Wenn ich mein Script damit kapsle, dann funktioniert plötzlich gar nichts mehr, keine Ahnung warum.
Für deine Anmerkungen in der Mitte fehlt mir leider einfach das grundsätzliche Verständnis für JavaScript. Das habe ich leider nur halb verstanden, tut mir leid.
Ich habe meinen Code durch deinen probeweise ausgetauscht, aber leider tut sich da dann gar nichts.
Ergibt für mich eigentlich Sinn und ich verstehe nicht, wieso es nicht funktioniert, aber leider ist es so. Hast du eine Idee woran es liegen könnte? Tippfehler habe ich keine gefunden.
Ich speise es am Ende der Seite, gleich nach dem </body>-Tag ein, dann folgt …
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
// dein obiges Script
</script>
Mehr habe ich nicht getan, sonst befindet sich auch kein anderes Script auf der Seite.
Vielen Dank und beste Grüße Boris
Ja sorry, ich sag ja: schnell zusammen getippt.
Das hier war leider Müll:
$.ready(function() {
// dein Code
});
Richtig gewesen wäre $().ready...
, aber nimm bitte das hier:
$(function() {
// dein Code
});
Grund: Die jquery-Doku sagt, dass .ready() und noch etliche weitere Varianten ab jQuery 3.0 als missbilligt gelten. Empfohlen ist nur noch das, was in der grünen Box steht. Die Kollegen bauen Altlasten ab :)
Der Rest müsste aber funktionieren; hab's jetzt schnell mal zusammen mit deinen DIVs in ein Fiddle kopiert und es hat geklappt.
Zwei Click-Handler brauchst Du meiner Meinung nach nicht, das kann alles einer lösen.
Dein Markup und die controlNavigation Funktion könnte übrigens einfacher werden, wenn Du das HTML etwas änderst - aber mein PC hier macht gerade einen unstoppbaren Countdown zum Neustart, das muss ich ein andermal schreiben.
Rolf
So, ich habe mal was gebastelt und deine Navigations-Elemente auf CSS umgestellt. Guckst Du hier:
https://jsfiddle.net/Rolf_b/9cndgm3r/1/
Das Nebeneinanderstellen von Buttons und Text habe ich per Flexbox gemacht, statt mit position und float, das kannst Du aber halten wie Du willst 😀
Guck's Dir einfach mal an.
Wenn Du die Sache mit der Closure nicht verstanden hast - keine Panik, das haben viele nicht. Es ist aber eine essenzielle Eigenschaft von Javascript - oder allgemein von funktionalen Programmierkonzepten, und eigentlich gar nicht schwer. Wenn Du Dir meine Haupt-Funktion anschaust: Die definiert Variablen pageNumber und $pages, sowie eine Funktion changePage. Innerhalb von changePage wird auf pageNumber und $pages zugegriffen. Dann wird changePage als Event-Handler registriert und DANN ENDET DER READY-HANDLER. In einer Programmiersprache ohne Closures wäre jetzt der Teufel los, weil es die Variablen nicht mehr gibt. Entweder gäbe es eine Fehlermeldung, oder das Programm würde bösartig in verlassenem und möglicherweise anderweit belegtem Speicher herumstochern. JavaScript ist anders. JavaScript bemerkt den Zugriff auf die Variable aus ihrer Umgebung, legt da ein Körbchen drumherum (die Closure) und hängt das Körbchen an die changePage Funktion. Auf diese Weise kann changePage mit Variablen eines längst verlassenen Aufruf-Kontextes weiterarbeiten und braucht keinerlei globale Variablen.
Den Rest meiner Hinweise habe ich im Codebeispiel bereits umgesetzt.
Rolf
So Rolf, habe jetzt alles nach deinem Vorbild umgesetzt und es ist einfach genial! Es ist sehr elegant und funktioniert wirklich ausgezeichnet! Tausend Dank!!! 👌
Kann man sich hier live anschauen: http://www.brsbaer.de/bibliothek/vvardenfell/flugblatt-des-paktes-herzlichen-glueckwunsch/
@@borisbaer
So Rolf, habe jetzt alles nach deinem Vorbild umgesetzt und es ist einfach genial!
Nein, von Genialität ist das noch ein Stück weit entfernt. Aber ein machbares Stück:
Es ist sehr elegant und funktioniert wirklich ausgezeichnet!
Außer dass es nicht funktioniert.
Zum einen haben die Buttons keine Beschriftung
Zum anderen ist bei Tastaturnavigation nicht erkennbar, wenn ein Button den Fokus hat. Ändere die Farbe nicht nur bei :hover
, sondern auch bei :focus
!
LLAP 🖖
@@Rolf b
Guckst Du hier:
Die fehlende Verlinkung hab ich mal für dich berichtigt.
Dann guck ich mal:
<button type="button" ></button>
Aua! Sowas sollte in keinem Beispielcode stehen!
Gib den Buttons bitte unbedingt noch eine Beschriftung!
<button type="button">vorige Seite</button>
und <button type="button">nächste Seite</button>
Die Beschriftung kannst du visuell verstecken, sie muss aber vorhanden sein.
LLAP 🖖
Hallo Gunnar Bittersmann,
Die Beschriftung kannst du visuell verstecken
Wobei ich das als Hilfestellung problematisch finde:
.visually-hidden { /*https://developer.yahoo.com/blogs/ydn/clip-hidden-content-better-accessibility-53456.html*/
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
padding:0 !important;
border:0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
body:hover .visually-hidden a,
body:hover .visually-hidden input,
body:hover .visually-hidden button {
display: none !important;
}
display: none;
versteckt auch vor Screenreadernbody
kann auch deutlich kleiner als der Viewport werden.Ich muss gestehen, dass ich den Sinn so nicht verstehe.
Bis demnächst
Matthias
@@Matthias Apsel
Die Beschriftung kannst du visuell verstecken
Wobei ich das als Hilfestellung problematisch finde:
.visually-hidden { /*https://developer.yahoo.com/blogs/ydn/clip-hidden-content-better-accessibility-53456.html*/ position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); padding:0 !important; border:0 !important; height: 1px !important; width: 1px !important; overflow: hidden; } body:hover .visually-hidden a, body:hover .visually-hidden input, body:hover .visually-hidden button { display: none !important; }
- die vielen importants sollten nicht notwendig sein
Doch, sind sie.
Beispiel: <foo class="bar visually-hidden">
mit foo.bar { position: relative }
Die Regel für einen spezifischeren Selektor soll ja überschrieben werden.
Vermutlich wurde !important
bei clip
und overflow
vergessen.
display: none;
versteckt auch vor Screenreadern
Soll auch. “The idea is to rely on the pseudo-class :hover to remove all focusable elements in the hidden container from the tabbing sequence.” (unter Tabbing Navigation)
- warum muss ein übergeordnetes Element (welches?) visuell versteckt werden?
Was meinst du damit?
body
kann auch deutlich kleiner als der Viewport werden.
Hm, ja. Das sollte wohl besser html:hover
heißen.
Ich muss gestehen, dass ich den Sinn so nicht verstehe.
LLAP 🖖
Danke für die Hinweise, Gunnar!
Reicht es, wenn ich in der CSS-Datei folgenden Code hinzufüge?
#next_page button:focus {
background-image: url('images/library/next_page-hover.png');
}
#previous_page button:focus {
background-image: url('images/library/previous_page-hover.png');
}
Den Buttons habe ich Text beigefügt, soll ich den Text einfach durch span style=display:hidden oder so verstecken? Gibt es eine elegantere Methode?
@@Boris Bär
Reicht es, wenn ich in der CSS-Datei folgenden Code hinzufüge?
#next_page button:focus { background-image: url('images/library/next_page-hover.png'); } #previous_page button:focus { background-image: url('images/library/previous_page-hover.png'); }
DRY! (Don’t repeat yourself!)
DU hast schon entsprechende Regeln für den :hover
-Status. In diesen die Selektoren für :focus
hinzufügen (wenn denn dasselbe passieren sool):
#next_page button:hover,
#next_page button:focus {
background-image: url('images/library/next_page-hover.png');
}
#previous_page button:hover,
#previous_page button:focus {
background-image: url('images/library/previous_page-hover.png');
}
Den Buttons habe ich Text beigefügt, soll ich den Text einfach durch span style=display:hidden oder so verstecken?
Nein. Damit würdest du den Text auch vor denen verstecken, die ihn nötig haben – Screenreader.
Gibt es eine elegantere Methode?
Die Beschriftung in ein <span class="visually-hidden">
packen und den gezeigten CSS-Code für die Klasse visually-hidden
übernehmen. ☞ CodePen
LLAP 🖖
Oha, hab's grad nochmal aufgerufen, scheinbar bastelst Du gerade arg herum 😀
Ich hatte nicht den Anspruch, eine rundum perfekten Vorlage zu liefern. Mein Fokus war die Verbesserung des Javascript-Teils.
Mit dem Button-Text bin ich mir noch uneins. Es gibt zwei Szenarien, wo der Text relevant ist: Screen-Reader, und ein fehlerhaft übertragenes Bild. Für Fall 2 wäre visually-hidden nicht passend.
Eine schöne Lösung dafür will mir gerade nicht einfallen. Oder gilt Fall 2 als irrelevant?
Rolf
@@Rolf b
Oha, hab's grad nochmal aufgerufen, scheinbar bastelst Du gerade arg herum 😀
?? Mit „du“ meinst du Boris?
Ich hatte nicht den Anspruch, eine rundum perfekten Vorlage zu liefern. Mein Fokus war die Verbesserung des Javascript-Teils.
Das JavaScript kann noch so gut sein – wenn das zugrundeliegende HTML zu Unbenutzbarkeit führt, dann taugt das Beispiel nichts.
Mit dem Button-Text bin ich mir noch uneins. Es gibt zwei Szenarien, wo der Text relevant ist: Screen-Reader, und ein fehlerhaft übertragenes Bild. Für Fall 2 wäre visually-hidden nicht passend. […] Oder gilt Fall 2 als irrelevant?
Gut, dass du den Fall erwähnst.
Eine schöne Lösung dafür will mir gerade nicht einfallen.
Sowas in der Art? (CodePen)
<button aria-label="vorige Seite">
<img src="…" alt="◀︎"/>
</button>
oder
<button>
<img src="…" alt="◀︎" aria-hidden="true"/>
<span class="visually-hidden">vorige Seite</span>
</button>
LLAP 🖖
@@Gunnar Bittersmann
Sowas in der Art? (CodePen)
Hm, Eric Eggert meint: „Das ist eine komplizierte Lösung für ein Nicht-Problem, IMHO.“
LLAP 🖖
Ja, mit dem Basteln meinte ich Boris. Und - wow, du hast Dich ja richtig reingehängt.
Eric hat natürlich recht - das wird eher selten passieren. Ich finde deine Idee mit img und Unicode-Symbol im alt aber recht charmant und nicht unnötig kompliziert.
Rolf
@@Rolf b
Eric hat natürlich recht - das wird eher selten passieren.
Wenn ein Entwickler „das wird eher selten passieren“ sagt, ist das ein sicheres Indiz für einen Bug im System.
LLAP 🖖
Nö. In dieser Allgemeinheit kann ich das nicht stehen lassen, das geht mir gegen die Entwickler-Ehre 😀
"System" ist hier etwas größer, wir reden ja von dem Szenario, dass ein Bild nicht beim Client ankommt. Da beginnt das System auf der Festplatte des Servers und endet im Brauser des Empfängers. Dazwischen liegen viele viele Hops, und ob von denen einer Haps macht, kann ich als Entwickler nicht beeinflussen.
Rolf
@@Rolf b
Nö. In dieser Allgemeinheit kann ich das nicht stehen lassen, das geht mir gegen die Entwickler-Ehre 😀
"System" ist hier etwas größer, wir reden ja von dem Szenario, dass ein Bild nicht beim Client ankommt. Da beginnt das System auf der Festplatte des Servers und endet im Brauser des Empfängers. Dazwischen liegen viele viele Hops, und ob von denen einer Haps macht, kann ich als Entwickler nicht beeinflussen.
Ähm, genau darum geht es doch hier: nicht zu sagen „das ist so unwahrscheinlich, dass einer Haps macht, das wird schon nicht passieren“, sondern genau darauf vorbereitet zu sein und das System so zu entwickeln, dass es auch dann noch funktioniert, wenn doch mal einer Haps macht.
LLAP 🖖
@@Rolf b
Eric hat natürlich recht - das wird eher selten passieren.
Womit Eric sicher recht hat, ist SVG zu verwenden.
LLAP 🖖
Habe alles so umgesetzt! Vielen Dank für die Hilfe! 👍
Hallo Gunnar Bittersmann,
- die vielen importants sollten nicht notwendig sein
Doch, sind sie.
Beispiel:
<foo class="bar visually-hidden">
mitfoo.bar { position: relative }
Die Regel für einen spezifischeren Selektor soll ja überschrieben werden.Vermutlich wurde
!important
beiclip
undoverflow
vergessen.
Nun ja, wir wollen ja kein weltweit gültiges Stylesheet schreiben, aber ok. 😉
display: none;
versteckt auch vor ScreenreadernSoll auch. “The idea is to rely on the pseudo-class :hover to remove all focusable elements in the hidden container from the tabbing sequence.” (unter Tabbing Navigation)
- warum muss ein übergeordnetes Element (welches?) visuell versteckt werden?
Was meinst du damit?
Der Selektor heißt (verkürzt) .visually-hidden button
. Warum sollte ich, wenn ich einen Button verstecken möchte, diesen in ein Element packen, das visuell versteckt ist?
Bis demnächst
Matthias
@@Matthias Apsel
Der Selektor heißt (verkürzt)
.visually-hidden button
. Warum sollte ich, wenn ich einen Button verstecken möchte, diesen in ein Element packen, das visuell versteckt ist?
Nein, andersrum. Du willst einen Button (Link etc.) nicht anzeigen/ausgeben/in der Tab-Reihenfolge haben, der sich in einem visuell versteckten Element befindet.
LLAP 🖖
Hallo Gunnar Bittersmann,
html:hover .visually-hidden button {display: none;}
Nein, andersrum. Du willst einen Button (Link etc.) nicht anzeigen/ausgeben/in der Tab-Reihenfolge haben, der sich in einem visuell versteckten Element befindet.
Bis demnächst
Matthias
@@Matthias Apsel
- Man kann auch durch die (visuell sichtbaren) Elemente tabben ohne dass sich der Mauszeiger über dem Dokument befinden muss.
Hier geht’s darum, dass man nicht durch die visuell nicht sichtbaren tabben soll.
- Aktuelle Browser scheinen das nicht zu benötigen. (FF, Chr, IE11, Edge; Win10)
Das schrub @A11YProject ja: “It's a very old hack, but that bit is for sighted users.”
Die Regel richtet keinen Schaden an. Aber wenn der Hack nur für Browser nötig ist, die langst niemand™ mehr benutzt, dann kann das weg.
LLAP 🖖
Hallo Gunnar Bittersmann,
- Man kann auch durch die (visuell sichtbaren) Elemente tabben ohne dass sich der Mauszeiger über dem Dokument befinden muss.
Hier geht’s darum, dass man nicht durch die visuell nicht sichtbaren tabben soll.
Ja schon klar.
Aber man kann auch tabben ohne das :hover
greift.
Bis demnächst
Matthias
Mensch! Jetzt funktioniert alles tadellos!
Vielen, vielen Dank, Rolf! Du hast mir sehr geholfen.
Wenn Du die Sache mit der Closure nicht verstanden hast - keine Panik, das haben viele nicht. Es ist aber eine essenzielle Eigenschaft von Javascript - oder allgemein von funktionalen Programmierkonzepten, und eigentlich gar nicht schwer. Wenn Du Dir meine Haupt-Funktion anschaust: Die definiert Variablen pageNumber und $pages, sowie eine Funktion changePage. Innerhalb von changePage wird auf pageNumber und $pages zugegriffen. Dann wird changePage als Event-Handler registriert und DANN ENDET DER READY-HANDLER. In einer Programmiersprache ohne Closures wäre jetzt der Teufel los, weil es die Variablen nicht mehr gibt. Entweder gäbe es eine Fehlermeldung, oder das Programm würde bösartig in verlassenem und möglicherweise anderweit belegtem Speicher herumstochern. JavaScript ist anders. JavaScript bemerkt den Zugriff auf die Variable aus ihrer Umgebung, legt da ein Körbchen drumherum (die Closure) und hängt das Körbchen an die changePage Funktion. Auf diese Weise kann changePage mit Variablen eines längst verlassenen Aufruf-Kontextes weiterarbeiten und braucht keinerlei globale Variablen.
Ah, ja okay, so etwas in der Art hatte ich mir schon gedacht. Danke, dass du es nochmal erklärt hast! 👍
Das Klick-Event habe ich noch ergänzt mit dem Code von 1unitedpower, damit auch die Seitenzählung unten funktioniert.
$("#next_page").click(function() {
changePage(pageNumber+1);
document.querySelector('#pageNumber').textContent = pageNumber;
});
$("#previous_page").click(function() {
changePage(pageNumber-1);
document.querySelector('#pageNumber').textContent = pageNumber;
});
Problem gelöst! Auf zum nächsten! Vielen Dank für die Mühe! 🌝
Hallo Boris,
Problem gelöst! Auf zum nächsten! Vielen Dank für die Mühe!
*nur zur Info Ich weiß nicht ob deine Seite jetzt eine Testseite ist oder schon das endgültige Layout. Daher für dich mal sicherheitshalber einen Screenshot wie es im IE11 aussieht.
Gruss
Henry