Schlagwort: IE

Fokussieren – nicht selektieren, bitte!

20. Juli 2010

Fokussieren - nicht selektieren, bitte!
Noch so ein Internet Explorer 6 Fehler, der bisher ganz an mir vorbei gegangen ist. Die Situation ist denkbar einfach: Ein Formular mit Auswahl-Feldern (SELECT) und dazugehörigen LABEL Elementen. Klickt der User auf das LABEL-Element wird das entsprechende Formular-Feld fokussiert. Funktioniert in allen mir bekannten Browsern fehlerfrei, nur der IE6 spielt verrückt. Hier wird das Formularfeld nicht nur fokussiert, nein, es wird auch gleich selektiert und zwar die erste Option des Auswahlfeldes.

Habe ein wenig herumgestöbert und siehe da, Microsoft ist das Problem bekannt und bietet eine Lösung. Interessant, dass gerade bei einem HTML-Element, das Usability und Accessibility erhöhen soll, auf eine JavaScript Lösung zurück gegriffen wird. Nicht so richtig sinnvoll, aber besser als gar nichts – hier der Beispielcode:

//Set a temp expando to store the current selectedIndex
function SelectOnFocusIn() {
  try {
    var eSrc = window.event.srcElement;
    if (eSrc)  eSrc.tmpIndex = eSrc.selectedIndex;
  } catch (e) {
    HandleError(e, false);
  }
}
 
//restore the selectedIndex
function SelectOnFocus() {
  try {
    var eSrc = window.event.srcElement;
    if (eSrc) eSrc.selectedIndex = eSrc.tmpIndex;
  } catch (e) {
    HandleError(e, false);
  }
}

Und der dazugehörige HTML-Code:

<select name="test" id="test"
  onfocusin="SelectOnFocusIn()" onfocus="SelectOnFocus()">
  <option value="3">Alien Perm </option>
  <option value="4">Alien Temp </option>
  <option value="1" selected="selected">Native </option>
  <option value="2">Naturalized </option>
  <option value="N">Not Indic. </option>
</select>

Eingebaut, getestet – und anscheinend hat der zuständige Entwickler noch nichts von multiple gehört, denn bei Auswahlfeldern mit Mehrfachauswahl greift der Code nicht. Es wird nur die erste selektierte Option übernommen, alle anderen Auswahlen gehen verloren – Bugfixing der besten Qualität. Welch hoher Maßstab hier angelegt wurde, sieht man schon an der Anweisung im catch Block der Funktionen, wo bitte ist die Funktion HandleError, oder gehört diese Funktion mittlerweile zu einem offiziellen JavaScript Standard? Nein – also weg damit, und dann auch gleich noch die fehlende Unterstützung von Mehrfachauswahlen implementiert:

function SelectOnFocusIn() {
  try {
    var eSrc = window.event.srcElement;
    if(eSrc)  {
      eSrc.firstSelected = eSrc.selectedIndex;
      var tmpIndex = [];
      for (var s = 0, l = eSrc.options.length; s<l; s++) {
        if (eSrc.options[s].selected == true) {
          tmpIndex.push(s);
        }
      }
      eSrc.tmpIndex = tmpIndex;
    }
  } catch (e) {}
}
 
function SelectOnFocus() {
  try {
    var eSrc = window.event.srcElement;
    if (eSrc) {
      /* muss gesetzt werden, anderenfalls wird die
          die erste Option immer mit aktiviert! */
      eSrc.selectedIndex = eSrc.firstSelected;
      for(var i=0, l = eSrc.tmpIndex.length; i<l; i++ ) {
        eSrc.options[eSrc.tmpIndex[i]].selected = true;
      }
    }
  } catch (e) {}
}

Mit diesen Korrekturen lässt sich der Fokus-Bug nun für alle Formen von SELECT-Feldern anwenden, und wenn dem schon so ist, dann würde eine allgemeine Regel für alle solche Felder doch deutlich weiter helfen, als in jedem einzelnen Feld zwei Event-Handler zu notieren. Das Ganze müsste dann nur noch zum frühst möglichen Zeitpunkt geladen werden, und idealerweise nur für den Internet Explorer 6. Meine finale Lösung sieht am Ende so aus:

(function () {
  var d   = document;
  selectFix = function() {
    var selFields = document.getElementsByTagName('select');
    if(!selFields || selFields.length==0) {return;}
    for(var i=0, l=selFields.length; i<l; i++) {
      var elm = selFields[i];
      elm.onfocusin = function() {
        try {
          var eSrc = window.event.srcElement;
          eSrc.firstSelected = eSrc.selectedIndex;
          var tmpIndex = [];
          for (var s = 0, l = eSrc.options.length; s<l; s++) {
            if (eSrc.options[s].selected == true) {
              tmpIndex.push(s);
            }
          }
         eSrc.tmpIndex = tmpIndex;
        } catch (e) {}
      };
      elm.onfocus = function() {
        try {
         var eSrc = window.event.srcElement;
         if (eSrc) {
           eSrc.selectedIndex = eSrc.firstSelected;
           for(var s=0, l = eSrc.tmpIndex.length; s<l; s++ ) {
             eSrc.options[eSrc.tmpIndex[s]].selected = true;
           }
         }
        } catch (e) {}
      }
    }
  };
  try { d.documentElement.doScroll('left'); selectFix(); }
  catch (err) { setTimeout(arguments.callee, 0); }
})();

