This question already has answers here:
How to get rid of extra space below svg in div element
(9 answers)
Closed 8 months ago.
I am trying to make SVG "canvas" full width & height of the container, which is a div.
SVG is set in CSS to be 100% width and height. Container div is set to 100vw and 100vh width and height respectively. Margin: 0. Padding: 0. No borders. The SVG overflows, but when I set it to 99% height, it does not.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
svg {
width: 100%;
height: 100%; /* overflows */
/* height: 99%; does not overflow*/
}
div {
background-color: aliceblue;
width: 100vw;
height: 100vh;
}
<div id="chart-area">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="1" fill="yellow" />
</svg>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
svg {
width: 100%;
height: 100%; /* overflows */
/* height: 99%; does not overflow*/
display:block;
/* margin-bottom:-5px; will work also*/
}
div {
background-color: aliceblue;
width: 100vw;
height: 100vh;
}
<div id="chart-area">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="1" fill="yellow" />
</svg>
</div>
if you add display block or 5px negative margin to the svg it'll work perfectly.
The explanation is that inline elements sit on the text baseline. The extra vertical space is for character descenders.
check this link for more info
Related
I'm trying to create this view but I'm not sure how to get the image to overlap half way with the black background. I've got an svg with the full wide graphic of the car and line where the line breaks in color.
I'm using Bulma as a framework. How would I get the image to overlap a black container as well as the white container?
Here's an example of what I've got now: https://codesandbox.io/s/bulma-autocomplete-forked-kdu4h?file=/src/index.js
To make the img responsive you want it to keep its aspect ratio while filling the same width as the black element but you want it to be translated up enough that the break between the white and the black line always stays at the top of the container.
This snippet does that by having the img as a child of the black element and the same width as it but translated upwards by just the right % of its height that the black line starts just above the black element. This is almost at 50% of its height, actually just very slightly more.
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
div {
width: 100vw;
height: 50vh;
margin: 0;
padding: 0;
position: relative;
top: 40%; /* just for this demo */
background-color: black;
}
img {
width: 100%;
height: auto;
transform: translateY(-52.5%);
margin: 0;
padding: 0;
position: absolute;
}
<div>
<img src="https://i.stack.imgur.com/mhA4r.png" />
</div>
You could have a svg wave with 2 colors like so
body {
background-color: teal;
}
<svg id="wave" width="740" height="110" viewBox="0 0 740 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 61.4997C243.5 -30.5003 306.5 2.9997 367 48.9997C427.5 94.9997 592.5 142.999 737 61.4997" stroke="black" stroke-width="5"/>
<path d="M1 63.6579C244.159 -28.917 307.33 4.79235 367.995 51.0798C428.659 97.3672 594.107 145.667 739 63.6579" stroke="white" stroke-width="3"/>
</svg>
Then put that down of you top container
.block {
height: 150px;
width: 100%;
}
.black {
background-color: black;
position: relative;
}
#wave {
float:left;
transform: translatey(-50%);
}
<div class="block black"></div>
<svg id="wave" viewBox="0 0 740 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 61.4997C243.5 -30.5003 306.5 2.9997 367 48.9997C427.5 94.9997 592.5 142.999 737 61.4997" stroke="black" stroke-width="5"/>
<path d="M1 63.6579C244.159 -28.917 307.33 4.79235 367.995 51.0798C428.659 97.3672 594.107 145.667 739 63.6579" stroke="white" stroke-width="3"/>
</svg>
<div class="block white"></div>
I have an inline block so that elements sizes are dynamically width-matched constrained on the height of the elements.
How can I make the bottom element positioned at the bottom and the top element still be dynamically sized and positioned from the top?
Ideally I want to just say position: absolute; bottom: 0 on the bottom element, and make the container have height: 100%, but doing so makes it so that the top element has size 0 (since having position absolute doesn't count for the container size when calculating from the bottom element?).
Links to relevant content on how to better understand positioning and dynamic sizing of elements would be greatly appreciated, because I can't seem to wrap my head around it.
.container {
display: inline-block;
background: pink;
}
.top {
max-height: 50vh;
min-width: 100%;
}
.bottom {
height: 100%;
max-height: 50vh;
min-width: 100%;
}
<div class="container">
<svg class="top" viewBox="0 0 100 100" preserveAspectRatio="xMinYMin meet">
<polygon points="0,0 100,0 100,100 0,100" fill="none" stroke="black" stroke-width="1"/>
</svg>
<svg class="bottom" viewBox="0 0 100 200" preserveAspectRatio="xMinYMin meet">
<polygon points="0,0 100,0 100,200 0,200" fill="none" stroke="black" stroke-width="1"/>
</svg>
</div>
Try to put position: relative; on your inlined element, i.e.
.container {
display: inline-block;
background: pink;
width: 300px;
height: 300px;
position: relative;
}
.top {
position: absolute;
top: 0;
max-height: 50vh;
min-width: 100%;
}
.bottom {
position: absolute;
bottom: 0;
height: 100%;
max-height: 50vh;
min-width: 100%;
}
A page element with relative positioning gives you the control to
absolutely position children elements inside of it.
s. https://css-tricks.com/absolute-positioning-inside-relative-positioning/
I was able to finally figure this out using an display: inline-flex; box as the container. It doesn't allow me to specify an absolute positioning for the children, but it does force the top element and bottom element to be spaced out.
Then the offset from the bottom and top can be specified with padding-bottom: 10; on the bottom element.
<html>
<head>
<style>
.container {
display: inline-flex;
flex-direction: column;
justify-content: space-between;
background: pink;
height: 100%;
}
.top {
min-width: 100%;
}
.bottom {
height: 100%;
max-height: 50vh;
min-width: 100%;
}
</style>
</head>
<body>
<div class="container">
<svg class="top" viewBox="0 0 100 100" preserveAspectRatio="xMinYMin meet">
<polygon points="0,0 100,0 100,100 0,100" fill="none" stroke="black" stroke-width="1"/>
</svg>
<svg class="bottom" viewBox="0 0 100 200" preserveAspectRatio="xMinYMin meet">
<polygon points="0,0 100,0 100,200 0,200" fill="none" stroke="black" stroke-width="1"/>
</svg>
</div>
</body>
</html>
I'd like to scale an SVG with a polygon shape to the full height of the container. Setting the SVG's height to 100% wouldn't work.
Relevant jsFiddle: https://jsfiddle.net/12yktprj/
Following line is causing me trouble:
aside svg {
height: 100%; /* somehow not working */
width: 100%; /* somehow not working */
}
The svg element need to have a viewBox attribute and no width and height. For the viewBox attribute I'm taking the size of the polygon.
Also in this case (flex-direction:row - the default) instead of declaring the width of the flex items I'm declaring the [flex property]
The aside has position:relative; and the svg has position:absolute; and overflows the aside. I hope this is what you were asking.
(https://developer.mozilla.org/en-US/docs/Web/CSS/flex)
*{padding:0,margin:0}
body {
height: 300px;
width: 900px;
border: 3px solid green;
padding: 0;
display: flex;
justify-content: space-between;
align-items: stretch;
position:relative;
background:#ddd;
}
aside {
position:relative;
flex: 1 1 25%;
height: 100%;
border: 1px solid blue;
}
aside svg {
position:absolute;
height:100%
}
article {
border: 2px solid orange;
flex: 1 1 75%;
height: 100%;
padding: 2px;
}
<body>
<aside>
<svg viewBox="0 0 100 100">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" preserveAspectRatio="slice" xlink:href="https://i.imgur.com/8OtgM8B.jpg" />
</pattern>
</defs>
<polygon fill="url(#pattern1)" points="0,0 70,0 100,100 0,100"/>
</svg>
</aside>
<article>
<h1>Title</h1>
<p>Sample Text</p>
</article>
</body>
I've been trying to scale an SVG to fit a container without using fixed pixel values. From what I've read online this should be possible but I haven't managed to get it to work. Some example code is shown below. Any advice on how I can get the examplesvg svg element to fill the width of the svgcontainer div (just by using HTML and CSS)? Thanks in advance.
body {
background: rgb(17,17,17);
}
.svgcontainer {
width: 400px;
height: 300px;
background: green;
position: relative;
}
#examplesvg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<div class="svgcontainer">
<svg><use xlink:href="#examplesvg"></use></svg>
</div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="examplesvg" viewBox="0 0 303 103" preserveAspectRatio="xMidyMid">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</symbol>
</defs>
</svg>
EDIT: Updated title to make intended behaviour clearer.
I think your CSS selector is wrong. You don't want to scale the symbol #example-svg, you want to scale the svg element in .svgcontainer. Is something like this what you were looking for?
Other things to note:
You don't need to specify preserveAspectRatio="xMidYMid"; that's equivalent to the default (see MDN/SVG/Attribute/preserveAspectRatio for details).
You had a typo: preserveAspectRatio="xMidyMid"; the y should be uppercase. SVG is super picky about this; you just got lucky because it's also the default. (Something you learn the hard way ;) )
It should be viewBox="-1.5 -1.5 303 103", because SVG borders get drawn half inside the shape, and half outside the shape.
body { background: grey; }
.svgcontainer {
width: 400px;
height: 300px;
background: green;
position: relative;
}
.svgcontainer > svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<div class="svgcontainer">
<svg><use xlink:href="#examplesvg"></use></svg>
</div>
<svg style="display:none">
<defs>
<symbol id="examplesvg" viewBox="-1.5 -1.5 303 103">
<rect width="300" height="100"
style="fill:blue;stroke-width:3;stroke:black" />
</symbol>
</defs>
</svg>
#zenoArrow, please check the below working snippet for the resolved issue you were facing.
let me explain, what went wrong:
set width and height to the svg within the div svgcontainer. so that it scale fully, if not mentioned it will set the viewBox="0 0 300 100" width and height to the svg
don't use preserveAspectRatio="xMidyMid" instead use preserveAspectRatio="none" to scale/fill the svg as per the parent container, if not added it will scale horizontaly but not vertically.
viewBox="0 0 303 103" should be equal to <rect width="300" height="100", it also depends on your requirement though.
body {
background: rgb(17, 17, 17);
}
.svgcontainer {
width: 400px;
height: 300px;
background: green;
position: relative;
}
.example-svg {
width: 100%;
height: 100%;
}
<svg style="display: none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="examplesvg" viewBox="0 0 300 100" preserveAspectRatio="none">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</symbol>
</defs>
</svg>
<div class="svgcontainer">
<svg class="example-svg">
<use xlink:href="#examplesvg"></use>
</svg>
</div>
I am trying to make the background image and SVG responsive. I have got them both in a container,where both are responsive from their own perspectives. But When I test it by Stretching the browser in and out,the SVG gets displaced. I need to fix the SVG overlays over the background image,where they will be settled at the position of the image I have set them.
<!DOCTYPE html>
<html>
<head>
<style>
.container {
background: url(http://i.imgur.com/b1K76Pf.jpg) no-repeat;
background-size: contain;
max-width: 960px;
height: 565px;
margin: auto;
}
</style>
</head>
<body>
<div class="container">
<div class="main-roof">
<svg width="100%" height="100%" viewbox="0 0 1200 180"
preserveAspectRatio="none">
<polygon fill="red" points="115,103 643,93 930,47 372,72">
</polygon>
<polygon fill="red" points="30,120 170,112 649,105 513,118 ">
</polygon>
<polygon fill="red" points="610,49 642,57 600,56 576,57">
</polygon>
</svg>
</div>
</div>
</body>
</html>
P.S. I have tried the .container with width and height of % and auto,but in that case,the image just doesn't show up.
So to close this question I summon up our comments as an answer.
I cannot reproduce your described behavior. I made a fiddle: https://jsfiddle.net/aL7keb3u. I ran it in FF54 and Chrome59. In both browsers the SVG resized the same as the bg-image in the container.
You want a SVG which scales according to the browser window, but in the same aspect ratio as the (background) image. Without having to set absolute pixel values, but relative ones. Right? If so, may that be helpfull to you: https://jsfiddle.net/aL7keb3u/4?
HTML:
<div class="container">
<img src="http://i.imgur.com/b1K76Pf.jpg" class="bg_image" />
<div class="main-roof">
<svg width="100%" height="100%" viewbox="0 0 1200 180"
preserveAspectRatio="none">
<polygon fill="red" points="115,103 643,93 930,47 372,72">
</polygon>
<polygon fill="red" points="30,120 170,112 649,105 513,118 ">
</polygon>
<polygon fill="red" points="610,49 642,57 600,56 576,57">
</polygon>
</svg>
</div>
</div>
CSS:
.container {
/*background: url(http://i.imgur.com/b1K76Pf.jpg) no-repeat;*/
/*background-size: contain;*/
max-width: 960px;
/*height: 565px;*/
margin: auto;
position: relative;
}
/* ---------------------- */
.container > img.bg_image {
width: 100%;
height: auto;
}
.main-roof {
max-width: 100%;
max-height: 100%;
overflow: hidden;
mix-blend-mode: multiply; /* nice effect */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
svg {
/*height: 565px;*/
width: 100%;
height: 103.5%;
}
As you yourself stated the issue was due to invalid HTML. Please validate your HTML first, when you run into (inexplicable) issues.