Diff- und Vergleichsansicht mit Tailwind CSS gestalten
AI generated
tw
Tailwind CSS · UI-Muster · Diff-Ansicht
Diff- und Vergleichsansicht
Side-by-Side und Inline, konsistente Farbcodierung und Zeilennummern mit Tailwind CSS

Eine Diff-Ansicht muss auf einen Blick zeigen, was hinzugefügt, entfernt oder geändert wurde, egal ob als Side-by-Side-Vergleich zweier Spalten oder als kompaktere Inline-Darstellung. Dieses Muster zeigt, wie sich beide Varianten mit Tailwind CSS konsistent einfärben, mit Zeilennummern versehen und an einem praktischen Textvergleich zwischen zwei Versionen durchspielen lassen.

14 Min. Lesezeit Side-by-Side vs. Inline Farbcodierung & Zeilennummern

1. Warum eine Diff-Ansicht mehr als drei Farben braucht

Eine Diff-Ansicht vergleicht zwei Versionen eines Inhalts, meist Text oder Code, und muss dabei drei grundsätzlich unterschiedliche Änderungsarten unterscheidbar machen: hinzugefügte Zeilen, entfernte Zeilen und geänderte Zeilen, bei denen ein Teil des Inhalts erhalten bleibt und ein anderer Teil ersetzt wird. Werden alle drei Zustände nur über eine einzige Akzentfarbe unterschieden, etwa alle drei blau mit unterschiedlicher Deckkraft, muss die Nutzerin den Zeileninhalt selbst lesen, um die Änderungsart zu verstehen, was den eigentlichen Zweck einer Diff-Ansicht untergräbt.

Die etablierte Konvention aus Versionskontrollsystemen wie Git ist Grün für Hinzugefügtes, Rot für Entferntes und eine dritte Farbe, meist Gelb oder Orange, für Geändertes oder für hervorgehobene Wortbereiche innerhalb einer ansonsten unveränderten Zeile. Diese Konvention sollte nicht ohne guten Grund gebrochen werden, da Entwicklerinnen und technisch versierte Nutzerinnen sie aus Terminal, IDE und Pull-Request-Ansichten bereits verinnerlicht haben und eine abweichende Farbwahl unnötige kognitive Reibung erzeugt.

2. Side-by-Side- und Inline-Layout mit Tailwind Grid

Die Side-by-Side-Ansicht stellt die alte und die neue Version nebeneinander in zwei Spalten dar, wobei entfernte Zeilen nur links und hinzugefügte Zeilen nur rechts erscheinen, während unveränderte Zeilen auf beiden Seiten auf gleicher Höhe stehen. Mit CSS Grid und zwei gleich breiten Spalten über grid-cols-2 lässt sich das sauber umsetzen, wichtig ist dabei, dass leere Platzhalterzeilen auf der jeweils anderen Seite eingefügt werden, damit die Zeilen trotz unterschiedlicher Länge der beiden Versionen synchron auf gleicher Höhe bleiben.

Die Inline-Ansicht dagegen zeigt alle Zeilen untereinander in einer einzigen Spalte, in der Reihenfolge, in der sie in der zusammengeführten Diff-Berechnung erscheinen. Sie braucht deutlich weniger horizontalen Platz und eignet sich daher besser für schmale Bildschirme oder eingebettete Vorschauen, verliert dabei aber den direkten visuellen Vergleich auf gleicher Zeilenhöhe, den die Side-by-Side-Ansicht bietet. In der Praxis bewährt sich ein Umschalter zwischen beiden Modi, oft per Alpine-Boolean gesteuert, damit Nutzerinnen je nach Bildschirmbreite und Vorliebe wählen können.


