Seitenverhältnis-Boxen

Avatar of Chris Coyier
Chris Coyier am

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

Ich hatte neulich eine kleine Situation, in der ich eine dieser seitenverhältnis-freundlichen Boxen erstellen musste. Das ist nichts Besonderes Neues. Ich glaube, die ursprüngliche Anerkennung geht bis ins Jahr 2009 zurück, mit Thierry Koblentz' Intrinsic Ratios und behielt auch für andere Arten von Inhalten mit Artikeln wie Uncle Dave’s Ol’ Padded Box an Popularität.

Lassen Sie uns auf eine kleine Reise durch dieses Konzept gehen, da es viel zu besprechen gibt.

Das Kernkonzept: Innenabstand in Prozent basiert auf der Breite

Auch wenn das etwas unintuitiv ist, wie bei vertikalem Innenabstand. Das ist kein Hack, aber es ist seltsam: padding-top und padding-bottom basieren auf der width des Elternelements. Wenn Sie also ein Element hätten, das 500 Pixel breit ist, und einen padding-top von 100 %, wäre der padding-top 500 Pixel.

Ist das nicht ein perfektes Quadrat, 500px × 500px? Ja, ist es! Ein Seitenverhältnis!

Wenn wir die Höhe des Elements auf Null erzwingen (height: 0;) und keine Ränder haben. Dann ist der Innenabstand der einzige Teil des Box-Modells, der die Höhe beeinflusst, und wir haben unser Quadrat.

Stellen Sie sich nun vor, wir hätten statt 100 % oberen Innenabstand 56,25 % verwendet. Das ist ein perfektes 16:9-Verhältnis! (9 / 16 = 0,5625).

Jetzt haben wir eine freundliche Seitenverhältnis-Box, die in flüssigen Breiten gut funktioniert. Wenn sich die Breite ändert, ändert sich auch die Höhe, und das Element behält dieses Seitenverhältnis bei.

Anwendungsfall: ein Hintergrundbild

Vielleicht haben wir ein typografisches Lockup erstellt. Es ist für den Titel eines Artikels, daher ist es sinnvoll, ein <h1>-Tag zu verwenden.

<h1>
  Happy Birthday
</h1>

Wir können dieses <h1> Tag zur Seitenverhältnis-Box machen und das Lockup als Hintergrundbild anwenden.

h1 {
  overflow: hidden;
  height: 0;
  padding-top: 56.25%;
  background: url(/images/happy-birthday.svg);
}

Aber ich habe bei dem Seitenverhältnis da oben gelogen. Es ist nicht wirklich ein 16:9-Bild. Ich habe diese Grafik gerade von einer Stockfoto-Website heruntergeladen. Es handelt sich zufällig um eine SVG mit einem viewBox="0 0 1127.34 591.44", was bedeutet, dass es sich im Hinblick auf das Seitenverhältnis im Wesentlichen um ein 1127,34 × 591,44-Bild handelt. Oder es könnte ein 328 × 791-Bild gewesen sein.

Ich würde sagen, es ist sehr üblich, dass zufällige Bilder nicht in ein ganz bestimmtes vordefiniertes Seitenverhältnis passen...

Die Mathematik jedes möglichen Seitenverhältnisses

Perfekte Quadrate und 16:9-Sachen sind großartig, aber die dafür verwendeten Werte sind nur einfache Mathematik. Ein Seitenverhältnis kann alles sein, und oft ist es vollkommen willkürlich. Ein Video oder Bild kann auf jede beliebige Größe zugeschnitten werden.

Wie ermitteln wir also den oberen Innenabstand für unsere SVG mit 1127,34 × 591,44 oben?

Eine Möglichkeit ist die Verwendung von calc(), wie hier

padding-top: calc(591.44 / 1127.34 * 100%);

