Flexbox filling div with blank space when text split over two lines - html

I have a flex container div with 2 elements - a title, and a "like" svg image that is vertically centered and is displayed just to the right of the title.
When the title is too long to be displayed on one line, it seems to fill the title div with extra space on the right, so the image will not display immediately to the right of the split text.
Here is what the HTML looks like:
.like-container {
display: flex;
align-items: center;
}
.like-div {
font-size: 10px;
margin-left: 20px;
order: 1;
}
.title {
font-size: 40px;
}
<div class="like-container">
<div class="like-div">
<svg xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px"
viewBox="0 0 283.46 283.46" enable-background="new 0 0 283.46 283.46" xml:space="preserve">
<metadata>
<sfw xmlns="http://ns.adobe.com/SaveForWeb/1.0/">
<slices/>
<sliceSourceBounds x="12.691" y="27.241" width="269.84" height="254.219" bottomLeftOrigin="true"/>
</sfw>
</metadata>
<path d="M12.691,251.967c0,2.349,1.904,4.252,4.252,4.252h38.293c2.348,0,4.252-1.903,4.252-4.252V131.653 c0-2.348-1.904-4.252-4.252-4.252H16.943c-2.348,0-4.252,1.904-4.252,4.252V251.967z"/>
<path d="M278.918,147.336c-8.606-14.737,11.983-21.831-5.778-35.607c-22.375-17.355-20.925-14.647-69.32-15.194 c-7.65-0.086-17.099,0.772-14.633-15.114c9.885-63.703-6.41-75.53-17.217-78.504c-22.753-6.26,4.787,19.854-23.702,68.758 c-2.513,4.313-10.086,9.271-15.194,17.567c-10.544,17.125-20.681,44.156-29.436,44.156c-6.252,0-22.42,0-36.091,0v108.504 c20.458-1.617,49.586-3.924,56.862-4.523c11.514-0.949,21.01,6.97,38.104,6.97c15.194,0,24.823,9.421,76.594,1.481 c7.314-1.121,20.896-15.174,18.194-26.576c-2.084-8.804,22.768-15.721,17.405-31.809 C268.403,168.538,290.992,168.011,278.918,147.336z"/>
</svg>
<span>Like</span>
</div>
<div class="title">
This is the very longish Title!
</div>
</div>
I have created a plnkr so that you can see what I mean: http://plnkr.co/edit/cPMp4sjIUTbX3ohMW4aI
Any ideas?

What you are seeking is often referred to as shrink-to-fit or shrink-wrapping, where a container neatly wraps its content without leaving extra space.
CSS3 does offer a new keyword for width and height called min-content, which makes the box wrap closely to the content, but browser support is still very weak.
Here's one alternative you may want to consider: Use the ::after pseudo-element.
Remove the "like" image from the HTML (at least for this demo) and add this to your CSS:
.title::after {
display: inline-block;
content: "";
height: 40px;
width: 40px;
background: url('http://i.imgur.com/99oDJSA.png') no-repeat;
vertical-align: baseline;
}
DEMO: http://jsfiddle.net/hjkh3dy1/

Related

Why are inline elements inside anchor tags not filling height of anchor, when anchor is flex item?

