What does vertical-align: middle really do? Where is it's reference? - css

When you have two inline elements that share the same line, and the bigger one is vertical-align: baseline and the smaller one is vertical-align: middle why does the middle aligned element appear below the baseline element?
I've put together a demo illustrating what I'm talking about:
http://jsfiddle.net/mLSG2/
It appears that the smaller element's mid-line is aligned to the larger elements baseline, but that doesn't seems to make much sense to me. If this is true, what is the rational behind it?
More generally, can someone explain how alignment is calculated when elements of varying line-heights and varying vertical alignment declarations share the same line? Is there a place in the spec that defines this?

By the specification, vertical-align: middle should “align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent”. In this case, the vertical middle of the line box for the italic text should be aligned to the baseline of the div element plus half the x-height of that element. This makes it rather close to that baseline, really.
Since fonts are not set here, browsers will typically use a default font size like 16px. The x-height depends on font, but let’s assume the rough average: half of the font size, 8px. Half of that makes 4px, making the difference rather small. (The font size of the div element is not changed by the presence of inner elements with larger font size.)
The situation may be obscured by browser bugs. The vertical-align property has a buggy history. Often it’s better to use relative positioning.

Related

CSS rule like inline-block to match exactly the space the text takes

If I do
<div style="display: inline-block;">Some text</div>
The div dimension fits closely the rectangle the text fits in, but not exactly:
More precisely, it fits perfectly horizontally, but not vertically. And the height will be the same wether the text is "A", "..." or "ppp", while the space used by the text changes. Is there a css property that would behave like inline block, but treat the text as a more floating element and have the smallest height that can contain the current text? Like (photoshoped):
No, there isn't.
To make that happen, and since every font has its own inner white space and renders different on different browsers, you need to measure a particular font's size and "cut" of the rest.
One way could be cloning the element and draw it on a canvas and the count colored pixels from top/bottom to get its exact height.
Further reading about fonts: http://www.freetype.org/freetype2/docs/glyphs/

What is the best way to stabilize vertical text rhythm?

I heard that relative units are better then absolute, but sometimes browsers round it wrong and it's hard to calculate. Do you know any tool that can help?
I used SASS/Compass. It's good and very easy, but not perfect…
As per the comment, “vertical text rhythm” seems to refer to line grid. Line grid has generally been ignored in CSS, largely because it is mostly relevant in print media and in multi-column text layout. Basically, the way to make things snap into a line grid is to use consistent sizing in vertical direction, using the same units. For example, if you set line height in em units, set heights and vertical margins in those units, too. To make an image fit into a line grid, wrap it in a container with a height in em units. Alternatively, do all vertical sizing in px units.
It is true that rounding may cause problems, since em dimensioned things ultimate get converted to pixels. So if you set line height to 1.3em and in image container height to 3.9em, the latter might not yield exactly 3 times as many pixels as the former but one pixel less or more. If this is crucial and you consider using pixels, remember that a CSS pixel need not correspond to a physical pixel in a device.
In CSS Line Grid Module, currently existing as an Editor’s Draft only, there are properties for using a real line grid. They have been partly implemented in Chrome, with the -webkit- prefix. If a line grid is desired, it can hardly hurt to add code that tries to snap content into the grid and may do so in Chrome:
body {
line-grid: yourNameForLineGrid;
line-snap: baseline;
-webkit-line-grid: yourNameForLineGrid;
-webkit-line-snap: baseline;
}

Line-height affecting spacing above first line and after last line

I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line (and maybe below the second). How can I increase spacing between the two lines only, without increasing above and below.
I know it's a behavior of Line-height. but just curious if there is any good solution for this.
This is just en example to what I'm asking.
Jsfiddle: http://jsfiddle.net/jitendravyas/V3eWV/
You can use negative margins for this, although there is something to keep in mind:
line-height is a funny thing. According to CSS2.1 it doesn't specify the line-height but the minimum height of line-blocks:
On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a "strut." (The name is inspired by TeX.).
A line box is defined in 9.4.2 Inline formatting contexts:
In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes. The boxes may be aligned vertically in different ways: their bottoms or tops may be aligned, or the baselines of text within them may be aligned. The rectangular area that contains the boxes that form a line is called a line box.
This doesn't change in CSS3 very much, at least if you don't change the line-stacking. However, there is no property which targets your problem directly: you can't change the line-height of the ::first-line, it will always get applied.
That said, use negative margins for the time being. Even better, wrap your elements in a generic container. By using :first-child and :last-child you can add as many elements as you like.
Example
<div>
<h1>I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line.</h1>
<h1>I've a text in side heading with multiple lines. Want the spacing the two lines to increase, so I set a line-height. When I do this, not only does it increase space between the two lines, it also increases spacing above the first line.</h1>
</div>
body {padding:30px;background:yellow;border:1px solid red;margin:0}
div{background:red;margin:0;padding:0;border:1px solid green;}
h1{line-height:2em;}
div > h1:first-child{
margin-top:-.25em;
}
div > h1:last-child{
margin-bottom:-.25em;
}

