Please help understanding line-height and vertical-align CSS 2.1 properties - vertical-alignment

I have some questions relating to the visual content which can be seen in
the attachment (use CTRL-+ in Firefox to see enlarged visual content with
the code that generated it on the left hand side). Let us name the visual
content listed with the numbers 1, 2, 3, 4, 5, and 6 from top to bottom.
I have several questions about this scenario, for instance:
A. How is line-height being measured for boxes containing just a single line
and how does it combine with the box height (and any font properties) to produce
the visual results?
B. How come in picture 1 there is some yellow space on the very top of the picture,
(zoom in to see it) which is missing from picture 2 and 3? And where does this
space come from, as I don't appear to have specified it anywhere. How come
picture 1 touches the top of the box while pictures 2 and 3 don't?
C. How come the height of box 2 differs from the height of box 5 (and the height of
box 3 differs from the height of box 6). After all, line-height is the same in
both cases, and besides vertical-align being specified for the nested image,
nothing else is different. So how does specifying vertical-align or not change
the outer box's height?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body>
<p style="height: 200px; width: 200px; background: yellow; line-height: 200px;">
<img src="images/jellyfish.jpg" width="100" height="100" /></span>
</p>
<p style="width: 200px; background: yellow; line-height: 100px;">
<img src="images/jellyfish.jpg" width="100" height="100" />
</p>
<p style="width: 100px; background: yellow; line-height: 100px;">
<img src="images/jellyfish.jpg" width="100" height="100" />
</p>
<hr />
<p style="width: 200px; background: yellow; line-height: 399px;">
<img style="vertical-align: middle;" src="images/jellyfish.jpg" width="100" height="100" />
</p>
<p style="width: 200px; background: yellow; line-height: 100px;">
<img style="vertical-align: middle;" src="images/jellyfish.jpg" width="100" height="100" />
</p>
<p style="width: 100px; background: yellow; line-height: 100px;">
<img style="vertical-align: middle;" src="images/jellyfish.jpg" width="100" height="100" />
</p>
</body>
</html>
The CSS 2.1 spec at http://www.w3.org/TR/CSS2/visudet.html in section 10.8.1 says:
Note. When there is only one value of 'line-height' for all inline
boxes in a block container box and they are all in the same font (and
there are no replaced elements, inline-block elements, etc.), the
above will ensure that baselines of successive lines are exactly
'line-height' apart. This is important when columns of text in
different fonts have to be aligned, for example in a table.
D. OK so line-height is the height between the font baselines on different lines,
thus contributing to space between lines. But what does this line-height do if
there is only one line? I guess what the spec doesn't say is that when considering
the very top line, the line-height will extend to the top of the container, creating
extra space at the top.
E. Would it be correct to say that if I have an image on the line, the (font) baseline
will be aligned to the lower edge of the image's content box, i.e., the bottom of
the image displayed in the box generated by the box model around the image?
Or is it also possible to achieve other effects, and if so than how?
Thanks.

I've decided to answer this question in order to bring the discussion to an end
given that the answer to the details for this post can be found in the above comments.
Regards.

Related

Remove space under svg icon - where to add "display: block;" in svg code