Mir wurde vor kurzem gesagt, dass die Verwendung von calc() hier "langsamer" sein mag, aber ich habe nie Beweise dafür gesehen. Ich stelle mir vor, dass ja, der Computer muss etwas berechnen, also ist bei einem Kopf-an-Kopf-Rennen gegen eine Situation, in der er es nicht tut, die Berechnung langsamer. Aber ein mathematisches Problem scheint für einen Computer keine allzu große Arbeit zu sein. Zum Beispiel konnte der beliebte Intel Pentium III (erschienen 1999) 2.054 MIPS oder "Millionen von Instruktionen pro Sekunde" verarbeiten, sodass er eine Division unmerklich schnell erledigen würde. Und jetzt sind Chips 50-mal schneller.

Wenn wir einen Präprozessor wie Sass verwenden würden, könnten wir die Berechnung im Voraus durchführen

padding-top: 591.44px / 1127.34px * 100%;

So oder so, ich bin ein Fan davon, die Mathematik im erstellten Code zu belassen.

Wie fügt man Inhalt ein, wenn der Innenabstand alles nach unten verschiebt?

Wir haben den Inhalt in der obigen Demo verborgen, indem wir den Inhalt herausdrängen und den Überlauf ausblenden. Aber was, wenn Sie eine Seitenverhältnis-Box benötigen und den Inhalt darin behalten möchten? Das ist etwas kniffliger. Wir müssen ihn wieder nach oben positionieren. Absolute Positionierung kann diese Aufgabe übernehmen.

Nehmen wir an, wir verwenden jetzt nur Text, möchten aber immer noch die Seitenverhältnis-Box. Wir benötigen einen inneren Wrapper für die absolute Positionierung. Lassen Sie uns spezifisch mit unseren Klassennamen werden

<h1 class="aspect-ratio-box">
  <div class="aspect-ratio-box-inside">
    Happy Birthday
  </div>
</h1>

Dann machen wir die Positionierung

