How to make an svg element responsive to it's parent container? - css

I'm trying to acheive this:
Rendering an svg square (w:h = 1:1 rectangular) inside of div,
when the div's width is greater than height, the square should fit into the container by the height(red box is the div, green box is the svg square):
When the div's height is greater than width, the squire should fit into the container by the width:
It can be easily achieved by specifying the size of the svg view port.But if I remove the size of the svg view port, instead when I add the size to the parent div(red box), it refuses to look at the height of the container, the image turns to be:
Is there a way we can make the square responsive to the container height?
here is my code:
#main {
width: 400px;
height: 100px;
border: 4px solid red;
}
<div id="main">
<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid Meet">
<rect x="0" y="0" width="100" height="100" fill="green"/>
</svg>
</div>

Just set the width and height attributes of the SVG to "100%". Either in the SVG, or via CSS.
Secondly, fix your other attributes:
viewBox values should not have commas.
it is preserveAspectRatio, not preserveAspect, and meet, not Meet
#main {
width: 400px;
height: 100px;
border: 4px solid red;
}
<div id="main">
<svg width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<rect x="0" y="0" width="100" height="100" fill="green"/>
</svg>
</div>

Related

How to scale svg size to exactly wrap its content?

I have a very simple svg with a circle inside:
<div>
<svg className="main-svg">
<circle pathLength="25" cx="50%" cy="50%" r="25%" />
</svg>
</div>
Then if I style it:
svg {
height: 250px;
width: 250px;
}
The svg will take up 250px width and height, but the circle inside it will be much smaller, so there's unwanted white space around the circle. Is it possible to make the svg wrap the circle without adding space, so that defining the width of height of the svg will result in setting the width and height of the circle inside it?
Stackblitz link: https://stackblitz.com/edit/react-ts-fwmjzn?file=style.css
Set radius attribute value to 50%
svg {border: 2px solid red; }
<svg width="250" height="250" viewBox="0 0 250 250">
<circle pathLength="25" cx="50%" cy="50%" r="50%" />
</svg>

Scale SVG clipPath and keep aspect ratio of Image