Fehlt nur noch die Anforderung, das Script nur für den IE 6 laufen zu lassen. Dafür gibt es verschiedene Möglichkeiten. Eine JavaScript basierte “Browserweiche” nutzen (muss aber nicht sein), das ganze Script in eine eigene Datei auslagern und innerhalb eines Conditional Comment einbinden, oder – für den Fall, dass der Code innerhalb einer größeren JavaScript Datei steht über die jscript Variante:

/*@cc_on @*/
/*@if (@_jscript_version == 5.6)
  // dieser Bereich ist für jscript-Interpreter version 5.6 sichtbar
  // (das entspricht dem Internet Explorer 6)
@*/
/*@end @*/

Wie gesagt, es ist alles andere als ideal, die Funktionalität von LABEL mit JavaScript nachträglich zu implentieren, geht es bei diesem Element doch gerade um eine Erhöhung der “Verfügbarkeit” auch ohne Zusatztechnologien. Aber bei dieser Browserversion ist ohnehin schon alles verloren, sollte jemand eine bessere – eine scriptfreie Lösung haben, dann bitte!

Ein kurzer Blick auf CSS im IE8

04. Oktober 2009

Ein kurzer Blick auf CSS im IE8 title=
Das ist bisher an mir vorbeigegangen: Auch der Internet Explorer 8 führt für seine browserspezifischen CSS Erweiterungen einen Präfix -ms ein. Damit ist die Syntax nun analog zum Mozilla -moz, Opera -o, oder Safari -webkit. Es gibt ein paar kleinere Syntaxänderungen und CSS expressions werden nicht mehr unterstützt.

Eine Liste der browserspezifischen CSS Erweiterungen für den Internet Explorer 8 findet man unter: CSS Improvements in Internet Explorer 8 und eine Kompatibilitätsliste für die unterschiedlichen IE Versionen liefert Microsoft ebenfalls. Zu den CSS Elementen, die mit dem -ms Präfix versehen wurden gehört u.a. die Eigenschaft filter. Die Syntax für dieses Element unterscheidet sich von der Syntax älterer Versionen:

/*ältere IE Versionen*/
filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
/*IE 8*/
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";

Die Präfix Elemente des IE8 sind zum guten Teil nicht neu, das Gestalten von Scrollbars, die Filter, das gab es alles bereits mit dem IE6. Auf die Implementierung von abgerundeten Ecken rounded-corners, Farbverläufen gradients oder Teiltransparenten Farbangaben rgba muß weiterhin gewartet werden. Dazu noch ein Tipp:

div {
   /* alte Browser */
   background: rgb(200, 54, 54);
   /* rgba fähige Browser */
   background: rgba(200, 54, 54, 0.5);
}
 
/* und für den ie über die Verwendung von Filter: */
<!--[if IE]>
   div  {
       background:transparent;
       filter:progid:DXImageTransform.Microsoft.gradient(
         startColorstr=#99000050,
         endColorstr=#99000050
       );
       zoom: 1;
    }
<![endif]-->

Die auf den ersten Blick merkwürdige Farbangabe #99000050 ist kein Schreibfehler, die Farbe wurde als AARRGGBB Wert notiert. Die ersten beiden Ziffern stehen für die Transparenz. Auf diesem Weg lässt sich rgba also auch für den Internet Explorer implementieren. Die Idee alternativ ein semi-transparentes PNG für diesen Effekt zu nutzen, scheitert an der Version 6 (ohne dem Einsatz von Javascript), der Filter funktioniert hingegen schon ab Version 5.

Wie bereits einleitend erwähnt: CSS expressions werden nicht mehr unterstützt. Microsoft schreibt:

While powerful, this feature was never standardized, has a high performance cost and increases the browser’s attack surface. Moreover, its main usage scenario has been to work around CSS bugs and limitations in Internet Explorer (for instance, to simulate max-width or pseudo-classes like : first-child).

Solche “wundervollen” CSS Spielereien (nochmal der IE6 und seine mangelnde PNG Unterstützung) gehören damit der Vergangenheit an – Schade nur, dass gerade die älteren ohnehin langsameren Browser diese Form der Hilfestellung weiterhin benötigen.

* html img, * html .png {
position:relative;
behavior: expression(
  (this.runtimeStyle.behavior="none") &&
   (this.pngSet ? this.pngSet=true:
    (this.nodeName == "IMG" &&
     this.src.toLowerCase().indexOf('.png') >-1 ?
     (this.runtimeStyle.backgroundImage = "none",
      this.runtimeStyle.filter = "
      progid:DXImageTransform.Microsoft.AlphaImageLoader(
       src='" + this.src + "', sizingMethod='image')",
       this.src = "transparent.gif"
     ) :
    (this.origBg = this.origBg? this.origBg :
     this.currentStyle.backgroundImage.toString().
     replace('url("','').replace('")',''),
     this.runtimeStyle.filter = "
      progid:DXImageTransform.Microsoft.AlphaImageLoader(
       src='" + this.origBg + "', sizingMethod='crop')",
       this.runtimeStyle.backgroundImage = "none"
     )
   ),
   this.pngSet=true
  )
);}

Bei generiertem Inhalt über CSS (Attribute wie content oder quotes) zieht der Internet Explorer 8 gleich, und führt die vollständige Unterstützung für generierten Inhalt nach der CSS 2.1 ein. Gleiches gilt für die Pseudo-Klassen :before, :after, :focus und :active.

Ohne Frage unterstützt der IE8 die CSS2.1 Spezifikation wesentlich besser und standardkonformer als seine Vorgänger Fassungen. Bleibt abzuwarten, ob es Microsoft gelingt das Tempo anderer Hersteller mitzugehen.