.aspect-ratio-box {
  height: 0;
  overflow: hidden;
  padding-top: 591.44px / 1127.34px * 100%;
  background: white;
  position: relative;
}
.aspect-ratio-box-inside {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Nur zum Spaß, machen wir hier alles rein und zentrieren den Text und skalieren ihn, damit er mit der Box skaliert

<h1 class="aspect-ratio-box">
  <div class="aspect-ratio-box-inside">
    <div class="flexbox-centering">
      <div class="viewport-sizing">
          Happy Birthday
      </div>
    </div>
  </div>
</h1>

Noch ein paar Klassen zum Stylen

.flexbox-centering {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.viewport-sizing {
  font-size: 5vw;
}

Anwendungsfall: Video

Dies ist wahrscheinlich der am häufigsten und praktischste Anwendungsfall für all diese Seitenverhältnis-Box-Sachen. HTML5 <video> ist kein Problem, da es sich verhält, als hätte es ein Seitenverhältnis, genau wie <img>. Aber viele Videos im Web kommen in <iframe>s, die sich nicht mit einem Seitenverhältnis skalieren.

Genau darum geht es bei FitVids. Es findet Videos auf der Seite, ermittelt ihre einzigartigen Seitenverhältnisse und wendet dann dieselben CSS-Konzepte an, um sie flüssig zu machen und gleichzeitig ihre einzigartigen Seitenverhältnisse beizubehalten.

FitVids basiert auf jQuery, aber es gibt Vanilla-JavaScript-Optionen, wie diese hier von Ross Zurowski.

Aber… was, wenn es zu viel Inhalt gibt?

Zurück zu beliebigem (wahrscheinlich textlichem) Inhalt für einen Moment.

Wir legen hier im Wesentlichen *Höhen* fest, was beim Arbeiten mit CSS immer ein *blinkendes rotes Licht* aufleuchten lassen sollte. Das Web wächst gerne nach unten, und das Festlegen fester Höhen ist ein Feind dieser natürlichen Bewegung.

Wenn der Inhalt für den Platz zu viel wird, befinden wir uns im Reich des schlechten Designs

Reich des schlechten Designs

Vielleicht könnten wir etwas wie overflow: auto; tun, aber das könnte im Reich des unbeholfenen Designs liegen.

Die Pseudo-Element-Taktik

Dies ist meiner Meinung nach der beste Weg, um eine Seitenverhältnis-Box mit völlig beliebigem Inhalt zu handhaben. Keith Grant hat einen guten Artikel dazu. Marc Hinse hatte bereits 2013 eine Erklärung und Demos.

Mit dieser Technik erhalten Sie die Seitenverhältnis-Box mit weniger Markup, und sie ist *immer noch sicher*, wenn der Inhalt die Höhe überschreitet.

Der Trick besteht darin, den %-Innenabstand auf ein Pseudo-Element statt auf die Box selbst anzuwenden. Sie schwebend das Pseudo-Element, damit der Inhalt darin schön platziert werden kann, und löschen dann den Float.

.aspect-ratio-box {
  background: white;
}
.aspect-ratio-box::before {
  content: "";
  width: 1px;
  margin-left: -1px;
  float: left;
  height: 0;
  padding-top: 591.44px / 1127.34px * 100%;
}
.aspect-ratio-box::after { /* to clear float */
  content: "";
  display: table;
  clear: both;
}

Sehen Sie, wie es sicherer ist

Und ein Video

Verwendung von benutzerdefinierten Eigenschaften

Dies ist vielleicht die coolste Idee von allen!

Thierry Koblentz hat dies kürzlich aufgeschrieben (Link entfernt, da Thierry's Seite tot ist.), Sérgio Gomes für die Idee gutgeschrieben.

Um es zu verwenden, setzen Sie eine benutzerdefinierte Eigenschaft, die direkt auf das benötigte Element beschränkt ist

<div style="--aspect-ratio:815/419;">
</div>

<div style="--aspect-ratio:16/9;">
</div>

<!-- even single value -->
<div style="--aspect-ratio:1.4;">
</div>

Das CSS, das dies stylt, ist verdammt genial

[style*="--aspect-ratio"] > :first-child {
  width: 100%;
}
[style*="--aspect-ratio"] > img {  
  height: auto;
} 
@supports (--custom:property) {
  [style*="--aspect-ratio"] {
    position: relative;
  }
  [style*="--aspect-ratio"]::before {
    content: "";
    display: block;
    padding-bottom: calc(100% / (var(--aspect-ratio)));
  }  
  [style*="--aspect-ratio"] > :first-child {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
  }  

Lassen Sie mich Thierry's Schritt-für-Schritt-Erklärung zitieren

  • Wir verwenden [style*="--aspect-ratio"] als Hook, um die entsprechenden Boxen anzusprechen
  • Wir strecken die innere Box, unabhängig von der Unterstützung für benutzerdefinierte Eigenschaften
  • Wir stellen sicher, dass die Höhe von Bildern aus ihrem intrinsischen Verhältnis und nicht aus ihren height -Attributen stammt
  • Wir stylen den Container als enthaltenden Block (damit die innere Box diesen Vorfahren für ihre Positionierung referenziert)
  • Wir erstellen ein Pseudo-Element, das mit dem "Padding-Hack" verwendet wird (es ist dieses Element, das das Seitenverhältnis erzeugt)
  • Wir verwenden calc() und var(), um den Innenabstand basierend auf dem Wert der benutzerdefinierten Eigenschaft zu berechnen
  • Wir stylen die innere Box so, dass sie den Abmessungen ihres enthaltenden Blocks entspricht

Andere Ideen & Werkzeuge

Lisi Linhart hat mich auf Ratio Buddy aufmerksam gemacht, was super cool ist

Beachten Sie, dass es ein Pseudo-Element verwendet, aber dann immer noch den inneren Container absolut positioniert. Das ist irgendwie seltsam. Sie würden wahrscheinlich entweder das Pseudo-Element überspringen und den Innenabstand direkt auf den Container legen oder das Pseudo-Element schweben lassen, damit Sie keinen inneren Container benötigen. Dennoch gefällt mir die Idee eines kleinen Generators dafür.

Tommy Hodgins hat CSSplus, das Aspecty enthält, das genau dafür da ist, vorausgesetzt, Sie sind damit einverstanden, dass eine JavaScript-Analyse und -Änderung Ihres CSS erfolgt


Ich habe im Laufe der Jahre tatsächlich ziemlich viel reale Nutzung von Seitenverhältnis-Boxen gesehen. Teilen Sie gerne mit, wenn Sie Erfahrungen damit haben!