I'm trying to get svg image to scale nicely (http://coub.com/view/5tbis) with sibling div content so that they'd look like one thing. I managed to get it working in fireforx but not in chrome and ie, all latest versions. Here is my code:
<!DOCTYPE html>
<html>
<body>
<div style="display: flex; height: 10em;">
<div style="height: 100%">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width: 100%; height: 100%; " viewBox="0 0 400 400">
<rect x="0" y="0" width="400" height="200" fill="yellow" stroke="black" />
<rect x="0" y="200" width="400" height="200" fill="green" stroke="black" />
<circle cx="200" cy="200" r="100" stroke="black" stroke-width="3" fill="red" />
</svg>
</div>
<div style="display: flex; flex-direction: column; width: 100%">
<div style="flex: 1; background-color: green"> </div>
<div style="flex: 1; background-color: yellow"> </div>
</div>
</div>
</body>
</html>
In IE and Chrome there is a blank space around svg and in Chome, svg proportions does not always match divs' ones.
Any help is highly appreciated.
UPDATE: ok, preserveAspectRatio="none" fixes the problem for ie and chrome, but I still don't understand why do they behave in this way? The wrapper div do not have width, why svg then doesn't change it according its own width?
UPDATE: preserveAspectRatio="xMidYMid slice" makes it even better, but only for ff and ie
Related
I'm having a problem coverting inline SVG to be wrapped in divs. I was using nested SVGs before and now I'm told I have to use nested divs with inline SVG.
Basically, I need the SVG to be sized to the "container" - the "container" is size to the browser window.
For an example of what works before I tried the whole div thing:
SVG Only Example - works perfectly
<html>
<body>
<svg id="container" style="position:relative;border:dashed;width:100%;height:100%;" viewBox="0 0 1000 500">
<svg id="background" name="Box" x="0" y="0">
<rect width="1000" height="500" stroke="lime" fill="blue" stroke-width="10" />
<svg id="shape" name="Triangle" x="275" y="50" fill="red" stroke="yellow" stroke-width="3">
<path d="M0,378L185,0L371,378Z" />
</svg>
</svg>
</svg>
</body>
</html>
But when I try to wrap divs around them, it just stays the same size as my viewBox, no matter what I've tried. I've looked up a lot on this on SO and elsewhere and nothing seems to work: padding tricks, 100vw, width, height, etc.
Here's the latest of what I've tried:
SVG wrapped in DIV Example - doesn't behave the same
<html>
<body>
<div id="container" style="position:relative;border:dashed;width:100%;height:0;margin:5px">
<div id="background" style="position:absolute;left:0px;top:0px;width:1000px;height:500px;">
<svg name="Box" viewBox="0 0 1000 500">
<rect width="1000" height="500" stroke="lime" fill="blue" stroke-width="10" />
</svg>
<div id="shape" style="position:absolute;left:275px;top:50px;width:371px;height:378px;">
<svg name="Triangle" viewBox="0 0 371 378" fill="red" stroke="yellow" stroke-width="3">
<path d="M0,378L185,0L371,378Z" />
</svg>
</div>
</div>
</div>
</body>
</html>
I put a "border:dashed;" in the first div, just to make sure it is resizing with the browswer window and it is. It's just that everything inside that div doesn't change.
Any advice on how to get the "wrapped in div" strategy to match the "plain SVG" strategy?
More clarity:
I guess what I'm saying is that "background" shape needs to be 1000w x 500h, relative to the "container" size. Any of it's children need to be absolutely positioned inside of that 1000w 500h and relative to it. The "container" size is the available space. So if if the browser window is 3000w x 2000h, then technically the "background" shape should be 3000w x 1500h (and the child shapes resize accordingly too - but the stay in their original relative position - relative to 1000w x 500h). If the window 800 w by 600 h, the "background" and child shapes shrink to fit that, relatively. Just like the SVG example.
It might be helpful to take the SVG example above, save it as an html file, launch locally and resize your browser up and down. That's what I'm to find help with, but divs don't seem to know how to handle this.
There's no real equivalent to viewBox property of SVG on DIV elements. The closest one would transform scale. So if you give your div containers a specific size in pixel without adjusting on resize, you're going to somewhat override the viewbox calculations.
That being said, if your div containers are resized with the window, then it can work. Also with minimal javascript you can get the same result as viewbox.
For the css only solution, you define your div containers so they are 100% the size of the window. The SVG viewbox is then still making the calculations. You'll need to define a preserveAspectRatio to have the same behavior as your SVG example. Like this:
html, body {
width: 100%;
height: 100%;
padding: 0px;
margin:0px;
}
* {
box-sizing: border-box;
}
<div id="container" style="position:relative;border:dashed;width:100%;height:100%;">
<svg name="Box" style="position:relative;width:100%;height:100%;" viewBox="0 0 1000 500" preserveAspectRatio="xMinYMin">
<rect width="100%" height="100%" stroke="lime" fill="blue" stroke-width="10" />
</svg>
<div id="shape" style="position:absolute;left:0px;top:0px;height:100%;width:100%;">
<svg style="position:relative;width:100%;height:100%;" viewBox="0 0 1000 500" preserveAspectRatio="xMinYMin">
<svg id="shape" name="Triangle" x="275" y="50" width="371" height="378" fill="red" stroke="yellow" stroke-width="3">
<path d="M0,378L185,0L371,378Z" />
</svg>
</svg>
</div>
</div>
For the javascript solution, you define the size on your div containers, and your svg can then be relative and not have the positioning info. And on resize you adjust the scale based on the innerWidth. Like this:
window.onload = window.onresize = calculateScale
function calculateScale() {
var scaleFactor = innerWidth / 1000;
document.getElementById('container').style.transform = `scale(${scaleFactor})`
}
html,
body {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
}
* {
box-sizing: border-box;
}
<div id="container" style="position:absolute;border:dashed;width:1000px;height:500px;transform-origin: left top">
<svg name="Box" style="position:relative;width:100%;height:100%;">
<rect width="100%" height="100%" stroke="lime" fill="blue" stroke-width="10" />
</svg>
<div id="shape" style="position:absolute;width: 371px;height: 378px;top: 50px;left: 275px;">
<svg style="width: 100%; height: 100%" id="shape" name="Triangle" fill="red" stroke="yellow" stroke-width="3">
<path d="M0,378L185,0L371,378Z" />
</svg>
</div>
</div>
I think I got what you are looking for but this is two different svgs not the same vector image.
I'm wrapping both svgs with a div and im overlaying the second div using an absolute position.
<html>
<body>
<div id="containerouter" style="position:relative;border:dashed;width:100%;height:100%;margin:0;">
<div id="background" style="position:relative;width:100%;height:100%;">
<svg name="Box" viewBox="0 0 1000 500">
<rect width="1000" height="500" stroke="lime" fill="blue" stroke-width="10" />
</svg>
</div>
<div id="shape" style="position:absolute;height:100%; width:auto;left:175px;top:10%;">
<svg name="Triangle" viewBox="0 0 371 378" fill="red" stroke="yellow" stroke-width="3" x="0" y="0" height="75%">
<path d="M0,378L185,0L371,378Z" />
</svg>
</div>
</div>
</body>
</html>
Like this?
<html>
<body>
<div class="container" style="width:100%; height:100%;">
<div class="container" style="width:100%; height:100%;">
<svg id="container" style="position:relative;border:dashed;width:100%;height:100%;" viewBox="0 0 1000 500">
<rect width="100%" height="100%" stroke="lime" fill="blue" stroke-width="10" />
<foreignObject x="275" y="50" width="371px" height="378px">
<div class="container" style="width:100%; height:100%;">
<svg id="shape" name="Triangle" x="0" y="0" fill="red" stroke="yellow" stroke-width="3" width="100%" height="100%">
<path d="M0,378L185,0L371,378Z" />
</svg>
</div>
</foreignObject>
</svg>
</div>
</div>
</body>
</html>
EDIT: Changed the snippet.
This version uses a <foreignObject> to wrap the inner svg with a div element. Outcome is as expected.
If you are trying to have something like this:
<div>
<div>
<svg> <!-- rect --> </svg>
</div>
<div>
<svg> <!-- triangle --> </svg>
</div>
</div>
Then you'll need to overlay the divs on top of one another and you can't manipulate the svg any further
I really hope someone here can help me out, since i'm stuck for 3 days straight now.
I have a header image with half a circle cut out by using a SVG mask, this half circle needs to have a colored stroke but since it's a mask it won't let me do this. I have tried and searched everything, and came upon this codepen snippet which is using the SVG use tag: https://codepen.io/rewfergu/pen/oJCif
However, i can not get this to work at all.
Here is my SVG code including the white transparent stroke (as far as i got):
<div id="myCarousel" class="carousel carousel-fade slide myCarousel-slide" style="height:auto; max-height:499px; overflow:hidden">
<div class="carousel-inner" role="listbox">
<div id="slide2" class="item active" data-navpos="" data-navposarrow="" data-center="1" data-maxheight="499" data-id="2" style="height:499px;"><img id="slideimg2" class="logofull img-responsive" src="http://placehold.it/1800x499.jpg"></div>
</div>
</div>
<svg width="100%" height="100%">
<defs>
<style type="text/css"><![CDATA[
circle {
stroke: #942994;
stroke-width: 5;
}
]]></style>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="#fff"/>
<circle id="c1" cx="50%" cy="105%" r="180" fill="#000"/>
</mask>
</defs>
<rect x="0" y="0" width="100" height="50" mask="url(#mask)" fill-opacity="0.7"/>
</svg>
And my CSS, applied on my header image (the carousel is 100% width and around 500px high):
#myCarousel .item {
border-bottom: 5px solid #942994;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: hidden;
mask: url(#mask);
}
Unfortunately i can not use PNG's, because the header images need to be easily changable.
Update:
Created a new fiddle with my exact setup: https://jsfiddle.net/oqfdfart/2/
Also some strange behaviour: In Chrome, Edge and IE the half circle does not appear at all in the headerimage.
Update:
I found the answer, following my latest fiddle i've separated both SVG's like so:
<svg width="100%" height="100%">
<defs>
<style type="text/css"><![CDATA[
#inner {
stroke: #942994;
stroke-width: 5;
fill-opacity: 0;
z-index: 9999;
}
]]></style>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" fill="#fff"/>
<circle id="c1" cx="50%" cy="105%" r="180" fill="#000"/>
</mask>
</defs>
<rect x="0" y="0" width="100" height="50" mask="url(#mask)" fill-opacity="0.7"/>
</svg>
<svg id="innercircle" width="100%" height="100%" x="0" y="0">
<circle id="inner" x="0" y="0" cx="50%" cy="105%" r="181" fill="#fff" />
</svg>
And added the following CSS:
#headeroverlay {
width: 100%;
position: absolute;
top:0;
background: rgba(255,255,255,0);
height: 499px;
z-index: -1;
}
#innercircle {
position: absolute;
top: 0;
left: 0;
}
First i had a very dark overlay on top of my headerimage, but this was fixed by giving #headeroverlay the z-index -1.
Maybe this solution is not so pretty since i had to define a fixed height for my headersection, but at least for this project that's no problem.
If someone has a better solution i'm very curious :)
Also i'm still stuck with Chrome, Edge and IE not rendering my SVG's at all.
Masks only affect the translucency of the element it is applied to.
If you want to outline the hole with a colour, then you'll need to create an element the same shape as the hole, then draw it on top of the masked element.
i want to put an svg inside the .container div created with the following code so that it fits exactly to the dimensions of the .container div but still scales with the size of the page as it is resized:
<html>
<body>
<style type='text/css'>
.container
{
position:relative;
width:50%;/*half the width of the whole page*/
margin:auto;/*center the whole thing*/
}
.set_height
{
padding-bottom:50%;/*2:1 aspect ratio*/
position:relative;
float:left;
width:100%;
height:100%;
}
</style>
<div class='container'>
<div class='set_height' style='background-color:blue;'>
</div>
</div>
</body>
</html>
a rectangular svg with an aspect ratio of 2:1 will do for the purposes of this question:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="50" stroke="black" fill="red" stroke-width="5"/>
</svg>
however when i do this, it messes up the aspect ratio of the .container div. using chrome the .container div height expands out to 100%, which is obviously not what i want :P
thanks in advance!
I think I got it. I just put an absolute div within the .container div:
.on_top
{
position:absolute;
top:0;left:0;bottom:0;right:0;/*expand this div to the size of its parent*/
}
<div class='set_width'>
<div class='on_top'>
<svg viewBox="0 0 100 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="50" stroke="black" fill="red" stroke-width="5"/>
</svg>
</div>
<div class='set_height'></div>
</div>
and I used viewbox on the svg as ali gajani suggested
I think you need to use the viewbox attribute: http://www.w3.org/TR/SVG/coords.html#ExampleViewBox
Check this, it scales now: http://jsfiddle.net/NKRPe/60/
<svg viewBox="0 0 1500 1000" preserveAspectRatio="none" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="50" stroke="black" fill="red" stroke-width="5"/>
</svg>
I am having an issue with Chrome and foreignObject were i would like to put this inside a SVG Element that is a child to another SVG element, for some reason chrome doesn't seem to like this. Am i missing something in my syntax or is it time file a bug repport?
Example:
<svg width="400" height="600" xmlns="http://www.w3.org/2000/svg" version="1.1">
<foreignObject x="0" y="0" width="400" height="200" overflow="hidden" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="pointer-events: all;">
<div contenteditable="true" xmlns="http://www.w3.org/1999/xhtml" style="background: black; color: white;">
<div>This works!</div>
</div>
<textarea>Here we can select text</textarea>
</foreignObject>
<svg x="0" y="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<foreignObject x="0" y="0" width="400" height="200" overflow="hidden" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="pointer-events: all;">
<div contenteditable="true" xmlns="http://www.w3.org/1999/xhtml" style="background: black; color: white;">
<div>But this does not in chrome, why not?</div>
</div>
<textarea>Unable to select text, but it's posible to edit</textarea>
</foreignObject>
</svg>
</svg>
JSFiddle example
First: the stuff I'm trying to do is not compatible with chrome for the time being. Please use firefox to check the examples.
Here is what I've done:
http://jsfiddle.net/Robodude/ev6VF/1/
<style type="text/css">
.clip3 {
clip-path: url(#c3);
}
</style>
<svg height="0">
<defs>
</defs>
<clipPath id="c3">
<polygon points="75,0 225,0 275,100 225,200 75,200 25,100" />
</clipPath>
</svg>
<div class="container left">
<div id="Image1" class="Image1 image clip3"></div>
<div id="Image2" class="Image2 image clip3"></div>
<div id="Image3" class="Image3 image clip3"></div>
</div>
What I would like to do, is draw on top of the html elements that were clipped in order to draw some accents and borders to the cut images as seen below via ms paint. Is this possible with SVG? Perhaps I can add another property to .clip3 and link it to some svg shapes somehow?
I'm trying out lots of different things - but they are just guesses and I can't find any resources or info on how to do this.
How I had hoped it would work was something like this:
<style type="text/css">
.clip3 {
clip-path: url(#c3);
border: url(#b1);
}
</style>
<defs>
<polyline id = "b1" points="75,0 225,0 275,100 225,200 75,200 25,100" stroke = "blue" stroke-width = "5"/>
</defs>
Came up with an idea that I don't consider ideal but it works... =\
http://jsfiddle.net/Robodude/ev6VF/4/
<svg height="0">
<clipPath id="c3">
<polygon points="75,0 225,0 275,100 225,200 75,200 25,100"/>
</clipPath>
<defs>
<polyline id="top" points="225,200 75,200 25,100" style="fill:none;stroke:blue;stroke-width:10" />
<polyline id="middle" points="225,0 275,100 225,200" style="fill:none;stroke:blue;stroke-width:10" />
<polyline id="bottom" points="25,100 75,0 225,0" style="fill:none;stroke:blue;stroke-width:10" />
</defs>
</svg>
<div class="container left">
<div id="Image1" class="Image1 image clip3">
<svg width="100%" height="100%">
<use xlink:href = "#top"/>
</svg>
</div>
<div id="Image2" class="Image2 image clip3">
<svg width="100%" height="100%">
<use xlink:href = "#middle"/>
</svg>
</div>
<div id="Image3" class="Image3 image clip3">
<svg width="100%" height="100%">
<use xlink:href = "#bottom"/>
</svg>
</div>
</div>