Consider the below code:
.container {
display: flex;
background: red;
align-items: center;
}
.inner {
background: blue;
}
<div class="container">
<a>
<span class="inner">Test<span>
</a>
</div>
The span is not filling the height of the anchor (you see the red below the bottom edge of the blue box).
Why is CSS behaving that way and how can it be fixed?
EDIT
The question above stems from the following code, which does not have a span but suffers from the same problem (i.e. the inside of the anchor element does not fill the height of the anchor):
.container {
display: flex;
flex-direction: row;
background: red;
}
svg {
height: 1em;
}
<div class="container">
<a>
Test
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-right" class="svg-inline--fa fa-arrow-right fa-1px " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="display: inline-block;"><path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path></svg>
</a>
</div>
This is what it looks like in Chrome DevTools, when inspecting the text inside the anchor element (the red box):
This is caused by the difference between the rendered height of the text - top of the ascent to the bottom of the descent - which depends on the font metrics, and the line height, which does not.
Because the default line height is almost the same as text height for a typical font, the difference is small, but still noticeable. We can see much better what's going on if we give the <a> element a larger line-height value.
.container {
display: flex;
background: red;
align-items: center;
}
.inner, svg {
background: blue;
}
a {
line-height: 3;
background: green;
}
svg {
height: 1em;
}
<div class="container">
<a>
<span class="inner">Test</span>
</a>
</div>
<hr>
<div class="container">
<a>
Test
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-right" class="svg-inline--fa fa-arrow-right fa-1px " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="display: inline-block;">
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
</svg>
</a>
</div>
Block containers that establish an inline formatting context, like the <a> element when the .container div is display:flex, or the span when it's assigned display:inline-block, take the sum of line heights of the lines they contain as their height, rather than the height of the rendered text as the inline elements and text sequences do.
You can experiment with the line-height value of the <a> element to see if you can get a value that works well for your font, but there's currently no way in CSS for the line-height to be derived from the font metrics. There is a draft CSS specification that may allow it in the future.
.container {
display: flex;
flex-direction: row;
background: red;
}
a {
display: flex;
align-items: center;
flex: 1;
}
svg {
height: 1em;
}
<div class="container">
<a>
Test
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-right" class="svg-inline--fa fa-arrow-right fa-1px " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="display: inline-block;"><path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path></svg>
</a>
</div>
.container {
display: flex;
background: red;
align-items: center;
}
a {
display: flex;
flex: 1;
}
.inner {
flex: 1;
background: blue;
}
<div class="container">
<a>
<span class="inner">Test<span>
</a>
</div>
you need to tell the a-tag that it should grow. flex-direction: row is by the way the default.
.container {
display: flex;
background: red;
}
a { flex-grow: 1; }
svg {
height: 1em;
}
<div class="container">
<a>
Test
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-right" class="svg-inline--fa fa-arrow-right fa-1px " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="display: inline-block;"><path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path></svg>
</a>
</div>

SVG oversized on load until CSS kicks in

