Subpixel-Rendering und das CSS-Objektmodell

Mit Windows 8 steht Ihnen eine nie dagewesene Auswahl an Geräten zum Browsen zur Verfügung, vom großen Desktopbildschirm bis zum kleinen Slate. Damit dieses Angebot an Geräten unterstützt wird, muss der Browser die Webinhalte für viele unterschiedliche Bildschirmgrößen und -maße skalieren und darstellen können. In vorherigen Beiträgen wurde bereits über einige Features von IE berichtet, die diese Szenarien unterstützen. Die Subpixel-Positionierung (von Text und Layout) gehört zu den wichtigsten Plattformtechnologien, mit deren Hilfe Webseiten ansprechend und in jeder Größe einheitlich dargestellt werden.

In diesem Beitrag werden die Änderungen beschrieben, die an IE10 zugunsten einer besseren Subpixel-Positionierung durch das CSS-OM vorgenommen wurden.

Webentwicklern steht für die Erstellung ansprechender Layouts eine Vielzahl von Plattformtechnologien zur Verfügung. Im Allgemeinen beschreiben Entwickler das Layout einer Website mithilfe von CSS-Stylesheets. In einigen Szenarien sind sie zudem auf JavaScript-Code angewiesen, um die Maße, die Ausrichtung oder die Position von Elementen auf einer Webseite pixelgenau festzulegen. Beispielsweise platzieren einige Internetherausgeber ein Bearbeitungsfeld genau über vorhandenen Inhalten, damit es wirkt, als würde dieser direkt bearbeitet. In solchen Szenarien können die APIs des CSS-Objektmodells (CSS-OM) verwendet werden, um die Elementposition auszulesen und/oder festzulegen. Das CSS-OM besteht aus einem Satz von JavaScript-APIs für die programmgesteuerte Bearbeitung von CSS.

Das Messen und Ausrichten von Layoutelementen mithilfe von CSS-OM-APIs kann aufgrund des Verfahrens problematisch sein, nach dem die Werte der Subpixel-Positionierung durch die APIs auf ganze Pixelzahlen gerundet oder verkürzt werden.

Eine kurze Bemerkung zu pixelgenauen Layouts

Pixelgenaue Layouts im Internet neigen im Allgemeinen dazu, dem Ziel offener, kompatibler und anpassbarer Inhalte im Weg zu stehen. Aus diesem Grund stellen sie auch keine bewährte Methode dar. Die folgende Collage enthält einige Fehler, die auftreten können, wenn ein Webdesigner ein pixelgenaues Design entwirft, dieses jedoch wegen unerwarteter Unterschiede zwischen einzelnen Webplattformen fehlerhaft angezeigt wird.

Beispiele für ein fehlerhaftes pixelgenaues Design
Beispiele für ein fehlerhaftes pixelgenaues Design

Webentwickler, die CSS-OM verwenden, um ein Layout dynamisch zu erstellen, sollten einige Pixel Spielraum für mögliche Fehler zulassen. Besser ist es jedoch, dass IE10 mehrere neue Layoutoptionen bietet, mit denen Entwickler viele gewünschte Layouts besser verwirklichen können, ohne auf die pixelgenaue Ausrichtung von CSS-OM angewiesen zu sein.

Beispiel

Im folgenden einfachen Beispiel wird dargestellt, weshalb es mit den CSS-OM-APIs zu heiklen Positionierungsproblemen kommen kann. Mithilfe der Subpixel-Positionierung können vier Felder gleichmäßig im Container verteilt werden, obwohl die Größe des Containers nicht durch vier teilbar ist.

Betrachten Sie das folgende HTML-Fragment:

<footer>

<div>content 1</div><div>content 2</div><div>content 3</div><div>content 4</div>

</footer>

Mit diesem Ausschnitt des CSS-Markups:

footer { width: 554px; border: 1px solid black; text-align: center; }

footer div { display: inline-block; width: 25%; }

footer div:nth-child(even) { background-color: Red; }

footer div:nth-child(odd) { background-color: Orange; }

