Targeting Inline SVG from stylesheet - css

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>

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>

How to scale SVGs that use real world units

I need to generate SVGs using real world units (e.g. inches) and have them scale proportionately to fit inside a div with fixed dimensions. Is this possible?
As a simple example, this SVG is overflowing the div's boundaries:
<div style="width: 600px; height: 400px;">
<svg width="60in" height="15in" viewBox="0 0 60 15" style="border: 1px solid black;">
<line x1="30" y1="0" x2="30" y2="15" style="stroke:rgb(0,0,0);stroke-width:2px" vector-effect="non-scaling-stroke" />
</svg>
</div>
Remove the width and height attributes from your SVG (they're not necessary). Then your SVG will scale automatically to your DIV's size. (Keep the viewBox since that will remind you that your dimensions are probably in inches)

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>

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

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>

Translate a SVG element relative to right of screen?

Is it possible to translate a SVG element relative to the right of the screen as opposed to the top left that is it's default?
<svg class="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text id="text" class="svgText">test text test text</text>
<rect id="border" class="textOutlineBox" x="0" y="0" width="440.5" height="90"/>
</svg>
#text, #border {
transform-origin: right center;
}
#text {
transform: translate(15vw, 20vh);
}
#border {
transform: translate(10vw, 10vh);
}
When I do this it still moves from the left of the screen. Is there a way to get it to transform relative to the right side of the screen?
jsFiddle describing my problem here!
When you use CSS translate (or translateX or translateY), you don't translate the element relative to the edge of the screen, but relative to where the element would be on the screen, were it not translated.
So if you want to move a SVG rect leftwards from the right of the screen, you first need to position it somewhere near to the right edge of the screen.
One way to do this might be to:
Give the <svg> element a viewBox so you have a parental width to work with
Subtract the width of the element from the width of the viewBox
Apply the value from 2. as the element's x value.
Now, with the rect over towards the right hand edge of the screen, you can translate it leftwards, by giving it a negative translateX value.
Working Example:
body {
margin: 0;
}
svg {
width: 99vw;
border: 1px solid gray;
}
#border {
transform: translate(-10vw, 10vh);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 200">
<rect id="border" x="559.5" y="0" width="440.5" height="90" />
</svg>

Resources