SVG file mask not being loaded with <use> - html

Let's say I have an SVG file test.svg
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="testsvg">
<mask id="mask3" x="0" y="0" width="100" height="100" >
<rect x="0" y="0" width="100" height="50"
style="stroke:none; fill: #ffffff"/>
<rect x="0" y="50" width="100" height="50"
style="stroke:none; fill: #666666"/>
</mask>
<rect x="1" y="1" width="100" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask3)"/>
</symbol>
</defs>
</svg>
If i try to use it like this in test.html
<svg>
<use href="test.svg#testsvg"/>
</svg>
The mask is not working I get a blue rectangle only. Doing an inspect element in firefox shows that the mask element is missing inside the shadow root. (Why ?)
The same thing as a direct inline SVG works just fine as expected, (I get two rectangles of different colors)
test2.html
<svg xmlns="http://www.w3.org/2000/svg">
<mask id="mask3" x="0" y="0" width="100" height="100" >
<rect x="0" y="0" width="100" height="50"
style="stroke:none; fill: #ffffff"/>
<rect x="0" y="50" width="100" height="50"
style="stroke:none; fill: #666666"/>
</mask>
<rect x="1" y="1" width="100" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask3)"/>
</svg>
Why is this happening?
Note To reproduce the above behavior security.fileuri.strict_origin_policy should be set to false in about:config in Firefox so that local files may be loaded

Related

Rotate svg in a div container

I created an svg. Since I need to rotate it by 45degree, I wrapped it in a div that I transform with a rotation.
It works but the svg overflows the window.
Here the code:
.container {
background-color: tomato;
transform: rotate(45deg);
width: max-content;
}
<div class="container">
<svg width="200" height="200" x="0" y="0">
<rect x="0" y="0" width="100" height="100" fill="pink" stroke="black" />
<rect x="100" y="0" width="100" height="100" fill="white" stroke="black" />
<rect x="0" y="100" width="100" height="100" fill="white" stroke="black" />
<rect x="100" y="100" width="100" height="100" fill="white" stroke="black" />
</svg>
</div>
This is what I would like to obtain:
I would rotate just svg, because you don't need to rotate whole container. You still need add some padding because, when you rotate square it is longer left to right than before.
.container {
width: max-content;
padding: 50px;
}
svg {
transform: rotate(45deg);
}
<div class="container">
<svg width="200" height="200" x="0" y="0">
<rect x="0" y="0" width="100" height="100" fill="pink" stroke="black" />
<rect x="100" y="0" width="100" height="100" fill="white" stroke="black" />
<rect x="0" y="100" width="100" height="100" fill="white" stroke="black" />
<rect x="100" y="100" width="100" height="100" fill="white" stroke="black" />
</svg>
</div>

Red border in transparent ellipse if affected by the opacity of the container

