Was passiert, wenn sich abgerundete Ecken überschneiden?

Avatar of Jay Sitter
Jay Sitter am

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

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?

Hey, diese linken Ecken sollten leicht abgerundet sein!

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!