I'm trying to build an SVG using transform attribute. But while my SVG looks as expected in Chrome and Firefox it looks broken in Safari. It looks like Safari doesn't respect transform-origin attribute and always applies the transform like transform-origin has "0 0" value.
I need to animate transform attribute and I need the resulting SVG to look the same in all browsers. I tried to work around the issue by providing different values to transform-box CSS property, but without success.
Is there any workaround for the issue?
Below is an example illustrating the issue. All images should look the same. They look the same in Chrome and Firefox, but not in Safari.
h1 {
font-family: sans-serif;
}
figure {
border: thin #c0c0c0 solid;
display: inline-flex;
flex-flow: column;
padding: 5px;
max-width: 200px;
margin: auto;
}
figcaption {
margin-top: 5px;
background-color: #222;
color: #fff;
font: smaller sans-serif;
padding: 3px;
text-align: center;
}
<h1>1. Reference image</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<circle cx="100" cy="100" r="100" stroke="none" fill="black"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
<circle cx="100" cy="100" r="75" stroke="none" fill="blue"/>
<line x1="100" y1="25" x2="100" y2="175" stroke="rebeccapurple" stroke-width="1.5"/>
<line x1="25" y1="100" x2="175" y2="100" stroke="rebeccapurple" stroke-width="1.5"/>
<circle cx="100" cy="100" r="50" stroke="none" fill="red"/>
<line x1="100" y1="50" x2="100" y2="150" stroke="rebeccapurple" stroke-width="1"/>
<line x1="50" y1="100" x2="150" y2="100" stroke="rebeccapurple" stroke-width="1"/>
<circle cx="100" cy="100" r="25" stroke="none" fill="yellow"/>
<line x1="100" y1="75" x2="100" y2="125" stroke="rebeccapurple" stroke-width="0.5"/>
<line x1="75" y1="100" x2="125" y2="100" stroke="rebeccapurple" stroke-width="0.5"/>
</svg>
<figcaption>Figure 1. Reference image, <code>transform</code> is not used. All other images should look the same.</figcaption>
</figure>
<h1>2. <code>transform</code> applied to <code><g></code> element</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-1">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-1" fill="black"/>
<use href="#target-g-1" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="0" y="0" width="200" height="200" viewBox="0 0 200 200">
<use href="#target-g-1" fill="red" transform="scale(0.5 0.5)" transform-origin="100 100"/>
<use href="#target-g-1" fill="yellow" transform="scale(0.25 0.25)" transform-origin="100 100"/>
</svg>
</svg>
<figcaption>Figure 2-1. Nested <code><svg></code> has the same size as the outermost <code><svg></code>.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-2">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-2" fill="black"/>
<use href="#target-g-2" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-g-2" fill="red" transform="scale(0.5 0.5)" transform-origin="100 0"/>
<use href="#target-g-2" fill="yellow" transform="scale(0.25 0.25)" transform-origin="100 33.3333"/>
</svg>
</svg>
<figcaption>Figure 2-2. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-3">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-3" fill="black"/>
<use href="#target-g-3" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-g-3" fill="red" transform="scale(0.5 0.5)" transform-origin="0 0"/>
<use href="#target-g-3" fill="yellow" transform="scale(0.25 0.25)" transform-origin="33.3333 33.3333"/>
</svg>
</svg>
<figcaption>Figure 2-3. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.</figcaption>
</figure>
<h1>3. <code>transform</code> applied to <code><svg></code> element</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-1" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-1" fill="black"/>
<use href="#target-svg-1" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="0" y="0" width="200" height="200" viewBox="0 0 200 200">
<use href="#target-svg-1" x="0" y="0" fill="red" transform="scale(0.5 0.5)" transform-origin="100 100"/>
<use href="#target-svg-1" x="0" y="0" fill="yellow" transform="scale(0.25 0.25)" transform-origin="100 100"/>
</svg>
</svg>
<figcaption>Figure 3-1. Nested <code><svg></code> has the same size as the outermost <code><svg></code>.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-2a" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-2a" x="0" y="0" fill="black"/>
<use href="#target-svg-2a" x="0" y="0" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-svg-2a" x="0" y="-50" fill="red" transform="scale(0.5 0.5)" transform-origin="100 50"/>
<use href="#target-svg-2a" x="0" y="-50" fill="yellow" transform="scale(0.25 0.25)" transform-origin="100 50"/>
</svg>
</svg>
<figcaption>
Figure 3-2a. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.
Transformed <code><svg></code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-2b" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-2b" x="0" y="0" fill="black"/>
<use href="#target-svg-2b" x="0" y="0" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-svg-2b" x="0" y="0" fill="red" transform="scale(0.5 0.5)" transform-origin="100 0"/>
<use href="#target-svg-2b" x="0" y="0" fill="yellow" transform="scale(0.25 0.25)" transform-origin="100 33.333333"/>
</svg>
</svg>
<figcaption>
Figure 3-2b. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.
<code>transform-origin</code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-3a" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-3a" fill="black"/>
<use href="#target-svg-3a" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-svg-3a" x="-50" y="-50" fill="red" transform="scale(0.5 0.5)" transform-origin="50 50"/>
<use href="#target-svg-3a" x="-50" y="-50" fill="yellow" transform="scale(0.25 0.25)" transform-origin="50 50"/>
</svg>
</svg>
<figcaption>
Figure 3-3a. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.
Transformed <code><svg></code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-3b" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-3b" fill="black"/>
<use href="#target-svg-3b" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-svg-3b" x="0" y="0" fill="red" transform="scale(0.5 0.5)" transform-origin="0 0"/>
<use href="#target-svg-3b" x="0" y="0" fill="yellow" transform="scale(0.25 0.25)" transform-origin="33.333333 33.333333"/>
</svg>
</svg>
<figcaption>
Figure 3-3b. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.
<code>transform-origin</code> is shifted.
</figcaption>
</figure>
Safari has implemented very little of SVG 2 - so the safe way is to only use SVG 1.1 capabilities for cross-browser (there is no transform-origin in SVG 1.1).
The cross-browser way to do this in SVG 1.1. is to transform/translate to the origin, do the scale and then reverse the translation. Something like:
transform="translate(100 200) scale(0.5 0.5) translate(-100 -200)"
Using this technique, the snippet from the question would transform into:
h1 {
font-family: sans-serif;
}
figure {
border: thin #c0c0c0 solid;
display: inline-flex;
flex-flow: column;
padding: 5px;
max-width: 200px;
margin: auto;
}
figcaption {
margin-top: 5px;
background-color: #222;
color: #fff;
font: smaller sans-serif;
padding: 3px;
text-align: center;
}
<h1>1. Reference image</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<circle cx="100" cy="100" r="100" stroke="none" fill="black"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
<circle cx="100" cy="100" r="75" stroke="none" fill="blue"/>
<line x1="100" y1="25" x2="100" y2="175" stroke="rebeccapurple" stroke-width="1.5"/>
<line x1="25" y1="100" x2="175" y2="100" stroke="rebeccapurple" stroke-width="1.5"/>
<circle cx="100" cy="100" r="50" stroke="none" fill="red"/>
<line x1="100" y1="50" x2="100" y2="150" stroke="rebeccapurple" stroke-width="1"/>
<line x1="50" y1="100" x2="150" y2="100" stroke="rebeccapurple" stroke-width="1"/>
<circle cx="100" cy="100" r="25" stroke="none" fill="yellow"/>
<line x1="100" y1="75" x2="100" y2="125" stroke="rebeccapurple" stroke-width="0.5"/>
<line x1="75" y1="100" x2="125" y2="100" stroke="rebeccapurple" stroke-width="0.5"/>
</svg>
<figcaption>Figure 1. Reference image, <code>transform</code> is not used. All other images should look the same.</figcaption>
</figure>
<h1>2. <code>transform</code> applied to <code><g></code> element</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-1">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-1" fill="black"/>
<use href="#target-g-1" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="0" y="0" width="200" height="200" viewBox="0 0 200 200">
<use href="#target-g-1" fill="red" transform="translate(100 100) scale(0.5 0.5) translate(-100 -100)"/>
<use href="#target-g-1" fill="yellow" transform="translate(100 100) scale(0.25 0.25) translate(-100 -100)"/>
</svg>
</svg>
<figcaption>Figure 2-1. Nested <code><svg></code> has the same size as the outermost <code><svg></code>.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-2">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-2" fill="black"/>
<use href="#target-g-2" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-g-2" fill="red" transform="translate(100 0) scale(0.5 0.5) translate(-100 -0)"/>
<use href="#target-g-2" fill="yellow" transform="translate(100 33.3333) scale(0.25 0.25) translate(-100 -33.3333)"/>
</svg>
</svg>
<figcaption>Figure 2-2. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="target-g-3">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</g>
</defs>
<use href="#target-g-3" fill="black"/>
<use href="#target-g-3" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-g-3" fill="red" transform="translate(0 0) scale(0.5 0.5) translate(-0 -0)"/>
<use href="#target-g-3" fill="yellow" transform="translate(33.3333 33.3333) scale(0.25 0.25) translate(-33.3333 -33.3333)"/>
</svg>
</svg>
<figcaption>Figure 2-3. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.</figcaption>
</figure>
<h1>3. <code>transform</code> applied to <code><svg></code> element</h1>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-1" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-1" fill="black"/>
<use href="#target-svg-1" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="0" y="0" width="200" height="200" viewBox="0 0 200 200">
<use href="#target-svg-1" x="0" y="0" fill="red" transform="translate(100 100) scale(0.5 0.5) translate(-100 -100)"/>
<use href="#target-svg-1" x="0" y="0" fill="yellow" transform="translate(100 100) scale(0.25 0.25) translate(-100 -100)"/>
</svg>
</svg>
<figcaption>Figure 3-1. Nested <code><svg></code> has the same size as the outermost <code><svg></code>.</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-2a" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-2a" x="0" y="0" fill="black"/>
<use href="#target-svg-2a" x="0" y="0" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-svg-2a" x="0" y="-50" fill="red" transform="translate(100 50) scale(0.5 0.5) translate(-100 -50)"/>
<use href="#target-svg-2a" x="0" y="-50" fill="yellow" transform="translate(100 50) scale(0.25 0.25) translate(-100 -50)"/>
</svg>
</svg>
<figcaption>
Figure 3-2a. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.
Transformed <code><svg></code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-2b" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-2b" x="0" y="0" fill="black"/>
<use href="#target-svg-2b" x="0" y="0" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="0" y="50" width="200" height="100" viewBox="0 0 200 100">
<use href="#target-svg-2b" x="0" y="0" fill="red" transform="translate(100 0) scale(0.5 0.5) translate(-100 0)"/>
<use href="#target-svg-2b" x="0" y="0" fill="yellow" transform="translate(100 33.33333) scale(0.25 0.25) translate(-100 -33.33333)"/>
</svg>
</svg>
<figcaption>
Figure 3-2b. Nested <code><svg></code> is centered in the outermost <code><svg></code> along single axis.
<code>transform-origin</code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-3a" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-3a" fill="black"/>
<use href="#target-svg-3a" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-svg-3a" x="-50" y="-50" fill="red" transform="translate(50 50) scale(0.5 0.5) translate(-50 -50)"/>
<use href="#target-svg-3a" x="-50" y="-50" fill="yellow" transform="translate(50 50) scale(0.25 0.25) translate(-50 -50)"/>
</svg>
</svg>
<figcaption>
Figure 3-3a. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.
Transformed <code><svg></code> is shifted.
</figcaption>
</figure>
<figure>
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<svg id="target-svg-3b" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
<circle cx="100" cy="100" r="100" stroke="none"/>
<line x1="100" y1="0" x2="100" y2="200" stroke="rebeccapurple" stroke-width="2"/>
<line x1="0" y1="100" x2="200" y2="100" stroke="rebeccapurple" stroke-width="2"/>
</svg>
</defs>
<use href="#target-svg-3b" fill="black"/>
<use href="#target-svg-3b" fill="blue" transform="translate(100 100) scale(0.75 0.75) translate(-100 -100)"/>
<svg x="50" y="50" width="100" height="100" viewBox="0 0 100 100">
<use href="#target-svg-3b" x="0" y="0" fill="red" transform="scale(0.5 0.5)"/>
<use href="#target-svg-3b" x="0" y="0" fill="yellow" transform="translate(33.333333 33.333333) scale(0.25 0.25) translate(-33.333333 -33.333333)"/>
</svg>
</svg>
<figcaption>
Figure 3-3b. Nested <code><svg></code> is centered in the outermost <code><svg></code> along both axes.
<code>transform-origin</code> is shifted.
</figcaption>
</figure>
According to https://developer.mozilla.org/de/docs/Web/CSS/transform-origin the problem here is that the transform-origin attribute or the transform-origin CSS style in Safari is only applied to the transform style, not the attribute.
So if you change:
<use href="#target-g-1" fill="blue" transform="scale(0.75 0.75)" transform-origin="100 100"/>
to look like this:
<use href="#target-g-1" fill="blue" style="transform: scale(0.75, 0.75);" transform-origin="100 100"/>
or even this:
<use href="#target-g-1" fill="blue" style="transform: scale(0.75, 0.75);transform-origin:100px 100px"/>
it would work in all browsers.
Related
Is it possible to vertically center align all the rects inside a tag without having to adjust the y attributes on <rect>? (see snippet for example)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" preserveAspectRatio="none" width="100%" height="100%">
<g fill="black">
<rect x="10" y="1" width="6" height="5" />
<rect x="20" y="1" width="6" height="10" />
<rect x="30" y="1" width="6" height="20" />
<rect x="40" y="1" width="6" height="5" />
<rect x="50" y="1" width="6" height="15" />
</g>
</svg>
<h3>desired result</h3>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" preserveAspectRatio="none" width="100%" height="100%">
<g fill="black">
<rect x="10" y="8" width="6" height="5" />
<rect x="20" y="6" width="6" height="10" />
<rect x="30" y="1" width="6" height="20" />
<rect x="40" y="8" width="6" height="5" />
<rect x="50" y="4" width="6" height="15" />
</g>
</svg>
No, it's not possible to center align <rect> elements.
But it is possible to center-align <line> elements and give them a stroke-width (note the viewBox is vertically centered around 0):
<svg viewBox="0 -19 225 38" width="100%" height="100%">
<g stroke="black">
<line x1="10" x2="16" stroke-width="5" />
<line x1="20" x2="26" stroke-width="10" />
<line x1="30" x2="36" stroke-width="20" />
<line x1="40" x2="46" stroke-width="5" />
<line x1="50" x2="56" stroke-width="15" />
</g>
</svg>
You could also achieve vertically centered <rect> elements by setting a transform: translate(0, -50%) css rule.
This approach also requires a transform-box: fill-box; (or content-box) property.
All <rect>elements get a y="50%" attribute to start at the vertical center of the svg viewBox.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3/org/1999/xlink" viewBox="0 0 225 38" width="100%" height="100%" style="border:1px solid #ccc">
<style>
rect {
transform: translate(0, -50%);
transform-origin: center;
transform-box: fill-box;
}
</style>
<g fill="black" >
<rect x="10" y="50%" width="6" height="5" />
<rect x="20" y="50%" width="6" height="10" />
<rect x="30" y="50%" width="6" height="20" />
<rect x="40" y="50%" width="6" height="5" />
<rect x="50" y="50%" width="6" height="15" />
</g>
</svg>
Browser support for transform-box is decent. (See caniuse).
However, if you need legacy browser (e.g. ie11) support, #ccprog's answer is a more robust solution.
When I try to embed an svg within another svg, the height and width of the embedded svg is not respected by the browser and it just defaults to the size of the painted element inside of the svg. This is a problem as I wish to show the effect of a change to the view box attribute on the embedded svg and will hence need some space around the actual element painted into the svg. Is there a way to force the browser to respect the embedded svg's height and width attributes
Example code
<div id='main'>
<svg id="svg-container" width="1200" height="600" >
<defs>
<marker id="1" refX="5" refY="5" markerUnits="markerWidth" markerWidth="10" markerHeight="10">
<circle cx="5" cy="5" r="2" fill="rgb(255,0,0)"></circle>
</marker>
</defs>
<line x1="0" y1="200" x2="100%" y2="200" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="0" y1="400" x2="100%" y2="400" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="200" y1="0" x2="200" y2="100%" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="400" y1="0" x2="400" y2="100%" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="600" y1="0" x2="600" y2="100%" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="800" y1="0" x2="800" y2="100%" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<line x1="1000" y1="0" x2="1000" y2="100%" stroke='white' stroke-width="2" stroke-dasharray='5,5'/>
<svg x='0' y="0" id="svg-1" width="200" height="200">
<circle cx="100" cy="100" r="50" fill="red" stroke="yellow" stroke-width="5" ></circle>
</svg>
<svg x='200' y="0" id="svg-2" width="200" height="200">
<rect x="50" y="50" width="100" height="100" fill="blue" stroke="#27f902" stroke-width="2" ></circle>
</svg>
<svg x='400' y="0" id="svg-2" width="200" height="200">
<rect x="50" y="50" rx="50" ry="20" width="100" height="100" fill="rgb(201, 52, 235)" stroke="blue" stroke-width="2" ></circle>
</svg>
</svg>
</div>
Please look at eaExperiment. I want to make a definition which takes StartArrow definition and rotates it by 180 degrees.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="450" height="400" version="1.1">
<style type="text/css">
<![CDATA[
rect {fill:white; stroke: black; stroke-width: 1;}
text {fill: black; font-family: sans-serif; font-size: 10pt}
line {stroke:black; stroke-width:2}
]]>
</style>
<defs>
<marker orient="auto" refY="0.0" refX="0.0" id="StartArrow" style="overflow:visible;">
<path style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " />
</marker>
<use id="eaExperiment" href="#StartArrow" transform="rotate(180)" />
<marker orient="auto" refY="0.0" refX="0.0" id="EndArrow" style="overflow:visible;">
<path style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="rotate(180)" />
</marker>
<svg id="Box">
<rect width="100" height="85" x="1" y="1" />
<text x="5" y="20">The box</text>
<svg x="10" y="25">
<rect width="70" height="50" x="1" y="1" />
<text x="5" y="20">Box</text>
<text x="5" y="40">Contents</text>
</svg>
</svg>
</defs>
<svg>
<svg x="10" y="120">
<rect width="100" height="50" x="1" y="1" />
<text x="5" y="20">Data</text>
<text x="5" y="40">source</text>
</svg>
<svg x="150">
<use href="#Box" y="1" />
<use href="#Box" y="100" />
<use href="#Box" y="200" />
</svg>
<svg x="300" y="120">
<rect width="100" height="50" x="1" y="1" />
<text x="5" y="20">Database</text>
<text x="5" y="40">server</text>
</svg>
<line x1="100" y1="120" x2="148" y2="40" style="marker-end:url(#EndArrow)" />
<line x1="110" y1="150" x2="147" y2="150" style="marker-end:url(#EndArrow)" />
<line x1="100" y1="170" x2="148" y2="240" style="marker-end:url(#EndArrow)" />
<line x1="254" y1="40" x2="297" y2="120" style="marker-start:url(#StartArrow); marker-end:url(#EndArrow)" />
<line x1="250" y1="150" x2="297" y2="150" style="marker-start:url(#eaExperiment); marker-end:url(#EndArrow)" />
<line x1="250" y1="240" x2="297" y2="170" style="marker-end:url(#EndArrow)" />
</svg>
</svg>
I am definitely doing it wrong, but what is the right way?
You need separate <marker> elements, but their content can be reused with <use> elements. For example like this:
<defs>
<path id="arrow" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " />
<marker orient="auto" refY="0.0" refX="0.0" id="StartArrow" style="overflow:visible;">
<use xlink:href="#arrow" />
</marker>
<marker orient="auto" refY="0.0" refX="0.0" id="EndArrow" style="overflow:visible;">
<use xlink:href="#arrow" transform="rotate(180)" />
</marker>
</defs>
(While the use of the xlink namespace with href is deprecated and also from a practical perspective no longer needed in current browsers, I tend to still use it for the sake of other renderers, Inkscape for example.)
I have this CODEPEN and here are my issues:
I am not understanding why the gradient I applied and referenced as my mask fill like so, doesn't render as it should. It should go from fully opaque to fully transparent. For the gradient I am using: http://angrytools.com/gradient/?0_800080,100_450045&0_0,100_100&l_180:
<mask id="myMask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="url(#grad1)" />
</mask>
In addition I don't understand why if I remove the fill="blue" attribute from my use element like so:
<use xlink:href="#myText" mask="url(#myMask)" />
The text appears black as if no gradient was applied. The gradient I defined is purple..
Thanks!
if you just want to apply your gradient to your text, there is no need to use masks, because gradients support the stop-opacity property.
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">
<defs>
<linearGradient id="lgrad" x1="100%" y1="50%" x2="0%" y2="50%">
<stop offset="0%" style="stop-color:rgb(128,0,128);stop-opacity:0" />
<stop offset="100%" style="stop-color:rgb(69,0,69);stop-opacity:1" />
</linearGradient>
<text x="100" y="120" text-anchor="middle" id="myText" font-size="50">Hello</text>
</defs>
<use xlink:href="#myText" fill="url(#lgrad)" />
</svg>
you only need masks if you want to seperate the opacity from your fills:
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">
<defs>
<linearGradient id="lgrad" x1="100%" y1="50%" x2="0%" y2="50%">
<stop offset="0" stop-color="black" />
<stop offset="1" stop-color="white" />
</linearGradient>
<mask id="myMask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="url(#lgrad)" />
</mask>
<text x="100" y="120" text-anchor="middle" id="myText" font-size="50">Hello</text>
</defs>
<g mask="url(#myMask)">
<use xlink:href=" #myText" transform="translate(0,-50) " fill="red " />
<use xlink:href="#myText" transform="translate(0,0)" fill="green" />
<use xlink:href="#myText" transform="translate(0,50)" fill="blue" />
</g>
</svg>
masks turn colors into opacity information. going from black(totally transparent) to white (totally opaque)
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">
<defs>
<mask id="myMask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="50%" height="50%" fill="white" />
<rect x="50%" y="0" width="50%" height="50%" fill="#333" />
<rect x="0%" y="50%" width="50%" height="50%" fill="#aaa" />
<rect x="50%" y="50%" width="50%" height="50%" fill="white" />
<circle cx="50%" cy="50%" r="15%" fill="black" />
</mask>
<text x="100" y="120" text-anchor="middle" id="myText" font-size="50">Hello</text>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="beige" />
<g mask="url(#myMask)">
<use xlink:href="#myText" transform="translate(0,-50)" fill="red" />
<use xlink:href="#myText" transform="translate(0,0)" fill="green" />
<use xlink:href="#myText" transform="translate(0,50)" fill="blue" />
</g>
</svg>
Have a code:
<svg id="view-svg-problem" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id='svg-marker-start' orient='auto' markerUnits="strokeWidth" markerWidth='10' markerHeight='10' refX='9' refY='5' class="svg-path-dec">
<rect x="1" y="1" width="8" height="8" />
<text x="3" y="7.1" font-weight="bold" font-family="Arial" font-size="5.5" fill="white" stroke="transparent">S</text>
</marker>
<marker id='svg-marker-end' orient='auto' markerUnits="strokeWidth" markerWidth='10' markerHeight='10' refX='5' refY='9' class="svg-path-dec">
<rect x="1" y="1" width="8" height="8" />
<text x="3" y="7.1" font-weight="bold" font-family="Arial" font-size="5.5" fill="white" stroke="transparent">F</text>
</marker>
</defs>
<path id="view-path-svg" class="svg-path" marker-start="url(#svg-marker-start)" marker-end="url(#svg-marker-end)" d="M 655,343 Q747,317 705.5,311 Q664,305 708,292 Q752,279 713.5,254 Q675,229 711.5,212.5 Q748,196 706.5,189 Q665,182 687,157.5 Q709,133 679.5,126.5 Q650,120 663,106 T676,92"></path>
</svg>
So result looks like on the picture:
Easy to see that marker-start aligns well with the path, but marker-end doesn't want to. Is there a solution to the problem?