Aufbau von skalierbaren Komponenten mit relativen CSS-Einheiten

Avatar of Ahmad Shadeed
Ahmad Shadeed am

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

Der folgende Beitrag ist ein Gastbeitrag von Ahmad Shadeed. Ahmad hat eine Menge Beispiele zusammengestellt, um zu zeigen, wie die Verwendung relativer Einheiten uns zugutekommen kann. Ich denke, viele von uns betrachten Einheiten wie em als nur für font-size, was sie auch sind, aber sie können auch für viele andere Dinge verwendet werden und typografische Größen mit anderen visuellen Elementen verbinden.

Wir leben in einer dynamischen Welt, alles, was wir tun, kann sich jederzeit ändern. Wir als Front-End-Entwickler sollten unsere Layouts dynamisch gestalten.

In diesem Artikel werden wir ein Konzept untersuchen, das es uns ermöglicht, unsere Komponenten mithilfe von relativen CSS-Einheiten (%, em oder rem) zu skalieren. Nicht nur die Textgröße, sondern die gesamte Benutzeroberfläche dieser Komponente. Wir werden praktische Beispiele, Vor- und Nachteile des Ansatzes und sogar eine vollständige Webseite betrachten, die auf diese Weise erstellt wurde.

Ein einfaches Beispiel für proportionale Schriftgrößen

Hier gibt es drei Elemente

  1. Untertitel
  2. Titel
  3. Linker Rand

Mit HTML etwa so

<article class="post">
   <a href="#">
     <span class="post-category">Featured</span>
     <h2 class="post-title">Building Dynamic Components is Awesome</h2>
   </a>
</article>

Ich möchte, dass alles proportional zueinander ist, so dass es sich beim Skalieren gemeinsam verändert

Nehmen wir an, wir haben in Pixeln angefangen

.post {
  border-left: 4px solid #4a90e2;
}
.post-category {
  font-size: 14px;
  color: #7d7d7d;
}
.post-title {
  font-size: 36px;
  font-weight: bold;
  color: #4a90de;
}

Die einzige Möglichkeit, die gesamte Komponente proportional zu skalieren, besteht darin, die font-size jedes Elements manuell anzupassen, damit sie bei einer neuen Größe übereinstimmen. Vielleicht teilt Ihnen Ihr Kunde mit, dass er diesen Bereich um das 1,5-fache vergrößert sehen möchte. Sie müssten die Größen entsprechend auf 21px und 54px anpassen.

Um die Anpassung etwas zu erleichtern, könnten wir prozentuale Schriftgrößen verwenden.

.post-category {
  font-size: 85%;
}
.post-title {
  font-size: 135%;
}

Das bedeutet: Die font-size sollte 85 % des nächstgelegenen Elternelements mit einer definierten font-size betragen.

Wir könnten diese font-size auf dem Elternelement festlegen

.post {
  font-size: 24px;

  /* 
    Child elements with % font sizes...

    85%
    0.85 * 24 = 20.4
    
    135%
    1.35 * 24 = 32.4
  */
}

Der Browser berechnet diese Schriftgrößen für Sie, wenn Sie Prozentsätze verwenden, und Sie müssen sich nicht wirklich um die endgültigen Werte kümmern. Es ist nur eine Proportion.

Wir könnten dasselbe tun, wenn wir em-Werte verwenden wollten. Bei font-size sind Prozent und em irgendwie dasselbe.

.post-category {
  font-size: 85%;
  /* the same as */
  font-size: 0.85em;
}
.post-title {
  font-size: 135%;
  /* the same as */
  font-size: 1.35em;
}

Wenn wir em für andere Werte als font-size verwenden, basiert der berechnete Pixelwert, den es darstellt, immer noch auf font-size. Dies unterscheidet sich beispielsweise von Prozentangaben, bei denen eine prozentuale width auf der width des Elternelements basiert und nicht auf der font-size!

Wenn wir zum Beispiel festlegen

.post {
  font-size: 24px;
  border-left: 0.25em solid #4a90e2;
}

Die border-left-width wird zu 6px berechnet.

In der folgenden interaktiven Demo ändert der Schieberegler die font-size beider Komponenten. Beim ersten sind alle Dinge in Pixeln eingestellt: Schriftgröße, Rahmen, Abstand, Ränder. Beim zweiten sind all diese Dinge in ems eingestellt.

Demo ansehen.

Proportionale Skalierung für alles!

Proportionale Schaltflächen

