CSS: Border-collapse auf Elementen imitieren, die keine Tabellen sind

Dieser Beitrag zeigt am Beispiel eines Kalenders, wie man das border-collapse Attribut auf grid- und flex-Elementen nachahmen kann.

CSS bietet ein praktisches Keyword namens border-collapse für Tabellen, das es ermöglicht, angrenzende Zellen ihre jeweiligen Borders gemeinsam nutzen zu lassen, um korrekte Zellgrößen beizubehalten und ein saubereres Erscheinungsbild zu erzielen.

Im Sinne der Lesbarkeit nutze ich für Attribute die ursprünglichen englischen (css-)Bezeichnungen.

Non-collapsing border:

Image

Collapsing border:

Image

(Bildquelle: MDN-Dokumentation zu border-collapse)

Leider ist dieses Schlüsselwort auf die Verwendung innerhalb von <table>-Elementen beschränkt und kann derzeit nicht auf andere Elemente angewandt werden.

Da moderne CSS-Layouts weitgehend von Tabellen auf Grids oder Flexboxen umgestiegen sind, verlieren wir dieses nützliche Feature. Beim Darstellen von Elementen in einem Raster kann es daher vorkommen, dass sich die Rahmen angrenzender Boxen überlagern und die doppelte Breite beanspruchen. Wie in diesem Kalender:

Image

Ein gängiger Workaround besteht darin, über css-selectors bestimmte borders zu entfernen, wenn ein Element neben einem anderen mit border liegt.

Je nach Komplexität der selectors und der Layoutstruktur ist das jedoch oft suboptimal:

  • Fehlende Rahmen können bei box-sizing: border-box die Zellengröße reduzieren und dadurch Layoutprobleme verursachen.
  • Eine mögliche Lösung wäre, die Rahmenfarbe stattdessen auf transparent zu setzen. Das kann jedoch zu Artefakten an Kreuzungspunkten führen. Besondere Beachtung auf die übertriebenen Schrägen, wo sich Rahmen treffen:
Image

Was können wir also tatsächlich tun?

Box-shadows ohne Weichzeichnung missbrauchen, um border-Verhalten zu imitieren.

Da wir mehrere box-shadows an einem einzigen Element hinzufügen können, sind die Möglichkeiten recht umfangreich. Zur Veranschaulichung erhält jeder box-shadow eine andere color, zusammen mit einer Erklärung, um den Code leichter nachvollziehbar zu machen.

  • Erster Schatten: 2px 0 0 0 lime erzeugt einen shadow rechts.
Image
  • Zweiter Schatten: 0 2px 0 0 teal fügt einen unten hinzu.
Image
  • Dritter Schatten: 2px 2px 0 0 red schließt die Ecke unten rechts.
Image
  • Vierter Schatten: 2px 0 0 0 orange inset erzeugt einen inset shadow links, der sich, wenn möglich, mit dem ersten (lime) überlappt. Dies ist unser erster echter „collapse“-ähnlicher Effekt, der ausnutzt, wie CSS shadows rendert.
Image
  • Fünfter (und letzter) Schatten: 0 2px 0 0 blue inset fügt oben einen inset shadow hinzu, der sich mit dem zweiten (teal) überlagert, wo möglich.
Image

Finalisierung

Wenn alle Schatten auf grey gesetzt werden, ergibt sich folgendes Resultat:

box-shadow:
  2px 0 0 0 grey,
  0 2px 0 0 grey,
  2px 2px 0 0 grey,
  2px 0 0 0 grey inset,
  0 2px 0 0 grey inset;
Image

Das lässt sich noch weiter verfeinern durch:

  • ein leichtes Verschieben des gesamten Kalenders nach links mittels negativem Margin (da unser linker shadow sich nicht mit der äußeren border verbindet),
  • zusätzliche paddings nach links und oben, die der border-width entsprechen, um den Inhalt näher zur Mitte der durch die shadows definierten Boxen zu rücken.
Image

Und damit sind wir fertig.

Wir haben collapsing borders nachgebildet, ohne tatsächliche borders zu verwenden – indem wir einige der Mittel, die CSS uns bietet, zweckentfremdet haben.