<div x-data="{ mode: 'side-by-side' }">
  <div class="mb-3 flex gap-2 text-sm">
    <button @click="mode = 'side-by-side'" :class="mode === 'side-by-side' && 'font-semibold text-blue-700'">
      Side-by-Side
    </button>
    <button @click="mode = 'inline'" :class="mode === 'inline' && 'font-semibold text-blue-700'">
      Inline
    </button>
  </div>

  <div x-show="mode === 'side-by-side'" class="grid grid-cols-2 divide-x divide-slate-200 font-mono text-sm">
    <div class="bg-red-50">
      <div class="flex px-2 py-0.5">
        <span class="w-8 shrink-0 select-none text-right text-slate-400">12</span>
        <span class="pl-3 text-red-800">- return $legacyPrice;</span>
      </div>
    </div>
    <div class="bg-green-50">
      <div class="flex px-2 py-0.5">
        <span class="w-8 shrink-0 select-none text-right text-slate-400">12</span>
        <span class="pl-3 text-green-800">+ return $priceFormatter->format($price);</span>
      </div>
    </div>
  </div>

  <div x-show="mode === 'inline'" class="divide-y divide-slate-100 font-mono text-sm">
    <div class="flex bg-red-50 px-2 py-0.5">
      <span class="w-8 shrink-0 select-none text-right text-slate-400">12</span>
      <span class="pl-3 text-red-800">- return $legacyPrice;</span>
    </div>
    <div class="flex bg-green-50 px-2 py-0.5">
      <span class="w-8 shrink-0 select-none text-right text-slate-400">12</span>
      <span class="pl-3 text-green-800">+ return $priceFormatter->format($price);</span>
    </div>
  </div>
</div>

3. Konsistente Farbcodierung über die gesamte Ansicht hinweg

Damit die Farbcodierung wirklich als verlässliches Signal funktioniert, muss sie an jeder Stelle der Diff-Ansicht identisch verwendet werden: dieselbe Grün-Nuance für den Zeilenhintergrund, die Zeilennummer, ein eventuelles Plus-Symbol am Zeilenanfang und einen möglichen Zähler in der Zusammenfassung über der Diff-Ansicht. Ein Bruch in dieser Konsistenz, etwa ein kräftigeres Grün im Hintergrund als im Zähler, lässt die Nutzerin unbewusst zweifeln, ob es sich tatsächlich um dieselbe Kategorie handelt.

Praktisch bewährt sich eine feste Zuordnung von Tailwind-Farbstufen pro Zustand, etwa green-50 für den Zeilenhintergrund und green-800 für den Text bei Hinzugefügtem, spiegelbildlich red-50 und red-800 für Entferntes. Diese Zuordnung sollte zentral als Konstante oder Tailwind-Komponente definiert werden, statt in jeder einzelnen Diff-Zeile erneut die passenden Klassen von Hand zusammenzustellen, denn eine spätere Anpassung der Farbpalette betrifft sonst potenziell Dutzende Stellen im Code.

4. Die Zeilennummern-Spalte richtig ausrichten

Zeilennummern müssen rechtsbündig ausgerichtet werden, damit einstellige und mehrstellige Nummern trotz unterschiedlicher Zeichenanzahl an derselben horizontalen Position enden und der Diff-Inhalt selbst in einer geraden Linie beginnt. Eine feste Spaltenbreite über w-8 oder w-10, je nachdem wie viele Zeilen die längste erwartete Datei hat, verhindert außerdem, dass die Spalte bei besonders langen Dateien mit vierstelligen Zeilennummern plötzlich breiter wird als der Rest der Ansicht.

Bei der Side-by-Side-Ansicht braucht jede der beiden Spalten eine eigene, unabhängige Zeilennummerierung, da die alte und die neue Version unterschiedlich viele Zeilen haben können und eine hinzugefügte Zeile in der alten Version schlicht keine entsprechende Nummer hat. Für Zeilen ohne Entsprechung auf der jeweils anderen Seite bleibt die Zeilennummer leer, statt eine Null oder einen Platzhalter wie einen Bindestrich anzuzeigen, was in Diff-Werkzeugen wie Git leicht mit einer echten Zeilennummer verwechselt werden könnte.

