Category Archives: HTML

Browser Update-Zyklen in Graphen

Nachdem wir letzte Woche schon einen kleinen Ausschnitt aus unseren Browserstatistiken zum Firefox 7 gepostet haben, hier noch 3 weitere interessante Graphen:

Firefox 3.6 bis Firefox 7.0 (01.11.2009 bis 01.10.2011)

Chrome 11 bis Chrome 14 (17.05.2011 bis 17.10.2011, der grüne Graph aka “Unknown Chrome” ist dem Chrome 13 zuzurechnen)

Internet Explorer 6 bis Internet Explorer 9 (1.10.2009 bis 1.10.2011)

Was denkt ihr: Machen die schnellen Release-Zyklen Sinn, oder sorgen die nur für Verwirrung beim Nutzer?

Firefox 7 Auto-Update

Spannend wie schnell Mozilla das automatische Updates zum Endnutzer bringt. In zwei Wochen wurden so gut wie alle Nutzer automatisch auf die neue Version migriert. Wird Zeit, dass die verbleibenden Browser ähnliche Mechanismen etablieren und es damit den Nutzern und auch den Web-Entwicklern einfacher machen.

(In der Grafik sind _nicht alle_ Browser abgebildet)

Wir unterstützen mit unserer neusten Version (GWT basierend) folgende Browser:

  • Firefox 3.6+
  • Chrome 11+
  • Internet Explorer 7+
  • Opera 11.5
  • Safari 5+

Traversieren/Modifizieren von TextNodes mit JQuery

In einer Webanwendung gibt es manchmal die Situation, dass man in bestehendem HTML-Code bestimmte Textinhalte modifizieren muss, unter Verwendung von zusätzlichem Markup. Z.B. Links klickbar machen, Highlighting von Suchergebnissen, etc. Folgendes Sample zeigt, wie man mit JQuery die Textnodes iterieren und dabei modifizieren kann:

// newElement enthält das zu modifizierende HTML. Dabei soll "Mein" durch "<b>Mein</b>" ersetzt
// werden, aber nur in Texten, nicht an sonstigen Stellen im HTML-Code
var newElement = $(['<ul><li>Erste <a href="http://www.Mein.de/">',
    'URL anders?</a> Zeile</li>',
    '<li>Meine zweite Zeile</li><li>Dein und Mein</li>',
    '<li>Nicht Mein sondern Main</li></ul>'].join(''));
  
// Diese Zeile selektiert/filtert die TextNodes in newElement:
var textnodes = $('*', newElement).contents().filter(function(){ return this.nodeType == 3 ; });
  
// Durchlaufen der TextNodes:
$.each(textnodes, function () {
  // mit this.nodeValue erhält man den Text-Inhalt des Text-Elements im DOM
  if (this.nodeValue.indexOf('Mein')>=0) {
    //Ersetzen des TextNodes durch ein HTML-Konstrukt
    $(this).replaceWith(this.nodeValue.replace('Mein', '<b>Mein</b>'));
  }
});
  
// Anzeige des Ergebnis
console.log(newElement.html());

Label inside – Beschriftung in Formularfeldern

(Dies ist eine leicht gekürzte Fassung des Artikels Label inside – Beschriftung in Formularfeldern.)

Auf unseren Plattformen verwenden wir an mehreren Stellen Eingabefelder, bei denen ihre zugehörige Beschriftung im Eingabefeld selbst angezeigt wird. Dies ist platzsparend und dem Nutzer können zusätzliche Informationen gegeben werden.

Die technische Umsetzung, die Beschriftung in den Wert des @value-Attribut des input-Elements bzw. den Inhalt des textarea-Elements zu setzen und per JavaScript aus- und einzublenden, ist jedoch problematisch:

  • Beschriftung und wirkliche Nutzereingabe im Feld müssen unterschieden werden; der Textstil (Farbe) muss mit JavaScript geändert werden. Sollen auch vorbelegte Felder verwendet werden, muss die Unterscheidung auch im Markup (HTML) erfolgen.
  • Wenn das JavaScript zu spät ausgeführt wird, gibt der Nutzer schon etwas ins Feld ein, bevor dessen Beschriftung gelöscht wurde. Dadurch wird der Beschriftungstext unerwünscht zu einem Teil der Eingabe.

Lösung mit label

Markup: Besser realisiert man die Beschriftung mit dem dafür vorgesehenen HTML-Element label. Dieses wird zusammen mit dem Eingabefeld in einem Containerelement der Klasse “labelinside” gekapselt. Auch vorbelegte Felder sind möglich:

<p>
  <span class="labelinside">
    <label for="foo">Label inside</label>
    <input id="foo"/>
  </span>
  <span class="labelinside">
    <label for="baz">Label inside</label>
    <input id="baz" value="vorbelegt"/>
  </span>