Manchmal brauchen wir Variationen einer Schaltfläche. Vielleicht eine größere Version, um eine wichtigere Handlungsaufforderung hervorzuheben. Wir können von em-Einheiten profitieren, indem wir sie für den Abstand verwenden. So können wir die Größe der Schaltfläche sowohl durch font-size als auch durch padding leicht erhöhen.

<button class="button">Save Settings</button>

<button class="button button--medium">Save Settings</button>

<button class="button button--large">Save Settings</button>

Wenn wir all diese Variationen in Pixeln einstellen, hätten wir etwas wie

.button {
  font-size: 16px;
  padding: 10px 16px;
  border-radius: 3px;
}

.button--medium {
  font-size: 24px;
  padding: 15px 24px;
  border-radius: 4px;
}

.button--large {
  font-size: 32px;
  padding: 20px 32px;
  border-radius: 5px;
}

Stattdessen könnten wir Prozent- und em-Werte kombinieren, um Dinge proportional zu machen, einschließlich border-radius!

.button {
  font-size: 1em; /* Let's say this computes to 16px */
  padding: 0.625em 1em; /* 0.1875 * 16 = 10px */
  border-radius: 0.1875em; /* 0.1875 * 16 = 3px */
}

.button--medium {
  font-size: 130%;
}

.button--large {
  font-size: 160%;
}

Sehen Sie, wie sie alle proportional skalieren

Demo ansehen.

Proportionale Breite/Höhe von Bildern

Hier ist ein Beispiel, bei dem wir einen Bildavatar etwas größer halten müssen als den Text und das Veröffentlichungsdatum. Beachten Sie die blaue Hervorhebung. Ihre Höhe sollte sich ändern, wenn wir die font-size skalieren.

Das HTML könnte so aussehen

<div class="bio">
  <img src="author.jpg" alt="Photo of author Ahmad Shadeed">
  <div class="bio__meta">
    <h3><b>By:</b> Ahmad Shadeed</h3>
    <time>Posted on August 5, 2016</time>
  </div>
</div>

Und wir würden nicht nur die Schriftgrößen in em-Werten festlegen, sondern auch die Breite und Höhe des Bildes. Stellen Sie sicher, dass das Bild selbst groß genug ist, um ohne zu viel Qualitätsverlust zu skalieren!

.bio h3 {
  font-size: 1em;
}
.bio time {
  font-size: 0.875em;
}
.bio img {
  width: 3.125em;
  height: 3.125em;
}

Ein skalierbarer "Rand"

Eine weitere Eigenschaft, die gerne in em-Werten angegeben wird: box-shadow.

Wir wissen bereits, dass Rahmen mit em-Werten skalierbar sind. Hier stellen wir die "Höhe" eines Innen-box-shadow mit einem em-Wert ein, damit er mit der Textgröße skaliert.

.headline {
  box-shadow: inset 0 -0.25em 0 0 #e7e7e7;
}

Demo ansehen.

Hinweis: Wir hätten dies auch mit CSS-Verläufen mit harten Farbstopfen erreichen können, da diese Stopfen auch mit em-Werten eingestellt werden könnten!

Platz für Icons schaffen

Nehmen wir an, wir haben ein dekoratives <blockquote> mit einem benutzerdefinierten Symbol oben links. Wir sollten das Szenario berücksichtigen, in dem sich die Schriftgröße ändert. Relative Einheiten können auch hier helfen.

<blockquote class="quote">
  <p>
    <span>
      Building dynamic web components using modular design concepts is awesome. 
      <em>- Ahmad Shadeed</em>
    </span>
  </p>
</blockquote>

Wir werden alles mit relativen Einheiten einstellen, wie wir es bereits besprochen haben. Das dekorative Symbol platzieren wir mit einem SVG-Bild, das über ein Pseudo-Element angewendet wird. Wir positionieren dieses Pseudo-Element absolut, wieder mit relativer Positionierung und Größenangabe, und lassen genug Platz dafür (mit relativen Abständen) im Elternelement.

.quote {
  position: relative;
  padding: 1.5em 2em;
  padding-left: 4.5em;
  border-radius: 0.3125em;
}
.quote p {
  font-size: 2em;
}
.quote span {
  box-shadow: inset 0 -0.25em 0 0 rgba(255, 255, 255, 0.4);
}
.quote:before {
  content: "";
  position: absolute;
  top: 2.125em;
  left: 1.875em;
  background: url("quotes.svg") no-repeat;
  height: 1.875em;
  width: 1.875em;
}

Damit skaliert alles gut, wenn wir die Schriftgröße ändern