5. Praxisbeispiel: zwei Textversionen vergleichen

Ein einfacher, aber lehrreicher Anwendungsfall ist der Vergleich zweier kurzer Textabsätze, etwa zwei Versionen eines Produktbeschreibungstextes vor und nach einer redaktionellen Überarbeitung. Der Diff-Algorithmus selbst, üblicherweise eine Zeilen- oder Wort-basierte Longest-Common-Subsequence-Berechnung, liefert eine Liste von Operationen: unverändert, hinzugefügt, entfernt. Diese Liste wird dann einfach zeilenweise mit den entsprechenden Tailwind-Klassen aus der Farbcodierung gerendert, ohne dass die Darstellung selbst irgendeine Diff-Logik enthalten müsste.

Für Textvergleiche auf Wortebene statt reiner Zeilenebene lohnt sich eine zusätzliche Hervorhebung einzelner geänderter Wörter innerhalb einer ansonsten identischen Zeile, etwa über ein mark-Element mit gelbem Hintergrund. Das macht kleine Änderungen wie eine korrigierte Zahl oder ein ausgetauschtes Adjektiv deutlich sichtbarer, als wenn die komplette Zeile pauschal als geändert markiert würde, was bei überwiegend identischen langen Zeilen die eigentliche Änderung leicht untergehen lässt.

6. Diff-Farben im Dark Mode anpassen

Die hellen Hintergrundfarben wie green-50 und red-50, die im Light Mode gut funktionieren, wirken im Dark Mode auf einem dunklen Hintergrund wie ein greller Fremdkörper, wenn sie unverändert übernommen werden. Über Tailwinds dark:-Präfix lassen sich für jeden Zustand dunklere, gesättigtere Hintergrundtöne definieren, etwa dark:bg-green-950 und dark:bg-red-950, kombiniert mit entsprechend helleren Textfarben wie dark:text-green-300, damit der Kontrast in beiden Modi vergleichbar bleibt.

Wichtig ist, die Farbzuordnung zwischen Light und Dark Mode konsistent zu halten, sodass Grün immer Grün bleibt und nicht etwa im Dark Mode zu einem anderen Farbton wechselt, nur weil ein bestimmter Grünton im Dunkeln schlecht lesbar war. Eine kleine Testrunde mit realistischen Diff-Inhalten in beiden Modi deckt außerdem zuverlässiger auf, ob der Kontrast tatsächlich ausreicht, als eine rein rechnerische Kontrastprüfung einzelner Farbpaare.

7. Barrierefreiheit: nicht nur auf Farbe verlassen

Wer Farben nicht unterscheiden kann, etwa bei Rot-Grün-Farbenblindheit, die einen relevanten Anteil der männlichen Bevölkerung betrifft, darf sich in einer Diff-Ansicht nicht ausschließlich auf die Hintergrundfarbe verlassen müssen, um Hinzugefügtes von Entferntem zu unterscheiden. Ein Plus- und ein Minus-Symbol am Zeilenanfang, wie es die meisten Terminal-Diffs ohnehin schon verwenden, liefert ein zweites, farbunabhängiges Signal und sollte in jeder Diff-Ansicht standardmäßig vorhanden sein, nicht nur als optionales Extra.

Für Screenreader-Nutzerinnen reicht die visuelle Kennzeichnung allein ohnehin nicht aus. Jede Diff-Zeile sollte über ein aria-label oder einen versteckten Text kommunizieren, ob es sich um eine hinzugefügte, entfernte oder unveränderte Zeile handelt, etwa aria-label="Hinzugefügte Zeile" auf dem umschließenden Element. Ohne diese textuelle Ergänzung bleibt der komplette Sinn der Diff-Ansicht für Screenreader-Nutzerinnen verborgen, selbst wenn Farbe und Symbol für sehende Nutzerinnen eindeutig sind.

