Duffy Sack: toggle Menü Katastrophe

Ja, also hallo erst mal.

Ich würde gerne etwas wie auf http://orf.at kreieren...

Klickt man da auf einen Link, so wird der dazugehörige Artikel direkt in die Seite geladen und klappt als Toggle-Menü auf.
Das habe ich versucht zu rekonstruieren, wenn auch wenig erfolgreich:

  
<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title>Toggle Toggle</title>  
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">  
</script>  
<script>  
$(document).ready(function(){  
  $("#toggle").click(function(){  
  	$("#switch").load("test.txt");  
    $("#switch").toggleClass("sichtbar");  
  });  
});  
</script>  
<style>  
.unsichtbar  
{  
display: none;  
}  
.sichtbar  
{  
display: block;  
}  
</style>  
</head>  
  
<body>  
<p><a href="" id="toggle">(Nicht) Anzeigen</a></p>  
<p id="switch" class="unsichtbar">Ich bin da ich bin weg</p>  
<p>Ich bin immer da</p>  
</body>  
  
</html>  

Das Resultat ist ein Link, dessen "Inhalt" nur kurz aufblitzt um gleich wieder zu verschwinden; das Laden von externem Content ("test.txt")
 funktioniert hingegen überhaupt nicht.

Bitte keine Verweise auf völlig andere Lösungen, da ich ja gerne nachvollziehen würde, was genau ich hier falsch mache.

Darüber hinaus wäre es natürlich erstrebenswert, wenn sich ein angezeigter Artikel mit dem Öffnen eines weiteren Artikels wieder schließt, wie es auf orf.at der Fall ist. Wie ließe sich dies bewerkstelligen?