Beachten Sie, wie alles proportional hochskaliert, genau wie wenn Sie diese Elemente gruppieren und in einer Design-Anwendung per Drag & Drop skalieren würden!

Wenn wir stattdessen Pixelwerte verwenden würden, hätten die Dinge nicht so gut skaliert. Insbesondere das Symbol könnte unangenehm nah am Text oder unangenehm weit entfernt sein.

Interaktives Beispiel

Demo ansehen.

Bild mit Unterschrift

Stellen Sie sich ein Foto und eine Bildunterschrift vor, die wie folgt angeordnet sind

Wir können einen Großteil dieses Designs basierend auf der Schriftgröße gestalten, z. B. wie weit es nach links und oben versetzt ist, den Abstand und sogar den Schatten.

<figure class="figure">
  <img src="sunrise.jpg" alt="Sunrise">
  <figcaption>The feeling you got from watching the sunrise is amazing.</figcaption>
</figure>
.figure figcaption {
  position: absolute;
  top: 1.25em;
  left: -1.875em;
  right: 0;
  padding: 1em;
  box-shadow: -0.3125em 0.3125em 0 0 rgba(0, 0, 0, 0.15);
  font-size: 1.75em;
}

Demo ansehen.

Ein dekorativer Hintergrund

Nehmen Sie diesen abgedunkelten Kreis hinter dem Titel in diesem Inhaltsblock

Stellen wir sicher, dass er sich entsprechend der Schriftgröße anpasst. Aber es gibt subtilere Details. Der border-radius sollte relativ sein, ebenso wie die Dicke dieser gestrichelten Linie.

<section class="block">
  <h3 class="block__title">Content outline</h3>
  <div class="block__content">
    <p>Description to be there....</p>
  </div>
</section>
.block__title {
  position: relative;
  font-size: 1.5em;
  padding: 0.5em;
}

.block__title:after {
  content: "";
  position: absolute;
  left: 0.25em;
  top: 0;
  width: 2.5em;
  height: 2.5em;
  border-radius: 50%;
  background: #000;
  opacity: 0.5;
  transform: scale(1.75);
}

.block__title:before {
  content: "";
  margin-left: 0.5em;
  border-bottom: 0.0625em dashed rgba(255, 255, 255, 0.5);
}

Wenn wir hier so viel wie möglich mit relativen Einheiten verwenden, skaliert alles

Demo ansehen.

Ein Suchfeld mit Icon

Es ist üblich, Icons mit Schaltflächen zu verwenden, aber Sie können sie auch in Eingabefeldern verwenden. Dies ist ein gängiges Beispiel, bei dem wir ein Suchfeld mit einem Lupen-Icon kennzeichnen

Das Icon wird mit background-image platziert, und padding-left wird hinzugefügt, um zu verhindern, dass der Text überlappt. Wenn die Schriftgröße steigt, sollten wir die Größe dieses Icons entsprechend erhöhen.

<form class="search">
  <label for="search">Enter keyword:</label>
  <input type="search" id="search" placeholder="What are you searching about?">
</form>
.search input {
  width: 25em;
  font-size: 1em;
  padding: 0.625em;
  padding-left: 2.5em;
  border-radius: 0.3125em;
  border: 0.125em solid #b4b4b4;
  background: url("search.svg") left 0.625em center/1.5em 1.5em no-repeat;
}

Alle Klassiker sind hier in relativen Einheiten eingestellt: Padding, Rand, Randradius... aber wir haben auch relative Einheiten für background-position und background-size verwendet. Jetzt skaliert alles schön!

Demo ansehen.

Schalter

Betrachten Sie eine benutzerdefinierte Checkbox in Form eines hin- und hergehenden Schalters

Nichts davon können wir nicht skalieren!

<form action="" class="switch">
  <p>Do you want to subscribe?</p>
  <input type="checkbox" name="" id="switch" class="off-screen">
  <label for="switch"><span class="off-screen">Do you want to subscribe?</span></label>
</form>
.switch label {
  width: 5.625em;
  height: 2.5em;
  border: 0.125em solid #b4b4b4;
  border-radius: 2.5em;
}

.switch label:before {
  content: "";
  right: 0.25em;
  top: 0.21875em;
  width: 2em;
  height: 2em;
}

Skalieren Sie los

Demo ansehen.

Begrenzung der Zeilenlänge, nur wenn Sie es brauchen

Nehmen Sie einen Inhaltsblock wie diesen

