Der SVG-Kreis sollte sich ohne Überlappung an die Höhe des CSS-Rasters anpassen


8

Im folgenden Beispiel passt sich der Kreis an die Rasterbreite an und behält sein Seitenverhältnis bei. Wenn die Behälterbreite kleiner wird, schrumpfen die Kreise mit ...

Wenn die Höhe jedoch kleiner als die Breite ist (zweites Feld), verkleinert sich der Kreis nicht außerhalb des Rasters. Gibt es eine Möglichkeit, ihn auch an die Höhe anzupassen, während das Seitenverhältnis beibehalten wird?

.container {
	display: grid;
	background-color: greenyellow;
	margin: 5px;
	min-height: 10px;
	min-width: 10px;
}

.portrait {
		max-height: 100px;
		max-width: 200px;
}

.landscape {
		max-height: 200px;
		max-width: 100px;
}

.aspect-ratio {
	grid-column: 1;
	grid-row: 1;
	background-color: deeppink;
	border-radius: 50%;
 align-self: center;
	justify-self: center;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

Das Ergebnis sollte folgendermaßen aussehen: Geben Sie hier die Bildbeschreibung ein


Haben Sie die Möglichkeit, den SVG-Code zu bearbeiten?
Der

Antworten:


8

Nachdem ich einige Zeit mit diesem Problem herumgespielt hatte, stellte ich fest, dass dies kein Problem mit dem Rasterlayout ist.

Da Sie nie definieren Höhe / max-height oder Breite / max-width für SVG, was berechnet wird, ist width:autoundheight:auto

Hinweis: Ich spreche max-height / max-width an, da diese Vorrang vor den Werten für width / height haben.


Nun, warum Ihre Landschaft Layout - Arbeiten und Ihr Porträt Layout nicht funktionieren? Weil die Breite Vorrang vor Ihrer Höhe hat.

Aus diesem Grund basiert im Blocklayout eine automatische Höhe auf der Gesamthöhe der Nachkommen und eine automatische Breite auf der enthaltenen Blockbreite.

Quelle - Warum verhält sich width: auto anders als height: auto?

Dies bedeutet, dass Ihre SVG die widthaus ihrem Container und die heightvon ihren Nachkommen nimmt.

In Ihrem Beispiel hat Ihre SVG keine Nachkommen, sondern ein übergeordnetes Element mit einer definierten maximalen Breite . Aber was bedeutet das für die Größe der SVG ?

Die SVG berechnet ihre Höhe anhand des Intrisic Ratio:

Wenn die 'viewBox' im 'svg'-Element korrekt angegeben ist:

  1. Lassen Sie viewbox das Ansichtsfeld sein, das durch das Attribut 'viewBox' im Element 'svg' definiert ist
  2. return viewbox.width / viewbox.height

Quelle

Und Ihr intrisisches Verhältnis ist 1/1 = 1

Also zwingst du deine height=width


Die Lösungen)

Die Lösung besteht darin, ein widthoder a marginfür Ihre SVG festzulegen, abhängig vom Anteil Ihres übergeordneten Div.

In dem Beispiel, das Sie gegeben haben, haben Sie ein Verhältnis von 2: 1, also sollte Ihr SVG width:50%oder haben margin: 0 25%.

Dies bedeutet, dass Sie, wenn Sie einen anderen Anteil einstellen möchten, diese entsprechend anpassen müssen (siehe Porträt-1-3 im folgenden Code).

Das Festlegen einer CSS-Regel für jeden Anteil kann vermieden werden, wenn dies heightkeine Einschränkung darstellt, da Sie eine widthfür Ihre SVG und Ihren Container definieren können, sodass die Elemente die anpassen könnenheight , um Ihr Seitenverhältnis beizubehalten.

Ich habe auch das letzte Beispiel hinzugefügt, wenn es jemandem nicht wichtig ist, das Seitenverhältnis beizubehalten, sondern das SVG in einem Satz heightund einem widthContainer enthalten muss.

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
}


/* Add 25% margin left and right to center the image  OR set the image width to 50% */

.portrait>.aspect-ratio {
  margin: 0 25%;
  /*
    or 
    
    width:50%;
  */
}

.landscape {
  max-height: 200px;
  max-width: 100px;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  background-color: deeppink;
  border-radius: 50%;
  align-self: center;
  justify-self: center;
}


/* Set fixed max-height and max-width rule (33% proportion)  */

.portrait-1-3 {
  max-height: 100px;
  max-width: 300px;
}


/* Align image with the new proportion */

.portrait-1-3>.aspect-ratio {
  margin: 0 33.33%;
  /*
    or 
    
    width:33.3%;
  */
}


/* Removed max-height and let the container adjust the height according to the max-width rule and the proportion set  */

.portrait-any-height {
  max-width: 400px;
}


/* Height will be adjusted through the width/margin defined here, so 10% width will correspond to 40px of height (10%*400px)*(aspect ratio=1)*/

