SVG with height 100% will never shrink below 150px - css

I'm trying to create a SVG which stretches (in height) to a paragraph with variable height next to it.
Currently I have the following working example code which works as long if the paragraph is bigger then 150px. As soon as the paragraph is less in height, the SVG stops shrinking.
<div style="display: flex">
<div>
<svg style="display:block;width: 40px;height:100%">
<line x1="20" y1="0" x2="20" y2="100%" stroke-width="1" stroke="black"></line>
</svg>
</div>
<div style="height: 300px;border:1px solid">
This paragraph is 300px, the svg will stretch accordingly
</div>
</div>
<br><br><br><br>
<div style="display: flex">
<div>
<svg style="width: 40px;height:100%">
<line x1="20" y1="0" x2="20" y2="100%" stroke-width="1" stroke="black"></line>
</svg>
</div>
<div style="height: 50px;border:1px solid">
This paragraph is 50px, the svg will not shrink below 150px
</div>
</div>
This can't be solved with javascript, it should be responsive. the SVG is in practice a lot more complicated and cannot be replaced with a simple border-left: 1px solid black

SVGs like other replaced elements have a default size of 300x150. If they don't have enough information to calculate their width or height, they will report their default width (300) or height (150)
For your first example div, when the browser is trying to calculate its height, it will ask the first child what its height is. It will report a default of 150px (from the SVG). The second child will report 300px. So the browser will set that first div to 300px. This is the greater of its two children.
In the second div, the same process will be followed. This time the max height will be the default height of the SVG (150px) since that is larger than the other child (50px). So that section will end up at a height of 150px.
To fix this, you don't have much choice other than giving the SVG a specific height, rather than using a percentage.
<svg style="width: 40px; height:50px">
Demo:
<div style="display: flex">
<div>
<svg style="display:block;width: 40px;height:100%">
<line x1="20" y1="0" x2="20" y2="100%" stroke-width="1" stroke="black"></line>
</svg>
</div>
<div style="height: 300px;border:1px solid">
This paragraph is 300px, the svg will stretch accordingly
</div>
</div>
<br><br><br><br>
<div style="display: flex">
<div>
<svg style="width: 40px; height:50px">
<line x1="20" y1="0" x2="20" y2="100%" stroke-width="1" stroke="black"></line>
</svg>
</div>
<div style="height: 50px;border:1px solid">
This paragraph is 50px, the svg will not shrink below 150px
</div>
</div>

Set your viewBox accordingly, I do not know the userSpaceOnUse (min x min y width height) of your SVG, let's say viewBox="0 0 100 100".
Remove width and height attributes.
Set the style attribute to 100% width and 100% height.
override the default xMidYMid value by setting preserveAspectRatio="none"
Resulting svg should look like this:
<svg preserveAspectRatio="none" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width:100%;height:100%;">

Related

How exactly does the fontSize of SVG foreignObject work

New to SVG, I was trying to use foreignObject to put a custom HTML component inside SVG, and I'm very confused about the fontSize.
It seems like the usual CSS like font-size: 10px doesn't work the same way here, when I add that style, the font I got is not exactly 10px. Besides, I noticed that the font size changes as the screen width change.
My question is, which factors are affecting the font size here? and how do I get a static style like 14px?
Here's my current code:
<div style="width: 100%">
<svg class="ProgressBar" viewBox="0 0 120 10">
<foreignObject height="30" width="50" x="0" y="0">
<div style="font-size: 10px; color: rgb(135, 144, 162);">
<div>Text</div>
</div>
</foreignObject>
</svg>
</div>
Like any other SVG element, <foreignObject> elements are subject to any scaling that the SVG undergoes.
Your SVG has a viewBox, so the contents will be scaled. That includes the foreignObject and the text within it.
If you don't want scaling, then remove the viewBox. Or set the SVG width and height so that the SVG doesn't scale (ie. has 1:1 scale).
For example, the text in the following snippet has a size of 10px. This is because the width has been set to the same value as the viewBox width value (120).
<div style="width: 120px">
<svg class="ProgressBar" viewBox="0 0 120 10">
<foreignObject height="30" width="50" x="0" y="0">
<div style="font-size: 10px; color: rgb(135, 144, 162);">
<div>Text</div>
</div>
</foreignObject>
</svg>
</div>

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)

wrap text inside a div which is inline-block