8. Lange Zeilen: Umbruch statt horizontalem Scrollen

Code-Zeilen oder lange Textsätze überschreiten schnell die verfügbare Breite der Diff-Spalte, besonders in der Side-by-Side-Ansicht, wo jede Spalte nur die Hälfte der Gesamtbreite zur Verfügung hat. Horizontales Scrollen pro Zeile ist technisch möglich, führt aber dazu, dass Nutzerinnen bei jeder langen Zeile erneut scrollen müssen, um den vollständigen Inhalt zu sehen, was bei einem Diff mit vielen langen Zeilen schnell mühsam wird.

Ein automatischer Zeilenumbruch über whitespace-pre-wrap statt whitespace-pre löst dieses Problem, erzeugt dafür aber Zeilen unterschiedlicher visueller Höhe, was in der Side-by-Side-Ansicht die exakte Zeilen-zu-Zeilen-Ausrichtung zwischen linker und rechter Spalte erschwert. In der Praxis ist ein Kompromiss üblich: automatischer Umbruch in der Inline-Ansicht, wo die exakte Zeilenhöhe keine Rolle spielt, und horizontales Scrollen mit einer sichtbaren Scrollbar in der Side-by-Side-Ansicht, um die Ausrichtung zu erhalten.

9. Grenzen des Musters und typische Fehler

Ein häufiger Fehler ist, die Diff-Berechnung selbst clientseitig für sehr große Dateien durchzuführen, etwa eine komplette generierte Datei mit zehntausenden Zeilen. Ein naiver Diff-Algorithmus hat in solchen Fällen eine Laufzeit, die den Browser-Tab für mehrere Sekunden blockieren kann, weshalb sich für große Vergleiche eine serverseitige Berechnung oder zumindest ein Web Worker lohnt, der die Berechnung außerhalb des Haupt-Threads durchführt, während die UI weiterhin reagiert.

Eine zweite Grenze betrifft reine Whitespace-Änderungen, etwa eine geänderte Einrückung ohne inhaltliche Änderung, die in einer naiven zeilenbasierten Diff-Berechnung als vollständig geänderte Zeile erscheinen, obwohl inhaltlich nichts Wesentliches passiert ist. Ein Umschalter, der Whitespace-Änderungen optional ignoriert, ähnlich der Option in Git-Diffs, reduziert in solchen Fällen erheblich das visuelle Rauschen und lässt die tatsächlich relevanten Änderungen deutlicher hervortreten.

Zustand Hintergrund (Light) Hintergrund (Dark) Zusätzliches Signal
Hinzugefügt bg-green-50, text-green-800 bg-green-950, text-green-300 Plus-Symbol am Zeilenanfang
Entfernt bg-red-50, text-red-800 bg-red-950, text-red-300 Minus-Symbol am Zeilenanfang
Geändert (Wortebene) bg-yellow-100 auf mark bg-yellow-900/40 auf mark Hervorhebung nur des geänderten Wortbereichs
Unverändert bg-transparent bg-transparent Kein zusätzliches Symbol nötig

Mironsoft

Tailwind-CSS-Architektur, Design-Systeme und Performance

Tailwind-Frontends, die trotz tausender Utility-Klassen wartbar bleiben?

Wir prüfen bestehende Tailwind-Projekte auf aufgeblähte Klassenlisten, inkonsistente Design-Tokens und ungenutzte CSS-Reste und bauen daraus ein Design-System, das sich sauber skaliert statt mit jeder Komponente unübersichtlicher zu werden.

Design-System-Review

Tokens, Spacing-Skala und Komponentenkonsistenz auf Wartbarkeit prüfen.

Performance-Optimierung

CSS-Bundle-Größe, Purge-Konfiguration und Ladezeiten systematisch reduzieren.

Component-Architektur