I have read a number of posts that answer how to remove the space under a .svg file. I have tried to use the "display: block;" without any luck. I think it is because I am not sure where to place the code to make it work.
A link to my js fiddle is at the following: [where do I put display block in .svg doc][1]
[1]: https://jsfiddle.net/bethabernathy/gsarhk4c/
Any help would be greatly appreciated. Thanks, Beth
Your main problem is that your viewBox is wrong.
If you want the circle to fill the area given to the SVG, then the viewBox has to match the dimensions of the circle. Your circle has a width and height of 75, but your viewBox describes an area 135 wide and high.
To avoid this in the future when using Illustrator, you should either:
Scale your image so that it fills the artboard, or
Uncheck the "Use artboards" option when saving as SVG.
The second problem (that display:block fixes) only becomes apparent when you have fixed the viewBox issue.
Have a look at the following example. There are three versions of the SVG wrapped in a <div>:
Your original SVG. I have simplified the SVG to remove some of the icon unneeded for this demo. I have also removed the SVG boilerplate that is not needed when SVGs are being inlined.
The SVG with fixed viewBox. Note the little gap at the bottom between the SVG and the bottom of the <div>.
Same as #2 but with display: block applied to the SVG. Note the gap at the bottom is now gone.
div {
border: solid 1px grey;
width: 300px;
float: left;
margin-right: 10px;
}
#example3 svg {
display: block;
}
<div id="example1">
<svg viewBox="0 0 135 135">
<style type="text/css">
.st0{fill:#398439;}
</style>
<circle class="st0" cx="37.5" cy="37.5" r="37.5"/>
</svg>
</div>
<div id="example2">
<svg viewBox="0 0 75 75">
<style type="text/css">
.st0{fill:#398439;}
</style>
<circle class="st0" cx="37.5" cy="37.5" r="37.5"/>
</svg>
</div>
<div id="example3">
<svg viewBox="0 0 75 75">
<style type="text/css">
.st0{fill:#398439;}
</style>
<circle class="st0" cx="37.5" cy="37.5" r="37.5"/>
</svg>
</div>

Internet Explorer Not Honoring SVG Percentage Width

The following SVG renders well in Firefox and Chrome, on both Windows and Linux. In IE11, however, the overall size of the rendered drawing is tiny - roughly 170 pixels wide - and does not respond at all to changes in browser window size, as it does (and should) in other browsers:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<svg width="65%" viewBox="0 0 700 620" style="margin-left:auto; margin-right:auto;display:block;">
<svg width="700" height="20" style="margin-left:auto; margin-right:auto;display:block;">
<rect width="100%" height="100%" style="fill:rgb(128,128,255);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
<svg width="700" height="600" y="20" viewBox="0 0 700 600" style="margin-left:auto; margin-right:auto;display:block;">
<rect width="100%" height="100%" style="fill:rgb(255,200,255);stroke-width:1px;stroke:rgb(0,0,0);" />
<rect width="100" height="100" x="0" y="0" style="fill:rgb(255,255,200);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
</svg>
</body>
</html>
(Sorry about the inline styles; just experimenting, and it was quicker that way)
I'm somewhat new to SVG, and I'm not seeing anything particularly wrong here. Is this just another IE-specific failure, or have I missed something?
Note: added jsfiddle link
So, it turns out this is yet another in the seemingly endless parade of Internet Explorer failures to comply with simple, widespread standards. I can boil this down to a dirt-simple example:
<!DOCTYPE html>
<body>
<svg width="65%" viewBox="0 0 700 600">
<rect width="100%" height="100%" style="fill:rgb(255,100,255);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
</body>
In any real browser, this will correctly draw a pink rectangle whose width is 65% of the browser window width, with an aspect ratio of 700w x 600h; changing the window size will change the rectangle size.
In Internet Explorer, this simply fails, and draws a tiny rectangle - albeit with the proper aspect ratio - that is about 170 pixels wide. Who knows where it is coming up with this size? Wherever it comes from, it is fixed, and unaffected by browser resizing. This is a failure regarding the SVG docs, which Firefox, Chrome, and probably every other browser on the planet manages to honor.
The workaround, as usual, is going to be to define a degraded, fixed-size SVG tag when IE is encountered, something like
<svg width="700mm" height="600mm"...>
and lose the much-desired resizing capability. And, I suppose, as long as I'm bothering with discerning which browser is in play - something I should never have to do in 2014 - I can also drop a nasty note on the page telling users to steer clear of Microsoft and get a real browser.
Instead of setting a % width on the SVG element itself, wrap your SVG within two nested div tags with css classes "svg-flex" and "svg-flex-inner" respectively. Set the width of the outer element with the percentage you want for your graphic instead of setting it on the SVG element directly. Make sure you give your SVG element a width of 100%.
<div class="svg-flex" style="width: 50%;">
<div class="svg-flex-inner" style="width: 50%; position: relative; padding-top: 100%;">
<svg style="width: 100%; height: 100%; position: absolute; margin-top: -100%;">
<!-- Whatever you want here -->
</svg>
</div>
</div>
Instead of inline css you could just add these styles to your page
.svg-flex-inner {
position: relative;
padding-top: 100%;
}
.svg-flex svg {
position: absolute;
margin-top: -100%;
width: 100%;
height: 100%;
}
Now you can control the width of your SVG by modifying the width on the outer "svg-flex" element.
If you have an element that is not a perfect square then you will need to tweak the the padding-top and margin-top values using the following formula:
(100 * height / width) %.
so, for a 16:9 graphic, the ratio would be 100 * 9 / 16 = 56.25%
padding-top: 56.25%;
...
margin-top: -56.25%
Here's the fiddle
this percentage svg does works on IE 11
If you do test it on http://www.w3schools.com/html/tryit.asp?filename=tryhtml_basic
<!DOCTYPE html>
<HTML style="width:100%; height: 100%">
<body style="width:100%; height: 100%">
<svg width="65%" viewBox="0 0 700 600" height ="100%">
<rect width="100%" height="100%" style="fill:rgb(255,100,255);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
</body>
</HTML>
I should test it also on older versions, the most curious change is setting the <html> and the <body> to "width:100%; height: 100%"
You can also put an external svg in an object tag and it will be resized correctly.
It appears from my experience that IE11 will not scale inline SVG graphics if increasing the width to fill the containing element will also increase the height of the containing element, even if the containing element is not fixed height.
In my current use case (heavily using flexbox) i solved it by setting
align-items: stretch;
instead of
align-items: center;
on my containing element.
My markup looked like so:
<section class="container">
<div class="cell">{LOTS OF TEXT</div>
<figure class="cell">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200">
...
</svg>
<figure>
</section>
And my CSS (actually Less) looked like this:
.container {
width: 70%;
max-width: 1600px;
display: flex;
align-items: stretch;
> figure {
margin: 0 20px 0 0;
> svg {
width: 100%;
}
}
> .cell {
display: flex;
justify-content: center;
flex-direction: column;
flex: 1 0 0px;
}
}
Of course, depending on your implementation you will probably need another solution to grow your containing element.
How IE decides what the "fixed" height of the containing element is, i do not know.
Use HTML5 and place svg in a DIV as shown below. OK for all browers
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<div style="width:700px;height:620px">
<svg width="65%" viewBox="0 0 700 620" style="margin-left:auto; margin-right:auto;display:block;">
<svg width="700" height="20" style="margin-left:auto; margin-right:auto;display:block;">
<rect width="100%" height="100%" style="fill:rgb(128,128,255);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
<svg width="700" height="600" y="20" viewBox="0 0 700 600" style="margin-left:auto; margin-right:auto;display:block;">
<rect width="100%" height="100%" style="fill:rgb(255,200,255);stroke-width:1px;stroke:rgb(0,0,0);" />
<rect width="100" height="100" x="0" y="0" style="fill:rgb(255,255,200);stroke-width:1px;stroke:rgb(0,0,0);" />
</svg>
</svg>
</div>
</body>
</html>
In theory the content of an SVG should not be aware of what is outside of it. This means especially that it should not have to know about the width(s) of its parent element(s). SVG is intended as a drawing canvas where you should specify all the positions and dimensions as pixels.
I found this article helpful

SVG viewbox, Image is set to parent element width and not fitted to parent element

I am trying to use the viewbox attribute of SVG to fit the selected area to the screen. The desired effect is that all of the view box area will be shown onscreen, with preserved aspect ratio.
Internet explorer and Chrome have the correct behavior with the image area centered both vertically and horizontally.
In opera and firefox the behaviour is not as desired. In wide screens the image is always full width and some of the area is then lost off the bottom
The code I am using is included below with some comments to the problems I have already solved. see the bottom of the page for screenshots
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Svg static view box</title>
<style>
body, html {
height: 100%; /* Required to make div fill to screen height, otherwise IE picks smaller image height */
margin: 0;
padding: 0; /* Remove standard behaviour for body margin */
overflow: hidden;
}
div {
background: red;
height: 100%;
}
</style>
</head>
<body>
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 2000 1000">
<rect height="1000" width="2000" y="0" x="0" fill="#afe9c6"/>
<path d="M40,1000,2000,40" stroke="#00aad4" stroke-width="10" fill="none"/>
<path d="M40,40,2000,1000" stroke="#00aad4" stroke-width="10" fill="none"/>
<text font-size="144px" y="550" x="500" >SVG DOCUMENT</text>
</svg>
</div>
</body>
</html>
Desired effect in chrome
Overflow in Opera
The viewBox attribute does not affect the layout of the SVG element. All it does is establish coordinates used within the SVG document. See the spec:
http://www.w3.org/TR/SVG11/coords.html#ViewBoxAttribute
Use HTML CSS to give the SVG element a margin or specific width and height. With what you have, there's no specified size for the SVG element, and so you're going to get undefined behavior.

Auto height for a foreignObject in SVG

I have, in my SVG, a foreignObject which contains a p element. I want the height of this structure to be adapted to the height of my text.
The p element is already adapted : I've done nothing for that.
But I have troubles for the foreignObject. If I remove the field height, it doesn't work. height:auto doesn't work either.
Since there is no real use of scaling up and down the foreignObject itself, then you can set both foreignObject height and width to 1, and via CSS set foreignObject { overflow: visible; } to make its content visible whatever it is and do whatever you need to do it with it.
You can set height of the foreignObject element in em units, maybe that could help?
Right now the width and height attributes of a foreignObject are required, and must have values > 0, otherwise the element will not be rendered.
Update: An alternative is to just set the dimensions of the foreignObject to 100%, and use the fact that the foreignObject has a transparent background per default. Since other elements in svg are laid out in an absolute manner anyway they don't depend on the foreignObject size.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
p { position: absolute; top: 50%; left: 50%; width: 100px; }
</style>
<circle cx="50%" cy="50%" r="25%" fill="lightblue"/>
<foreignObject width="100%" height="100%">
<p xmlns="http://www.w3.org/1999/xhtml">
some wrapped text...
some wrapped text...
some wrapped text...
some wrapped text...
</p>
</foreignObject>
</svg>

Weird overflow inside foreignObject elements

I get some weird overflow whenever I want to fit an object inside foreignObject tag.
Take the code below. Instead of expanding to 100x100, the box expands to 120px, which is double the border width. I've tried nearly everything in my mind to counteract this effect, but nothing seems to solve the issue.
<svg width="4in" height="3in" version="1.1"
xmlns = 'http://www.w3.org/2000/svg'>
<foreignObject width="100" height="100">
<div style="width:100%;height:100%;background-color: #fcefa1;border:10px solid #ff0000;"></div>
</foreignObject>
</svg>
It's double the border width because you have a border on both sides, ten plus ten is twenty. Try this:
<svg width="4in" height="3in" version="1.1"
xmlns = 'http://www.w3.org/2000/svg'>
<foreignObject width="100" height="100">
<div style="width:100%;height:100%;background-color: #fcefa1;border:10px solid #ff0000; -moz-box-sizing: border-box; box-sizing: border-box;"></div>
</foreignObject>
</svg>
The box-sizing CSS property lets you control what the width applies to.

Resources