I have the following html
<div >
<div _ngcontent-c1="" style="display: inline-block;vertical-align: middle">
<svg _ngcontent-c1="" xmlns:xlink="http://www.w3.org/1999/xlink" height="23px" version="1.1" viewBox="0 0 26 23" width="26px"
xmlns="http://www.w3.org/2000/svg">
<title _ngcontent-c1="">ic_report_problem_black_24px</title>
<desc _ngcontent-c1="">Created with Sketch.</desc>
<defs _ngcontent-c1=""></defs>
<g _ngcontent-c1="" fill="none" fill-rule="evenodd" id="Business-customer-link" stroke="none" stroke-width="1">
<g _ngcontent-c1="" id="Desktop-BCP" transform="translate(-378.000000, -117.000000)">
<g _ngcontent-c1="" id="ic_report_problem_black_24px" transform="translate(377.000000, 115.000000)">
<polygon _ngcontent-c1="" id="Shape" points="0 0 27.8935742 0 27.8935742 27.8935742 0 27.8935742"></polygon>
<path _ngcontent-c1="" d="M1.16223226,24.4068775 L26.731342,24.4068775 L13.9467871,2.32446452 L1.16223226,24.4068775 Z M15.1090194,20.9201807
L12.7845549,20.9201807 L12.7845549,18.5957162 L15.1090194,18.5957162 L15.1090194,20.9201807 Z M15.1090194,16.2712516 L12.7845549,16.2712516 L12.7845549,11.6223226
L15.1090194,11.6223226 L15.1090194,16.2712516 Z" fill="#65E3F1" fill-rule="nonzero" id="Shape"></path>
</g>
</g>
</g>
</svg>
</div>
<div style="display: inline-block;min-width:224px">
simple text that should wrap around the div instead of falling down to the bottom
</div>
</div>
When the screen size becomes small I want the text inside the div to start wrapping inside the div until it reaches the min-width. However what happens is that as soon as the text cannot be displayed on one line the whole div drops to the bottom line. How do I get the text inside the div to wrap within the div until it reaches the min-width?
The width of inline-block div is calculated by "shrink-to-fit", which equals to min(max(preferred minimum width, available width), preferred width). In your case: preferred width is the width of your text, available width is the width of its container. As a result, the width will be calculated to the width of its container if you reduce the width of its container to a value smaller than its preferred width. Plus the width of the icon, they cannot fit in one line. That's why it warped to a new line.
There are few choices you may want to try for your target:
Make the inline-block div inline. Text will normally warped to second line.
Use display table or flex, to force the text and icon keeps in one line.
Use max-width: calc(100% - ??px) limit its width to fit the container.
Place the inline-block element inside a table-caption, such as:
<table>
<caption>
<div style="display: inline-block;>
</div>
</caption>
</table>

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>

SVG inline - default or inherited height

please help me understand from where element get 150px of height?
In my project, I want element the same size as content
but root svg element and visible svg get 150px of height (from out of space likely)
I make demo with similar conditions.
http://plnkr.co/edit/2EJiwZFSwjD2f4wrETiX?p=preview
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<symbol id="icon-smile" viewBox="0 0 1024 1024">
<rect fill="yellowgreen" width="100%" height="100%"/>
<path class="path1" d="M512 1024c282.77 0 512-229.23 512-512s-229.23-512-512-512-512 229.23-512 512 229.23 512 512 512zM512 96c229.75 0 416 186.25 416 416s-186.25 416-416 416-416-186.25-416-416 186.25-416 416-416zM256 320c0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64s-64-28.654-64-64zM640 320c0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64s-64-28.654-64-64zM704.098 627.26l82.328 49.396c-55.962 93.070-157.916 155.344-274.426 155.344s-218.464-62.274-274.426-155.344l82.328-49.396c39.174 65.148 110.542 108.74 192.098 108.74s152.924-43.592 192.098-108.74z"></path>
</symbol>
</svg>
<div class=kx-rule>
<div class="cell col-md-3 col-sm-3">
<svg class="u-icon" >
<use xlink:href='#icon-smile'/>
</svg>
</div>
</div>
</body>
I know I can size svg but I want understand it's behavior. I red that svg canvas infinite, but why it(viewport?) render with such height?
The svg element
<svg class="u-icon" >
Does not have either height/width attributes/styles or a viewBox so it gets the fallback height/width of 300 x 150 px per the rules on replaced elements.

Resources