I have an image inside of an SVG element with a clipPath.
I want the clip path to behave like it is in my codePen https://codepen.io/celli/pen/rNBvmyx with preserveAspectRatio="none" so that I always get the same height for my clipPath which matches the parent and stretch from edge to edge of my browser.
The issue is that I want my image to preserve it's aspect-ratio and not appear squashed, while maintaining that the mask is the only element that is being squeezed and not preserving it's aspect ratio.
I tried adding css to the image to preserve the aspect ratio, but it seems to follow the SVGs preserveAspectRatio="none", but I only want that to apply to my clipPath part of the SVG.
<div id="containerId">
<svg class="svg-graphic" preserveAspectRatio="none" viewBox="0 0 1920 1080" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="auto">
<g>
<clipPath id="svgmask">
<polygon points="0,0 0,650 1920,1045 1920,394 "/>
</clipPath>
</g>
<image clip-path="url(#svgmask)" style="width:100%; height:auto; max-width:100%;" xlink:href="https://img-fotki.yandex.ru/get/5607/5091629.6b/0_612e6_b9039c0d_M.jpg" />
</a>
</svg>
</div>
A solution to your problem would be clipping a div with the image as a background. In this case you use a path instead of a polygon where the coords values are from 0 to 1 and clipPathUnits="objectBoundingBox". This won't work on IE and on Edge: https://caniuse.com/#feat=css-clip-path
*{margin:0;
padding:0;}
#containerId {
width: 100%;
height: 800px;
background-color: green;
}
#media (max-width: 800px) {
#containerId {
width: 100%;
height: 500px;
background: orange;
}
}
.img {
width: 100%;
height: 100%;
background-image: url("https://img-fotki.yandex.ru/get/5607/5091629.6b/0_612e6_b9039c0d_M.jpg");
background-size: cover;
-webkit-clip-path: url(#svgmask);
clip-path: url(#svgmask);
}
<svg height="0" width="0" style="position:absolute;">
<defs>
<clipPath id="svgmask" clipPathUnits="objectBoundingBox">
<path d="M0,0 L0,0.6 1,1 1,0.4"/>
</clipPath>
</defs>
</svg>
<div id="containerId">
<div class="img"></div>
</div>
I found an alternative way to do it that works in IE, without SVG, in-case anyone is interested: https://codepen.io/celli/pen/KKPReKE I wanted to use SVG, but this way seems to be the best solution by using a pseudo element and a rotated div.
<div id="head">
<div id="headAddBkgColor"></div>
</div>
<div id="slantElm"></div>

Use part of CSS-Sprite as repeated background image

I have a div with a width and height of approximately 300px each. The background of this div should be filled repeatedly with a smaller image of 8px width and 8px height. This smaller image is embedded into a larger sprite image. How can I only use this 8x8 pixel tile to pave the background?
What I've tried so far:
.world {
width: 300px;
height: 300px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wcYFjsX3EPV0QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAxklEQVQ4y+2UsQ3CMBBF/0VImYDKFWNQZB28AwOwQ7KOC8agomKCVJ8ituU7GwkhVxFXWT+nF8nvy0JSRFAMye0wqRghxrheTmV+Wx4A9G7BmlpfAi0lswZ0mj2DsiNjLbBx09lRw1oN+m0OAKB7hIQWvFSM43ZY5V7mI88AhB+KZCiZZSiZ9e/RN6BaP1k6MtY2Ry1rPXv01D1yET3qR2ZF+qXX+zMBDJaSuGP1VMXEV/te9q6/G8hV+h2VI2NtrvZn9uzRGzl9Uzsn2uDrAAAAAElFTkSuQmCC') 0 -16px repeat;
}
<div class="world"></div>
In this example code, the shritesheet has a width and height of 24px each. It contains 9 differently coloured points, each of which has a diameter of 7px.
I want that only one single point is used repeatedly as background for the div. However, in this code, the whole picture is repeated instead beginning at the third row of points.
Note, this exemplary spritesheet is only an example. The actual spritesheet is a little more complicated. Replacing the spritesheet
with CSS code is not a solution.
One idea is to consider SVG as background. The trick is to make the image inside the SVG and rely on viewbox to cut the image and show only the needed part then make the whole SVG a pattern for your background.
Simply edit the viewBox to select the pattern you want (x y 8 8 where x,y are equal to [0,8,16])
.box {
width: 100px;
height: 100px;
display:inline-block;
}
.one {
background: url('data:image/svg+xml;utf8,<svg viewBox="16 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wcYFjsX3EPV0QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAxklEQVQ4y+2UsQ3CMBBF/0VImYDKFWNQZB28AwOwQ7KOC8agomKCVJ8ituU7GwkhVxFXWT+nF8nvy0JSRFAMye0wqRghxrheTmV+Wx4A9G7BmlpfAi0lswZ0mj2DsiNjLbBx09lRw1oN+m0OAKB7hIQWvFSM43ZY5V7mI88AhB+KZCiZZSiZ9e/RN6BaP1k6MtY2Ry1rPXv01D1yET3qR2ZF+qXX+zMBDJaSuGP1VMXEV/te9q6/G8hV+h2VI2NtrvZn9uzRGzl9Uzsn2uDrAAAAAElFTkSuQmCC" x="0" y="0" height="24" width="24" /></svg>') repeat;
}
.two {
background: url('data:image/svg+xml;utf8,<svg viewBox="16 8 8 8" width="8" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wcYFjsX3EPV0QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAxklEQVQ4y+2UsQ3CMBBF/0VImYDKFWNQZB28AwOwQ7KOC8agomKCVJ8ituU7GwkhVxFXWT+nF8nvy0JSRFAMye0wqRghxrheTmV+Wx4A9G7BmlpfAi0lswZ0mj2DsiNjLbBx09lRw1oN+m0OAKB7hIQWvFSM43ZY5V7mI88AhB+KZCiZZSiZ9e/RN6BaP1k6MtY2Ry1rPXv01D1yET3qR2ZF+qXX+zMBDJaSuGP1VMXEV/te9q6/G8hV+h2VI2NtrvZn9uzRGzl9Uzsn2uDrAAAAAElFTkSuQmCC" x="0" y="0" height="24" width="24" /></svg>') repeat;
}
.three {
background: url('data:image/svg+xml;utf8,<svg viewBox="8 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wcYFjsX3EPV0QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAxklEQVQ4y+2UsQ3CMBBF/0VImYDKFWNQZB28AwOwQ7KOC8agomKCVJ8ituU7GwkhVxFXWT+nF8nvy0JSRFAMye0wqRghxrheTmV+Wx4A9G7BmlpfAi0lswZ0mj2DsiNjLbBx09lRw1oN+m0OAKB7hIQWvFSM43ZY5V7mI88AhB+KZCiZZSiZ9e/RN6BaP1k6MtY2Ry1rPXv01D1yET3qR2ZF+qXX+zMBDJaSuGP1VMXEV/te9q6/G8hV+h2VI2NtrvZn9uzRGzl9Uzsn2uDrAAAAAElFTkSuQmCC" x="0" y="0" height="24" width="24" /></svg>') repeat;
}
<div class="box one"></div>
<div class="box two"></div>
<div class="box three"></div>

Can anyone explain why firefox crops this SVG image?

Can anyone explain why firefox crops this SVG image?
It's within a container and being scaled to fit by CSS.
I'm using <symbol> and <use>.
.container {
width: 1em;
height: 1em;
}
svg {
width: 100%;
height: 100%;
}
<svg style="display:none">
<symbol id="icon_triangleup" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24">
<path d="M12.8,5.4c-0.377-0.504-1.223-0.504-1.6,0l-9,12c-0.228,0.303-0.264,0.708-0.095,1.047 C2.275,18.786,2.621,19,3,19h18c0.379,0,0.725-0.214,0.895-0.553c0.169-0.339,0.133-0.744-0.095-1.047L12.8,5.4z" />
</symbol>
</svg>
<div class="container">
<svg>
<use xlink:href="#icon_triangleup"></use>
</svg>
</div>
I can tell you why, as in, how to fix it. But not why Chrome seems to ignore what's causing the issue in Firefox.
Firefox is using the 24px width and height set on the <symbol> element, so remove those and the symbol will expand to fill the space of it's container.
You can always set the width and height on the <use> element if you want the individual instances of the symbol to be different sizes.
.container {
width: 1em;
height: 1em;
}
svg {
width: 100%;
height: 100%;
}
<svg style="display:none">
<symbol id="icon_triangleup" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12.8,5.4c-0.377-0.504-1.223-0.504-1.6,0l-9,12c-0.228,0.303-0.264,0.708-0.095,1.047 C2.275,18.786,2.621,19,3,19h18c0.379,0,0.725-0.214,0.895-0.553c0.169-0.339,0.133-0.744-0.095-1.047L12.8,5.4z" />
</symbol>
</svg>
<div class="container">
<svg>
<use xlink:href="#icon_triangleup"></use>
</svg>
</div>

Targeting Inline SVG from stylesheet

I'm surprised to be having this problem, but there must be some funniness about SVG + CSS I'm not quite getting.
Short version, this doesn't work:
HTML
<div class="svg-container>
<svg class="mybox">...</svg>
</div>
CSS from stylesheet
.mybox { max-height: 150px; }
Long version
I have some SVG "widgets", some which are 2:1 width:height ratio, others which are 1:1 width:height, and need the flexibility for anything between and beyond.
The "widgets" will be shown in a gallery, each item having a width of 318px and a height of 150px.
However, the gallery is not the only (or even primary) display of these "widgets", they will be used elsewhere, and need to scale, so adding an inline SVG style block of max-height: 150px is not an option. Each SVG is sitting in a container, 'svg-container'.
Repeat: Inline SVG styles are not an option. SVG itself probably has to be inline, as we're passing data to the SVG, so linking to the SVG as an image, etc, not an option.
Here is a CodePen (yes, it's ugly, proof of concept)
Note: the arrow inside resizes to the max-height of 150px, however, the SVG loses its aspect ratio, as you can see from the border.
The trick was to set an height on the .svg-container. This implies that the height of the SVG element is 25vw (viewport width unit) but not more than 150px at max. Since the height of the element is now known, the width is set based on the viewBox specified on the SVG. The actual value (25vw in this case) is just a random value and can be modified as necessary.
The text-align: center on the container (as you would have guessed) is to center the SVG element horizontally within the container.
.svg-container {
text-align: center;
height: 25vw;
/* This is the key. I have used vw units for responsiveness */
margin-bottom: 10px;
border: 1px solid;
}
.mybox {
max-height: 150px;
height: 100%;
}
<div class="svg-container">
<svg class="mybox" style="border: solid" x="0" y="0" viewBox="0, 0, 500, 500">
<polygon fill="orange" points="256,512 512,256 352,256 352,0.001 160,0 160,256 0,256 "></polygon>
<text text-anchor="middle" x="250" y="250" style="font-size: 100px;" stroke="black" fill="black">000</text>
</svg>
</div>
<div class="svg-container">
<svg class="mybox" style="border: solid" x="0" y="0" viewBox="0, 0, 250, 500">
<polygon fill="orange" points="128,512 256,256 176,256 176,0.001 80,0 80,256 0,256 "></polygon>
<text text-anchor="middle" x="125" y="250" style="font-size: 50px;" stroke="black" fill="black">000</text>
</svg>
</div>

Resources