How to prevent line-height from adding a margin in the top?

Whenever i use a large line-height like 1.6em it always adds a margin in the very top of the text which i don't want.
Example: http://jsfiddle.net/EstpJ/1/
i want the text to be sharply lined with the borders and not have any kind of top or bottom margin.
How to fix that?
That's exactly what line-height is, it's a manual way to set the height of a line of text for the purposes of wrapping text and such. The actual visible size is determined by the font-size and to a lesser extend by the font-family. The average line-height for normal text/font is around 1.2em. Anything larger than that will cause visible letterboxing, which is exactly what you are describing. Using a smaller value will cause successive lines to overlap each other.
The only way to fix your exact example is introduce more markup to determine line numbers so that you can style the first/last line differently.
You could maybe slightly alter your markup (I prefer wrapping <p> tags around lines of text) and use a negative top margin?
As Matthew said, this is what lineheight does.
You could try to set the line height on an inner div (inside the one with borders), and counteract the top and bottom effect by also setting a negative top and bottom margin. But it's likely that the negative margin won't work in all browsers.

How to use very large font sizes in Internet Explorer with CSS that won't affect design?

The font size I need to match the design I have is 85pt, which is extremely large. In IE6 and IE7, my design is affected because the divs that contain these elements become larger than they normally are, and as a result, elements under these are pushed further down, somewhat breaking the design. I have the height defined for these elements and when I decrease the font size, the elements begin to shrink to the correct size. I've added line-height: 0; to the element and this works in all modern browsers.
Unfortunately, the design I'm working on cannot be shown publicly, but I was hoping to get some insight into other possible techniques that I could try to get the design to render correctly. The height of the parent element is 144px, which includes 10px padding on top and bottom and a top and bottom 1px border.
Unfortunately there's not a lot more that I can add to this, but I'll include whatever info I can if asked.
line-height:0 is a great start. However, I'm a little concerned about the 10px padding on the parent element. Whenever you mix padding with IE, you start to lose control over width & height.
I'd start by removing the padding-top on the parent and convert that into a margin-top:10px on the actual child element. If that still gives you trouble, remove the margin and try a position:relative on the child with a top:10px.
Finally, try adding a overflow:hidden to your parent element to force it to not budge when the font-size gets larger.
All this depends on what your child element actually is. If you convert it to an inline element (like a span, em, or strong) it might help alleviate some rendering issues, depending on your predefined styles.
Another thing to consider - are you using floats? Sometimes you'll get a double-float issue with IE and floats. A quick google for "IE double float" will show you why.
Does that help?
Convert the font-sizes to pixels and use px instead of pt. Make sure there that padding, margin and border is 0. Verify that there are no whitespace in your HTML except for between words. Whitespace can end up being displayed as a newline or space, making elements bigger than intended. Also don't set line-height to 0, set it to either auto or the same as font-size.
Thank you all for your input. Originally I needed absolute positioning on the element in question, while the parent element had relative positioning. However, using this with line-height: 0 caused the text to disappear in IE6 and 7; after trying to figure out where the text was initially, I removed absolute positioning and decided to leave the text left aligned in IE6 and 7, which affected the position of other elements as a result. I revisited the original absolute positioning and added border to the element to reveal its location. Doing this showed that it was exactly as I defined it: an element with a line-height of 0px, so the top and bottom borders were next to each other. For IE6 and 7, I defined line-height: 100%; and my text was almost where I needed it. I added top and the needed pixels and now my element is in the correct position with its line-height not affecting any of the other elements because of the positioning.
Thank you all again for your assistance.
My first thought when reading your post was to adjust the line-height, but since you've already done that, I'm not sure how much more can be done. From your summary, I gather that the design cannot be modified to account for the large font sizes.
Another answerer recommended using pixel sizes, but I would recommend using ems as they are percentage dimensions and will be more consistent across browsers, screens, and resolutions.
Line-height can be left as 0 (or set it to the height of the parent element), but you will likely see the text floating over other elements if the text's height surpasses the line-height.
Any possible way you could use an image for the text instead? That's really the only fool-proof method for getting all browsers to look consistent.

Resources