Nun wird eine Funktion hinzugefügt, die beim Laden ausgeführt wird und die Breite dieser Elemente meldet:

onload = function () {

var footerBoxes = document.querySelectorAll("footer div");

var s = "";

var totalSize = 0;

for (var i = 0; i < footerBoxes.length; i++) {

// Reporting

var offsetWidth = footerBoxes[i].offsetWidth;

s += "content " + (i + 1) + " offsetWidth = " + offsetWidth + "px" + "<br />";

totalSize += offsetWidth;

}

s += "Total <i>calculated</i> offsetWidth = " + totalSize + "px" + "<br />";

s += "Container width = " + document.querySelector("footer").clientWidth + "px" + "<br />";

document.querySelector("#message").innerHTML = s;

}

Wenn dieses Markup und der Code in IE9 ausgeführt werden, sieht das Ergebnis in etwa wie folgt aus:

content 1content 2content 3content 4 content 1 offsetWidth = 139content 2 offsetWidth = 139content 3 offsetWidth = 139content 4 offsetWidth = 139Total calculated offsetWidth = 556Actual container width = 554

Beachten Sie, dass die Summe der von der CSS-OM-API zurückgegebenen offsetWidth-Werte zu einem Gesamtergebnis führt, das um zwei Pixel vom tatsächlich berechneten offsetWidth-Wert des Containers abweicht. Dies geschieht, da die offsetWidth-Werte der einzelnen div-Elemente gerundet werden.

In anderen Browsern führen die Ergebnisse zu ähnlichen Abweichungen. Dabei liegt die Summe in einigen Fällen über und in anderen Fällen unter dem tatsächlichen Wert.

Wenn das Runden/Kürzen eine Gesamtsumme ergibt, die zu einem Überlauf der Containergröße führt (wie dargestellt), wird entweder der Inhalt umgebrochen, oder es werden unerwünschte Bildlaufleisten angezeigt. Zudem wird die Größe vieler Container dem darzustellenden Text und der entsprechenden Schriftart angepasst. Diese Maße der Schriftart können in verschiedenen Browsern unterschiedlich ausfallen, oder es können andere Schriftarten ausgewählt werden, wenn die gewünschte Schriftart nicht verfügbar ist.

Die offsetWidth-API bietet, zusammen mit diversen weiteren häufig verwendeten CSS-OM-Eigenschaften (von denen die meisten 1997 mit IE4 eingeführt wurden), eine praktische und schnelle Methode, um für ein Element aus einer Vielzahl unterschiedlicher Koordinaten ganzzahlige Pixelwerte zu extrahieren. Diese APIs werden aus Kompatibilitätsgründen in allen bekannteren Browser übernommen. Zudem sind sie Bestandteil des Moduls CSS-OM View und ein Standard des W3C-Entwurfs.

In neuen Browserfeatures werden immer wieder die Defizite deutlich, die aus der Begrenzung der CSS-OM-Eigenschaften auf ganzzahlige Pixel hervorgehen. Beispielsweise können die Maße eines Elements in Features wie SVG und CSS-2D/ 3D-Transformierungen schnell Werte ergeben, die zwischen Pixeln liegen.

Lösung des Problems

In Anbetracht dieser (teilweisen) Einschränkung werden die über die getBoundingClientRect() zurückgegebenen Koordinaten in den W3C-Spezifikationen für CSS-OM View als Gleitkommazahlen beschrieben, d. h. in Werten, die Subpixel-Präzision darstellen können. (Bei getBoundingClientRect() handelt es sich um eine weitere CSS-OM-API, die mithilfe desselben Ursprungs wie die offsetWidth-API, die Position und Größe des Begrenzungsrahmens eines Elements bereitstellt.)

Für IE10 wurde die getBoundingClientRect()-API aktualisiert, damit im IE10-Standards-Modus die Subpixel-Auflösung zurückgegeben wird und die Interoperabilität mit anderen Browsern sowie die Ausrichtung am W3C-Standard gewährleistet sind.

Nachdem das obenstehende Beispiel so aktualisiert wurde, dass die width-Komponente des von getBoundingClientRect() zurückgegebenen Rechtecks angegeben wird, meldet IE10 nun folgende Dezimalwerte:

content 1content 2content 3content 4 content 1 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 2 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 3 offsetWidth = 139, getBoundingClientRect().width = 138.5 content 4 offsetWidth = 139, getBoundingClientRect().width = 138.5 Total calculated offsetWidth = 556 Total calculated getBoundingClientRect().width = 554 Actual container width = 554

Subpixel-Werte in anderen Funktionen

Zusätzlich zu getBoundingClientRect werden im IE10-Standards-Modus auch die Subpixel-Positionen von Maus-/Zeigerereignissen gemeldet. Eine Maus bzw. ein Zeiger kann nur zwischen den Pixeln positioniert werden, wenn der Zoomfaktor auf einen anderen Wert als 100 % festgelegt ist. Die folgenden Maus-/Zeiger-APIs sind davon betroffenen:

  • MouseEvent.offsetX/Y
  • MouseEvent.layerX/Y
  • MouseEvent.clientX/Y
  • MouseEvent.pageX/Y
  • MouseEvent.x/y

Um das Engagement für die Kompatibilität mit veralteten Webseiten (Seiten, die nicht für den Umgang mit Subpixel-Werten des CSS-OM eingerichtet sind) fortzusetzen, meldet IE10 weiterhin standardmäßig ganzzahlige Pixeleinheiten für die anderen CSS-OM-Eigenschaften. Dabei handelt es sich um folgende APIs:

  • Element.clientHeight
  • Element.clientWidth
  • Element.clientLeft
  • Element.clientTop
  • Element.scrollTop
  • Element.scrollLeft
  • Element.scrollWidth
  • Element.scrollHeight
  • HTMLElement.offsetWidth
  • HTMLElement.offsetHeight
  • HTMLElement.offsetTop
  • HTMLElement.offsetLeft
  • TextRange.offsetLeft
  • TextRange.offsetTop

Bei Bedarf wird es Webentwicklern mit IE10 nun jedoch ermöglicht, auch die Werte der Subpixel-Position der oben aufgeführten CSS-OM-Eigenschaften zu aktivieren. Für die Verwendung dieses speziellen Features sind der IE10-Standards-Modus sowie eine Aktivierung auf der Website durch Festlegen der folgenden Eigenschaft für das Dokumentobjekt erforderlich:

document.msCSSOMElementFloatMetrics = true;

Wenn alle CSS-OM-APIs aus der vorherigen Liste durch Festlegen von document.msCSSOMElementFloatMetrics auf true aktiviert sind, beginnt die Meldung von Werten in Subpixel-Präzision. Auf diese Weise werden die intern vom Layout- und Rendering-Modul verwendeten Berechnungen exakt wiedergegeben. Beachten Sie, dass der Wert 1,00 von JavaScript in 1 konvertiert wird und die zurückgegebenen Werte nicht unbedingt ein Dezimalkomma aufweisen.

Wenn im vorangegangenen Beispiel document.msCSSOMElementFloatMetrics auf true festgelegt wird, ergibt dies in IE10 folgendes Ergebnis:

content 1content 2content 3content 4 content 1 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 2 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 3 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 content 4 offsetWidth = 138.5, getBoundingClientRect().width = 138.5 Total calculated offsetWidth = 554 Total calculated getBoundingClientRect().width = 554 Actual container width = 554

Beachten Sie, dass offsetWidth nun Dezimalwerte zurückgibt und alle Summen übereinstimmen.

Zusammenfassung

In einigen Fällen ist es hilfreich (und selten sogar erforderlich) die CSS-OM-Eigenschaften für die pixelgenaue Layout-Berechnung zu verwenden. Beachten Sie bei der Verwendung von CSS-OM die Eigenschaft der APIs, ganze Zahlen zu melden. Wenn Sie Ihre Layouts mit CSS oder den CSS-OM-APIs entwerfen, achten Sie darauf, einige Toleranzpixel beizubehalten, um eine ordnungsgemäße Website für mehrere Browser und/oder Geräte bereitzustellen.

– Travis Leithead, Program Manager, Internet Explorer