Wir haben dort ziemlich viel horizontalen Platz. Ohne etwas zu begrenzen, wäre die Zeilenlänge dieses Absatzes etwas zu lang zum angenehmen Lesen gewesen. Das Setzen von max-width ist eine großartige Möglichkeit, die Zeilenlänge zu begrenzen. Wir würden es wahrscheinlich nicht in Pixeln einstellen (aus all den gleichen Gründen, die wir bisher behandelt haben: es skaliert nicht) und wir würden wahrscheinlich auch keine Prozentsätze verwenden, da bei schmaleren Breiten 100 % wahrscheinlich ausreichen. Relative Einheiten also!

<div class="hero">
  <h2>This is title for this hero section</h2>
  <p>And this paragraph is a sub title, as you know I'm writing an article about using em units to build dynamic components.</p>
  <a href="#">Read about hero</a>
</div>
.hero h2 {
  margin-bottom: 0.25em;
  font-size: 1.75em;
}

.hero p {
  margin-bottom: 1em;
  max-width: 28.125em; /* limit line length */
  font-size: 1.25em;
}

.hero a {
  display: inline-block;
  background: #4a90e2;
  padding: 0.7em 1.5em;
}

Jetzt ist die Zeilenlänge begrenzt, dehnt sich aber gerne auf die volle Breite aus, wenn weniger Platz zur Verfügung steht.

Demo ansehen.

SVG-Icons in Schaltflächen

Einer der Gründe, warum Leute gerne mit Icon-Schriftarten arbeiten, ist, dass die Schriftart automatisch mit dem Text skaliert wird. Aber das kann auch mit <img> (wie wir gesehen haben) funktionieren und auch mit Inline-<svg>-Icons!

Wir verwenden em-Werte, um width und height festzulegen, und dann skalieren die Icons proportional, wenn die Schrift skaliert.

<ul class="social">
    <li class="social__item">
      <a href="#">
        <svg width="32" height="32" viewBox="0 0 32 32">
        <!-- SVG Data -->                    
        </svg> 
        Like on Facebook
      </a>
    </li>
    <li class="social__item">
      <a href="#">
        <svg width="32" height="32" viewBox="0 0 32 32">
        <!-- SVG Data -->                    
        </svg>  
        Follow on Twitter
      </a>
    </li>
    <li class="social__item">
      <a href="#">
        <svg width="32" height="32" viewBox="0 0 32 32">
        <!-- SVG Data -->                    
        </svg> 
        Follow on Dribbble
      </a>
    </li>
</ul>
.social__item svg {
  display: inline-block;
  vertical-align: middle;
  width: 2.1875em;
  height: 2.1875em;
}

Demo ansehen.

Listen-Zähler

Nehmen wir an, wir haben eine Liste mit individuell gestalteten Zählern erstellt. Mit Text, der in solche Container gesetzt wird, sollten wir besser sicherstellen, dass alles proportional skaliert, sonst haben wir ein Problem wie dieses.

<ul class="list">
  <li>Go to example.com and click on Register</li>
  <li>Enter your email address</li>
  <li>Pick a strong password</li>
  <li>Congrats! You now have an account</li>
</ul>
.list li {
  position: relative;
  padding-left: 3.125em;
  margin-bottom: 1em;
  min-height: 2.5em;
}

.list li:before {
  font-size: 1em;
  width: 2.5em;
  height: 2.5em;
  text-align: center;
  line-height: 2.5em;
  border-radius: 50%;
}

Viel Spaß beim Skalieren

Demo ansehen.

Positioniertes Icon in einer Liste/Warnung/Modal

Ich glaube, Sie verstehen den Punkt jetzt, also machen wir noch ein paar Beispiele mit einer Demo, bei der Sie selbst sehen können, wie hilfreich die relative Skalierung ist.

Demo ansehen.

Hamburger Menü-Icon

Vielleicht haben Sie ein Icon "gefälscht", indem Sie es aus Elementen und Pseudo-Elementen aufgebaut haben. Das sollte auch skalierbar sein.

Demo ansehen.

Verläufe

Wir haben bereits gesehen, wie wir relative Einheiten für background-size verwenden können. Wir haben auch angedeutet, dass ein Farbstopfen in einem Verlauf mit einer relativen Einheit eingestellt werden kann. Machen wir genau das!

.box-1 {
  background: 
    linear-gradient(
      to right, 
      #4a90e2 0, 
      #4a90e2 0.625em, 
      #1b5dab 0.625em, 
      #1b5dab 1.875em, 
      #4a90e2 0, 
      #4a90e2 3.125em
    );
  background-size: 1.25em 100%;
}

