How to position an svg to vertically fill a variable height div? - svg

I've created some svg graphics that I would like to set as backgrounds in some variable height divs. I'm trying to use them as a sprite, so one svg file has a few groups, each with its own id, and I'm using those ids to specify which background is rendered in each div.
Here's a link to a (non-working) JSFiddle.
HTML:
<svg width="0" height="0">
<defs>
<!-- BLUE GRAPHIC -->
<g id="blue_background">
<polygon fill="#C8D9E5" points="[...in the fiddle...]"/>
</g>
<!-- GREEN GRAPHIC -->
<g id="green_background">
<path fill="#49B974" d="[...in the fiddle...]"/>
</g>
</defs>
</svg>
<div class="box">
<h1>asdasdasd</h1>
<h1>asdasdasd</h1>
<h1>asdasdasd</h1>
<svg class="svg1" viewBox="0 0 600 200" >
<use xlink:href="#blue_background" width="100%" height="100%"></use>
</svg>
</div>
<div class="box">
<h1>asdasdasd</h1>
<h1>asdasdasd</h1>
<h1>asdasdasd</h1>
<svg class="svg2" viewBox="0 0 200 200">
<use xlink:href="#green_background" width="100%" height="100%"></use>
</svg>
</div>
Ideally the graphic would be aligned with the right side, and stretch to fill the div's height.
Thanks

Since you're describing your SVGs as "backgrounds", I assume you don't need them to push text out of the way.
In that case, I would recommend using absolute positioning for the SVGs (relative to the "box" containers). With absolute positioning, a height of 100% is valid even if the parent element doesn't have fixed height.
.box {
position: relative;
width: 400px;
border: 1px solid #ddd;
}
svg {
position:absolute;
height:100%;
top:0; right:0;
z-index:-1;
}
http://jsfiddle.net/svag2/1/

Related

CSS transform-origin on <g> element for centered rotation?

I don't quite understand the transform-origin CSS rule.
If you have a plain <svg> with changing sizes (width, height) and some <rect> elements in it, how can you rotate a <g> element in it correctly?
It should be right next to the <rect>, so I am using transform: translate(x,y).
Then I'd like to rotate the group with rotate(45), but it ends up at strange places:
HTML
<div class="box">
<svg class="svg-main" width="600px" height="600px">
<rect x="0" y="50" width="90" height="40" fill="blue" stroke="blue"></rect>
<g transform="translate(100,50),rotate(7)"
transform-origin="center"
class="group">
<path d="M38.15,20.54,28.9,11.29a1.4,1.4,0,0,0-2.4,1v1.89a1.41,1.41,0,0,1-1.4,1.41H3.2A1.4,1.4,0,0,0,1.79,17v9.11a1.41,1.41,0,0,0,1.41,1.4H25.1a1.41,1.41,0,0,1,1.4,1.41v1.89a1.41,1.41,0,0,0,2.4,1l9.25-9.25A1.41,1.41,0,0,0,38.15,20.54Z" stroke="#000" strokeMiterlimit="10" strokeWidth="2"/>
</g>
</svg>
</div>
CSS
div.box {
padding: 30px;
background-color: #dfcfcf;
}
svg.svg-main {
background-color: white;
border: 2px solid #dedada;
}
svg.svg-main g.group path {
fill: rgba(215, 20, 45, 0.5);
}
JSFiddle
https://jsfiddle.net/bair_web/ajLgzoey/
Result for 17deg
Where is the origin?
Question
I would like to rotate the group with its <path> and using center for transform-origin.
MDN
How can I achieve a simple, centered rotation of a group in an SVG, which is also translated? It seems like transform-origin points to the parent element (the SVG)? So do I need to calculate the position of the<g> element relative to the <svg> elment and use it for transform-origin?
Because, when I just omit the origin, the rotated group also moves around and does not keep its center.

Half of line stroke is hidden on the SVG edge

If SVG line touches SVG edge, half of the line stroke will be outside of SVG and will be hidden (see example of line chart below, last tick at the right has half-width tickness).
What are the techincs to avoid it? Is there a way to scale out SVG a little bit, so the SVG image will be smaller and don't touch SVG borders? Something like adding padding?
I'm using non-fixed aspect ratio as height:1rem and width:100%, as it's supposed to take all the place available.
The viewbox scaling doesn't work
svg {
display: block;
}
.chart {
width: 300px;
border: 1px solid #ccc;
}
<div class="chart">
<svg height="1rem" width="100%" class="text-left" viewBox="-5% 0 105% 1rem">
<line x1="25%" y1="5%" x2="25%" y2="25%" stroke="#6B7280" stroke-width="2"></line>
<line x1="50%" y1="5%" x2="50%" y2="25%" stroke="#6B7280" stroke-width="2"></line>
<line x1="100%" y1="5%" x2="100%" y2="25%" stroke="#6B7280" stroke-width="2"></line>
<rect x="0%" y="25%" width="15.138888888888888%" height="50%" fill="#111827"></rect>
</svg>
</div>

Sizing pattern element based on viewport