</p>
<div class="labelinside">
  <label for="bar">Label inside</label>
  <textarea id="bar"></textarea>
</div>
<div class="labelinside">
  <label for="quz">Label inside</label>
  <textarea id="quz">vorbelegt</textarea>
</div>

Stylesheet: Damit die Beschriftung im Eingabefeld erscheint, wird das label-Element per absoluter Positionierung aus dem Fluss genommen und im Containerelement oben links positioniert. Dazu muss das Containerelement selbst auch positioniert sein:

.labelinside
{
  margin: 3px 0;
  position: relative;
}

.labelinside label
{
  color: silver;
  cursor: text;
  display: none;
  font-size: 0.8em;
  left: 0;
  line-height: 0.8em;
  padding: 6px 3px;
  position: absolute;
  top: 0;
}

.labelinside input,
.labelinside textarea
{
  margin: 0;
}

JavaScript: Wir verwenden auf unseren Plattformen das jQuery-Framework. Damit lassen sich recht einfach alle input- und textarea-Elemente selektieren, die Kindelemente eines Containerelements der Klasse “labelinside” sind. Beim Seitenaufruf sollen die Beschriftungen aller dieser Eingabefelder eingeblendet werden, die nicht vorausgefüllt sind; die anderen bleiben ausgeblendet. Beim Fokussieren eines Eingabefeldes wird dessen Beschriftung ausgeblendet; beim Verlassen wird dessen Beschriftung eingeblendet, wenn kein Eingabewert im Feld steht.

Außerdem wird die display-Eigenschaft von inzeiligen Containerelementen auf “inline-block” geändert, damit die Beschriftung auch bei diesen passt; dies jedoch nicht für Internet Explorer < 8 (Abfrage per conditional compilation und document.documentMode).

var $inputControl = $(".labelinside>input, .labelinside>textarea");

$inputControl.each(function (index, domElement)
{
  /*@cc_on if (document.documentMode && document.documentMode >= 8) @*/
  if ($(this).parent().css("display") == "inline")
    $(this).parent().css("display", "inline-block");

  if (!$(this).val())
    $(this).parent().children("label").show();
});

$inputControl.bind("focus", function(event)
{
  $(this).parent().children("label").hide();
});

$inputControl.bind("blur", function(event)
{
  if (!$(this).val())
    $(this).parent().children("label").show();
});

Und so sieht’s aus: Beipiel 1

Automatisch fokussiertes Eingabefeld

Besondere Beachtung erfordert das beim Seitenaufruf automatisch fokussierte Eingabefeld (HTML5: @autofocus), denn für dieses ist das initiale Ausblenden der Beschriftung nicht ratsam, wenn der Nutzer dadurch keine Information bekommt, was er in dieses Feld eintragen sollte. Auf unseren Plattformen betrifft dies bspw. das Login-Feld.

Hier wird die Beschriftung anfangs eingeblendet. Im Internet Explorer ist dabei eine kurze Verzögerung notwendig (per conditional compilation eingebunden, damit die Ausführung in anderen Browsern nicht verzögert wird). Die Beschriftung wird ausgeblendet, sobald Text eingegeben wird oder wenn mit der Maus in das Eingabefeld geklickt wird.

var $autofocus = $inputControl.filter("[autofocus]");  // oder Selektion per ID

$autofocus.focus();  // setzt den Fokus auch in Browsern, die @autofocus noch nicht interpretieren

if (!$autofocus.val())
  /*@cc_on setTimeout(function () { @*/
  $autofocus.parent().children("label").show();
  /*@cc_on }, 0); @*/

$autofocus.bind("click", function(event)
{
  $(this).parent().children("label").hide();
});

$autofocus.bind("keyup", function(event)
{
  $(this).parent().children("label").hide();
});

Und so sieht’s aus: Beipiel 2

Vorteile dieser Lösung

Bei dieser Lösung genügen wenige Codezeilen für alle Eingabefelder auf einer Webseite. Für neu hinzukommende Eingabefelder ist kein zusätzliches JavaScript erforderlich.

Präsentationsschicht (CSS) und Verhaltensschicht (JavaScript) sind sauber voneinander getrennt. Beschriftung und Nutzereingaben sind sauber voneinander getrennt; eine ungewollte Übernahme des Beschriftungstextes als Eingabe kann nicht erfolgen. Zur Unterscheidung von Beschriftung und Nutzereingaben in den Feldern sind keine Flags oder gar Stringvergleiche des value mit dem (für jedes Eingabefeld anderen) Beschriftungstext erforderlich. Der Stil für den Beschriftungstext steht im Stylesheet; mit JavaScript muss lediglich die Sichtbarkeit geändert werden, nicht jedoch die Textfarbe o.a. Dadurch ist die Lösung nicht nur einfach, sondern auch schnell.