Übergang zu automatischer Höhe

Avatar of Geoff Graham
Geoff Graham am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich weiß, das ist etwas, das Chris schon ewig wollte, also ist es keine Überraschung, dass er bereits einen fantastischen Beitrag nur einen Tag nach Bekanntwerden der Nachricht geschrieben hat. Tatsächlich habe ich zum ersten Mal durch seinen Beitrag davon erfahren und konnte keine Ankündigung finden. Deshalb dachte ich, ich fasse ein paar Notizen zusammen, da es sich um eine bedeutende Entwicklung handelt.

Die Nachricht: Der Übergang zu auto ist jetzt Realität! Nun, es wird Realität werden. Chrome Canary hat kürzlich die Unterstützung dafür eingeführt, und das ist der einzige Ort, an dem Sie es im Moment finden können. Und selbst dann wissen wir nicht, ob die Implementierung in Chrome Canary seinen Weg in die Syntax findet, wenn die Funktion offiziell wird.

Das Problem

Hier ist die Situation. Sie haben ein Element. Sie haben es markiert, Inhalte hineingepackt und ihm viele Stile zugewiesen. Wissen Sie, wie hoch es ist? Natürlich nicht! Sicher, wir können JavaScript bitten, das Element für uns zu bewerten, aber was CSS betrifft, sind die berechneten Abmessungen des Elements unbekannt.

Das macht es schwierig, zum Beispiel dieses Element von height: 0 auf height: beliebig zu animieren. Wir müssen wissen, was "beliebig" ist, und das können wir nur tun, indem wir dem Element eine feste Höhe zuweisen. So haben wir Zahlen, von denen wir von einer Höhe von Null auf diese spezifische Höhe übergehen können.

.panel {
  height: 0;
  transition: height 0.25s ease-in;

  &.expanded {
    height: 300px;
  }
}

Aber was passiert, wenn sich dieses Element im Laufe der Zeit ändert? Vielleicht ändert sich die Schriftart, wir fügen Polsterung hinzu, es werden mehr Inhalte eingefügt ... alles, was die Abmessungen verändert. Wir müssen wahrscheinlich diese height: 300px auf die neue feste Höhe aktualisieren, die am besten funktioniert. Deshalb wird JavaScript oft verwendet, um Dinge zu schalten, die sich vergrößern und verkleinern, sowie für andere Workarounds.

Ich spreche hier von der height-Eigenschaft, aber wir sprechen auch von ihrem logischen Äquivalent, block-size, sowie von width und inline-size. Oder von jeder Richtung, wenn wir das schon sagen.

Übergang zu auto

Das ist das Ziel, oder? Wir neigen dazu, zu height: auto zu greifen, wenn die Höhenabmessung unbekannt ist. Von dort aus lassen wir JavaScript berechnen, was das ergibt, und kümmern uns um den Rest.

Die aktuelle Chrome-Implementierung verwendet CSS calc-size() für die Hauptarbeit. Sie erkennt das Schlüsselwort auto und berechnet, wie der Name schon sagt, diese Zahl. Mit anderen Worten, wir können dies anstelle des Ansatzes mit fester Höhe tun.

.panel {
  height: 0;
  transition: height 0.25s ease-in;

  &.expanded {
    height: calc-size(auto);
  }
}

Das ist im Grunde alles! Natürlich ist calc-size() zu komplexeren Ausdrücken fähig, aber die Tatsache, dass wir ihm nur ein vages Schlüsselwort über die Höhe eines Elements übergeben können, ist verdammt beeindruckend. Es ermöglicht uns, von einem festen Wert zur intrinsischen Größe des Elements und zurück zu gelangen.

Ich musste es ausprobieren. Ich bin sicher, dass es hier unzählige Anwendungsfälle gibt, aber ich habe mich für eine schwebende Schaltfläche in einer Kalenderkomponente entschieden, die eine bestimmte Anzahl ausstehender Kalendereinladungen anzeigt. Klicken Sie auf die Schaltfläche, und ein Bereich erweitert sich über dem Kalender und zeigt die Einladungen an. Klicken Sie erneut darauf, und der Bereich kehrt zu seinem ursprünglichen Zustand zurück. JavaScript kümmert sich um die Klickinteraktion, die eine Klassenänderung auslöst, die die Höhe in CSS übergibt.

Ein Video, falls Sie keine Lust haben, Canary zu öffnen

Dies ist das relevante CSS

.invite-panel {
  height: 0;
  overflow-y: clip;
  transition: height 0.25s ease-in;
}

Beim Klicken setzt JavaScript die automatische Höhe des Elements als Inline-Stil, um das CSS zu überschreiben.

<div class="invite-panel" style="height: calc(auto)">

Die transition-Eigenschaft in CSS teilt dem Browser mit, dass wir die height-Eigenschaft irgendwann ändern wollen, und macht dies reibungslos. Und wie bei jeder Übergangs- oder Animationsbewegung ist es ratsam, Bewegungsunempfindlichkeiten zu berücksichtigen, indem Sie die Bewegung mit prefers-reduced-motion verlangsamen oder entfernen.

Was ist mit display: none?

Dies ist eine der ersten Fragen, die mir in den Sinn kamen, als ich Chris' Beitrag las, und er geht auch darauf ein. Der Übergang von einem Element von display: none zu seiner intrinsischen Größe ist ähnlich wie der Übergang von height: 0. Es mag den Anschein haben, dass ein nicht angezeigtes Element keine Höhe hat, aber es hat tatsächlich eine berechnete Höhe von auto, es sei denn, ihm wird eine bestimmte Höhe zugewiesen.

DevTools showing computed values for an element with display none. The height value shows as auto.

Daher ist zusätzliche Arbeit erforderlich, wenn wir von display: none in CSS übergehen wollen. Ich werde einfach den Code von Chris einfügen, da er die wichtigsten Teile gut demonstriert.

.element {
  /* hard mode!! */
  display: none;

  transition: height 0.2s ease-in-out;
  transition-behavior: allow-discrete;

  height: 0; 
  @starting-style {
    height: 0;
  }

  &.open {
    height: calc(auto);
  }
}
  • Das Element beginnt sowohl mit display: none als auch mit height: 0.
  • Es gibt eine .open-Klasse, die die Höhe des Elements auf calc-size(auto) setzt.

Das sind die beiden Punkte, die wir verbinden müssen, und das tun wir, indem wir zuerst transition-behavior: allow-discrete auf das Element setzen. Das ist neu für mich, aber die Spezifikation besagt, dass transition-behavior "festlegt, ob Übergänge für diskrete Eigenschaften gestartet werden oder nicht". Und wenn wir allow-discrete deklarieren, "werden Übergänge für diskrete Eigenschaften sowie für interpolierbare Eigenschaften gestartet".

Nun, DevTools hat uns genau dort gezeigt, dass height: auto eine diskrete Eigenschaft ist! Beachten Sie jedoch die @starting-style-Deklaration. Wenn Sie damit nicht vertraut sind, sind Sie nicht allein. Die Idee ist, dass sie es uns ermöglicht, einen Stil für einen Übergang festzulegen, mit dem dieser "startet". Und da die diskrete Höhe unseres Elements auto ist, müssen wir dem Übergang mitteilen, stattdessen bei height: 0 zu starten.

.element {
  /* etc. */

  @starting-style {
    height: 0;
  }
}

Jetzt können wir von Null zu auto übergehen, da wir die diskrete Höhe mit @starting-style quasi überschreiben. Ziemlich cool, dass wir das können!

Direkter Link →