this code
<svg viewbox="0 0 100% 100%" width="100%" height="400px">
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="#fff"/>
<ellipse cx="50%" cy="50%" rx="100" ry="150" stroke="red" stroke-width="10"/>
</mask>
<rect x="0" y="0" width="100%" height="100%" mask="url(#mask)" fill-opacity="0.7"/>
</svg>
return this as a result
I want to have this same result, but with a red border instead of gray in the ellipse and that this is not affected by the opacity of the rect.
I also need the inside of the ellipse to be transparent (not white) and that it is not affected by the opacity of the rect.
Is this possible?
If you are asking whether you can include a red ellipse as part of your mask, then the answer is no. Any colours in a mask are converted to alpha values.
If you want a red ellipse around your "hole", then you need to add it as a separate element on top of the rect.
body {
background-color: linen;
}
<svg viewbox="0 0 100% 100%" width="100%" height="400px">
<defs>
<!-- pull ellipse out as a reusable shape. Used by mask and for red border. -->
<ellipse id="one" cx="50%" cy="50%" rx="100" ry="150"/>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="#fff"/>
<use xlink:href="#one" fill="black"/>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" mask="url(#mask)" fill-opacity="0.7"/>
<use xlink:href="#one" fill="none" stroke="red" stroke-width="10"/>
</svg>
for set order you can use tag use with the attribute xlink:href for more detail see this How to use z-index in svg elements?
add fill="#fff" tag and id="one" to ellipse and draw it again with <use xlink:href="#one"/>
<svg viewbox="0 0 100% 100%" width="100%" height="400px">
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="#fff"/>
<ellipse id="one" cx="50%" cy="50%" rx="100" ry="150" stroke="red" fill="#fff" stroke-width="10"/>
</mask>
<rect x="0" y="0" width="100%" height="100%" mask="url(#mask)" fill-opacity="0.7"/>
<use xlink:href="#one"/>
</svg>

How to make svg size to fit content text

Please check my code link
<div class="suj_content">
<header class="suj_content_hd">
<div id="suj_content_hd_ytb"><iframe class="suj_content_hd_ytb" src="https://www.youtube.com/embed/kOc6ME2J_Us?mute=1&loop=1&playlist=kOc6ME2J_Us&autoplay=1&showinfo=0&controls=0" width="100%" height="100%" frameborder="0"></iframe></div>
<h2>
<svg id="suj_content_svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100% 100%" preserveAspectRatio="xMidYMid slice">
<defs>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%"></rect>
<text>
<tspan x="0" dy="33.333333333333%" alignment-baseline="middle" text-anchor="start">mittel</tspan><tspan x="0" dy="23.222222222222%" alignment-baseline="middle" text-anchor="start">stand</tspan><tspan x="0" dy="23.222222222222%" alignment-baseline="middle" text-anchor="start">digital</tspan> </text>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%"></rect>
</svg>
</h2>
</header>
How can I set the width and height of SVG tag to fit its content (the tspan tags). The number of tspan tags is not fixed.
Thanks
First: you are using an invalid viewBox attribute. No percentages are allowed. The value of the viewBox is fromX fromY width height.
I am using a viewBox where the width is 41 - the width of the bounding box of the text.
Second: I suspect you intend to cut the text from the last rect. In this case you need the text to be white.
console.log(t.getBBox())
text{font-size:16px;}
<svg id="suj_content_svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 41 50" preserveAspectRatio="xMidYMid slice">
<defs>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%"></rect>
<text fill="white" id="t">
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">mittel</tspan>
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">stand</tspan>
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">digital</tspan>
</text>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" mask="url(#mask)"></rect>
</svg>

How do maskUnits & maskContentUnits attributes affect mask positioning?

I've read a bit of the spec for the SVG mask element but the sections on maskUnits and maskContentUnits aren't clear to me, and also how they affect each other isn't clear to me.
From the spec:
maskUnits = 'userSpaceOnUse': x, y, width and height represent values in the current user coordinate system in place at the time when the mask element is referenced.
maskUnits = 'boundingBox': x, y, width and height represent fractions or percentages of the object bounding box of the element to which the mask is applied.
maskContentUnits = 'userSpaceOnUse': The user coordinate system for the contents of the mask element is the current user coordinate system in place at the time when the mask element is referenced.
maskContentUnits = 'boundingBox': The coordinate system has its origin at the top left corner of the bounding box of the element to which the clipping path applies to and the same width and height of this bounding box.
I've tried editing the maskUnits example and maskContentUnits example on MDN but whenever I change anything something unexpected happens, like the whole element disappears or the mask doesn't seem to be applied.
The snippet below is a sandbox with a few examples of the confusing behavior. I'd expect all of the squares to look different but there are 2 pairs each that are identical, and one of the pairs look like no mask was applied at all:
* {
margin: 0;
padding: 0;
}
body {
padding: 20px 0 0 20px;
}
.hidden {
width: 0;
height: 0;
margin: 0;
}
svg {
width: 100px;
height: 100px;
margin: 0 20px 20px 0;
display: block;
}
p {
margin-bottom: 10px;
font-family: monospace;
}
<!-- mask definitions -->
<svg viewBox="0 0 100 100" class="hidden">
<mask
id="usou-usou"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
<mask
id="usou-obb"
maskUnits="userSpaceOnUse"
maskContentUnits="objectBoundingBox"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
<mask
id="obb-usou"
maskUnits="objectBoundingBox"
maskContentUnits="userSpaceOnUse"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
<mask
id="obb-obb"
maskUnits="objectBoundingBox"
maskContentUnits="objectBoundingBox"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
</svg>
<p>maskUnits = userSpaceOnUse &<br> maskContentUnits = userSpaceOnUse</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#usou-usou)"
/>
</svg>
<p>maskUnits = userSpaceOnUse &<br> maskContentUnits = objectBoundingBox</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#usou-obb)"
/>
</svg>
<p>maskUnits = objectBoundingBox &<br> maskContentUnits = userSpaceOnUse</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#obb-usou)"
/>
</svg>
<p>maskUnits = objectBoundingBox &<br> maskContentUnits = objectBoundingBox</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#obb-obb)"
/>
</svg>
We know what units are in ordinary life, there are inches, miles, kilometers etc.
One inch is not the same as one kilometre. If you draw a tiny picture, one inch across and you put a frame round it 2 inches across, the picture itself won't change if we make the frame 2 kilometres across. Equally, changing the picture size doesn't change how much is visible inside the picture frame unless the frame is too small for the picture.
maskUnits affect the units of the picture (mask) frame, maskContentUnits affect the units of the picture (mask).
objectBoundingBox units are defined such that 0 is the left side of the masked shape and 1 is the right side.
userSpaceOnUse units use the same co-ordinate system as the masked shape itself. If you mask a rect which extends from 50-100 then your mask ought to cover that area too if you want to mask the entire rect.
If you draw a circle with a radius of 100 kilometres centred 100 kilometres from the origin in both directions, then look at a square 1 millimetre across that starts at the origin, that square will have nothing drawn on it as everything is drawn outside that area.
We're masking
<rect x="0" y="0" width="100" height="100"/>
So our mask's x, y, width and height i.e.
<mask maskUnits="userSpaceOnUse" x="0" y="0" width="100" height="100"/>
need to cover the same area (or more) if we want to mask that shape and they do.
If we had maskUnits="objectBoundingBox" we'd need
<mask maskUnits="objectBoundingBox" x="0" y="0" width="1" height="1"/>
Using 100 for the width and height would make the mask 100 times the size it needs to be but other than wasting lots of memory, it has no visible effect.
maskContentUnits work the same for the mask's content i.e.
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
Either they need to be 0..1 for objectBoundingBox or 0..100 for the shape. Since they are far too big for objectBoundingBox the mask is all one colour as the shapes are outside the area you can see i.e. the area over the shape.
<!-- mask definitions -->
<svg viewBox="0 0 100 100" class="hidden">
<mask
id="usou-usou"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
<mask
id="usou-obb"
maskUnits="userSpaceOnUse"
maskContentUnits="objectBoundingBox"
x="0"
y="0"
width="100"
height="100"
>
<rect x="0" y="0" width="1" height="1" fill="white" />
<!-- if we wanted the same mask as above it would be r="0.25" -->
<circle cx=".5" cy=".5" r=".1" fill="black" />
</mask>
<!-- have the mask cover only the top left quarter of the shape -->
<mask
id="obb-usou"
maskUnits="objectBoundingBox"
maskContentUnits="userSpaceOnUse"
x="0"
y="0"
width="0.5"
height="0.5"
>
<rect x="0" y="0" width="100" height="100" fill="white" />
<circle cx="50" cy="50" r="25" fill="black" />
</mask>
<!-- have the mask cover only the top left quarter of the shape -->
<mask
id="obb-obb"
maskUnits="objectBoundingBox"
maskContentUnits="objectBoundingBox"
x="0"
y="0"
width="0.5"
height="0.5"
>
<rect x="0" y="0" width="1" height="1" fill="white" />
<!-- if we wanted the same mask as above it would be r="0.25" -->
<circle cx=".5" cy=".5" r=".1" fill="black" />
</mask>
</svg>
<p>maskUnits = userSpaceOnUse &<br> maskContentUnits = userSpaceOnUse</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#usou-usou)"
/>
</svg>
<p>maskUnits = userSpaceOnUse &<br> maskContentUnits = objectBoundingBox</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#usou-obb)"
/>
</svg>
<p>maskUnits = objectBoundingBox &<br> maskContentUnits = userSpaceOnUse</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#obb-usou)"
/>
</svg>
<p>maskUnits = objectBoundingBox &<br> maskContentUnits = objectBoundingBox</p>
<svg viewBox="0 0 100 100">
<rect
x="0"
y="0"
width="100"
height="100"
mask="url(#obb-obb)"
/>
</svg>

Keep <text> element scaled inside <svg> with viewBox

I'm trying to put some text as labels inside some scaled elements, and the text is too big to fit in the container. What can I do here?
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 6 1" preserveAspectRatio="none">
<g>
<rect x="0" y="0" width="1" height="0.4"><title>Nov-21</title></rect>
<text x="0.5" y="0.5" fill="red">A<text>
</g>
<rect x="1" y="0" width="1" height="1"><title>Nov-22</title></rect>
<rect x="2" y="0" width="1" height="1"><title>Nov-23</title></rect>
<rect x="3" y="0" width="1" height="1"><title>Nov-24</title></rect>
<rect x="4" y="0" width="1" height="1"><title>Nov-25</title></rect>
<rect x="5" y="0" width="1" height="1"><title>Nov-26</title></rect></svg>
</div>
Here is a codepen with the result.
You have a very small custom viewport="0 0 6 1" size. 6px - width, 1px - height, so the font can not be displayed with such parameters.
I increased the size of the viewBox 100 times viewBox="0 0 600 100"
Squares for clarity painted in different colors. You can change their coloring according to your choice.
The text is placed inside the squares. I hope that's exactly what you wanted when you used the command
<title> Nov-24 </ title> inside the squares.
But the command <title> in SVG is a system tooltip, the information from which appears when you hover the cursor.
The size of the tooltip and its font can not be changed, so I added in the squares more tags <text> ... </ text>, the parameters of which you can change.
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 600 100" >
<g>
<rect x="0" y="0" width="100" height="40"><title>Nov-21</title></rect>
<text x="35" y="75" font-size="36" fill="red">A</text>
</g>
<rect x="100" y="0" width="100" height="100" fill="orange">
<title>Nov-22</title></rect>
<text x="125" y="55" font-size="18" fill="white">Nov-22</text>
<rect x="200" y="0" width="100" height="100" fill="orangered">
<title>Nov-23</title></rect>
<text x="225" y="55" font-size="18" fill="white">Nov-23</text>
<rect x="300" y="0" width="100" height="100" fill="green">
<title>Nov-24</title></rect>
<text x="325" y="55" font-size="18" fill="white">Nov-24</text>
<rect x="400" y="0" width="100" height="100" fill="dodgerblue">
<title>Nov-25</title></rect>
<text x="425" y="55" font-size="18" fill="white">Nov-25</text>
<rect x="500" y="0" width="100" height="100" fill="yellowgreen">
<title>Nov-26</title></rect>
<text x="525" y="55" font-size="18" fill="white">Nov-26</text>
</svg>
</div>