Inhaltsverzeichnis
1. Inhaltsverzeichnis erstellen und andere Formatierungen
3. Fancy Box
5. Fotografierte Objekte freistellen
6. Eigene globale IPv4-Adresse ermitteln
7. Grafik in C-Array konvertieren
Ich vergesse immer wieder, wie manche Dinge aufgebaut werden ...
<div class="contents">
<p class="contentsHead">Inhaltsverzeichnis</p>
<p class="contentsE1">1. <a href="#k1">Kapitel 1</a></p>
<p class="contentsE1">2. <a href="#k2">Kapitel 2</a></p>
<p class="contentsE2">a. <a href="#k2a">Unterkaptitel 2a</a>
</div>
Das Inhaltverzeichnis wird in ein div-Tag mit der Klasse contents gesetzt. Diese erzeugt den Rahmen in der eingestellten Farbe und legt diverse Abstände fest. Die einzelnen Elemente des Verzeichnisses sind Paragraphen:
So sieht es dann aus:
Ein größeres Beispiel befindet sich am Anfang dieser Seite.
Ein kleines selbst geschriebenes Programm erleichtert die Erstellung eines Inhaltsverzeichnisses (geschrieben in c#, .NET Core 3.1).
Das Programm scannt die angegebene Datei nach h1-, h2- und h3-Tags, extrahiert das id-Attribut und den Text und erstellt für jedes Tag eine Zeile in der Form
"<" + TagName + " class=\"" + ClassName + "{LEVEL}\"><a href=\"#{ID}\">{TEXT}</a></" + TagName + ">".
Tag(Name) und Class(Name) können auf dem Formular angegeben werden.
Die zu bearbeitende Datei kann
Download eine ZIP-Archivs mit Quellen und Binary.
Bei Aufzählungen mit Überschrift stört meist der große Abstand zwischen Überschrift und Liste. Einrücken ist auch nicht gewünscht.
Überschrift
Zwei Klassen ListHeader für die Überschrift und ListBody für die Liste (<ul>- oder <ol>-Tag) lösen das Problem:
<p class="ListHeader"<strong>Überschrift</strong></p>
<ul class="ListBody">
<li>Liste 1</li>
<li>Liste 2</li>
</ul>
Überschrift
Hypernator.js macht Probleme beim Kopieren der Code-Beispiele und wurde deshalb auf Ullis Roboter Seite wieder deaktiviert. Bis auf Chrome haben alle großen Browser mittlerweile einen eigenen internen Silbentrennungsalgorithmen. Leider muss man noch browserspezifische Class-Attribute zur Aktivierung einsetzen. Ich hoffe, dass sich das bald vereinheitlicht.
Die Aktivierung der automatischen Silbentrennung geschieht über folgende Style-Attribute (für jeden Browser eins):
-moz-hyphens: auto; -o-hyphens: auto; -webkit-hyphens: auto; -ms-hyphens: auto; hyphens: auto;
Am besten legt man eine entsprechende Klasse an und weist sie den gewünschten HTML-Elemente zu. Am einfachsten geht dies, wenn man das <body>-Tag mit dieser Klasse versieht.
Als ich vor kurzem viel Text in einer Tabelle unterbringen wollte, sah das recht unansehnlich aus. Insbesondere die langen Worte führten zu großen Lücken und hohen Zeilen. Zunächst habe ich versucht, mit Soft Hyphens ("­" in HTML) nachzuhelfen. Doch das war sehr mühselig und das Ergebnis befriedigte auch nicht wirklich. Dann fand ich den Hyphenator von Mathias Nater aus der Schweiz. Hyphenator ist ein Script (Javascript), dass allein durch Einbinden des Scripts eine Online-Silbentrennung durchführt. Die Ergebnisse sind wirklich gut, ich habe noch keinen Fehler entdecken können. Das Ganze klappt auch bei der Druckausgabe. Insgesamt müssen etwa 100 kB zusätzlich herunter geladen werden.
Das Einbinden ist auch recht einfach. Zunächst sollte man das Script von der o.g. Seite herunterladen. Man erhält eine ZIP-Datei mit einer Windows und einer Mac-Variante. Die Windows-Variante enthält das Script in einer ausführlich kommentierten ("Hyphenator_debug.js") und einer komprimierten Version ("Hyphenator.js"). Hinzu kommt einer Verzeichnis "patterns" mit Mustern für verschiedene Sprachen und eine Testseite ("WorkingExample.html"). Hyphenator.js und patterns müssen im gleichen Ordner zur Verfügung gestellt werden. In einem Script-Teil wird Hypernator den eigenen Anforderungen angepasst. Ich habe die minimale Wortlänge (=4) aus dem mitgelieferten Beispiel übernommen. Zum Schluss muss das Script mit Hypernator.run() gestartet werden.
Siehe unten: Update 30.5.2014 <head> ... <!-- ========================= Hyphenator ==================================== --> <script src="Hyphenator/Hyphenator.js"></script> <script> Hyphenator.setMinWordLength(4); Hyphenator.run(); </script> <!-- ========================== Hyphenator Ende ============================== --> ... </head>
Damit die Silbentrennung ordentlich funktioniert, muss dem Hypernator die zu Grunde liegende Sprache bekannt sein. Dies geschieht durch das lang-Attribut, dass man sinnvoller Weise gleich dem html-Tag mitgibt.
<html lang="de">
Als letztes müssen die HTML-Elemente markiert werden, für die die Silbentrennung stattfinden soll. Dies geschieht durch Angabe der Klassebezeichnung "hyphenate", z.B.
<div class="hyphenate">
Alle Texte innerhalb dieses Elements, d.h. auch in untergeordneten Elementen, werden nun Umgebrochen. Soll die Silbentrennung auf der gesamte Seite erfolgen, kann man auch das body-Tag mit dieser Klasse versehen. Für den Fall, dass ein Element nicht umgebrochen werden soll, erhält dies die Klassenbezeichnung "donthyphenate". Die Klassennamen können ebenso wie viele weitere Parameter individuell angepasst werden. Hierzu gibt es eine ausführliche Online-Dokumentation.
In diese Seite ist übrigens die Silbentrennung mit Hyphenator eingebaut.
Es gibt eine neue Version des Hyphenator. Die Konfiguration erfolgt über die Methode config. Weiterhin macht es Sinn, die Konfigurationseinstellungen in einer zentralen Datei abzulegen, damit Änderung en für alle Seiten wirksam werden.
<head> ... <!-- ========================= Hyphenator ==================================== --> <script src="Hyphenator/Hyphenator.js"></script> <script> // seitenindividuelle Einstellungen </script> <script src="Hyphenator/urs-Hyphenator-config.js"></script> <!-- ========================== Hyphenator Ende ============================== --> ... </head>
urs-Hyphenator-config.js sieht dann so aus:
Hyphenator.config({ minwordlength : 8, displaytogglebox : false, donthyphenateclassname : 'donthyphenate' }); Hyphenator.run();
Mit Fancy Box ist man in der Lage, Bilder, die auf der Seite nur verkleinert angezeigt werden, auf der gleichen Seite vergrößert darzustellen.
Zunächst lädt man sinnvoller Weise die benötigten Dateien herunter. Ich benutze die Version 2.1.4. Eingebunden werden die Scripts im head-Tag. Fancy Box basiert auf jquery. Deshalb muss zunächst eine eine Minimalversion dieser Bibliothek eingebunden werden.
<head> ... <!-- ========================= Fancy Box =================================== --> <!-- Add jQuery library --> <script src="fancybox/jquery-1.9.0.min.js"></script> <!-- Add fancyBox main JS and CSS files --> <script src="fancybox/jquery.fancybox.js?v=2.1.4"</script> <link href="fancybox/jquery.fancybox.css?v=2.1.4" media="screen" rel="stylesheet" type="text/css"> <!-- fancybox aktivieren --> <script src="fancybox/fancybox.js"></script> <!-- ========================== Fancy Box Ende ============================== --> ... </head>
Um ein Bild, wie das obige Bespiel vergrößert anzeigen zu können ist nicht viel zusätzliches notwendig. Bereits Standard-HTML bietet die Möglichkeit, zu einem Image einen Link anzugeben, über den dann das vergrößerte Bild angezeigt wird. Versieht man nun den Link mit der Klasse "fancybox" und einem title-Tag, geschieht die Anzeige auf gleichen Seite, schön mit einem Rahmen drum herum, einem Titel und einer Schaltfläche zum schließen.
<a class="fancybox" href="ARDUINO_V2.png" title="Großes Bild"> <img alt="Kleines Bild" title="Kleines Bild, zum Vergrößern klicken" src="ARDUINO_V2-thumb.png"></a>
Eine interessante Zusatz-Option ist das rel-Attribut, das man dem Link hinzufügen kann. Zwischen allen Bilder mit dem gleichen Attribut kann dann im vergrößerten Modus weitergeschaltet werden.
<a class="fancybox" href="ARDUINO_V2.png" title="Großes Bild" rel="Group1"> <img alt="Kleines Bild" title="Kleines Bild, zum Vergrößern klicken" src="ARDUINO_V2-thumb.png"></a> <a class="fancybox" href="ARDUINO_Web.png" title="Noch ein großes Bild" rel="Group1"> <img alt="Noch ein leines Bild" title="Noch ein kleines Bild, zum Vergrößern klicken" src="ARDUINO_Web-thumb.png"></a>
Syntaxhervorhebung macht Programm-Code besser lesbar. Nahezu jeder Programm-Editor macht so etwas. Einige –wie die Arduino-IDE– bieten sogar eine HTML-Export-Funktion mit entsprechender Farbcodierung an, Visual Studio leider nicht.
Es gibt eine Reihe von Web-Sites, die einen solchen Dienst online zur Verfügung stellen. Man kopiert die Code-Passage in ein Textfeld und erhält einen HTML-Text mit entsprechenden Formatierungsvorschriften, den man in seine Seite einkopieren kann.
Eine andere Möglichkeit besteht darin, ein eigenständiges Programm für solch einen Zweck einzusetzen. Auch hier gibt es eine Reihe von Leuten, die solche Programme geschrieben haben und zum zum Download anbieten. Ich gehöre selbst dazu.
Für die Dokumentation von VB-Code habe ich in der Vergangenheit (bis etwa Oktober 2014) immer wieder einen kostenlosen Online-Dienst genutzt. Diejenige Seite, die bisher die besten Ergebnisse lieferte, ist jetzt leider nicht mehr online. Pech gehabt :-((. Darum habe ich mich auf die Suche nach einer Alternativen gemacht und bin vermehrt auf Seiten gestoßen, die das Problem mit JavaScript lösen. Am besten hat mir das Ergebnis von highlight.js gefallen. Die VB-Codierung sieht exakt so aus, wie sie im Visual Studio dargestellt wird. Außerdem ist der Sourcecode über GitHub und eine ausführliche Dokumentation verfügbar. Die Nutzung ist ebenfalls extrem einfach, drei Zeilen zusätzlicher Code reichen aus:
|
/path/to" muss noch durch den passenden Dateipfad ersetzt werden. Ebenso kann man den Stil anpassen. Im Verzeichnis "styles" sind eine ganze Reihe hinterlegt. Damit es wie im Visual Studio aussieht, muss "default.css" durch "vs.css" ersetzt werden. |
Fügt man die aufgeführten Anweisungen in das head-Segment ein, werden alle mit <pre><code> markierten Segmente "gehighlighted". Die Programmiersprache wird selbständig erkannt. Man kann nachhelfen, indem das <code>-Tag mit einer entsprechenden Klasse versieht, z.B. <code class="vbnet">.
Die Klassenreferenz ist über http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html abrufbar.
Die Box oberhalb dieses Absatzes ist ein Beispiel für formatierten HTML-Code und die nachfolgende Box zeigt ein VB-Beispiel:
Imports StateModel
''' <summary>
''' The interface <i>SensorModell</i> provides Method to validate a <see cref="Pose"/> object
''' against an information from the environment.
''' </summary>
Public Interface ISensorReading
''' <summary>
''' This method is called for each <i>Particle</i> of a
''' ParticleSet after a sensor reading onject is applied to it.
''' </summary>
''' <param name="Pose"><see cref="Pose">Pose</see> to be validated.</param>
''' <returns>A value between 0.0 and 1.0. The probability with which the
''' measured value is consistent with the particle position.</returns>
''' <remarks>Uncertainties and noise of the sensor values have to be taken into account.</remarks>
''' <exception cref="ArgumentOutOfRangeException">Will be thrown by the <i>Particle</i> object if the
''' return value ist not in range of 0.0 to 1.0.</exception>
Function CheckPose(ByVal Pose As Pose) As Double
End Interface
Ich möchte, dass der präsentierte Code mit einem leicht grauen Hintergrund dargestellt wird. Damit dies ordentlich aussieht, müssen zwei Punkte beachtet werden:
pre {
...
background-color : #eee;
...
}
<code class="vbnet hljs">
In der entsprechenden CSS-Vorlage von
highlight.js
vs.css (in Version 9.4.0) muss in der Klassendefinition für hljs
die Festlegung der Hintergrundfarbe auskommentiert werden:
.hljs {
...
/* background: white; */
...
}
Syntaxhervorhebungen kann man verhindern indem man dem <code>-Tag die Klasse "nohighlight" zuweist.
<pre><code class="nohighlight"> ... </code></pre>
Eine kleinen Haken hat die Sache allerdings. Wenn im Code spitze Klammern enthalten sind, werden diese von den Browsern und auch von highlither.js als Klammern um Tags interpretiert. Diese Klammern muss man durch "<" bzw. ">" ersetzen. Ebenso sollte für die HTML-Dartstellung ein einzelnes "&" durch "&" esetzt werden. Dies kann man per Hand, per "Suchen & Ersetzen" oder ein Editor-Script machen, je nachdem was der eingesetzte HTML-Editor so kann. Meiner kann so gut wie gar nichts (oder ich weiß nicht, wie es geht). Deshalb habe ich ein kleines Programm geschrieben, dass die Ersetzung für mich erledigt.
Den zu verschönernden Code nimmt man einfach in die Zwischenablage und kopiert ihn per Strg+V in das Textfeld. Alternativ kann man die Schaltfläche "Clipboard" betätigen". Das Programm ersetzt die Klammern und kopiert den geänderten Text zurück in die Zwischenablage. Von hier kann der Code dann direkt in den HTML-Editor kopiert werden.
Auf Wunsch fügt das Programm auch noch <pre>- und <code>-Tags ein, gibt ein "class"-Attribut beim Code-Tag an.
Die jeweils letzten Einstellungen werden gespeichert und beim nächsten Aufruf vorbelegt.
Binary und Source zum download.
In diesem Tutorial bei instructables wird genau beschrieben, wie man es schafft, mit einfachen Mitteln fotografierte Objekte vor einen weißen Hintergrund zu platzieren. Hier die Kurzfassung in deutsch mit Ergänzungen. Als Beispiel dient das Bild meines Kabeltesters
Wichtig ist
Macht man am besten mit seinem Lieblingsbildbearbeitungsprogramm. Das Beispielfoto hat diesen Schritt bereits durchlaufen.
Mit dem Lieblingsbildbearbeitungsprogramm das Objekt grob freistellen. Dies erhöht die Justierungsmöglichkeiten für den folgenden Schritt. Meisten ist es so, dass die Helligkeit des Hintergrunds unterschiedlich ist. Im Beispiel ist die linke obere Ecke deutlich dunkler. Diese Unterschiede werden durch diesen Schritt verringert.
Dazu öffnet man das Bild mit GIMP. Dies geht
am einfachsten, indem man das Bild mit der rechten Maustaste anklickt und im aufgehenden Kontextmenü
den Punkt "Mit GIMP öffnen" auswählt.
Mit der rechten Maustaste klickt man in GIMP auf das Bild. Im aufgehenden Kontextmenü wählt man
"Farben" -> "Werte...".
Es erscheint ein Dialog, mit dem man Einstellen kann, welcher Bereich im Bild verbleiben soll.
Histogramm vom Original-Bild Man sieht deutlich den hohen Grau-Anteil |
Histogramm vom bereinigten Bild Der Grau-Anteil ist schon nahezu verschwunden |
Im nächsten Schritt zieht man den rechten Regler soweit nach links, bis der graue Hintergrund
komplett verschwunden ist. Auf Grund der Vorbereinigung muss hier weniger abgeschnitten werden.
Als Letztes kann man versuchen, über den mittleren Schieber das Bild weiter zu verbessern (Helligkeits-
und Kontrast-Eindruck).
Geht in GIMP per "Exportieren" (Menü "Datei" -> "Exportieren als ...". Fertig:
Regelmäßig muss ich wieder suchen. Eine Seite, die die eigene IP-Adresse ohne Schnick-Schnack anzeigt, ist:
<html><head><title>Current IP Check</title></head><body>Current IP Address: XXX.XXX.XXX.XXX</body></html>
Noch einfacher geht es mit ipify. Die Abfrage "https://api.ipify.org/" liefert die eigene IP als Klartext. Sie liefert
XXX.XXX.XXX.XXX
ohne weitere Zusätze. Es sind auch andere Formate möglich.
Eine Web-Server-Applikation sollte auch Images einbinden und versenden können. Üblicherweise wird hierzu einfach zusammen mit einem HTTP-header der Inhalt der Image-Datei ohne weitere Konvertierung versandt. Steht jedoch kein Datei-System zur Verfügung, wie z.B. bei einem Arduino, muss man die Daten irgendwie im Flash unterbringen. Das sieht dann etwa so aus:
uint8_t ImgData[] ={0x89,0x50,0x4E,0x47,0x0D, ...};
Wie kommt man an die Zeichenkette? Hier hilft das freie Programm Hexplorer, das übrigens auch ansonsten sehr nützlich ist. Zieht man die Image-Datei per Drag & Drop auf das Hexplorer-Fenster, wird der Dateiinhalt im Hexadezimal-Format und im Klartext angezeigt.
Mit <Strg+A> markiert man zunächst den gesamten Inhalt. Mit der rechten Maustaste öffnet man das Kontext-Menü, wählt "Copy As" und erhält dann ein Auswahl an Kopierformaten. "C Data" liefert das o.g. C-Array. Die Kopie wird in die Zwischenablage gelegt und kann direkt in den Programm-Code eingefügt werden.
Nach langer Suche habe ich das tolle Tool Xenu's Link Sleuth gefunden, das Broken Links in einer Website aufspürt. Hat auch gleich einige Dutzend auf Ullis Roboter Seite gefunden. Sehr von Vorteil ist, dass man die Suchparameter den Bedürfnissen entsprechend einstellen kann.
Am Ende der Suche wird ein ausführlicher Report im HTML-Format erstellt. Dieser enthält:
Man versieht das betreffende HTML-Element mit einem title-Attribut:
Dieser Text ist mit einem Tooltip versehen. Maus über den Text positionieren.
Bei menucool.com habe ich diese Anleitung für ein Tooltip gefunden, das ausschließlich mit CSS auskommt. Ich habe es für meine Bedürfnisse ein wenig angepasst.
Im Prinzip wird für ein <a>-Tag (Link) eine spezielle Klasse definiert, die spezielle CSS-Attribute erhält. Es gibt zwei Varianten:
Light | Strong |
Heller Hintergrund und blendet rechts neben dem Text auf. | Dunkler Hintergrund und blendet unter dem Text auf. |
Beide Varianten können mit einer Grafik versehen werden: | |
Am besten schaut man sich zunächst einmal die Elemente und den zugehörigen HTML-Code an
So sieht es aus: | Das Wort
Tooltip
Most Light-weight Tooltip This is the easy-to-use Tooltip driven purely by CSS. ist mit einem Tooltip versehen. |
|
Umgebender Text. | <p>Das Wort | |
Den Tooltip-Rahmen bildet ein <a>-Tag. Die Klasse legt den Style und die Hintergrundgrafik fest. | <a href="#!" class="tooltip-strong"> | |
Text oder Bild, das mit einem Tooltip versehen werden soll. | Tooltip |
|
Der Tooltip-Text ist in ein <span>-Tag eingeschlossen. | <span> | |
Die "callout"-Grafik wird über den Rahmen gelegt. Die Klasse bestimmt Style und Position. Die Grafik kann ausgelassen werden. | <img alt="" class="callout-strong" src="_grafiken/css-tooltip-callout-strong-top.gif"
/> |
|
Der Inhalt der Tooltip-Box wird festgelegt. Im Prinzip stehen alle Formatierungsoptionen zur Verfügung. Im Bespiel wird eine Grafik eingebunden, die per "style='float:right'" an den rechten Rand platziert wird. | <img alt="" src="undsonst-web/tooltip-image.png" style="float:right;" /> | |
Der Tooltip-Text. Auch hier stehen div. Formatierungsmöglichkeiten zur Verfügung. Im Beispiel: Überschrift in fett und Erläuterungstext in Folgezeile. | <strong>CSS only Tooltip</strong><br /> Pure CSS popup tooltips with clean semantic XHTML. |
|
Abschluss der Tags und nachfolgender Text. | </span></a> ist mit einem Tooltip versehen.</p> |
Das Ganze noch einmal im Zusammenhang:
<p>Das Wort <a class="tooltip-strong" href="#!">Tooltip
<span>
<img alt="" class="callout-strong" src="_grafiken/css-tooltip-callout-strong-top.gif" />
<strong>Most Light-weight Tooltip</strong><br />
This is the easy-to-use Tooltip driven purely by CSS.</span></a>
ist mit einem Tooltip versehen.</p>
Eine minimalistische Version ist sieht so aus:
Das Wort Tooltip Most Light-weight Tooltip ist mit einem Tooltip versehen. |
|
Die zugehörigen CSS-Styles sehen wie folgt aus:
/* Siehe http://www.menucool.com/tooltip/css-tooltip */
/*---------------------------------------------*/
/* Tooltip Light (zur rechten Seite aufblendend)
/*---------------------------------------------*/
a.tooltip-light-right {outline:none;text-decoration:none;color: blue}
a.tooltip-light-right strong {line-height:30px;}
a.tooltip-light-right:hover {text-decoration:none;}
a.tooltip-light-right span {
z-index:10;display:none; padding:14px 20px;
margin-top:-30px; margin-left:28px;
width:300px; line-height:16px;
}
a.tooltip-light-right:hover span{
display:inline; position:absolute; color:#111;
border:1px solid #DCA; background:#fffAF0;}
.callout-light {z-index:20;position:absolute;top:30px;border:0;left:-12px;}
/*CSS3 extras*/
a.tooltip-light-right span
{ border-radius:4px;
box-shadow: 5px 5px 8px #CCC;
}
/*---------------------------------------------*/
/* Tooltip Strong (zur rechten Seite aufblendend)
/*---------------------------------------------*/
a.tooltip-strong-right {outline:none;text-decoration:none;color: blue}
a.tooltip-strong-right strong {line-height:30px;}
a.tooltip-strong-right:hover {text-decoration:none;}
a.tooltip-strong-right span {
z-index:10;display:none; padding:14px 20px;
margin-top:-30px; margin-left:28px;
width:300px; line-height:16px;
}
a.tooltip-strong-right:hover span{
display:inline; position:absolute; color:#EEE;
border:2px solid #FFF;
background:#333 url(_grafiken/css-tooltip-gradient-bg.png) repeat-x 0 0;
}
.callout-strong-right {z-index:20;position:absolute;top:30px;border:0;left:-12px;}
a.tooltip-strong-right span
{
border-radius:2px;
box-shadow: 0px 0px 8px 4px #666;
/*opacity: 0.8;*/
}
/*---------------------------------------------*/
/* Tooltip Light (nach unten aufblendend)
/*---------------------------------------------*/
a.tooltip-strong {outline:none;text-decoration:none;color: blue}
a.tooltip-strong strong {line-height:30px;}
a.tooltip-strong:hover {text-decoration:none;}
a.tooltip-strong span {
z-index:10;display:none; padding:14px 20px;
margin-top:60px; margin-left:-160px;
width:300px; line-height:16px;
}
a.tooltip-strong:hover span{
display:inline; position:absolute;
border:2px solid #FFF; color:#EEE;
background:#333 url(_grafiken/css-tooltip-gradient-bg.png) repeat-x 0 0;
}
.callout-strong {z-index:20;position:absolute;border:0;top:-14px;left:120px;}
/*CSS3 extras*/
a.tooltip-strong span
{ border-radius:2px;
box-shadow: 0px 0px 8px 4px #666;
/*opacity: 0.8;*/
}
Tooltip
Most Light-weight Tooltip This is the easy-to-use Tooltip driven purely by CSS. |
|
CSS only
Tooltip Pure CSS popup tooltips with clean semantic XHTML. |
|
Tooltip
Most Light-weight Tooltip This is the easy-to-use Tooltip driven purely by CSS. |
|
CSS only Tooltip Pure CSS popup tooltips with clean semantic XHTML. |
|
Tooltip
Most Light-weight Tooltip This is the easy-to-use Tooltip driven purely by CSS. |
|
CSS only
Tooltip Pure CSS popup tooltips with clean semantic XHTML. |
|
Manchmal stören längere Passagen, z.B. erläuternder Programmcode, den Lesefluss. Im Folgenden wird ein Mechanismus dargestellt, mit dem solche Passagen auf- und zugeklappt werden können. Hier ein Beispiel.
Genau genommen wird zwischen zwei Varianten zur optischen Darstellung hin und her geschaltet.
Die genaue Aussehen der einzelnen Varianten wird über das class-Attribut
der HTML-Elemente gesteuert und ist durch entsprechende style-Angaben
(CSS) der Klassen in weiten Bereichen manipulierbar. Das Auf- und Zuklappen z.B. wird durch unterschiedliche
Festlegung des display-Attributs erreicht, also zwischen sichtbar
(style="display:block")
und unsichtbar (style="display:none"
). Natürlich
ist diese Funktion nicht auf das verbergen von HTLM-Elementen beschränkt. Es können beliebige
style-Elemente geändert werden (s.
Farbwechsel-Beispiel). Der
Einfachheit wird aber weiterhin von Auf- und Zuklappen geredet.
Nützlich ist außerdem, dass die Klassendefinitionen abhängig vom Ausgabemedium festgelegt werden können. Einige Bereiche können somit bei einer Druckausgabe ausgeblendet oder aber immer aufgeklappt angezeigt werden.
<head>
...
<script src="urs-snapped-text.js"></script>
...
</head>
Jeder Snapped-Text-Bereich besteht aus zwei Elementen: einem Überschriften-Element und einem darauf folgenden Detail-Element. Durch Anklicken des Überschriften-Elements wird die Darstellung des Detail-Elements verändert.
Das Überschriften-Element kann ein beliebiger HTML-Element-Typ sein, der auf dem Medium screen eine sichtbare Darstellung hat, also z.B. ein <p>, <h1>-Element o.ä. Es funktioniert auch mit Containern (<div>), wenn diese sichtbare untergeordnete Elemente (Child) besitzen. Dieses Element muss ein Klassenattribut class="..." besitzen. Über die im class-Attribut angegebene Klasse wird später auf das Überschriften-Element zugegriffen. Der Name der Klasse ist beliebig. Die Klasse kann wie üblich mit weiteren Klassen zur Ausgestaltung der Erscheinungsbildes kombiniert werden.
Auf einer HTML-Seite können zugleich unterschiedliche (Steuer-) Klassen verwandt werden, wenn mehrere Stile benötigt werden. Das Beispiel zeigt dies.
<p class="ButtonSnappedCode" style="margin-left:30px"> - Code verbergen | + Code anzeigen </p>
Im vorhergehenden Code-Beispiel wird die Klasse ButtonExpandedCode verwandt, für die in der Style-Datei "urs-snapped-text.css" ein Design hinterlegt ist, das folgende Darstellung ergibt.
|
Eine weitere Funktionalität ist das Umschalten des Überschriften-Textes. Wenn in der Original-Version zwei durch "|" getrennte Texte angegeben werden, werden diese abwechselnd gezeigt. Das Ganze funktioniert sowohl mit Textinhalten, wie auch mit HTML.
<x class="...">Text im aufgeklappten Zustand|Text im zugeklappten Zustand</x> <!-- x= p, h1, h2, ... -->
⇒ | ⇒ | ⇒ |
Es können auch HTML-Elemente eingebunden werden (Beispiel: .NET FAQ).
<p class="HeadlineSnappedText" expandedclass="HeadlineExpandedText"
<img alt="" src="up-arrow.png"> Aufgeklappt|<img alt="" src="down-arrow.png"/> Zugeklappt</p>
⇒ | ⇒ | ⇒ |
Man kann sogar unterschiedliche Elementarten verwenden.
<div class="HeadlineSnappedText" expandedclass="HeadlineExpandedText">
<h1> Aufgeklappt</h1>|<h2> Zugeklappt</h2>
</div>
⇒ | ⇒ | ⇒ |
Eine weitere Möglichkeit der Gestaltung ist die Angabe zweier Zusatz-Attribute, eins für die zu verwendende Klasse für das Überschriftenelement im aufgeklappten und eins für die im zugeklappten Zustand. Dies beträfe das <div>-Element im letzten Beispiel. Die Attribute sind snappedClass und expandedClass. Die hier angegebenen Klassennamen werden den Überschriftenelementen entsprechend dessen Zustand zugemischt. Fehlt eine dieser Angaben, wird die die Angaben im class-Attribut genommen. In Initialisierungs-Script (s.u.) muss
<p class="HeadlineSnappedText" expandedClass="RedHeadLine" snappedClass="BlueHeadLine"
Versieht man das Überschriften-Element noch mit einem title-Attribut, kann man erreichen, dass ein entsprechender Hinweis erscheint, wenn die Maus über das Element fährt.
<x class="..." title="Klicken, um den Code auf- und zuzuklappen">Offen|Zu</x>
Das class-Attribute des nächsten HTML-Element auf gleicher Ebene (Detail-Element) wird dann durch Klicken des Überschriften-Elements jeweils hin und her geschaltet. An dieses Element werden keine besonderen Anforderungen gestellt. Also z.B.
<pre><code clas="vbnet">
Public Function DoAnything As Integer
</code></pre>
Zum Schluss der HTML-Seite muss dann das Ganze due Aufruf der Funktion InitSnappedTextElements initialisiert werden. Diese Funktion darf wirklich erst am Schluss der Seite stehen, weil zum Zeitpunkt des Aufrufs alle betroffenen HTML-Elemente bereits geladen sein müssen.
<script>
InitSnappedTextElements("FarbwechselUeberschrift", "GreenText", "RedText", "");
</script>
Die Funktion ist wie folgt definiert:
function InitSnappedTextElements(headLineClassName, DetailsExpandedClassName, DetailsSnappedClassName, InitialState)
Sind auf einer Seite unterschiedliche Stile vorhanden (= unterschiedliche class-Attribute bei den Überschriften-Elementen), muss InitSnappedTextElements entsprechend mehrfach aufgerufen werden.
In der Datei "urs-snapped-text.css" sind folgende Klassen-Definitionen hinterlegt:
Wenn eine dieser Klassen benötigt wird, kann die Datei im head-Element eingebunden werden.
<link href="urs-snapped-text.css" rel="stylesheet">
Für diese Klassen gibt es eine vordefinierte Initialisierungsfunktion: InitSnappedTextStandard .
<script>
InitSnappedTextStandard();
</script>
Nutzt man die vordefinierten Klassen sieht der HTML-Code wie folgt aus:
- Code verbergen | + Code anzeigen
<!DOCTYPE html>
<html>
<head>
...
<link href="urs-snapped-text.css" rel="stylesheet">
<script src="urs-snapped-text.js"></script>
...
</head>
<body>
...
<p class="ButtonSnappedCode"> - Code verbergen | + Code anzeigen </p>
<pre><code>Public Function DoAnything As Integer ...</code></pre>
...
<script>
InitSnappedTextStandard();
</script>
</body>
</html>
Das nächste Beispiel zeigt den Seitenaufbau bei individueller Gestaltung.
- Code verbergen | + Code anzeigen
<!DOCTYPE html>
<html>
<head>
...
<script src="urs-snapped-text.js"></script>
...
</head>
<body>
...
<h1 class="FarbwechselUeberschrift">Farbwechsel</h1>
<p>Lorem ipsum</p>
...
<script>
InitSnappedTextElements("FarbwechselUeberschrift", "GreenText", "RedText", "");
</script>
</body>
</html>
Beide Varianten sind kombinierbar.
Man kann Links auf Seiten mit zugeklappten Texten so erstellen, dass der gewünschte Text aufgeklappt und abgesprungen wird.
Die Funktion ExpandSnappedTextDetails(headLineId) erlaubt es, den durch die ID definierten Block per Script aufzuklappen. Der Parameter headLineId gibt die ID des Überschriftenelements an. Groß-/Kleinschreibung spielt keine Rolle. Auf Grund der ggf. unterschiedlich genutzten Zeichensätze empfiehlt es sich, auf Umlaute und andere sprachspezifische Zeichen zu verzichten.
Im folgenden Code-Beispiel wird diese Funktion verwandt, um ein, in der URL angegebenes Element aufzuklappen und anzuzeigen. Zur Funktion getUrlParameter siehe Kapitel URL-Parameter auslesen.
function gotoTopic()
{ var topic = getUrlParameter("topic");
if (topic != "")
{ ExpandSnappedTextDetails(topic);
document.getElementById(topic).scrollIntoView();
}
}
...
<body onload="gotoTopic();">
...
Der Aufruf der Seite mit Anzeige des aufgeklappten Elements ist dann:
<URL>?topic=<headLineID>
http://ullisroboterseite.de/dotnet-faq.html?topic=labelheight
Die HTML-Code-Passage in dotnet-faq.html ist dann:
<section class="FAQSection">
<p id="labelheight" class="HeadlineSnappedText" expandedclass="HeadlineExpandedText"
title="Klicken, um den Abschnitt auf- und zuzuklappen">
<img alt="" src="_grafiken/up-arrow.png"> <span class="symbolNoWrap">Label</span>-Größe an Text anpassen
|<img alt="" src="_grafiken/down-arrow.png"/> <span class="symbolNoWrap">Label</span>-Größe an Text anpassen </p>
<div class="FAQDiv">
<p>
...</p>
.rar-Archiv mit den Scripts ("urs-snapped-text.js") und den Stil-definitionen ("urs-snapped-text.css") |
Am besten versteht man die Funktionsweise, wenn man sich mit dem zugehörigen Code auseinander setzt.
Bei der Initialisierung sucht InitSnappedTextElements alle (Überschriften-)Elemente mit der im Parameter headLineClassName angegebenen Klasse und versieht diese mit einem eindeutigen id-Attribut, sofern das Element noch kein solches besitzt.
var x = document.getElementsByClassName(headLineClassName);
for (var i = 0; i < x.length; i++)
{ // Falls das Element keine ID besitzt, eine ID vergeben
if (x[i].id == "")
x[i].id = headLineClassName + i;
headLineId = x[i].id; // ID merken
Falls das gefundene Überschriften-Element keine Text-Node besitzt, wird eine solche angefügt.
// Überschriften-HTML ermitteln
// ---------------------------------------------------------------------------
temp = x[i].innerHTML ; // innerHTML enthält den Code
if(!temp) // kein HTML, also eins einfügen
{ x[i].innerHTML = "HeadLine";
temp = x[i].innerHTML; // innerHTML enthält den Code
}
Aus der zum Überschriften-Element gehörenden innerHTML werden
die Überschriften-Elemente ermittelt und präpariert. isExpanded
wird zu Beginn ermittelt: var
isExpanded = Boolean(InitialState ==
"Expand"); // Initialer Zustand der Detail-Elemente
temp = temp.split("|");
if (temp.length == 0) continue; // kein Text enthalten
headLineExpandedHTML = temp[0];
if (temp.length < 2)
headLineSnappedHTML = headLineExpandedHTML; // gleichen Text verwenden
else
headLineSnappedHTML = temp[1];
if((headLineExpandedHTML != "") && (headLineSnappedHTML == "")) // Leerer Text ist blöd!
headLineSnappedHTML = headLineExpandedHTML;
if((headLineExpandedHTML == "") && (headLineSnappedHTML != ""))
headLineExpandedHTML = headLineSnappedHTML;
if((headLineExpandedHTML == "") && (headLineSnappedHTML == ""))
headLineExpandedHTML = headLineSnappedHTML = "HeadLine";
headLineExpandedHTML = headLineExpandedHTML.replace(/\r\n|\n/g,""); // Zeilenvorschübe im Text führen zu Problemen
headLineSnappedHTML = headLineSnappedHTML.replace (/\r\n|\n/g,"");
// Überschrift das korrekte innerHTML zuweisen
if(isExpanded)
x[i].innerHTML = headLineExpandedHTML;
else
x[i].innerHTML = headLineSnappedHTML;
Das Klassen-Attribut wird zusammengesetzt. Dazu werden die zu vergebenden Klassennamen aus den Attributen snappedClass und expandedClass ermittelt. Diese werden aus der angegebenen Klassenliste herausgefiltert. Der verbleibende Rumpf wird dann entsprechend um die in den o.g. Attributen vergebenden Klassen-Namen zu den Variablen headLineSnappedClass und headLineExpandedClass ergänzt. Je nach Zustand wird dem Überschriften-Element dann die passende Klasse zugeordnet.
// Überschriften-Klassen
// ---------------------------------------------------------------------------
headLineSnappedClass = x[i].getAttribute("snappedClass");
if (!headLineSnappedClass)
headLineSnappedClass = headLineClassName;
headLineExpandedClass = x[i].getAttribute("expandedClass");
if (!headLineExpandedClass)
headLineExpandedClass = headLineClassName;
// Klassen des Überschriften-Elements analysieren
temp = x[i].className.split(" ");
// Neuen Klassennamen aufbauen
newClass = "";
for (var j = 0; j < temp.length; j++) // Die beiden Zielklassennamen herausfiltern
{ if((temp[j] == headLineExpandedClass ) || (temp[j] == headLineSnappedClass))
continue; // nicht weitergeben
newClass += " " + temp[j];
}
headLineExpandedClass = newClass + " " + headLineExpandedClass;
headLineSnappedClass = newClass + " " + headLineSnappedClass;
if(isExpanded)
x[i].className = headLineExpandedClass;
else
x[i].className = headLineSnappedClass;
Das darauf folgende Element auf gleicher Ebene ist das Detail-Element. Dieses wird mit einem id-Attribut versehen, wenn es noch keins besitzt.
// ===========================================================================
// Detail-Element bearbeiten
// ===========================================================================
// Das folgende Element auf gleicher Stufe ist das Detail-Element
detailElement = x[i].nextElementSibling;
if(!detailElement) continue; // kein folgendes Element
// Das Detail-Element mit einer ID versehen
if (detailElement.id == "")
detailElement.id = detailsExpandedClassName + detailCount++;
detailElementId = detailElement.id;
Danach wird das class-Attribut des Detail-Elements eingestellt. Bestehende Klassenzuordnungen werden übernommen, außer Zuweisungen der beiden Klassen, die zum Auf- und Zuklappen benutzt werden. Je nach Einstellung von isExpanded wird dann die gewünschte Klasse angehängt.
// Klassen des Detail-Elements analysieren
temp = detailElement.className.split(" ");
// Neuen Klassennamen aufbauen
newClass = "";
for (var j = 0; j < temp.length; j++) // Die beiden Zielklassennamen herausfiltern
{ if((temp[j] == detailsExpandedClassName) || (temp[j] == detailsSnappedClassName))
continue; // nicht weitergeben
newClass += " " + temp[j];
}
detailsExpandedClassName = newClass + " " + detailsExpandedClassName;
detailElement.className = detailsSnappedClassName ;
if(isExpanded)
detailElement.className = detailsExpandedClassName;
else
detailsSnappedClassName = newClass + " " + detailsSnappedClassName;
Alle gesammelten Daten werden in einem Array zwischengespeichert. allBlocks
ist global definiert: var allBlocks = []; // Speichert die Daten
der vorhandenen Blöcke
// ===========================================================================
// Daten ablegen
// ===========================================================================
var snp = {headLineId: headLineId,
detailElementId: detailElementId,
headLineExpandedClass: headLineExpandedClass,
headLineExpandedHTML: headLineExpandedHTML,
headLineSnappedClass: headLineSnappedClass,
headLineSnappedHTML: headLineSnappedHTML,
detailsExpandedClassName:detailsExpandedClassName,
detailsSnappedClassName: detailsSnappedClassName,
isExpanded: isExpanded};
allBlocks.push(snp);
Als letztes wird das onclick-Attribut des Überschriften-Elements mit einem Aufruf von ToggleSnappedTextDetails belegt. Diesem Aufruf werden der Index zu den gespeicherten Daten übergeben.
// onClick für die Überschriften belegen
x[i].setAttribute("onclick",
"ToggleSnappedTextDetails(" + (allBlocks.length-1) + ")");
Wird nun auf das Überschriften-Element geklickt, wird ToggleSnappedTextDetails aufgerufen. ToggleSnappedTextDetails ermittelt die betroffenen Elemente anhand deren ID und ermittelt den aktuellen Zustand isExpanded anhand des eingeführten Attributs detailsexpanded.
// Schaltet die Klassen der Detail-Elemente um und ändert den Text der Überschrift
function ToggleSnappedTextDetails(ind)
{ var snp=allBlocks[ind];
var headLineElement = document.getElementById(snp.headLineId); // Das Kopf-Element
var detailElement = document.getElementById(snp.detailElementId); // Das Element mit den Details
Der Zustand wird umgekehrt.
snp.isExpanded = !snp.isExpanded;
Die gespeicherten Daten werden entsprechend des aktuellen Zustands zugewiesen.
// Die gespeicherten Daten gemäß des aktuellen Zustands zuweisen
if(snp.isExpanded)
{ detailElement.className = snp.detailsExpandedClassName;
headLineElement.innerHTML = snp.headLineExpandedHTML;
headLineElement.className = snp.headLineExpandedClass
}
else
{ detailElement.className = snp.detailsSnappedClassName;
headLineElement.innerHTML = snp.headLineSnappedHTML;
headLineElement.className = snp.headLineSnappedClass;
}
Einer HTML-Seite kann man eine Wertepaarliste in der Form
http://<url>?<key>=<value>&<key>=<value>&...
übergeben. Diese kann man mit der folgenden JavaScript-Funktion einfach auslesen:
function getUrlParameter(key)
{ var query = window.location.search.substring(1);
var pairs = query.split('&');
for (var i = 0; i < pairs.length; i++)
{ var pair = pairs[i].split('=');
if(pair[0] == key)
{ if(pair[1].length > 0)
return pair[1];
}
}
return "";
};
Es wird der <value>-Teil des ersten Wertepaares mit dem passenden <key>-Element zurückgeliefert, dessen <value>-Teil nicht leer ist. Wird kein passendes Wertepaar gefunden, wird "" zurückgeliefert.
JavaScript und CSS-Dateien enthaltenen eine Menge für die Ausführung nicht notwendigen Ballast zur Steigerung der Lesbarkeit, wie Kommentare, Einrückungen, Zeilenvorschübe etc. Diese sollte man entfernen. Es gibt eine Reihe von Online-Tools, die dies erledigen. Für JavaScript habe ich gute Erfahrungen mit JSCompress gemacht. Die komprimierte Datei wird dann üblicherweise mit der Namenserweiterung "-min" abgelegt (UrsOdometer.js -> UrsOdometer-min.js).
Will man einen Build-Vorgang automatisieren, ist ein Online-Minifier nicht hilfreich. Googles Closure Compiler bietet hier eine Alternative. Auf der Seite gibt es einen Download-Link () mit dem man eine ZIP-Datei mit einem Java-Programm herunterladen kann. Dieses Archiv entpackt man am besten im Programm-Verzeichnis. Eine Batchdatei in einem durch PATH zugreifbaren Verzeichnis erleichtert die Benutzung.
jsCompress.cmd:
java -jar "C:\Program Files (x86)\closure-compiler\closure-compiler-v20180204.jar" %1 >%~d1%~p1%~n1-min%~x1
Der Aufruf jsCompress any.js
liefert die komprimierte Datei "any-min.js".
ClipboardToText reduziert bei Texten die in der Zwischenablage gespeicherten Formate auf einfachen Text (plain Text).
Tastaturkürzel, Unicode und UTF-8 Tabellen
Ausführliches Tutorial for die Web-Seiten-Entwicklung: web.dev/learn
... insbesondere die
mathematischen Funktion in CSS