SVG - stroke von Umrandungen
mark
- svg
Guten Tag,
ein Problem/Verhalten, das mich bei der Verwendung von SVGs stört ist, wenn ich ein Icon habe mit einer umrandenden Linie und diese Umrandung passgenau zum viewport ist (width und height ist nicht gesetzt), so wird diese Linie bei einer Ändernung der stroke-width beschnitten.
Alles, was den Viewport verlässt wird beschnitten.
Ich habe daraufhin gesehen, dass die Browser Firefox & Chrome intern den style "svg:not(:root) { overflow: hidden; }" verwenden. Wenn ich das in meinem stylesheet überschreibe mit overflow: visible; bekomme ich im Firefox das gewünschte Verhalten: der stroke ist außerhalb des viewports sichtbar.
Die einzige Methode die bisher wirklich funktioniert ist, dass ich den viewport eben größer mache. Dann ist der umrandende Stroke sichtbar, aber ich verliere den Vorteil, dass das Icon passgenau ist, weil ja sein viewport nicht mehr bündig ist und ich muss schon beim Erstellen des Icons diesen Stroke berücksichtigen, was sehr frickelig werden kann, wenn ich ein und das selbe Icon in unterschiedlichen Größen darstellen möchte.
Gibt es hierfür eine bessere Lösung?
lg mark
Servus!
Guten Tag,
ein Problem/Verhalten, das mich bei der Verwendung von SVGs stört ist, wenn ich ein Icon habe mit einer umrandenden Linie und diese Umrandung passgenau zum viewport ist (width und height ist nicht gesetzt), so wird diese Linie bei einer Ändernung der stroke-width beschnitten.
Alles, was den Viewport verlässt wird beschnitten.
Lege einfach Werte für x und y mit der halben Konturstärke fest. (Bei stroke-width="2" also x="1", da die Kontur mittig auf dem Rand verläuft.)
Siehe auch : SVG/Farben/Kontur
Ich habe daraufhin gesehen, dass die Browser Firefox & Chrome intern den style "svg:not(:root) { overflow: hidden; }" verwenden. [...]
Die einzige Methode die bisher wirklich funktioniert ist, dass ich den viewport eben größer mache. Dann ist der umrandende Stroke sichtbar, aber ich verliere den Vorteil, dass das Icon passgenau ist, weil ja sein viewport nicht mehr bündig ist und ich muss schon beim Erstellen des Icons diesen Stroke berücksichtigen, was sehr frickelig werden kann, wenn ich ein und das selbe Icon in unterschiedlichen Größen darstellen möchte.
Geht m.E. nach nicht anders.
Gibt es hierfür eine bessere Lösung?
Deine Lösungen sind m.E. eher Umwege, die einfachste Lösung siehe oben.
lg mark
Herzliche Grüße
Matthias Scharwies
wenn ich ein Icon habe mit einer umrandenden Linie und diese Umrandung passgenau zum viewport ist (width und height ist nicht gesetzt), so wird diese Linie bei einer Ändernung der stroke-width beschnitten.
Alles, was den Viewport verlässt wird beschnitten.
In SVG 2 kannst du dafür stroke-alignment:inside verwenden.
Gruß Jonathan
@@Matthias Scharwies
Lege einfach Werte für x und y mit der halben Konturstärke fest. (Bei stroke-width="2" also x="1", da die Kontur mittig auf dem Rand verläuft.)
So einfach ist das nicht. Dadurch rückt der Rahmen nach innen, näher an das Icon. Je nach Rahmendicke macht sich das mehr oder weniger stark störend bemerkbar.
Sinnvoller dürfte sein, die ViewBox um die halbe Konturstärke zu vergrößern.
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
@@mark
Die einzige Methode die bisher wirklich funktioniert ist, dass ich den viewport eben größer mache.
Du meinst viewBox.
Dann ist der umrandende Stroke sichtbar, aber ich verliere den Vorteil, dass das Icon passgenau ist, weil ja sein viewport nicht mehr bündig ist
?? Wenn du die ViewBox nach allen Seiten um die halbe Strichstärke der Rahmenlinie vergrößerst, sollte es genau passen.
und ich muss schon beim Erstellen des Icons diesen Stroke berücksichtigen, was sehr frickelig werden kann, wenn ich ein und das selbe Icon in unterschiedlichen Größen darstellen möchte.
Was wäre daran frickelig?
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
Hallo Gunnar,
Du meinst viewBox.
Ja, es müsste natürlich viewBox heißen.
Dann ist der umrandende Stroke sichtbar, aber ich verliere den Vorteil, dass das Icon passgenau ist, weil ja sein viewport nicht mehr bündig ist
?? Wenn du die ViewBox nach allen Seiten um die halbe Strichstärke der Rahmenlinie vergrößerst, sollte es genau passen.
Das geht eben nur, wenn die stroke-width nicht variabel ist. Wenn ich ein icon mit unterschiedlicher stroke-width darstellen möchte ist das ein Problem.
Dies ist beispielsweise dann der Fall, wenn dieses Icon in Unterschiedlichen Größen dargestellt werden soll. Bei kleinen Abmessungen habe ich dann wegen des Antialiasing (Stichwort: Subpixel-Rendering) das Problem dass die Umrandung kaum noch sichtbar ist und ich deshalb die stroke-width verändern muss. Mache ich das aber, schneidet mich die viewBox ab.
Auch müsste ich die stroke-width, schon im voraus kennen, was nicht der Fall ist, da ich das Icon erst per CSS im Browser auf seine eigentliche Größe bringe.
Was wäre daran frickelig?
Mein Workflow, sieht folgendermaßen aus:
Das ist frickelig. Schritt e, f und g wären überflüssig, wenn der Stroke außerhalb der viewBox sichtbar wäre. Aber es gibt ja gute Gründe, warum die viewBox beschneidet.
Eine Alternative wäre natürlich, dass ich die viewBox überdimensioniert setze, dass es mit ziemlicher Sicherheit keinen overflow gibt.
lg
@@mark
Das geht eben nur, wenn die stroke-width nicht variabel ist. Wenn ich ein icon mit unterschiedlicher stroke-width darstellen möchte ist das ein Problem.
Dies ist beispielsweise dann der Fall, wenn dieses Icon in Unterschiedlichen Größen dargestellt werden soll. Bei kleinen Abmessungen habe ich dann wegen des Antialiasing (Stichwort: Subpixel-Rendering) das Problem dass die Umrandung kaum noch sichtbar ist und ich deshalb die stroke-width verändern muss.
Verstehe. Du suchst vector-effect: non-scaling-stroke
. Per CSS oder als Attribut.
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
Verstehe. Du suchstvector-effect: non-scaling-stroke
Ich bin mir ziemlich sicher, dass es damit nicht funktioniert.
Ich habe nun alle Varianten getestet. Matthias Scharwies Methode ist bislang die einzige, die zufriedenstellend funktioniert.
Eine kleine Anmerkung vielleicht zu Matthias Scharwies Lösungsvorschlag: Statt x/y kann und muss man manchmal sogar transform: translate(X, Y) verwenden.
Ich habe ein kleines Testdokument zusammengebastelt, damit man wirklich genau versteht, was ich meine und vielleicht ist es dem einen oder anderen hilfreich.
Ich bin alle drei Lösungsvorschläge durchgegangen. stroke-alignment:inside wird noch nicht unterstützt, sonst wären es 4.
https://codepen.io/anon/pen/YWgRNN
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>SVG Bounding Box Test</title>
<style>
.svg-samples{
display: none;
}
section{
margin-bottom: 5em;
padding-bottom: 4em;
border-bottom: 3px dashed lightgrey;
}
.testing-area{
width: 100%;
overflow: hidden;
}
.testing-area svg{
display: inline-block;
vertical-align: middle;
width: 12em;
height: 12em;
fill: none;
margin: 1em;
}
.testing-area svg.small{
width: 3em;
height: 3em;
}
/*
*
* Stroke-width defaults
*
* */
.rect{
stroke: deeppink;
stroke-width: 4;
}
.circle-l{
stroke: lightblue;
stroke-width: 50;
}
.circle-s{
stroke: lime;
stroke-width: .04;
}
.octagon{
stroke: black;
stroke-width: .5;
}
/*
*
* Stroke-width changes
*
* */
.attempt-1 .rect,
.attempt-2 .rect{
stroke-width: 44;
}
.attempt-1 .circle-l,
.attempt-2 .circle-l{
stroke-width: 400;
}
.attempt-1 .circle-s,
.attempt-2 .circle-s{
stroke-width: .3;
}
.attempt-1 .octagon,
.attempt-2 .octagon{
stroke-width: 8;
}
.attempt-3 .rect{
stroke-width: 1;
}
.attempt-3 .circle-l{
stroke-width: 1;
}
.attempt-3 .circle-s{
stroke-width: 1;
}
.attempt-3 .octagon{
stroke-width: 1;
}
/*
*
*
* LÖSUNGSANSATZ 1 svg:not(:root){ overflow: visible; }
*
* */
.attempt-1 svg:not(:root){
overflow: visible;
}
</style>
</head>
<body>
<h1>SVG Bouding Box Test</h1>
<svg class="svg-samples">
<symbol id="rectangle" preserveAspectRatio="xMidYMid meet" viewBox="0 0 800 800">
<rect width="800" height="800" />
</symbol>
<symbol id="circle-large" preserveAspectRatio="xMidYMid meet" viewBox="0 0 8000 8000">
<circle cx="4000" cy="4000" r="4000" />
</symbol>
<symbol x="0" y="0" id="circle-small" preserveAspectRatio="xMidYMid meet" viewBox="0 0 10 10">
<circle cx="5" cy="5" r="5" />
</symbol>
<symbol id="octagon" preserveAspectRatio="xMidYMid meet" viewBox="0 0 177.9 177.9">
<path d="M.2 52.2l52-52h73.4l52 52v73.4l-52 52H52.2l-52-52z" />
</symbol>
<!-- /*
*
*
* LÖSUNGSANSATZ 2 angepasste viewBox
*
* */
-->
<!-- +44 -->
<symbol id="rectangle-mod" preserveAspectRatio="xMidYMid meet" viewBox="0 0 844 844">
<rect x="22" y="22" width="800" height="800" />
</symbol>
<!-- +400 -->
<symbol id="circle-large-mod" preserveAspectRatio="xMidYMid meet" viewBox="0 0 8400 8400">
<circle cx="4200" cy="4200" r="4000" />
</symbol>
<!-- +.3 -->
<symbol id="circle-small-mod" preserveAspectRatio="xMidYMid meet" viewBox="0 0 10.3 10.3">
<circle cx="5.15" cy="5.15" r="5" />
</symbol>
<!-- +8 -->
<symbol id="octagon-mod" preserveAspectRatio="xMidYMid meet" viewBox="0 0 185.9 185.9">
<path transform="translate(4, 4)" d="M.2 52.2l52-52h73.4l52 52v73.4l-52 52H52.2l-52-52z" />
</symbol>
<!-- /*
*
*
* LÖSUNGSANSATZ 3 non-scaling-stroke
*
* */
-->
<symbol id="rectangle-non-scaling-stroke" preserveAspectRatio="xMidYMid meet" viewBox="0 0 800 800">
<rect vector-effect="non-scaling-stroke" stroke-width="4" width="800" height="800" />
</symbol>
<symbol id="circle-large-non-scaling-stroke" preserveAspectRatio="xMidYMid meet" viewBox="0 0 8000 8000">
<circle vector-effect="non-scaling-stroke" cx="4000" cy="4000" r="4000" />
</symbol>
<symbol id="circle-small-non-scaling-stroke" preserveAspectRatio="xMidYMid meet" viewBox="0 0 10 10">
<circle vector-effect="non-scaling-stroke" cx="5" cy="5" r="5" />
</symbol>
<symbol id="octagon-non-scaling-stroke" preserveAspectRatio="xMidYMid meet" viewBox="0 0 177.9 177.9">
<path vector-effect="non-scaling-stroke" d="M.2 52.2l52-52h73.4l52 52v73.4l-52 52H52.2l-52-52z" />
</symbol>
</svg>
<section class="problem">
<h2>Das Problem:</h2>
<div>
Idealerweise wären große und kleine Icons in der Farbintensität identisch. Dafür ist jedoch eine Änderung der
stroke-width nötig, sonst ist die Umrandung ggf. nicht mehr erkennbar. Siehe nachfolgende Darstellung: zuerst sind die Icons
groß abgebildet, dann, fast nicht sichtbar klein. Bei einem Rechteck ist das Problem nicht sofort ersichtlich,
da der Stroke gleichmäßig beschnitten wird.
<ul>
<li>Die Stroke-width ist abhängig von der viewBox.</li>
<li>Die ViewBox beschneidet den Stroke.</li>
</ul>
</div>
<div class="testing-area">
<svg class="rect">
<use xlink:href="#rectangle" />
</svg>
<svg class="circle-l">
<use xlink:href="#circle-large" />
</svg>
<svg class="circle-s">
<use xlink:href="#circle-small" />
</svg>
<svg class="octagon">
<use xlink:href="#octagon" />
</svg>
<svg class="rect small">
<use xlink:href="#rectangle" />
</svg>
<svg class="circle-l small">
<use xlink:href="#circle-large" />
</svg>
<svg class="circle-s small">
<use xlink:href="#circle-small" />
</svg>
<svg class="octagon small">
<use xlink:href="#octagon" />
</svg>
</div>
</section>
<section class="attempt attempt-1">
<h2>Lösungsansatz 1</h2>
<p>
svg:not(:root) {overflow: visible;}<br />
Nachteil: funktioniert nur im Firefox
</p>
<div class="testing-area">
<svg class="rect small">
<use xlink:href="#rectangle" />
</svg>
<svg class="circle-l small">
<use xlink:href="#circle-large" />
</svg>
<svg class="circle-s small">
<use xlink:href="#circle-small" />
</svg>
<svg class="octagon small">
<use xlink:href="#octagon" />
</svg>
</div>
</section>
<section class="attempt attempt-2">
<h2>Lösungsansatz 2</h2>
<p>
Anpassung der viewBox<br />
Vorteil: Funktioniert in allen Browsern.<br />
Nachteil: relativ aufwendig.<br />
Bemerkung: Verschiebung der X/Y-Koordinate kann, bzw. muss in manchen Fällen mit transform: translate(X, Y) erfolgen.
</p>
<div class="testing-area">
<svg class="rect small">
<use xlink:href="#rectangle-mod" />
</svg>
<svg class="circle-l small">
<use xlink:href="#circle-large-mod" />
</svg>
<svg class="circle-s small">
<use xlink:href="#circle-small-mod" />
</svg>
<svg class="octagon small">
<use xlink:href="#octagon-mod" />
</svg>
</div>
</section>
<section class="attempt attempt-3">
<h2>Lösungsansatz 3</h2>
<p>
vector-effect="non-scaling-stroke"<br />
Funktioniert nicht: beschneidet die stroke-width.<br />
Funktioniert nicht im IE11. Edge konnte ich nicht testen.
</p>
<div class="testing-area">
<svg class="rect small">
<use xlink:href="#rectangle-non-scaling-stroke" />
</svg>
<svg class="circle-l small">
<use xlink:href="#circle-large-non-scaling-stroke" />
</svg>
<svg class="circle-s small">
<use xlink:href="#circle-small-non-scaling-stroke" />
</svg>
<svg class="octagon small">
<use xlink:href="#octagon-non-scaling-stroke" />
</svg>
</div>
</section>
</body>
</html>
@@mark
Verstehe. Du suchst
vector-effect: non-scaling-stroke
Ich bin mir ziemlich sicher, dass es damit nicht funktioniert.
Ich bin mir ziemlich sicher, dass es damit vor ein paar Tagen bei mir funktioniert hat.
Gerade nochmal positiv getestet in Firefox und Safari.
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
Ich bin mir ziemlich sicher, dass es damit vor ein paar Tagen bei mir funktioniert hat.
Gerade nochmal positiv getestet in Firefox und Safari.
Ich habs gerade eben negativ getestet. Siehe meinen verlinkten Test: https://codepen.io/anon/pen/YWgRNN
Wenn du magst kannst du mir ja deinen Test zeigen, oder meinen korrigieren. Ich kriegs nicht zum laufen.
Auch mag der IE11 (Edge hab' ich nicht getestet) kein vector-effect: non-scaling-stroke, was die Latte dieses Attribut zu verwenden nochmal höher hängt.
@@mark
Ich habs gerade eben negativ getestet.
Ah ja, die halbe Strichstärke des Rahmens liegt dann ja außerhalb der ViewBox (wenn der Pfad genau auf deren Rand liegt).
Die ViewBox größer zu machen dürfte nicht gehen, da deren Ausmaße ja das mitskalierende Koordinatensystem angeben, die Strichstärke des Rahmens bei vector-effect: non-scaling-stroke
aber gerade nicht mitskaliert.
Abhilfe: padding
mit halber Strichstärke des Rahmens im Zusammenhang mit overflow: visible
. →Pen
Auch mag der IE11 (Edge hab' ich nicht getestet) kein vector-effect: non-scaling-stroke, was die Latte dieses Attribut zu verwenden nochmal höher hängt.
Vielleicht für alte Browser (und für ganz alte sowieso) eine Rastergrafik als Fallback verwenden?
@supports(vector-effect: non-scaling-stroke) { … }
LLAP 🖖
sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|