Wiederverwendbare, gut strukturierte Komponenten statt Klassenlisten-Wildwuchs aufbauen.

10. Zusammenfassung

Diff-Vergleichsansicht mit Tailwind: Das Wichtigste auf einen Blick

Farbkonvention

Grün für hinzugefügt, Rot für entfernt, Gelb für geändert, konsistent über Hintergrund, Text und Zusammenfassung hinweg.

Side-by-Side vs. Inline

Zwei Grid-Spalten mit Platzhalterzeilen gegen eine einzelne Spalte in Diff-Reihenfolge, oft per Umschalter wählbar.

Barrierefreiheit

Plus-/Minus-Symbole und aria-label ergänzen die Farbcodierung, damit Farbenblinde und Screenreader-Nutzerinnen nicht ausgeschlossen werden.

Lange Zeilen

whitespace-pre-wrap in der Inline-Ansicht, horizontales Scrollen mit erhaltener Zeilen-Ausrichtung in der Side-by-Side-Ansicht.

11. FAQ: Diff-Vergleichsansicht mit Tailwind: Das Wichtigste auf einen Blick

1Welche Farben sollte ich für eine Diff-Ansicht verwenden?
Grün für hinzugefügte, Rot für entfernte und Gelb oder Orange für geänderte Inhalte, angelehnt an die etablierte Konvention aus Git und den meisten IDEs.
2Was ist der Unterschied zwischen Side-by-Side- und Inline-Diff?
Side-by-Side zeigt alte und neue Version in zwei Spalten nebeneinander, Inline zeigt alle Zeilen in einer einzigen Spalte in der Reihenfolge der Diff-Berechnung.
3Wie richte ich Zeilennummern in einer Diff-Ansicht aus?
Rechtsbündig in einer festen Spaltenbreite, damit ein- und mehrstellige Nummern an derselben Position enden und der Diff-Inhalt in einer geraden Linie beginnt.
4Warum reicht Farbe allein für die Diff-Kennzeichnung nicht aus?
Weil Nutzerinnen mit Rot-Grün-Farbenblindheit die Zustände sonst nicht unterscheiden können. Plus- und Minus-Symbole liefern ein zweites, farbunabhängiges Signal.
5Wie kennzeichne ich Diff-Zeilen für Screenreader?
Über ein aria-label oder versteckten Text auf jeder Zeile, das den Zustand explizit benennt, etwa Hinzugefügte Zeile oder Entfernte Zeile.
6Wie gehe ich mit sehr langen Codezeilen in der Diff-Ansicht um?
In der Inline-Ansicht mit automatischem Umbruch über whitespace-pre-wrap, in der Side-by-Side-Ansicht meist mit horizontalem Scrollen, um die Zeilen-Ausrichtung zwischen den Spalten zu erhalten.
7Wie passe ich Diff-Farben für den Dark Mode an?
Mit dunkleren, gesättigteren Hintergrundtönen über das dark:-Präfix, etwa dark:bg-green-950 statt bg-green-50, kombiniert mit helleren Textfarben für ausreichenden Kontrast.
8Wie markiere ich einzelne geänderte Wörter statt ganzer Zeilen?
Mit einem mark-Element mit gelbem Hintergrund um den geänderten Wortbereich, während der Rest der Zeile unverändert dargestellt bleibt.
9Warum wird die Diff-Berechnung bei großen Dateien langsam?
Weil ein naiver zeilenbasierter Diff-Algorithmus mit der Dateigröße überproportional an Rechenzeit zulegt. Für große Dateien lohnt sich serverseitige Berechnung oder ein Web Worker.
10Wie filtere ich reine Whitespace-Änderungen aus einer Diff-Ansicht heraus?
Mit einem Umschalter, der Whitespace-Unterschiede beim Vergleich ignoriert, ähnlich der entsprechenden Option in Git, um visuelles Rauschen zu reduzieren.