CSS: Unscharfen Text in Webkit-Browsern nach `transform` vermeiden

Eine viel benutzte Methode, um DOM-Elemente mit undefinierter Breite (z.B. Überschriften) und Höhe zu zentrieren, ist die Verschiebung über den "translate"-Hack:

.zentriert {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
}

Man verschiebt damit quasi den Ursprung der Positionierung von der linken, oberen Ecke auf den Mittelpunkt des Elements.
Dabei kann es passieren, dass das zu positionierende Element eine ungerade Pixelbreite hat (z.B. 519px). Wendet man auf so ein Element eine Transformierung an, berechnen aktuell die meisten WebKit-Browser die transformierte Position mit Halb-Pixeln. Somit wird dann das Element um 259.5px verschoben und auf dem Halb-Pixel platziert, was den Text in WebKit-Browsern unscharf rendert.

Berechneter Pixelwert einer Transformierung

Es gibt verschiedene Vorschläge, mit denen man dies umgehen können soll, die bei mir in Chrome 53 unter OS 10.11 alle nicht funktionieren. Dazu zählt:

  • backface-visibility: hidden hinzufügen
  • 3D-transforms nutzen statt 2D-transforms: transform: translate3d(-50%,-50%,0);
  • perspective(1px) zur tranforms-Property hinzufügen, um nur ganze Pixel zu erzwingen

Scharfer Text mit scale() und zoom

Das Einzige, was bei mir funktioniert, ist folgende Lösung:

.zentriert {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%) scale(2);
  zoom: 0.5;
}

Durch diesen Hack skaliert man zunächst über die transform-Property das Element auf die doppelte Größe und setzt es dann durch die zoom-Funktion auf die Ausgangsgröße zurück. Mit dieser Methode werden dann zur Positionierung nur ganze Pixel verwendet, so dass der Text scharf erscheint. Klingt umständlich und unperformant, ist aber wie gesagt das Einzige, was bei mir hilft.

Progressive Enhancement

Ich will den Hack eigentlich nur bei WebKit-Browsern anwende, was aber noch wichtiger ist, ist dass in jedem Fall sowohl scale, als auch zoom angewendet wird zur korrekten Darstellung. Da die scale-Property besser supported ist, als die zoom-Property, will ich beispielsweise vermeiden, dass der Text z.B. im Firefox nur hochskaliert wird, aber dann nicht nochmal verkleinert wird. Aus diesem Grund wende ich eine @supports Regeln für das zoom-Property an, so dass nur Browser, die den zoom unterstützen beide Properties anwenden. Das passt in diesem Falle sehr gut, da Firefox aktuell der einzige Browser ist, der zoom nicht unterstützt und ich diesen sowieso nicht abdecken muss. Gleiches gilt für die Browser IE und Edge, die die @supports Regel noch nicht unterstützen. Da auch diese Browser nicht WebKit nutzen, können beide die Regel ignorieren.
Alternativ könnte man natürlich über eine Browser-Detection gezielt nur WebKit-Browser ansprechen.

So sieht dann der komplette Code mit der @supports-Regel aus:

.zentriert {
  position: absolute;
  top: 50%;
  left: 50%;
}

@supports (zoom: 0.5) {
    .zentriert {
        transform: translate(-50%,-50%) scale(2);
        zoom: 0.5;
    }
}