Ich wette, die meiste Zeit, wenn wir Ecken in CSS abrunden, wenden wir einen einheitlichen Wert für `border-radius` auf den gesamten Rand an. Das ist in vielen Designs eine schöne Verfeinerung. Aber es gibt Zeiten, in denen wir unterschiedliche Radien für verschiedene Ecken wünschen könnten. Einfach, oder? Dann nimmt die Eigenschaft vier Werte an. Nun, wie sich herausstellt, ist es tatsächlich möglich, sich selbst in die Ecke zu malen, weil abgerundete Ränder sich gegenseitig überlappen können.
Viele von uns kennen den gängigen „999em-Hack“, um ein „pill-förmiges“ Rechteck zu erhalten
Wir setzen `border-radius` auf eine absurd große Zahl, wie 999em oder 999vmax, und anstatt einer Art unmöglichen, Escher-esken Möbius-Schleife werden die Ecken schön abgerundet, um einen Halbkreis zu bilden. Das ist praktisch, weil es bedeutet, dass wir die Abmessungen des Rechtecks nicht kennen müssen, um diesen Effekt zu erzielen – es „funktioniert einfach“.
Die Ursprünge dieses Tricks sind für mich unklar, aber ich habe ein frühes Beispiel in einem Kommentar auf Leas Verou’s Blog von David Baron gefunden.
Aber wie bei vielen „Hacks“ können wir in bestimmten Grenzfällen auf ungewöhnliches Verhalten stoßen. Warum funktioniert zum Beispiel dies, wenn das nicht funktioniert?
Wir möchten, dass die rechte Seite des Rechtecks „pill-förmig“ ist und die linke Seite Ecken mit 40px abgerundet hat. Aber unsere 40px Ecken sind verschwunden! Wohin sind sie gegangen?

Die Antwort ist, dass sie nirgendwo hingegangen sind; der Browser hat ihre Werte einfach auf einen Wert reduziert, der so nahe bei Null liegt, dass sie nur so aussehen, als wären sie weg.
Der Browser weicht irgendwie von den angeforderten Werten ab, aber wann und wie entscheidet er, einzugreifen? Schauen wir uns die Spezifikation an.
Sei f = min(Li/Si), wobei i ∈ {oben, rechts, unten, links}, Si die Summe der beiden entsprechenden Radien der Ecken auf Seite i ist und Loben = Lunten = die Breite des Kastens und Llinks = Lrechts = die Höhe des Kastens. Wenn f < 1, dann werden alle Eckradien reduziert, indem sie mit f multipliziert werden.
Ah, das erklärt es! Haben Sie eine schöne Restwoche! :reibt sich die Hände ab
…Ich scherze natürlich. Das erfordert ein wenig Entschlüsselung, also betrachten wir es auf zwei Arten, mathematisch und geometrisch. Behalten Sie immer im Hinterkopf, dass der Zweck dieser Formel darin besteht, **die Überschneidung von Radien zu verhindern**. Tatsächlich ist das der Grund, warum der „999em-Hack“ überhaupt funktioniert!
Hier ist, was ich meine.
Einfach ausgedrückt, denkt der Browser im Wesentlichen: „Schrumpfe alle Radien proportional, bis es keine Überschneidung zwischen ihnen gibt.“ (Beachten Sie, dass es die Radien sind, die sich nicht überschneiden dürfen; die Kreise, die sie bilden, dürfen sich tatsächlich überschneiden.)
Aber ein Computer versteht kein Englisch, also tut die Formel Folgendes.
Zuerst berechnet sie das Verhältnis der Länge jeder Seite des Rechtecks zur Summe der angrenzenden Radien. In unserem Standard-„Pill-Hack“ ergibt sich also
[Width of Side] / [Adjacent Border Radius 1 + Adjacent Border Radius 2]
Top: 200px / (400px + 400px) = 0.25
Right: 100px / (400px + 400px) = 0.125
Bottom: 200px / (400px + 400px) = 0.25
Left: 100px / (400px + 400px) = 0.125