I have a large svg image that will be scrolled. I would like to add a tiled background image behind all the elements. This is currently leaving me with two problems:
I haven't found a way to keep a background image fixed, and not scroll it with the svg elements on top of it.
Assuming that's not possible, I wanted to size the tile elements to occupy 20% of the viewable area rather than 20% of the total svg size.
<svg width="3560.00px" height="1350.00px" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<pattern id="G-BG" width="20.00%" height="20.00%">
<image xlink:href="https://static.vecteezy.com/system/resources/thumbnails/000/301/800/small/jfyo_waxi_190121.jpg" x="0" y="0" width="20.00%" height="20.00%"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#G-BG)" fill-opacity="0.20"/>
<circle fill="green" cx="200" cy="200" r="100.00"/>
</svg>
If you run this little example, it sets a background composed of 5 x 5 copies of some arbitrary image, but the repeat interval of the tiling is based on 20% of the full svg size. If I try and use vw/vh units then the pattern size seems to go to zero, and so disappear.
My ideal choice would be to have a fixed 5 x 5 image that doesn't scroll, but the CSS background support doesn't seem to work for for svg.
My second choice would be to have a scrolling background image, but where there are 5 x 5 tiles visible at any one time.
Can either of these goals be achieved?
Not sure if there is anything here that might help?
html,body{
height: 100%;
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrapper{
width: 100%;
height: 100%;
}
.wrapper svg{
background-color: 'red';
top: 0;
left:0;
position: fixed;
width: 100%;
height: 100%;
}
<div class="wrapper">
<svg xmlns="http://www.w3.org/2000/svg" >
<pattern id="pattern" width="0.2" height="0.25" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet">
<image width="0.5" height="0.5" href="https://static.vecteezy.com/system/resources/thumbnails/000/301/800/small/jfyo_waxi_190121.jpg" />
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern)"></rect>
</svg>
</div>

Svg clip path resizing according to viewport

I'm struggling with resizing clipped svg on my HTML setup. I looked for similar solutions but I could not find any yet. I'm trying to resize clipped svg according to vertical screen viewport. Here is the codepen example of my setup:
.slider-image {
clip-path: url(#clip);
-webkit-clip-path: url(#clip);
}
<div>
<img class="w-full h-full slider-image object-cover absolute top-0 left-0 z-20" src="https://images.unsplash.com/photo-1558611848-73f7eb4001a1?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1051&q=80" >
<svg width="100%" height="90vh" viewBox="0 0 1159 548" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip">
<path d="M989 547.5H0V0H1156L1159 9L1157.5 18.5L1147 89.5L1157.5 126L1120 244.5L1088 309L1041 369.5L989 445.5L962 503.5L989 547.5Z" fill="url(#paint0_linear)"/>
<circle cx="350" cy="168" r="80"/>
</clipPath>
</defs>
</svg>
</div>
https://codepen.io/ilkrclm/pen/oNNMQor?editors=1100
In this case the solution is using clipPathUnits="objectBoundingBox"
The clipPathUnits attribute indicates which coordinate system to use for the contents of the <clipPath> element.
objectBoundingBox indicates that all coordinates inside the <clipPath> element are relative to the bounding box of the element the clipping path is applied to. It means that the origin of the coordinate system is the top left corner of the object bounding box and the width and height of the object bounding box are considered to have a length of 1 unit value.
Read about clipPathUnits
Since the object bounding box is considered to have a length of 1 unit you will need to scale the path: transform="scale(0.00086)". The width of the bounding box of the path is 1159. 1/1159 = 0.00086.
I've commented out the circle since in this case is not doing anything.
*{margin:0;padding:0}
.slider-image {
width:100%;
clip-path: url(#clip);
-webkit-clip-path: url(#clip);
}
<div>
<img class="w-full h-full slider-image object-cover absolute top-0 left-0 z-20" src="https://images.unsplash.com/photo-1558611848-73f7eb4001a1?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1051&q=80" >
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<path transform="scale(0.00086)" d="M989 547.5H0V0H1156L1159 9L1157.5 18.5L1147 89.5L1157.5 126L1120 244.5L1088 309L1041 369.5L989 445.5L962 503.5L989 547.5Z" fill="url(#paint0_linear)"/>
<!--<circle transform="scale(0.00086)" cx="350" cy="168" r="80"/>-->
</clipPath>
</defs>
</svg>
</div>

Why does this SVG image have a height of 150px

Why is this SVG image displayed at 150px height inside this 500px container? Why this specific value?
I found this weird behavior in both js bin and Codepen, so I think it is something to do with my code and not with the online editors.
Note: a 700px div container results in the same thing. So the height of the parent doesn't matter.
<div style="padding: 30px; background-color: yellow; height: 500px; width: 500px; ">
<svg>
<pattern id="basicPattern" x="10" y="10" width="40" height="40" patternUnits="userSpaceOnUse" >
<rect x= "0" y="0" width="4" height="4"
stroke = "red"
stroke-width = "1"
fill = "black"/>
</pattern>
<!-- <rect x="0" y="0" width="300" height="151" // why this deletes the bottom line? -->
<!-- <rect x="0" y="0" width="300" height="150" // why this deletes 1 px from the bottom line? -->
<!-- but this height="149" is the bottom limmit for this picture..
what prevent's it bor beeing extended further - we have unthil 500 px as you can see on the div.-->
<rect x="0" y="0" width="300" height="149"
stroke= "red"
stroke-width="2"
fill="url(#basicPattern)" />
</svg>
This is Jsbin and this is CodePen.
You didn't set the SVG width and height, so it goes to the default size of 300px width x 150px height (for some user-agents).
Here is your JSBin with the SVG width and height both set to 500px. Now the rectangle can go beyond 150px of height: https://jsbin.com/yafenemawe/1/edit?html,output

Resources