Demo ansehen.

Bild-Sprites

Einige Dinge haben feste Größen, die einfacher in Pixeln zu verstehen sind, wie Rasterbilder. Aber das bedeutet nicht, dass wir sie nicht mehr mit relativen Einheiten verwenden können. Wenn wir background-position und background-size in ems kombinieren, können wir CSS-Sprites verwenden, die größenmäßig skalierbar sind.

Demo ansehen.


Kombinieren von em und rem

Wir haben die em-Einheit in diesem Artikel hauptsächlich verwendet. Wir haben festgestellt, dass die em-Einheit auf font-size basiert und kaskadiert. Aber em hat eine Cousine-Einheit: rem. Die rem-Einheit ist immer noch relativ, aber nur relativ zum Stamm (z. B. html {} oder :root {}). Sie kaskadiert also nicht wirklich wie em, aber wenn Sie die Stamm-font-size ändern, ändert sie sich entsprechend.

Durch die Kombination von em und rem können wir einige Größen fixieren und die anderen dynamisch halten. Zum Beispiel, wenn Sie möchten, dass der Text in diesen Komponenten nur relativ zum Stamm ist, aber andere Elemente relativ zur unmittelbareren Schriftgröße sein sollen. Wie zum Beispiel das Bild

Sehen Sie, wie die Anpassung der unmittelbaren Schriftgröße jetzt nur das Bild beeinflusst

Demo ansehen.


Erstellung einer vollständigen Website mit relativen Größen

Ich habe eine ganze Seite erstellt, um zu demonstrieren, wie wir das Konzept dynamischer Komponenten auf etwas Reales anwenden können und es nicht nur auf ein einzelnes Beispiel beschränken.

Alles hier ist dynamisch dimensioniert: Logo, Tags, Titel, Autor, Abschnittstitel, nummerierte Listen, Formularfelder, Schaltflächen, Blockquotes... praktisch alles.

Wenn wir die Standard-Browser-Schriftgröße von 16px auf 20px ändern würden, würde die Website so skalieren.

Fantastisch, oder? Haben Sie bemerkt, wie alles skaliert ist, nicht nur die Typografie? Das ist die Schönheit von em! 😍

Sehen Sie sich die vollständige Demo der Seite an.

Beachten Sie, dass sich die Schriftgröße auch mit einem Media-Query-Breakpoint ändert.

Zoomen

Unser em-basiertes Design ist auch mit Browser-Zoom kompatibel.

Während das Pixel-basierte Design auf Probleme stoßen kann.

Herausforderungen mit em

Eine Sache, die man bei der Verwendung von em beachten sollte, ist, dass die font-size in em auf dem nächstgelegenen Elternelement mit einer deklarierten font-size basiert.

.parent {  
  font-size: 20px;
  .child { 
    /* This is based on 20px, so it's 30px */
    font-size: 1.5em;
  }
}

Ich denke, das haben wir ziemlich klar dargelegt.

Aber wenn wir andere Dinge in em skalieren, basiert es nun auf der neu angepassten font-size des aktuellen Elements. Zum Beispiel

.parent {
  font-size: 20px;
  .child {

    /* This is based on 20px, so it's 30px */
    font-size: 1.5em;
    
    /* This is based on 1.5em (not 20px), so it's also 30px */
    border: 1em solid black;
    
  }
}

Es kann einfach seltsam sein, zwei verschiedene em-Werte im selben Element zu sehen, die zum gleichen Endergebnis führen.

Dies zusätzlich zu der Tatsache, dass der kaskadierende Effekt von ems manchmal selbst eine Herausforderung darstellt. Wenn Sie Dinge innerhalb von Komponenten in ems skalieren und diese Komponenten verschachtelt werden können, kann dies zu einer Kaskadierung von Größen führen, die unerwünscht sein kann.

Abschluss

  • Die Skalierung in Pixeln ist schwieriger zu warten. Sie sind nicht relativ zueinander. Sie müssen alle manuell anpassen, um eine Proportion zu ändern. Schwierig, zeitaufwendig, fehleranfällig.
  • Das Setzen von Werten in ems macht Dinge proportional zur Schriftgröße, sodass das Ändern der Schriftgröße alle Werte dieses Elements skaliert (und zu den Kindern kaskadiert).
  • Das Festlegen von Schriftgrößen in Pixeln kann den Benutzer daran hindern, seine Standard-Schriftgröße über seine Browsereinstellungen zu ändern, was schlecht für die Barrierefreiheit ist.

Weitere Lektüre