Scale SVG along other content with CSS flexbox - html

I want to display a rectangular SVG between two vertically aligned DIVs, so that the SVG takes up as much space as possible (but keeps its aspect ratio). As the SVG itself is dynamically generated, I have to use the <svg> HTML tag to include it (and i.e. can't use an <img> tag).
So I tried to use flexbox, but the SVG doesn't stick to the rules and gets too large:
html, body, .parent {
height: 100%;
}
.parent {
display: flex;
flex-flow: column nowrap;
}
.contentSVG {
flex-grow: 1;
}
<div class="parent">
<div class="contentA">
content A
</div>
<div class="contentSVG">
<!-- arbritrary SVG -->
<svg viewBox="0 0 10 10">
<circle cx="5" cy="5" r="5" fill="red" />
</svg>
</div>
<div class="contentB">
content B
</div>
</div>
If I replaced the SVG with some other content the example works as expected.
Do you have any idea how I can realize this without any JS involved?

You need to add width:100%;height:100% to the SVG and min-height:0 to the parent to allow the shrink effect
html, body, .parent {
height: 100%;
margin:0;
}
.parent {
display: flex;
flex-flow: column nowrap;
}
.contentSVG {
flex-grow: 1;
min-height:0;
}
svg {
width:100%;
height:100%;
}
<div class="parent">
<div class="contentA">
content A
</div>
<div class="contentSVG">
<!-- arbritrary SVG -->
<svg viewBox="0 0 10 10">
<circle cx="5" cy="5" r="5" fill="red" />
</svg>
</div>
<div class="contentB">
content B
</div>
</div>

Related

How can I make an <svg> element scale to a parent element's height?

I have an <svg> element within a wrapping element.
I want the <svg> to fill the height of the wrapping element, however I cannot seem to get this to work.
I have tried the following:
.image-banner__overlay {
height: 90%;
position: absolute;
z-index: 999;
}
svg {
height: 100%;
background-color: black;
}
path {
fill: red;
height: 100%;
}
<div class="cell small-12 medium-6 image-banner__image-wrapper">
<div class="image-banner__overlay">
<svg>
<path d="M91.91,125c0-50.63,10.58-95.75,27.07-125H69.22V250H119C102.49,220.75,91.91,175.63,91.91,125Z" transform="translate(-69.22)" />
</svg>
</div>
<div class="image-banner__image" style="#backgroundImage">
</div>
</div>
But the <svg> seems to only ever take up a max of about 75% of the space, eg:
I've tried using viewBox, eg:
height="100%" width="100%" viewBox="0 0 100 100" preserveAspectRatio="none"
But this makes the SVG way too big (overflows the parent element).
Would anyone know how I could get this to stretch the complete height of the parent element (without turning it into an <img>)?
Here's a viewbox for you, I know it's horrible but you should read up on it!
.image-banner__overlay {
height: 90%;
position: absolute;
z-index: 999;
}
svg {
height: 100%;
background-color: black;
}
path {
fill: red;
height: 100%;
}
<div class="cell small-12 medium-6 image-banner__image-wrapper">
<div class="image-banner__overlay">
<svg viewbox="0 0 80 250">
<path d="M91.91,125c0-50.63,10.58-95.75,27.07-125H69.22V250H119C102.49,220.75,91.91,175.63,91.91,125Z" transform="translate(-69.22)" />
</svg>
</div>
<div class="image-banner__image" style="#backgroundImage">
</div>
</div>

Stacking SVG's ontop of each other in a DIV

I"m looking to stack these three images ontop of each other. I don't care if they're showing as they're animated and two will pop out horizontally from the side of each.
I however am getting an issue.
Please see attached photo:
All three SVG's are contained within the below structure:
<ImageContainer>
<MainIcon />
<JobListingIcon />
<SingularListing />
</ImageContainer>;
This is within a flex box:
const ImageContainer = styled.div`
width: 90%;
height: 400px;
margin-top: 20px;
background-color: #636388;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
`;
I don't understand why they're being shown this way, and I have tried to have all 3 SVG's positioned absolute, but nothing.
What's the way to stack these? It it not a flex box? Potentially something like a MUI grid?
Sorry!
The problem with a phrase like "on top of each other" is that it is ambiguous. Do you mean:
vertically arranged on the page, or
one covers the other
It sounds like you might mean the second one. You can achieve that with absolute positioning.
parent <-- make this "position: relative;"
child )
child ) make either (or both) of these "position: absolute; top: 0;"
If those child elements are <svg> elements, then you'll also need to make them display: block, since SVGs are display: inline-block by default.
Demo
.parent {
position: relative;
width: 100px;
height: 150px;
}
svg {
display: block;
}
.svg-two {
position: absolute;
top: 0;
}
<div class="parent">
<svg class="svg-one" width="100" height="100">
<rect x="0" y="0" width="100" height="100" fill="linen"/>
<circle cx="50" cy="50" r="40" fill="red"/>
</svg>
<svg class="svg-two" width="100" height="150">
<rect x="20" y="0" width="60" height="150" fill="limegreen"/>
</svg>
</div>

