Das Problem

Eine Pricing-Card ist per transform: scale(1.05) leicht vergrößert dargestellt – ein klassischer Effekt um die empfohlene Option hervorzuheben. Alles sieht gut aus, bis man weiter scrollt: Der Abschnitt direkt darunter wird von der Card überlappt.

.pricing-card--featured {
    transform: scale(1.05);
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
}

Die Card ragt visuell in den nächsten Abschnitt hinein. Was jetzt?


Diagnose 1 (falsch): “Das ist ein Padding-Problem”

Gedanke: Der Container hat zu wenig Platz unten. Mehr Padding macht Luft.

.pricing-grid {
    padding-bottom: 2rem;
}

Ergebnis: Keine Wirkung. Die Überlappung bleibt.

Warum das nicht funktioniert: padding-bottom fügt Platz innerhalb des Containers hinzu. Aber das Problem ist nicht, dass der Container zu klein ist – transform: scale() verändert die visuelle Größe des Elements, ohne den DOM-Flow zu beeinflussen. Der Browser reserviert für die Card immer noch genau den gleichen Platz wie ohne Transform. Der Container weiß gar nicht, dass die Card optisch herausragt.


Diagnose 2 (falsch): “Das ist ein Stacking-Problem”

Gedanke: Die Card liegt über dem nächsten Abschnitt, weil der Stacking Context falsch ist. Mit z-index kann man das regeln.

.folgeauftrag {
    position: relative;
    z-index: 2;
}

Ergebnis: Der Text des nächsten Abschnitts wird jetzt sichtbar durch die Card gerendert – also über ihr. Die physische Überlappung bleibt trotzdem bestehen.

Das macht die Sache sogar schlimmer: Jetzt überlagern sich Card und Abschnitts-Inhalt visuell, aber keiner von beiden weicht zurück.

Warum das nicht funktioniert: z-index steuert die Render-Reihenfolge, nicht den physischen Platz im Layout. Das Element wird zwar über der Card gerendert, aber es nimmt immer noch denselben Platz im DOM ein wie vorher. Es gibt keine Kollisionsvermeidung – die beiden Elemente teilen sich denselben Bildschirmbereich, nur wer oben gerendert wird ändert sich.


Diagnose 3 (richtig): “Das ist ein Layout-Abstandsproblem”

Gedanke: Wenn transform: scale() den DOM-Flow nicht verändert, muss der nötige Abstand explizit geschaffen werden. Nicht durch Padding (innen), sondern durch Margin (außen).

.pricing-grid {
    margin-bottom: 5rem;
}

Ergebnis: Die Überlappung ist weg. Der nächste Abschnitt beginnt mit ausreichend Abstand.


Die Ursache: Was transform:scale() wirklich macht

transform: scale(1.05) ist eine rein visuelle Operation. Der Browser rendert das Element 5% größer, aber im Dokument-Layout bleibt der Platz für das Element unverändert.

Konkret bedeutet das:

  • Der Grid-Container berechnet seine Höhe ohne den Scale-Effekt
  • Die skalierte Card ragt visuell über den Container hinaus
  • Der box-shadow: 0 15px 40px verstärkt diesen Effekt noch – der Schatten hat ebenfalls keinen Einfluss auf den DOM-Flow
  • Der nächste Abschnitt beginnt direkt unterhalb des unveränderten Containers
┌──────────────────────────────────┐
│  Pricing Grid (DOM-Größe)        │
│                                  │
│  ┌────┐  ┌──────────┐  ┌────┐   │
│  │Card│  │  Card    │  │Card│   │
│  │    │  │ featured │  │    │   │
│  └────┘  └──────────┘  └────┘   │
└──────────────────────────────────┘
            ╔════════════╗  ← visuell
            ║  scale(1.05)║    herausragend
            ╚════════════╝
┌──────────────────────────────────┐
│  Nächster Abschnitt              │  ← beginnt hier (DOM)
│  ...wird überlappt...            │
└──────────────────────────────────┘

Das margin-bottom auf dem Grid verschiebt den Startpunkt des nächsten Abschnitts nach unten. Genug, um den visuellen Überhang (Scale + Shadow) aufzufangen.


Warum zuerst z-index probiert wird (und warum es falsch ist)

“Etwas überlappt etwas anderes” klingt intuitiv nach einem Stacking-Problem. Aber Stacking-Probleme entstehen wenn Elemente absichtlich übereinandergelegt werden (z.B. Overlays, Modals, Dropdowns). Dann regelt z-index wer oben liegt.

Bei Transform-Overlaps ist das anders: Die Elemente sollen gar nicht übereinanderliegen. Eines soll unter dem anderen stehen, aber der visuelle Effekt des ersten ragt in das zweite hinein. Hier hilft kein z-index – hier fehlt Abstand.

Faustregel:

  • Element liegt absichtlich über einem anderen? → z-index
  • Element nimmt zu viel visuellen Platz ein? → margin oder padding
  • transform: scale() beteiligt? → Fast immer margin

Lessons Learned

  1. transform: scale() ist unsichtbar für den Layout-Engine. Es verändert nie den Platz im DOM-Flow. Alle Folge-Elemente positionieren sich so, als wäre der Scale nicht vorhanden.

  2. box-shadow ist ebenfalls unsichtbar für den Layout-Engine. Ein großer Schatten ragt visuell weit heraus, nimmt aber keinen Platz ein. Bei skalierten Elementen mit Schatten braucht man doppelt so viel margin-Puffer.

  3. z-index ist die falsche Werkzeugkiste für Abstandsprobleme. Wenn die Frage ist “warum überlappt das?”, kommt z-index erst infrage wenn die Antwort auf “haben diese Elemente genug Abstand?” bereits “Ja” ist.

  4. Debuggen mit DevTools: Im Browser-Inspector kann man transform: none temporär auf dem Element setzen. Wenn das Element dann nicht mehr überlappt – ist transform die Ursache und margin ist die Lösung. Wenn es trotzdem überlappt – stimmt etwas anderes nicht.


Quick-Reference

SymptomUrsacheFix
transform:scale() Element überlappt nächsten AbschnittDOM-Flow ignoriert scalemargin-bottom auf Element oder Container
z-index macht Text “durchsichtig” sichtbarStacking Order geändert, nicht Platzz-index rückgängig, stattdessen margin
padding-bottom auf Container hat keine WirkungElement ragt aus Container herausmargin-bottom auf Container statt padding
Überlappung bleibt trotz viel PlatzShadow ragt weiter als das Elementmargin-bottom um shadow-blur-radius erhöhen