I have a SVG inside a fixed-size div (width: 350px; height: 400px;) and everything is fine once the page loads, but during the loading, the SVG is oversized and mangled up until CSS kicks in:
Here is the code, HTML first:
<div class="dashboard-tasks-completed">
<figure>
<svg width="100%" height="100%" viewBox="0 0 42 42" class="donut">
<circle class="donut-hole" cx="21" cy="21" r="15.91549430918954" fill="#fff"></circle>
<circle class="donut-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#19222a" stroke-width="5"></circle>
<circle id="active" class="donut-segment" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#206996" stroke-width="5" stroke-dasharray="66.66666666666666 33.33333333333333" stroke-dashoffset="25"></circle>
<circle id="completed" class="donut-segment" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#B8E1FA" stroke-width="5" stroke-dasharray="33.33333333333333 66.66666666666666" stroke-dashoffset="58.33333333333334"></circle>
<g class="chart-text">
<text x="50%" y="50%" class="chart-number">3</text>
<text x="50%" y="50%" class="chart-label"> Tasks </text>
</g>
</svg>
<figcaption class="figure-key">
<ul class="figure-key-list" aria-hidden="true" role="presentation">
<li>
<span class="shape-circle shape-blue"></span>2 Active (66.67%)
</li>
<li>
<span class="shape-circle shape-lightblue"></span>1 Completed (33.33%)
</li>
</ul>
</figcaption>
</figure>
</div>
CSS:
.dashboard-tasks-completed {
width: 350px;
height: 400px;
}
.chart-text {
font: 16px/1.4em "Montserrat", Arial, sans-serif;
fill: #000;
transform: translateY(0.25em);
}
.chart-number {
font-size: 0.6em;
line-height: 1;
text-anchor: middle;
transform: translateY(-0.25em);
}
.chart-label {
font-size: 0.2em;
font-weight: bold;
text-transform: uppercase;
text-anchor: middle;
transform: translateY(0.7em);
}
.figure-key-list {
list-style: none;
}
.figure-key-list li {
margin: 0 0 8px;
font-size: 14px;
}
.shape-circle {
display: inline-block;
vertical-align: middle;
width: 32px;
height: 32px;
border-radius: 50%;
margin-right: 10px;
}
.shape-blue { background-color: #206996; }
.shape-lightblue { background-color: #B8E1FA }
I have created a minimal example, unfortunately it is not reproducible in neither JSFiddle or Codepen, but here is the demo in any case.
How can I overcome the issue?
As others have said, you are letting the SVG fill the page until the CSS loads and it becomes the correct size.
If you know your SVG is going to be width: 350px; height: 400px;, then you could set those dimensions on the SVG instead.
<svg width="350px" height="400px" ...>
Then put it back to what you want in the CSS.
.dashboard-tasks-completed svg {
width: 100%;
height: 100%;
}
Or you could inline some basic styling in your document, that would set up some important sizes until the rest of the SVG loads.
<head>
<style>
.dashboard-tasks-completed {
width: 350px;
height: 400px;
}
.chart-text {
font: 16px/1.4em "Montserrat", Arial, sans-serif;
fill: #000;
transform: translateY(0.25em);
}
</style>
...
And if your font size never changes, then why not just set those attributes on your <text> element instead of using CSS?
<g class="chart-text" style="font: 16px/1.4em "Montserrat", Arial, sans-serif; fill: #000; transform: translateY(0.25em);">
One option is to hide the div (or other elements within) initially and then reveal it after the page finishes loading.
For example, modify your div thusly:
<div id="showme" class="dashboard-tasks-completed" style="display:none;">
And then add the following javascript:
window.onload = function () {
document.getElementById("showme").style.display = "block";
};
The inline CSS display:none; lets the browser know not to display it, even before external CSS is loaded. Once everything is loaded, your onload event will fire, and the javascript above will display the previously-hidden elements.
The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.
The value of the viewBox attribute is a list of four numbers min-x, min-y, width and height, separated by whitespace and/or a comma, which specify a rectangle in user space which is mapped to the bounds of the viewport established for the associated SVG element (not the browser viewport).
Taken from MDN.
The viewbox property defines the region of an svg element which should be zoomed in on to fit inside it's container. However, the element will keep it's aspect ratio and not stretch to fit inside the container.
So in your case, this means that the svg element will fill all it's parents space while maintaining it's aspect ratio, until css arrives and tells it to size it self inside a 350px by 400px space.

How can you make an img element the same size and alignment as emojis or text?

For some reason, no matter which vertical-align I use, the image is slightly under center from the text line. How do I match the size of the text? How do I match size of the emojis? How do I vertically center the image?
body {
color: #fff;
background: #000;
}
svg {
height: 1em;
width: 1em;
vertical-align: middle;
}
<section>
<h1>
Emoji, image and size tests
</h1>
<p>
Notice in the following lines, the svg element (fullscreen icon) is not vertically aligned with the text, and its size isn't the same as the other square emojis.
</p>
<p>
ABC<svg xmlns="http://www.w3.org/2000/svg" width="330" height="330" viewBox="0 0 87.312 87.312"><g fill="none" stroke="#fff" stroke-width="15.875"><path d="M34.396 79.375H7.937V52.917M52.917 79.375h26.458V52.917M34.396 7.938H7.937v26.458M52.917 7.938h26.458v26.458"/></g></svg>DEFG
</p>
<p>
🔇😊K▶️<svg xmlns="http://www.w3.org/2000/svg" width="330" height="330" viewBox="0 0 87.312 87.312"><g fill="none" stroke="#fff" stroke-width="15.875"><path d="M34.396 79.375H7.937V52.917M52.917 79.375h26.458V52.917M34.396 7.938H7.937v26.458M52.917 7.938h26.458v26.458"/></g></svg>🔇😊K▶️
</p>
</section>
Just add paddding bottom, Ive tweaked the fiddle.
svg {
height: 1em;
width: 1em;
vertical-align: middle;
padding-bottom:0.2em
}
https://jsfiddle.net/6hd320f4/
One solution would be to use flexbox like this:
p {
display: flex;
align-items: center;
flex-wrap: wrap;
}
Don't forget flex: wrap in order to maintain the text line break.
Note: if you edit line-height and test different values, you will find a pixel inconsistency that is hard to avoid due to the fixed proportions.
Perhaps counter-intuitive, but if you use vertical-align: top;
margin: 1px 0; on the svg, it aligns correctly.
Try text-top as value of vertical-align
body {
color: #fff;
background: #000;
}
svg {
height: 1em;
width: 1em;
vertical-align: text-top;
}
<section>
<h1>
Emoji, image and size tests
</h1>
<p>
Notice in the following lines, the svg element (fullscreen icon) is not vertically aligned with the text, and its size isn't the same as the other square emojis.
</p>
<p>
ABC<svg xmlns="http://www.w3.org/2000/svg" width="330" height="330" viewBox="0 0 87.312 87.312"><g fill="none" stroke="#fff" stroke-width="15.875"><path d="M34.396 79.375H7.937V52.917M52.917 79.375h26.458V52.917M34.396 7.938H7.937v26.458M52.917 7.938h26.458v26.458"/></g></svg>DEFG
</p>
<p>
🔇😊K▶️<svg xmlns="http://www.w3.org/2000/svg" width="330" height="330" viewBox="0 0 87.312 87.312"><g fill="none" stroke="#fff" stroke-width="15.875"><path d="M34.396 79.375H7.937V52.917M52.917 79.375h26.458V52.917M34.396 7.938H7.937v26.458M52.917 7.938h26.458v26.458"/></g></svg>🔇😊K▶️
</p>
</section>

I get weird top and bottom whitespace between svg in rems

maybe its stupid question but still..
Maybe someone can explain me why i am getting weird whitespace between svg in div block when i am writing with rems.
P.S font-size in html must be 10vw;
example: http://codepen.io/anon/pen/OWqwXZ
a
SVGs are treated the same as <img>. By default, they are inline-block and thus sit on the baseline of the text.
If you don't want that, then just set the <svg> to display:block.
html{
font-size: 10vw;
}
.wrapper{
width: 100%;
background-color: pink;
padding: 0;
margin: 0;
}
svg{
wdith: 0.30rem;
height: 0.30rem;
background-color: red;
display: block;
vertical-align: top;
}
<div class="wrapper"><svg viewBox="0 0 30 30">
<path d="M429.9 758.48C425.78 751.33 416.63 748.88 409.47999999999996 753.01C402.33 757.13 399.87999999999994 766.28 404.00999999999993 773.43C408.12999999999994 780.5799999999999 417.2799999999999 783.03 424.42999999999995 778.9C431.5799999999999 774.77 434.03999999999996 765.63 429.9 758.48ZM422.94 776.31C417.21999999999997 779.6199999999999 409.9 777.66 406.6 771.9399999999999C403.29 766.2199999999999 405.25 758.9 410.97 755.5999999999999C416.70000000000005 752.29 424.01000000000005 754.2499999999999 427.32000000000005 759.9699999999999C430.62000000000006 765.6999999999999 428.66 773.0099999999999 422.94000000000005 776.31ZM422.34 766.85L414.57 771.33C413.84999999999997 771.75 413.27 771.4100000000001 413.26 770.59L413.21999999999997 761.52C413.21999999999997 760.6999999999999 413.79999999999995 760.36 414.51 760.78L422.34 765.35C423.04999999999995 765.76 423.04999999999995 766.44 422.34 766.85Z " fill-opacity="1" transform="matrix(1,0,0,1,-402,-751)"></path>
</svg></div>

HTML/CSS Cross Browser Inconsistency with SVG

I have have been tinkering, trying to get images to render consistently across browser.
HTML:
<fieldset class="legend">
<img class="legend-a"/>
<img class="legend-b"/>
<img class="legend-c"/>
<img class="legend-d"/>
<img class="legend-e"/>
</fieldset>
CSS:
.legend {border: 0; display: inline;}
.legend-a{ background: url(yellow.svg); }
.legend-b{ background: url(orange.svg);}
.legend-c { background: url(purple.svg);}
.legend-d { background: url(dull_purple.svg); }
.legend-e { background: url(blue.svg);}
Currently the above works fine (the images display in a row side by side) for IE (Version 11) But not (blank, no images) in Chrome or Firefox.
Previously I had used content: url(purple.svg); instead of background: url(purple.svg); but that only worked in Chrome; but not in IE or FireFox.
It's very bothersome. I have to keep the <fieldset.../> HTML as succinct as possible as it is repeated all over the place, as <td>
The .svg look like this (for example)
blue.svg:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 36.232 36.232" enable-background="new 0 0 36.232 36.232" xml:space="preserve">
<circle fill="#37ADC4" cx="17.981" cy="18.179" r="16"/>
</svg>
Here's a JSFiddle . Only the 'content' version works with JFiddle.
Thats because your <img>s don't have a size. If you provide a size then the background renders as well. I don't know what size IE would pick in this case anyways...?
.legend {border: 0; display: inline;}
.legend-a{ background: url(https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg); }
.legend-b{ background: url(https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg);}
.legend-c { background: url(https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg);}
.legend-d { background: url(https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg); }
.legend-e { background: url(https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg);}
.legend img{width:32px;height:32px}
<fieldset class="legend">
<img class="legend-a"/>
<img class="legend-b"/>
<img class="legend-c"/>
<img class="legend-d"/>
<img class="legend-e"/>
</fieldset>