Vielen Dank,
D.D.

  1. Moin!

    Richtige Reihenfolge beim Lernen:

    1. HTML
    2. CSS
    3. Javascript
    erst 4. Bibliotheken wie jquery

    1.) Dies hier tut was du willst und ist sehr viel kleiner und durchschaubarer:

      
    <!DOCTYPE html>  
      <html>  
        <head>  
          <meta charset="UTF-8">  
          <title>Toggle Toggle</title>  
          <script type="text/javascript">  
          function toggleDisplay(element) {  
    	    object=document.getElementById(element);  
    	    if (object.style.display=='block') {  
    		object.style.display='none';  
    	    } else {  
    		object.style.display='block';  
    	    }  
    	  }  
          </script>  
          <style>  
    	  .unsichtbar  
    	  {  
    	  display: none;  
    	  }  
    	  .sichtbar  
    	  {  
    	  display: block;  
    	  }  
          </style>  
      </head>  
      <body>  
    	<p><a href="javascript:toggleDisplay('switch')">(Nicht) Anzeigen</a></p>  
    	<p id="switch" class="unsichtbar">Ich bin da ich bin weg</p>  
    	<p>Ich bin immer da</p>  
      </body>  
    </html>  
    
    

    2. Dies hier tut auch in etwa was Du willst, geht aber sogar ganz ohne Javascript:

    <!DOCTYPE html>  
    <html>  
    <head>  
    <style type="text/css">  
    .sitepart {  
       display:none;  
       height:0;  
       overflow:hidden;  
       transition: height 1s;  
      
    }  
    .sitepart:target {  
        display:block;  
        height:300px;  
    }  
    </style>  
    </head>  
    <body>  
    <nav>  
    <ul>  
    <li><a href="#seite1">Seite 1</a></li>  
    <li><a href="#seite2">Seite 2</a></li>  
    </ul>  
    </nav>  
    <article class="sitepart" id="seite1">  
    <h1>Seite 1</h1>  
    <p>Lorem ipsum dolor sit amet. </p>  
    <a href="#">(ausblenden)</a>  
    </article>  
      
    <article class="sitepart" id="seite2">  
    <h1>Seite 2</h1>  
    <p>At vero eos et accusam et justo duo dolores et ea rebum.</p>  
    <a href="#">(ausblenden)</a>  
    </article>  
      
    </body>  
    </html>
    
    1. Hallo Jörg Reinholz,

      vielen Dank für die Antwort!

      Das Problem, das ich jetzt allerdings habe, ist die Integration externen Contents [Im ursprünglichen Beispiel ein fiktives Textdokument "test.txt"]. Dafür bräuchte ich dann wiederum doch javascript, steckt ja bereits im Namen AJAX :)

      Dies müsste sich meiner Meinung nach irgendwie mittels genereller "load() in parent_div" Angabe im js-Skript (Mir ist schon klar, dass parent_div kein authentisches Code-Segment darstellt, ich versuche nur, meinen Gedankengang diesbezüglich zu konstruieren) bewerkstelligen lassen, die effektiv nachzuladende URL müsste natürlich im body selbst [ <a href=""> ] angegeben werden. (Wie) lässt sich dies mit der bereits "besetzten" Link-Funktion [ javascript:toggleDisplay('switch') ] kombinieren?

      Danke,
      D.D.

    2. Hallo!

      Richtige Reihenfolge beim Lernen:

      Darüber streiten die Gelehrten. Die wenigsten heutzutage kennen Low-Level-DOM-Grundlagen, und das halte ich auch nicht für schlimm. Bei deren Anwendung kann man nämlich weitaus mehr falsch machen als bei der Anwendung von jQuery und Co.

      function toggleDisplay(element) {
          object=document.getElementById(element);
          if (object.style.display=='block') {
      object.style.display='none';
          } else {
      object.style.display='block';
          }
        }

      Wenn man so etwas in reinem JavaScript schreibt, braucht man eine Menge an Wissen und muss viele Annahmen machen, um einfachen Code zu schreiben:

      Es muss sich hier um Blockelemente handeln. Wenn das Element standardmäßig sichtbar ist, muss es den Inline-Style style="display: block" haben, sonst ergibt .style.display == 'block' nämlich false. Das Auslesen von CSS-Eigenschaften geht anders. Diese Funktion eignet sich also nicht zum beliebigen Togglen, sondern zum Einblenden und *anschließenden* Ausblenden.

      Es hat schon seine Gründe, warum die show-, hide- und toggle-Methoden von jQuery ziemliche Monster sind. Über die Einschränkungen und Fallstricke beim Zeigen und Verstecken von Elementen könnte man einen ganzen Aufsatz schreiben.

      <style>
        .unsichtbar
        {
        display: none;
        }
        .sichtbar
        {
        display: block;
        }
            </style>

      Hier arbeitest du mit Klassen, warum beim Togglen hingegen mit Inline-Styles. Vieles spricht dafür, Styles wenn möglich konsequent per Stylesheet zu setzen und nur Klassen oder andere Flags zu ändern, die dafür sorgen, dass andere Stylesheet-Regeln angewandt werden.

      <p><a href="javascript:toggleDisplay('switch')">(Nicht) Anzeigen</a></p>

      Das ist ein Rückschritt gegenüber dem Workflow mit jQuery. <a href="javascript:…"> sollte man nicht verwenden, sondern HTML und JavaScript sauber trennen – Stichwort Unobtrusive JavaScript – und Event-Handler im JavaScript registrieren. Dabei hilft einem jQuery hervorragend.

      Einige würden noch einwenden, dass das kein echter Hyperkink ist, wenn das href-Attribut nicht sinnvoll gefüllt ist und nur JavaScript-Event-Handler existieren. Das sehe ich nicht so streng, aber es wirft die wichtige Frage auf, was passiert, wenn JavaScript nicht verfügbar ist: Die Inhalte bleiben in diesem Fall für immer unsichtbar.

      1. Dies hier tut auch in etwa was Du willst, geht aber sogar ganz ohne Javascript:

      .sitepart {
         display:none;
         height:0;
         overflow:hidden;
         transition: height 1s;

      }
      .sitepart:target {
          display:block;
          height:300px;
      }

      Das ist elegant, geht aber wieder von einigen Vorannahmen aus. Es ist eine Lösung für einen sehr speziellen Fall: Das Element ist nur sichtbar, wenn gerade der Anker in der URL darauf zeigt. Es wird nicht dauerhaft eingeblendet. Aktiviert der Nutzer einen anderen Anker, so verschwindet das Element wieder. Das kann gewünscht sein, hat aber nichts mit einem generischen Ein- und Ausblenden auf Knopfdruck zu tun.

      Hinzu kommt, dass mit einem festen height-Wert gearbeitet werden muss, damit die Transition funktioniert. Das heißt, wenn sich der Inhalt ändert, muss auch das CSS angepasst werden, sonst wird der Inhalt u.U. abgeschnitten. Das würde ich als Albtraum für die Wartbarkeit bezeichnen.

      Ferner funktioniert :target nicht in IE < 9 funktioniert. In diesen Browsern ist der Inhalt komplett unzugänglich.

      Schließlich lässt sich anmerken, dass display: none Inhalte in einer Weise versteckt, sodass sie für Screenreader unzugänglich sind. Nutzt man eine zugängliche Methode, wird eine Animation gleich viel komplizierter.

      Was ich damit sagen will: Es hat schon seine Gründe, warum Bibliotheken wie jQuery verwendet werden. Sie lösen nicht alle Probleme und man muss immer noch selbst gewisse Fälle abdecken, aber sie vereinfachen vieles und setzen verschiedene Best Practices um. »Das geht auch einfach mit ein paar Zeilen CSS« ist zwar korrekt, verschweigt aber die Einschränkungen und Vorannahmen dieser vermeintlich einfachen Lösungen.

      Grüße,
      Mathias

      1. Hallo Mathias,

        als jemand, der im Bildungswesen arbeitet, vertrete ich natürlich die Meinung, dass Grundlagenwissen wichtig ist. Natürlich bieten Bibliotheken wie jQuery Webseitenerstellern mit wenig Ahnung die Möglichkeit, mit wenig Aufwand ganz tolle Effekte zu realisieren.

        Ich sehe da aber u.A. zwei Probleme:
        Hier im Forum schlagen oft Leute auf, die in ihre Seiten mehrere Effekte eingebaut haben und sich wundern, dass es "nicht funktioniert". Blickt man dann in den Quelltext, sieht man, das sie mehrere Bibliotheken eingebunden haben, teilweise sogar mehrere Versionen von jQuery oder sogar die gleiche zweimal. Ein klarer Fall von fehlendem Grundlagenwissen.

        Bibliotheken müssen, wie du geschrieben hast, alle Eventualitäten abdecken. Das erfordert einen recht großen Aufwand für der Browser, Informationen zu ermitteln, die der Seitenersteller eigentlich weiß. Wenn ich z.B. mittels $-Funktion ein Element anspreche, ist es toll, dass die Selection-Engine selbst ermittelt, ob der Parameter eine ID, ein Name, ein Tagname, ein Classname etc. ist. Toll. Der Seitenersteller sollte dieses auch wissen. So muss der Browser jedes mal ermitteln, was bei der Seitenerstellung eigentlich schon bekannt ist. Aber das scheint in der SW-Entwicklung inzwischen normal zu sein: Zeiteinsparung beim Programmierer zu lasten der CPU-Zeit beim User.

        Wer sich professionell oder als ambitionierter Amateur im WWW-Geschäft bewegt, sollte meiner Meinung nach neben den Bibliotheken unbedingt auch die Grundlagen kennen. Sonst bewegt man sich auf verdammt dünnen Eis.

        Gruß, Jürgen

        1. @@JürgenB:

          nuqneH

          Aber das scheint in der SW-Entwicklung inzwischen normal zu sein: Zeiteinsparung beim Programmierer zu lasten der CPU-Zeit beim User.

          Das war es schon immer. Sonst würden wir alle in Assemblersprache programmieren.

          Wer sich professionell oder als ambitionierter Amateur im WWW-Geschäft bewegt, sollte meiner Meinung nach neben den Bibliotheken unbedingt auch die Grundlagen kennen. Sonst bewegt man sich auf verdammt dünnen Eis.

          Da stimme ich dir zu.

          Qapla'

          --
          „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
          1. Hallo Gunnar,

            Aber das scheint in der SW-Entwicklung inzwischen normal zu sein: Zeiteinsparung beim Programmierer zu lasten der CPU-Zeit beim User.

            Das war es schon immer. Sonst würden wir alle in Assemblersprache programmieren.

            vielleicht liegt es an meinem Alter ("früher war alles besser"), aber mein Eindruck ist schon, dass die SW-Entwickler das Rennen gegen die HW-Entwickler nicht nur regelmäßig gewinnen, sondern ihren Vorsprung sogar immer weiter ausbauen. Inzwischen sind wir Anwender ja schon froh, wenn eine neue Version oder auch nur ein Update nur "minimal" langsamer läuft, trotz immer schneller werdender Hardware.

            Gruß, Jürgen

            1. Hallo,

              Das Grundproblem ist m.E. eher, dass Software- und Hardwareentwicklung auseinander laufen.

              • Heutige CPUs werden nicht mehr signifikant schneller, sondern bekommen mehr Kerne. Nebenläufige Programmierung wird damit wichtiger. Es entstehen neue Programmiersprachen und Programmiersprachen-Features, damit nebenläufige Programmierung auf mehreren Kernen einfacher wird. Es gehört aber noch nicht zur Regel.
              • Zwar wird Hardware immer noch kleiner und schneller, aber durch den Boom von Mobilgeräten (»Post-PC«) erlangen andere Prozessorarchitekturen, vor allem ARM, wieder stärkere Bedeutung. Selbst große Software-Firmen schaffen es nicht mal eben, ihre Betriebssysteme und Programme für verschiedene Architekturen anzupassen. Microsoft hat z.B. lange gebraucht, bis das neueste Windows vernünftig auf einem x86- und ARM-Tablet läuft, das so leistungsfähig wie ein PC vor 10 Jahren ist.
              • Immer mehr Operationen müssen auf spezialisierten Prozessoren durchgeführt werden, derzeit vor allem Grafikprozessoren. Das betrifft sämtliches Grafik-Rendering, aber auch andere mathematische Operationen. Auch hier ist es noch nicht die Regel, dass Programme CUDA usw. verwenden.

              Die meiste Software, die entwickelt wird, trägt diesen Hardware-Veränderungen noch keine Rechnung.

              Mathias

          2. Om nah hoo pez nyeetz, Gunnar Bittersmann!

            Das war es schon immer. Sonst würden wir alle in Assemblersprache programmieren.

            Assembler? Warum denn das? ;-)

            Matthias

            --
            Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Blei und bleichen.

        2. Hallo,

          Bibliotheken müssen, wie du geschrieben hast, alle Eventualitäten abdecken. Das erfordert einen recht großen Aufwand für der Browser, Informationen zu ermitteln, die der Seitenersteller eigentlich weiß. Wenn ich z.B. mittels $-Funktion ein Element anspreche, ist es toll, dass die Selection-Engine selbst ermittelt, ob der Parameter eine ID, ein Name, ein Tagname, ein Classname etc. ist. Toll. Der Seitenersteller sollte dieses auch wissen. So muss der Browser jedes mal ermitteln, was bei der Seitenerstellung eigentlich schon bekannt ist.

          Das nennt sich Flexibilität und ist eine gute Sache. Das Gegenteil hieße, sämtliche *aktuellen* Parameter hart zu kodieren und die Umsetzung auf die *gegenwärtigen* Anforderungen zuzuschneiden. Dann schreibt man natürlich nur so viel Code wie gerade nötig und dieser kann auf die *gegenwärtigen* Anwendungsfälle optimiert sein, aber Änderungen und Erweiterungen sind umso aufwändiger.

          Es ist ferner sinnvoll, allgemeine APIs zu verwenden. Nachdem wir uns mit document.links, document.forms, document.layers, document.all, getElementById, getElementsByTagName, getElementsByClassName usw. herumgeplagt haben, sind wir heute bei querySelector(All) und jQuery-artigen APIs angekommen. Diese APIs geben einem die nötige Abstraktheit und Kürze, um Logik lesbar und wartbar auszudrücken, z.B. $('.foo').on('mouseenter', '.bar', function(event) {}).

          Aber das scheint in der SW-Entwicklung inzwischen normal zu sein: Zeiteinsparung beim Programmierer zu lasten der CPU-Zeit beim User.

          JavaScript ist mittlerweile so schnell, dass selbst dicke Bibliotheken wie jQuery keinen merklichen Overhead erzeugen. jQuery besteht aus einem Haufen Funktionen, Objekten und Listenoperationen. So etwas frisst ein moderner JIT-Compiler zum Frühstück.

          DOM-Queries und DOM-Operationen wirken sich generell negativ auf die Performance aus. Es ist zudem schwierig, bei Animationen 60fps hinzubekommen. I/O-Operationen sind ebenfalls »teuer«.

          Eine Abstraktion wie jQuery ist jedoch kein Performance-Problem mehr, jQuery ist selbst auf Teufel komm raus optimiert worden. jQuery hilft einem eher weiter, z.B. indem intern DocumentFragments verwendet werden und Event-Delegation einfach möglich ist. Es ist in der Summe einfacher, mit jQuery performanten Code zu schreiben als ohne.

          Wer sich professionell oder als ambitionierter Amateur im WWW-Geschäft bewegt, sollte meiner Meinung nach neben den Bibliotheken unbedingt auch die Grundlagen kennen. Sonst bewegt man sich auf verdammt dünnen Eis.

          Fragt sich was Grundlagen sind. Als Grundlagen sehe ich das, was ich z.B. in meiner JavaScript-Dokumentation beschreibe. Vieles davon läuft darauf hinaus, dass man sich zur sicheren Anwendung dieser Grundlagen am besten eine vernünftige Bibliothek sucht, die ausgereift, gut dokumentiert und automatisiert getestet ist.

          Dann gibt es noch die Grundlagen, die jQuery und Co. selbst einsetzen. Das sind fiese Details, Fallstricke und Browserbugs, die man kennen und behandeln muss, um eine robuste Software zu schreiben. Fast niemand kennt diese Grundlagen. Man kann sie als Einzelperson gar nicht vollständig kennen. Zum Glück *muss* sie heutzutage nicht mehr jeder kennen, weil es große Bibliotheken gibt, in denen tausende Leute ihr Wissen bündeln.

          Mathias

      2. Das Auslesen von CSS-Eigenschaften geht anders.

        Gemeint war http://molily.de/js/css.html#werte-auslesen

        Schließlich lässt sich anmerken, dass display: none Inhalte in einer Weise versteckt, sodass sie für Screenreader unzugänglich sind. Nutzt man eine zugängliche Methode, wird eine Animation gleich viel komplizierter.

        Gemeint war http://snook.ca/archives/html_and_css/hiding-content-for-accessibility

      3. Moin!

        Darüber streiten die Gelehrten.

        Gelegenheit für Glaubenskriege.

        Die wenigsten heutzutage kennen Low-Level-DOM-Grundlagen, und das halte ich auch nicht für schlimm.

        Art 5 GG: Die Meinung ist frei. Ich habe dazu eine andere.

        Wenn man so etwas in reinem JavaScript schreibt, braucht man eine Menge an Wissen und muss viele Annahmen machen, um einfachen Code zu schreiben:

        Naja. Sollte nicht der Plan am Anfang stehen? Die Bibel (Johannes 1) ist da falsch übersetzt, da steht in der deutschen Fassung "Im Anfang war das Wort". Ich denke, die frühen Übersetzer hatten das Wort "Plan" noch nicht zur Verfügung. Sieht man auch daran, dass behauptet wird "das Wort ward Fleisch" - zweifelsfrei meinten die tatsächlich, der Plan wurde umgesetzt.

        Es hat schon seine Gründe, warum die show-, hide- und toggle-Methoden von jQuery ziemliche Monster sind.

        Hier arbeitest du mit Klassen, warum beim Togglen hingegen mit Inline-Styles.

        Auch in nativem JS korrigierbar. Feeilich wäre es eine gute Idee hier mit Klassen und/oder Selektoren zu operieren.

        Das ist ein Rückschritt gegenüber dem Workflow mit jQuery. <a href="javascript:…"> sollte man nicht verwenden, sondern HTML und JavaScript sauber trennen – Stichwort Unobtrusive JavaScript – und Event-Handler im JavaScript registrieren. Dabei hilft einem jQuery hervorragend.

        Ich bin hier nach wie vor anderer Meinung. Ich behalte gern die Kontrolle und ich kenne eine Menge negativer Beispiele die deshalb so besch... funktionieren, weil der Ersteller weder Ahnung von JS noch von jQuery hat, letzteres aber verwendet.

        Die Inhalte bleiben in diesem Fall für immer unsichtbar.

        Korrigierbar.

        Das ist elegant, geht aber wieder von einigen Vorannahmen aus. Es ist eine Lösung für einen sehr speziellen Fall: Das Element ist nur sichtbar, wenn gerade der Anker in der URL darauf zeigt.

        Korrigierbar.

        Das kann gewünscht sein, hat aber nichts mit einem generischen Ein- und Ausblenden auf Knopfdruck zu tun.

        Ich denke, wir wissen beide, dass Frage und eigentliches Problem oft nicht ganz übereinstimmen. Es ist eine Erweiterung in eine vermutete Richtung.

        Hinzu kommt, dass mit einem festen height-Wert gearbeitet werden muss, damit die Transition funktioniert.

        Jaja. Die hatte mit dem Problem nichts zu tun, mein Beispiel war aus einem Experiment rauskopiert.

        Ferner funktioniert :target nicht in IE < 9 funktioniert. In diesen Browsern ist der Inhalt komplett unzugänglich.

        Korrigierbar. <! if [gt IE 8] > (oder so...)

        Schließlich lässt sich anmerken, dass display: none Inhalte in einer Weise versteckt, sodass sie für Screenreader unzugänglich sind. Nutzt man eine zugängliche Methode, wird eine Animation gleich viel komplizierter.

        Wie? Das Verkleinern auf einen Punkt ist komplizierter? Gibts für Screenreader nicht etwas wie @medium aural { ... } im stylesheet?

        Was ich damit sagen will: Es hat schon seine Gründe, warum Bibliotheken wie jQuery verwendet werden.

        Ich habe KEIN Problem damit, wenn Bibliotheken wie jQuery verwendet werden - aus einer anderen Äußerung von Dir entnehme ich, dass Du das vermutest und dass Du Dich darüber ärgerst. Ich vertrete aber die Meinung, dass triviale Probleme auch trivial gelöst werden sollten. Ich baue doch keine Autofabrik wenn ich nur den Rückspiegel einstellen will. Will ich aber eine Webseite bauen, die browserseitig entsprechenden Aufwand erfordert, dann habe ich kein Problem auf passende Bibliotheken zurück zu greifen.

        Nur mache ich eher auf "serveseitige Logik".

        [Bibliotheken wie jQuery] setzen verschiedene Best Practices um.

        Wobei "Best Practices" wieder eine Frage der Definition ist. Die Definition ist übrigens auch zeitabhängig.

        So long.

        Jörg Reinholz

        1. @@Jörg Reinholz:

          nuqneH

          Naja. Sollte nicht der Plan am Anfang stehen? Die Bibel (Johannes 1) ist da falsch übersetzt, da steht in der deutschen Fassung "Im Anfang war das Wort". Ich denke, die frühen Übersetzer hatten das Wort "Plan" noch nicht zur Verfügung. Sieht man auch daran, dass behauptet wird "das Wort ward Fleisch" - zweifelsfrei meinten die tatsächlich, der Plan wurde umgesetzt.

          *g*

          Ferner funktioniert :target nicht in IE < 9 funktioniert. In diesen Browsern ist der Inhalt komplett unzugänglich.
          Korrigierbar. <! if [gt IE 8] > (oder so...)

          Oder so.

          Gibts für Screenreader nicht etwas wie @medium aural { ... } im stylesheet?

          AFAIK nein. Screenreader sind was sie sind: _Screen_reader. Die lesen das, was sie auf dem
          Schirm haben. Reagieren also auf @media* screen, nicht aural.

          Qapla'

          * Plural!

          --
          „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
  2. Hallo,

    Der Code sieht auf den ersten Blick in Ordnung aus – hast du ein Onlinebeispiel? Für Ajax-Geschichten ist immer ein HTTP-Kontext zum testen sinnvoll, bei dem eine echte Ressource vom Server geladen wird.

    Darüber hinaus wäre es natürlich erstrebenswert, wenn sich ein angezeigter Artikel mit dem Öffnen eines weiteren Artikels wieder schließt, wie es auf orf.at der Fall ist.

    Versehe die Element mit einer Klasse (.artikel) und füge allen außer der aktuellen wieder die Klasse .unsichtbar hinzu.

    $(''.article').not(aktuellerArtikel).addClass('unsichtbar');

    Mathias