borisbaer: JavaScript: Toggle für verschiedene Elemente

problematische Seite

Hallo alle zusammen!

Ich bin’s wieder und dieses Mal stehe ich vor einem wie ich glaube vergleichsweise leicht zu lösenden Problem. Am besten erklärt es sich, wenn man diese Seite aufruft:

http://eso.tamriel-hero.com/quests/hauptgeschichte/gesprengte-ketten/

Ich möchte den Inhalt unter „Konversationen“ anzeigen lassen, wenn man darauf klickt. Kann mir jemand verraten, wie ich conv-stage-1, conv-stage-2 … usw. mit dem onClick-Befehl assoziieren kann, damit derselbe Button („Konversationen“) immer nur den darunter liegenden Content ein- bzw. ausblendet?

Vielen Dank schon mal und beste Grüße

Boris

  1. problematische Seite

    Servus!

    Ich möchte den Inhalt unter „Konversationen“ anzeigen lassen, wenn man darauf klickt. Kann mir jemand verraten, wie ich conv-stage-1, conv-stage-2 … usw. mit dem onClick-Befehl assoziieren kann, damit derselbe Button („Konversationen“) immer nur den darunter liegenden Content ein- bzw. ausblendet?

    Mit toggle hast du schon das passende Stichwort geliefert:

    Herzliche Grüße

    Matthias Scharwies

    --
    Es gibt viel zu tun: ToDo-Liste
    1. problematische Seite

      Vielen Dank, aber bei dem Beispiel sind bei z.B. 30 Schritten auch 30 verschiedene Variablen zu erstellen. Ich dachte, es gäbe evtl. eine Möglichkeit, das zu umgehen.

    2. problematische Seite

      @@Matthias Scharwies

      Mit toggle hast du schon das passende Stichwort geliefert:

      Ach, wirklich? Ist nicht schon JavaScript das unpassende Stichwort?

      HTML: details/summary

      Look Ma, no JavaScript!

      LLAP 🖖

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

        details/summary Tag:

        • MDN: Dies ist eine experimentelle Technologie.
        • caniuse.com: Keine IE oder Edge Unterstützung. Insgesamt 88% globale Unterstützung, 83% in Deutschland.

        Wenn das für dich ok ist, wäre das vermutlich genau das Richtige für dich.

        Mit Javascript+jQuery und ohne Variablen-Schwemme würde ich das so machen (Die JQuery API Doku kennst Du?)

        • Jeden Schritt in einen Container legen. Dieser Container bekommt eine eigene Klasse. Das hast Du schon: div class="qp-container". Gerne darfst Du dafür auch das section-Element verwenden.
        • Den Click-Handler für die Buttons mit jQuery registrieren. Das musst Du nicht für jeden Button einzeln von Hand machen, jQuery kann das besser.

        Möglichkeit 1:

        $(".qp-container button").on("click", function() {...})
        

        Damit registrierst Du einen Click-Handler pro Button in einem qp-container. D.h. bei 17 Schritten mit je 4 Konversationen registrierst Du 68 Eventhandler, und vor allem muss jQuery das ganze DOM nach diesem Selektor durchflöhen. Das dauert ggf. etwas. Innerhalb der Handler-Funktion bezieht this sich auf diesen Button.

        Wie Du von dort aus zu den Konversationselementen kommst, hängt von deiner HTML Struktur ab. Wenn der Button und die Konversationselemente Geschwisterknoten sind, d.h. das gleiche direkte Parent-Element haben, kannst Du mit

        $(this).nextAll(".qp-conversations")

        arbeiten (ich unterstelle mal, dass Du die Konversationen mit einer Klasse qp-conversations identifizierst). Ist diese direkte Verwandschaft nicht gegeben, musst Du zuerst zu einem gemeinsamen Elternteil hoch und von da aus wieder hinab:

        $(this).parent(".qp-container").find(".qp-conversations")

        würde funktionieren. Daran hängst Du noch ein .toggleClass("visible") oder ähnlich an und sorgst per CSS dafür, dass die Elemente nur sichtbar sind wenn sie die visible-Klasse haben. Das hat gegenüber show/hide den Vorteil, dass Du nicht wissen musst, ob sie gerade sichtbar sind oder nicht.

        Möglichkeit 2: Du legst um alle Schritte noch einen weiteren Container, am besten mit einer ID. Hier nehme ich mal die ID "conversations". Dann kannst Du mit delegierten Events arbeiten.

        $("#conversations").on("click", ".qp-container button", function() {...})
        

        Diese Methode muss nur ein Element finden und registriert nur einen einzigen Event-Handler, nicht einen pro Button. Sie nutzt aus, dass Ereignisse "nach oben blubbern", d.h. wenn Du den Button klickst, werden der Reihe nach der Button und dann seine Eltern-Elemente vom Klick benachrichtigt. Der zweite Parameter von on ist ein Filter, er sorgt dafür, dass nur click-Events von button-Elementen in einem Element mit Klasse .gp-container verarbeitet werden. D.h. die Zeit, die Du beim Registrieren sparst, geht beim Filtern der Events wieder drauf. Unterm Strich solltest Du damit aber günstiger fahren. Auch hier bezieht sich in der Handler-Funktion this wieder auf das geklickte Element, und du kannst wie oben die Konversationen suchen.

        Details zur Event-Registrierung mit jQuery stehen hier.

        Rolf

        1. problematische Seite

          @@Rolf b

          details/summary Tag:

          • MDN: Dies ist eine experimentelle Technologie.
          • caniuse.com: Keine IE oder Edge Unterstützung. Insgesamt 88% globale Unterstützung, 83% in Deutschland.

          Wenn das für dich ok ist

          Das ist OK. Wie ich schon schrieb, funktioniert das ja auch in IE und Edge. Progressive enhancement at work.

          … Daran hängst Du noch ein .toggleClass("visible") oder ähnlich an und sorgst per CSS dafür, dass die Elemente nur sichtbar sind wenn sie die visible-Klasse haben.

          Und wo ist die Kennzeichnung am Button, ob das nun gerade auf- oder zugeklappt ist?

          Möglichkeit 2: Du legst um alle Schritte noch einen weiteren Container

          Wozu das denn? Reichen die die ohnehin schon vorhandenen Container (html, body, ggfs. main) nicht aus?

          LLAP 🖖

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

            Und wo ist die Kennzeichnung am Button, ob das nun gerade auf- oder zugeklappt ist?

            Ok - wenn man die haben möchte kann man sie ja noch realisieren. Abgesehen davon, dass das von Dir vorgeschlagene aria-Attribut eine elegantere Lösung darstellen kann.

            Möglichkeit 2: Du legst um alle Schritte noch einen weiteren Container

            Wozu das denn? Reichen die die ohnehin schon vorhandenen Container (html, body, ggfs. main) nicht aus?

            Möglichkeit 2 beschreibt die Idee der event delegation. Dazu braucht man einen geeigneten Deckel, der die Blubberbläschen von den gewünschten Elementen einfängt. Den Deckel sollte man nicht zu groß machen; ohne einen Extracontainer müsste Henry den click Handler bei div#c51 oder div#content-standard registrieren. Damit schlägt dann jeder Klick in die Seite im Handler auf, das kann langsam werden wenn man mehrere Handler hat. Auf einem Core-i7 oder A10 Prozessor mag das egal sein, aber ein Ein-Watt Öfchen mit seinen 8 Transistoren könnte einknicken.

            Rolf

    3. problematische Seite

      1. problematische Seite

        @@Henry

        oder alternativ eine CSS-Lösung.
        Beispiel: http://www.olivergast.de/blog/2013/04/16/css3-der-checkbox-hack/

        Nein, ein Checkbox-Hack ist keine Lösung. Das würde einiges dazugehören, um das für alle nutzbar (also barrierefrei) zu machen: die Kombination Checkbox/Label müsste sich verhalten wie ein Button (inclusive Tastaturbedienung), die Rolle müsste explizit angegeben und dem Nutzer mitgeteilt werden. Viel zu viel Aufwand, viel zu viel notwendiges Wissen, über das die meisten (leider!) (noch?) nicht verfügen.

        Das von dir verlinkte Beispiel ist besonders schlecht umgesetzt. Mit Tastatur funktioniert gar nichts. Mal nachgeschaut: input[type="checkbox"] { display: none } – das kann ja so nicht funktionieren. Nicht nachmachen, Kinder! Ein interaktives Element darf niemals mit display: none versteckt werden. Es darf visuell versteckt werden, nicht mehr und nicht weniger.

        LLAP 🖖

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

      @@Matthias Scharwies

      Das Beispiel zeigt, wie man Boxen größer und kleiner macht; aber nicht, wie man Inhalte ein- und ausblendet.

      LLAP 🖖

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

        @@Gunnar Bittersmann

        Das Beispiel zeigt, wie man Boxen größer und kleiner macht; aber nicht, wie man Inhalte ein- und ausblendet.

        Abgesehen davon, dass das Beispiel hier unpassend und allgemein etwas sinnfrei ist, ist es auch etwas kaputt: Der Button ändert seine Beschriftung von „mehr …“ auf „weniger“, aber nicht wieder zurück.

        Zu Änderungen von Buttonbeschriftungen siehe auch Changing labels im Inclusive-Components-Artikel Toggle Buttons.

        LLAP 🖖

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

    Was haltet ihr davon? https://www.w3schools.com/w3js/w3js_toggle_show.asp

    Funktioniert zumindest so wie ich es mir vorgestellt habe!

    1. problematische Seite

      @@borisbaer

      Was haltet ihr davon? https://www.w3schools.com/w3js/w3js_toggle_show.asp

      Abstand.

      Funktioniert zumindest so wie ich es mir vorgestellt habe!

      Das tut reines HTML auch. Wozu also JavaScript?

      Und wenn du doch eine Lösung mit Button und JavaScript willst, dann schau dir mal dieses Menü bei schmalem Viewport an. Das einzige, was JavaScript tut, ist den Wert des aria-expanded-Attributs des Buttons(!) zwischen true und false umzuschalten. Mehr sollte JavaScript nicht tun; den Rest erledigt CSS. Bei Wunsch auch animierte Übergänge mit transition.

      LLAP 🖖

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

        Hallo,

        Das tut reines HTML auch. Wozu also JavaScript?

        damits auch im IE/EDGE klappt? ;-)

        Gruss
        Henry

        1. problematische Seite

          @@Henry

          Das tut reines HTML auch. Wozu also JavaScript?

          damits auch im IE/EDGE klappt? ;-)

          Na wenn’s denn klappen soll. Funktionieren tut’s im IE auch mit details/summary.

          LLAP 🖖

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

            Jetzt übertreibst Du aber. Wenn "funktionieren" sich für dich nur noch auf a11y bezieht, dann siehst Du es doch etwas eng.

            IE/Edge zeigen den Text konstant an. Das ist nicht das, was "funktionieren" meint - im Sinne von "die von Henry gewünschte Usability". Okay, u7y hat eine kleinere Zahl als a11y, ist aber deshalb nicht unwichtiger.

            Die aria-expanded Lösung ist dagegen sehr elegant. Kannte ich nicht (aria ist für mich bis immer noch was Gesungenes), hätte ich aber in meinem Vorschlag auch mit einer Klasse am Button realisieren können. Das setzt nur voraus, dass die Konversationen vom Button aus per + Kombinator erreichbar sind. Wenn das so ist - sehr schön, hab ich wieder einen Trick mehr gelernt :)

            Rolf

            1. problematische Seite

              @@Rolf b

              IE/Edge zeigen den Text konstant an. Das ist nicht das, was "funktionieren" meint

              Doch. „Funktionieren“ meint: alle Nutzer kommen an alle Inhalte.

              im Sinne von "die von Henry gewünschte Usability".

              Progressive enhancement in den Browsern, die das unterstützen.

              Die Frage ist: Ist das Ein-/Ausklappen wirklich notwendig? Werden Nutzer ohne Ein-/Ausklapp-Effekt sonst mit der schieren Flut von Informationen überfrachtet?

              Wenn dem so sein sollte, wäre zu überlegen, ob die Information wirklich auf die Seite gehört oder nicht doch Links auf separate Seiten sinnvoll wären – auch das mit progressive enhancement: die Standardfunktion der Links werden unterdrückt und die zusätzlichen Inhalte werden per fetch() (oder AJAX) geholt und in die Seite eingebaut.

              aria ist für mich bis immer noch was Gesungenes

              ARIA serious? Gehe zu ID24.

              hätte ich aber in meinem Vorschlag auch mit einer Klasse am Button realisieren können.

              Eine Klasse ist für assitive Technologien wertlos.

              LLAP 🖖

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

        Abstand.

        Wieso?

        Das tut reines HTML auch. Wozu also JavaScript?

        Ich nehme gerne HTML, aber nur, wenn ich das „Design“ beibehalten kann. Sprich, das Dreieck müsste weg und ich müsste selbst bestimmen können, welcher Button den Inhalt ausklappt. Ich weiß nicht, ob das mit dem details tag geht.

        Und wenn du doch eine Lösung mit Button und JavaScript willst, dann schau dir mal dieses Menü bei schmalem Viewport an. Das einzige, was JavaScript tut, ist den Wert des aria-expanded-Attributs des Buttons(!) zwischen true und false umzuschalten. Mehr sollte JavaScript nicht tun; den Rest erledigt CSS. Bei Wunsch auch animierte Übergänge mit transition.

        Leider bin ich in JavaScript eigentlich gar bewandert, meine Versuche aus der Seite schlau zu werden sind bisher gescheitert. Wo kann ich denn das Ganze mit eienr ID verknüpfen? Hmm …

        Trotzdem danke soweit für die vielen Vorschläge!