.portrait-any-height>.aspect-ratio {
   width:10%;
}


/* Set fixed max-height and max-width rule (proportion doesn't matter)  */

.portrait-squeezed {
  max-height: 100px;
  max-width: 300px;
}


/* Make sure SVG complies with the the given max with and height (squeezing your svg)  */

.portrait-squeezed>.aspect-ratio {
  max-height: inherit;
  max-width: inherit;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-1-3">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-any-height">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-squeezed">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

Beachten Sie, dass ich mit SVGs nicht sehr gut arbeite und diese Antwort ein Ergebnis von Forschung und viel Experimentieren ist! Ich würde mich über Anpassungen und / oder Korrekturen meiner Antwort freuen.


Vielen Dank für die ausführliche Erklärung ... Ich muss feststellen, dass Ihre Forschung leider die gleichen Ergebnisse wie meine lieferte. Es scheint keine Lösung für meine Anforderungen zu geben: 1. Das SVG-Seitenverhältnis ist festgelegt. 2. Das Seitenverhältnis des Containers ist variabel / unbekannt. 3. Die Größe des Containers ist je nach Umgebung sowohl durch die Höhe als auch durch die Breite begrenzt (z. B. Größe des Browserfensters). Die vorgeschlagene Lösung durch Festlegen der SVG-Breite auf einen bestimmten Prozentsatz des Containers würde funktionieren, wenn der Container hatte ein festes Seitenverhältnis, tut es aber nicht.
Th3S4mur41

Das Aufgeben der maximalen Höhe funktioniert auch nicht. Das würde nur bedeuten, dass das Überlaufproblem auf das übergeordnete
Element übertragen wird

Mit diesen drei Anforderungen scheint es keine Lösung zu geben, dh nur CSS zu verwenden. Kommt die Verwendung von Javascript zur Berechnung der entsprechenden SVG-Breite nicht in Frage?
H. Figueiredo

Das ist es, was meine aktuelle Lösung tut, die ich vermeiden möchte;)
Th3S4mur41

Ich hoffe, dass das Seitenverhältnis zur Lösung dieses Problems beiträgt, bin mir aber nicht einmal sicher. Drafts.csswg.org/css-sizing-4/#aspect-ratio
Th3S4mur41

0

Fügen Sie dem Container die spezifische Höhe und Breite neben der maximalen Höhe und der maximalen Breite hinzu.

vw & vh-Einheiten können verwendet werden, um dieses Layout flexibler zu gestalten.

  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;

Auf diese Weise ist es möglich, max-width: 100%; max-height: 100%;das SVG einzustellen und es wird sich nicht überlappen.


-BEARBEITEN-

Da das SVG-Ansichtsfeld bereits mit dem richtigen Seitenverhältnis gerendert wurde, ist es sicher, den SVG-Hintergrund innerhalb des SVG selbst zu verschieben, um das erwartete Ergebnis zu erzielen: Ein Cicle-Tag reicht aus.

Ist es möglich, den Randradius mit einem anderen Kreistag innerhalb einer Maske zu imitieren?

Alle anderen Elemente des SVG sollten dann in einer maskierten Gruppe platziert werden. dh:<g mask="url(#mask)">

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;
}

.landscape {
  max-height: 200px;
  max-width: 100px;
  width: 100vw;
  height: 100vh;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
  justify-self: center;
  max-width: 100%;
  max-height: 100%;
}

.aspect-ratio .bkg{
  fill: deeppink;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio"viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>


1
Die Frage lautete "Gibt es eine Möglichkeit, es auch an die Höhe anzupassen, während das Seitenverhältnis beibehalten wird", was in Ihrem Beispiel nicht der Fall ist. Dies ist eine Möglichkeit, das SVG in den Container zu zwingen, führt jedoch nicht zum beabsichtigten Ergebnis. Es ist das gleiche wie das letzte Beispiel meiner Antwort, bei der das SVG zusammengedrückt wird , um in den Container zu passen
H. Figueiredo

Die Erklärung mag etwas verwirrt sein, aber mit der vorgeschlagenen Lösung passt sich die SVG-Höhe an die Höhe des Containers an.
Der

Das SVG- Seitenverhältnis bleibt jedoch nicht erhalten ! Haben Sie das gewünschte Ergebnis gesehen, das das OP veröffentlicht hat?
H. Figueiredo

Oh, wow ... Ich habe es gerade mit Chrome überprüft und verstehe jetzt, was Sie sagen. Ich habe es in Firefox codiert und mit diesem Browser funktioniert es wie beabsichtigt. Ich hatte nicht erwartet, dass das Ergebnis so unterschiedlich ist. Mein schlechtes
thetont

Das ist eigentlich ein ziemlich interessantes Verhalten. Ich vermute, dass Firefox und Chrome zu 100% unterschiedlich rechnen. Wie auch immer, wir machen alle Fehler, sonst würde SO nicht existieren: D
H. Figueiredo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.