Svg clipPath to clip a div doesn't work in Safari when i duplicate it

I have created a clip path that I reuse on multiple divs in the page. I use the property clipPathUnits="objectBoundingBox" to make it apply to each div based on its position.
It works great in Chrome and Firefox. When I tried it in safari it only works based on the first div. Meaning that it works well the first time than when i call it again the boudingbox is still based on the first Div. I realized this when i gave a negative margin to the second div until it overlaped with the first one partial then I could see it.
Here is an example of the issue:
.bar {
height: 100px;
width: 100px;
}
.block {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background: white;
z-index: 100;
display: block;
clip-path: url(#clipping);
-webkit-clip-path: url(#clipping);
}
<svg style="background: blue; height: 0px; overflow: hidden;">
<defs>
<clipPath id="clipping" clipPathUnits="objectBoundingBox">
<path fill="#FFFFFF" d="M0.501,0.971c-0.014,0-0.027-0.003-0.04-0.011l-0.34-0.194c-0.024-0.014-0.04-0.041-0.04-0.069L0.081,0.306
c0-0.028,0.015-0.055,0.04-0.069L0.458,0.04c0.013-0.007,0.026-0.011,0.04-0.011s0.027,0.003,0.04,0.011l0.339,0.194
c0.025,0.014,0.041,0.041,0.041,0.069l0.001,0.391c0,0.028-0.015,0.055-0.04,0.069L0.542,0.96C0.529,0.968,0.515,0.971,0.501,0.971z
" />
</clipPath>
</defs>
</svg>
<div class="bar" style="background: blue;">
<div class="block">
</div>
</div>
<div class="bar" style="background: green;">
<div class="block">
</div>
</div>
http://codepen.io/appteamio/pen/WbdRgx
I'm I doing something wrong or is it a Safari issue.If sois there any work aroung.
thanks

Fixed SVG height & variable (100%) width

I'm trying to put a svg object on my html page and I want it to have a 100% width and a fixed height.
In my fiddle you can see that the height of the dark-grey object changes according to the window proportions. (This is not what I want)
http://jsfiddle.net/Lq207ery/6/
HTML
<body>
<!-- HEADER -->
<header>
<div class="logo"></div>
<div class="triangle">
<svg data-type="vertical_parallax" data-speed="2" x="0px" y="0px" width="410" height="410" viewBox="0 0 310 310" style="-webkit-transform: translate3d(0px, 0px, 0px); transform: translate3d(0px, 0px, 0px);">
<g>
<!--<polyline stroke="#222" fill="none" stroke-width="1" points="0,210 0,210 310,0 "></polyline>-->
<polyline fill="#CC0000" points="0,0 0,200 300,0 "></polyline>
</g>
</svg>
</div>
<div class="nav">
<svg width="100%" viewBox="0 0 10 10" preserveAspectRatio="xMinYmin">
<polygon fill="#222" stroke-width="0" points="0,1.5 0,0 10,0 15,0 " />
</svg>
</div>
</header>
<!-- CONTENT -->
CSS
body {
margin: 0;
}
header svg {
display: block;
margin: 0;
}
header .triangle {
z-index: 200;
}
header .logo {
margin-top: -90px;
}
header .nav {
position: absolute;
top:0;
left:0;
width:100%;
z-index:-1;
}
Give your SVG element a fixed height. If you do not do this the height of the element will change proportional to the width.
Adjust your viewBox to crop to the height of your content.
Fix your preserveAspectRatio value to have the proper case-sensitive value, e.g. xMinYMin (not xMinYmin).
Demo: http://jsfiddle.net/Lq207ery/8/
If you want your dark grey triangle to stretch (not preserving its aspect ratio) then instead use preserveAspectRatio="none".
Demo: http://jsfiddle.net/Lq207ery/9/
You explanation is somewhat short, but you could do it like this :
HTML Code :
<header>
<div class="triangle">
<svg x="0px" y="0px" width="410" height="410" viewBox="0 0 310 310">
<g>
<polyline fill="#CC0000" points="0,0 0,200 300,0"/>
</g>
</svg>
</div>
<div class="nav"></div>
</header>
CSS Code :
html, body {
margin: 0;
}
header {
position: relative;
}
header .triangle {
position: relative;
z-index: 2;
}
header .nav {
position: absolute;
top:0;
left:0;
width: 2000px; // big screens
height: 100px;
background-image:url('data:image/svg+xml;utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%22150px%22%20height%3D%2215px%22%20viewBox%3D%220%200%20150%2015%22%3E%3Cg%3E%3Cpolygon%20fill%3D%22%23222%22%20points%3D%220%2C15%200%2C0%20100%2C0%20150%2C0%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
background-size: cover;
background-position: bottom left;
z-index: 1;
}
SVG before url encoding :
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="150px" height="15px" viewBox="0 0 150 15">
<g>
<polygon fill="#222" points="0,15 0,0 100,0 150,0"/>
</g>
</svg>
Demo : http://jsfiddle.net/sparkup/21uaffpy/
Or line this maybe : http://jsfiddle.net/sparkup/21uaffpy/18/
In addition I'd like to add If the svg has the viewBox and preserveAspectRatio all set, another place possibility is to use a container div and font-size something like:
<div style="height: 50px; width: 50px; fontSize: 50px">
<svg>...</svg>
</div>

How to force this div to span the height of viewport?

This jsFiddle shows the problem. I have not managed to prevent the div0 div from "collapsing" its top margin with that of its sibling, div1. (HTML below.)
I want div0 to span the entire viewport vertically, and the red rect inside it to appear flush against the top left corner of the viewport. (The placement of div1 and its contents is exactly as desired, and should not be changed in any way.)
I have tried to disable the collapsing of margins by putting borders around both div0 and div1, but, as the jsFiddle shows, this has made no difference.
Here's the relevant HTML:
<!doctype html>
<body>
<div id="div0">
<svg id="svg0" width="50px" height="50px">
<g>
<rect x="0px" y="0px"
width="50px" height="50px" style="fill:red;"></rect>
</g>
</svg>
</div>
<div id="div1">
<div id="div2">
<svg id="svg1" width="100px" height="100px"></svg>
</div>
</div>
Here is a solution for you. I added a .wrapper class, with a absolute position, to contain the elements and maintain elasticity in your document. I also added overflow: hidden to your div0 id to prevent the red svg rect from flowing outside of that containing div.
Here is an updated >>>JSFiddle<<<
HTML:
<div class="wrapper">
<div id="div0">
<svg id="svg0" width="50px" height="50px">
<g>
<rect x="0" y="0" width="50px" height="50px"></rect>
</g>
</svg>
</div>
<div id="div1">
<div id="div2">
<svg id="svg1" width="100px" height="100px"></svg>
</div>
</div>
</div>
CSS:
body {
margin: 0;
padding: 0;
}
.wrapper {
position: relative;
width: 100%;
height: 100%;
border: 1px solid blue;
}
#div0 {
position: absolute;
top: 0;
left: 0;
width: 30%;
height: 100%;
background-color: yellow;
border: 1px solid blue;
overflow: hidden;
}
#div1 {
margin-top: 20px;
border: 1px solid green;
background: lightgray;
min-height: 27px;
display: -webkit-flex;
display: flex;
}
#div2 {
background: black;
margin: 0px auto;
}
rect {
fill: red;
}
#div0 {
height:100vh;
}
You can use the vh for viewport height.
OK, I found the solution: comment out the position:relative in the CSS for body. This is illustrated in this revision of the original fiddle. Notice that the only difference between this and the original fiddle is the commented-out line just mentioned.
(I'm ashamed to say that I found this solution by blind trial-and-error; I have no idea of why the new version works and the original one didn't.)