Dann multipliziert sie alle Radien mit dem kleinsten dieser Verhältnisse. Das kleinste Verhältnis ist 0,125, also multiplizieren wir das mit unseren ursprünglichen 400px Radien.
400px * 0.125 = 50px
Das lässt alle unsere Radien bei 50px. Für ein Rechteck, dessen kürzeste Seiten 100px sind, ergibt dies eine perfekte Pillenform. Cool! Sehen Sie sich die folgende Animation an.
(Um es leichter zu erkennen, verwenden wir hier 400px für unsere „absurd großen“ Radien anstelle von 999em; sie werden sich überschneiden, solange sie mindestens halb so lang wie die kürzeste Seite des Rechtecks sind.)
Die Kreise, die die von uns angegebenen Radien darstellen, beginnen in ihrer angeforderten Größe, schrumpfen dann um das durch die obige Formel bestimmte Verhältnis. Wichtig ist zu beachten, dass sie alle um das gleiche Verhältnis schrumpfen. Es ist vielleicht intuitiver, da sie sowieso alle gleich groß beginnen.
Nun kehren wir zu unserem „kaputten“ Beispiel zurück, das alles ins Rollen gebracht hat.
Was passiert hier? Versuchen wir ein weniger extremes Beispiel, um abgerundete Ecken zu zeigen, die von diesem Schrumpfen betroffen sind, aber nicht in dem Maße, dass sie praktisch verschwinden.
Dort sehen wir, dass wir nicht die 40px Radien erhalten, die wir in den oberen linken und unteren linken Ecken anfordern, aber wir bekommen etwas. Lassen Sie uns die Formel noch einmal durchgehen und zuerst die Verhältnisse zwischen allen Seiten und ihren angrenzenden Radien ermitteln.
Top: 200px / (40px + 400px) = 0.455
Right: 100px / (400px + 400px) = 0.125
Bottom: 200px / (40px + 400px) = 0.455
Left: 100px / (40px + 40px) = 1.25
Wiederum ist unser niedrigstes Verhältnis dort 0,125, also multiplizieren wir alle angegebenen Radien damit, was uns 50px Radien für die rechten Ecken und 5px Radien für die linken Ecken ergibt.
Die Formel stellt hier sicher, dass sich die beiden großen Radien auf der rechten Seite des Rechtecks nicht überschneiden, aber dabei hat sie die kleinen Radien auf der linken Seite des Rechtecks mehr geschrumpft, als sie „müssen“, um eine Überschneidung der Radien auf der oberen, unteren und linken Seite zu verhindern.
Hier ist ein reichhaltigeres Beispiel, das zeigt, was unter verschiedenen Umständen passiert. Spielen Sie mit einigen Werten herum, um zu sehen, was passiert. Wiederum sind die großen Größen die Radien, die wir im Code angegeben haben, und die kleinen Größen sind, wie der Browser sie abgleicht, um eine Überschneidung zu verhindern.
Warum würden die Oz-artigen Spezifikationsersteller dies so entscheiden? Warum nicht zuerst die größeren abgerundeten Ecken schrumpfen, anstatt alle Radien von Anfang an zu schrumpfen?
Ich kann ihnen natürlich nicht in den Kopf schauen, aber der Vorteil dieses Ansatzes ist, dass die Radien ihre Proportionen zueinander beibehalten. Wenn wir den Browser anweisen würden, den größten Radius zu verringern, bis keine Überschneidung mehr besteht oder bis er dem zweitgrößten Radius entspricht (je nachdem, was zuerst eintritt) und dies zu wiederholen, dann wäre unser „Hybrid-Pillen-Hack“ funktioniert; aber es gibt Fälle, in denen man vier gleiche Radien erhalten könnte, wenn der Benutzer sehr unterschiedliche Größen angefordert hätte. Mit anderen Worten, die Implementierung muss auf die eine oder andere Weise „untreu“ zu den Zahlen sein, und das ist die Art und Weise, die sie gewählt haben (meiner Meinung nach klugerweise).
Vielen Dank an meine Kollegen Catherine, die dieses Problem der „verschwindenden Radien“ zuerst bemerkt hat, und James, der mir geholfen hat, die Spezifikation zu verstehen!
Ich mag die Formel sehr. Das Schrumpfverhalten kannte ich aus Leas Vortrag https://youtu.be/b9HGzJIcfDE, war mir aber nicht bewusst, dass es eine Formel gibt. Ist diese Formel Teil der Spezifikation oder obliegt sie noch den Browserherstellern?
Ich habe dieses `border-radius`-Tool erstellt, mit dem Sie alle acht Griffe einzeln verschieben können. Vielleicht hilft das zu verstehen, was passiert, wenn zwei Seiten zusammen mehr als 100% ergeben. Früher habe ich es nicht verstanden, obwohl ich dieses Tool erstellt habe :-) Vielen Dank für diesen Artikel.
https://9elements.github.io/fancy-border-radius/full-control.html#41.38.37.34-68.49.51.64-.
Ich mag dein Werkzeug sehr. Danke!
Ich habe noch nie vom 999em-Hack gehört. Es scheint einfacher zu sein, `border-radius` mit verständlichen Werten einzustellen. Zum Beispiel, um einen „Pill“-Button zu erstellen: `border-radius: calc(var(--button-height) / 2) / 50%;`
Ich stimme zu. Habe noch nie davon gehört und wenn ich darüber stolpere, würde es mich wahrscheinlich verwirren …
CSS bietet Variablen und Funktionen, die meiner Meinung nach besser lesbar sind und nicht so sehr wie ein Hack.
Danke! Ihre Lösung funktioniert hervorragend, wenn die Größe des Elements vorhersehbar ist; wenn seine Größe nicht vorhersehbar ist (zum Beispiel, wenn es eine unbekannte Menge Text enthält), können Sie keinen festen Wert für den abgerundeten Rand angeben. Ebenso, wenn Sie ein Designsystem verwenden, bei dem sich beispielsweise der Abstand ändern könnte oder sich die Schriftgröße ändert, kann die Verwendung eines festen Wertes für den abgerundeten Rand zu unvorhersehbarem Verhalten führen. Der 999em-Hack stellt sicher, dass Ihr Element immer Pillen-Ecken hat.
Ich benutze immer `border-radius: 100vh`. Auf diese Weise sieht es irgendwie wie 100% aus, was es einfacher zu merken macht.
Wirklich toller Artikel, aber ich würde vorschlagen, diesen Teil zu platzieren
„(Um es leichter zu erkennen, verwenden wir hier 400px für unsere ‚absurd großen‘ Radien anstelle von 999em; sie werden sich überschneiden, solange sie mindestens halb so lang wie die kürzeste Seite des Rechtecks sind.)“
Etwas weiter oben in der Erklärung, da ich viel zu lange damit verbracht habe, herauszufinden, woher Sie die 400px im ersten Beispiel haben :P