Vertical centering various sized spans with line-height - html

I want to gain a deeper understanding of how line-height works, in particular with centering text vertically within a fixed height element. In the example link below, you can see that setting the line-height to be equal to the container's height will center items as long as the items are all of the same size. When you put two different sized spans in, then the larger one will be centered, while the other will not be. I am at a loss to explain this, since both the large and small elements work separately. How can I accomplish having a large and small span to be centered (using line-height)? (and why is this behavior happening in the first place?)
.header {
background: grey;
width: 100%;
height: 65px;
}
.big, .small {
line-height: 65px;
}
.big {
font-size: 1.5em;
}
.
<div class="header">
<span class="big">A</span>
<span class="small">B</span>
</div>
<br/>
<div class="header">
<span class="small">A</span>
<span class="small">B</span>
</div>
<br/>
<div class="header">
<span class="big">A</span>
<span class="big">B</span>
</div>
JS Fiddle Example

This happens, because default vertical-align is baseline. If you switch it to vertical-align:middle you get the expected behaviour.
Edit for clarification:
As span's are inline elements they share the same baseline, regardless of the font size you are using. Vertical alignment of text is baseline initially, but by setting it to middle, you force these inline elements to align vertically centered.
More info on vertical align here: https://developer.mozilla.org/en/docs/Web/CSS/vertical-align

You need vertical-align: middle; . default value is baseline.
.big, .small {
line-height: 150px;
vertical-align: middle;
}
JSFiddle

Related

Is this a bug in CSS? [duplicate]

This question already has answers here:
Why my inline-block divs are not aligned when only one of them has text? [duplicate]
(4 answers)
Why does this inline-block element have content that is not vertically aligned
(4 answers)
My inline-block elements are not lining up properly
(5 answers)
Why is this inline-block element pushed downward?
(8 answers)
Understand inline-element, vertical-align, line-box and line-height
(1 answer)
Closed 4 years ago.
This might sound like an outdated topic since no one still uses inline-block property thanks to flex-box and grid but I was wondering about it and I would like to inquire about it.
When creating two divs and assigning them both to display as inline-block and then adding any element inside one of them, the result is quite strange, where the div which contains that element will slide down to the bottom of the other div minus the height of the added element.
div {
display: inline-block;
width: 100px;
height: 150px;
background: gray;
}
<div id="left">
<span>Text</span>
</div>
<div id="right"></div>
To fix the issue it's only enough to align the div vertically to the top, but what is strange too is that we get the same result even if we align the other div which is not affected without aligning the affected one, so what exactly is happening here?
div {
display: inline-block;
width: 100px;
height: 150px;
background: gray;
}
#left{
vertical-align: baseline;
}
#right{
vertical-align: top;
}
<div id="left">
<span>text</span>
</div>
<div id="right"></div>
UPDATE:
To clarify things more I removed the child element and added a text outside the two divs, and added two more divs, now all divs are without a flow content, but the first two both of them have a top property while the last two are different, one top and the other is baseline:
div {
display: inline-block;
width: 100px;
height: 150px;
background: gray;
}
.right{
vertical-align:baseline;
}
.left{
vertical-align:top;
}
Text
<div class="right"></div>
<div class="left"></div>
<br>
Text
<div class="left"></div>
<div class="left"></div>
In the first case the Text aligned to the top and in the next aligned to the baseline of the divs even they don't have a flow content.
The reason this happens, is because the default vertical-align value for inline elements is baseline.
Then the question becomes: what is the baseline of an inline-block element? Here, we have to make a distinction between elements with and without flow content:
For elements with flow content, such as the left div in your question, the baseline is the same as the baseline of the last content element.(*) For the left div, this corresponds to the baseline of the inner span.
(*) There are some additional considerations when setting the element's overflow, but I'll leave that out of scope.
For elements without flow content, such as the right div in your question, the baseline is the bottom of the element's margin box. For the right div, this corresponds to the bottom of the div itself.
So, to summarize: the reason you're seeing a vertical shift is because the elements are vertically aligned according to their baseline, and the baselines for elements with and without content are calculated differently.
To test this out, just try adding some text to the right div, and you'll see how both baselines are now the same.
div {
display: inline-block;
width: 100px;
height: 100px;
background: gray;
}
<div id="left">Text</div>
<div id="right">Other text</div>
By animating the font size, the example below demonstrates even more clearly how changes in the baseline affect vertical positioning:
div {
display: inline-block;
width: 100px;
height: 100px;
background: gray;
}
#left {
transition: all 2s ease;
animation: anim 2s infinite linear alternate;
}
#keyframes anim {
0% {font-size: 100%;}
100% {font-size: 300%;}
}
<div id="left">Text</div>
<div id="right"></div>
The display: inline-block Value
Compared to display: inline, the major difference is that display: inline-block allows to set a width and height on the element.
Also, with display: inline-block, the top and bottom margins/paddings are respected, but with display: inline they are not.
Compared to display: block, the major difference is that display: inline-block does not add a line-break after the element, so the element can sit next to other elements.
and
excuse me textarea is inline-block, but what line is correct,
the browser think the bottom of second inline-block is position of line so
when he go to draw children he see the textarea must be inline and change position of it to the bottom of second inline-block is position of line and because it is any padding and it position are relative it cause to parent div move to bottom just for textarea be inline

Bootstrap3 - vertically align label within h2

I am facing an interesting issue with Bootstrap3 where the label ("Name") seems to be aligned at the bottom of the <h2> tag (see the blue box in the image (highlighted by the Chrome dev tool).
(From the Bootstrap 3 documentation putting labels inside headings seem to be a suggested way)
I can't figure out how to vertically align the label in center of <h2>. vertical-align doesnt work on h2 it seems. This answer to another SO post suggests changing the line-height but that doesn't seem to be an intuitive approach since it increases the padding on both sides of h2 (basically increasing the size of the h2 block).
This label is inside a table cell whose code is as follows:
<td class="text-right"><h2><span class="label label-default vcenter">Name</span></h2></td>
(vcenter is the class I am trying to use to vertically align)
It looks like all solutions teach you how to vertically center your .label in the <td>. However, none of them takes into consideration the difference between top and bottom margins on the h2 element.
Basically, you're trying to vertically center with something that's not vertically centered. The only way to account for it is to raise the label with half the margins difference, which should be .5rem. So this will most likely to the job:
h2 > .label {
position: relative;
top: -.5rem;
}
If it doesn't, you have stronger CSS rules applying and I'll need to take a look at them. Feel free to change -.5rem to whatever works for you (in rem or px).
Another approach is to use any vertical centering technique and make the top and bottom margins equal on td>h2 elements:
td>h2 { margin-top: 1rem; margin-bottom: 1rem; }
After this, most of the other answers will work.
You can add display: flex to the headline tag and then center its children vertically:
h2 {
display: flex;
align-items: center;
/* Just for presentation */
background: #ececec;
height: 100px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<td class="text-right">
<h2><span class="label label-default vcenter">Name</span></h2>
</td>
add valign middle for td
<td valign="middle" class="text-right"><h2><span class="label label-default vcenter">Name</span></h2></td>
or
add this css
.table tbody>tr>td.vert-align
{
vertical-align: middle;
}
<td class="text-right vert-align"><h2><span class="label label-default vcenter">Name</span></h2></td>

baseline vertical-align, but at the top

I'm trying to get a vertical alignment similar to baseline, but at the first line of text rather than the last. Neither top nor text-top gets the alignment right. Any ideas? Thanks!
edit: This assumes that the font size is the same in the elements being aligned. See comment below by #FelipeAls on the accepted answer.
edit: now with code sample and picture:
What I'm trying to do is vertically align the text in several inline-block elements so that their baselines are all in the same position. I'd rather not do something like nudging things using margins and padding, because I find whenever I do that, I ended up playing whack-a-mole with the different browsers.
HTML:
<div class="foo">
<span>one</span>
<span>two two two two</span>
<span>three three three three three three three three three</span>
<button type="button">action</button>
</div>
<div class="bar">
<span>one</span>
<span>two two two two</span>
<span>three three three three three three three three three</span>
<button type="button">action</button>
</div>
CSS:
body {
font-family: sans-serif;
font-size: 12px;
}
button {
font-family: inherit;
font-size: inherit;
}
div {
position: relative;
width: 500px;
text-align: center;
}
div.foo, div.bar {
margin-bottom: 2em;
}
div span {
text-align: center;
}
div.foo span {
display: inline-block;
width: 50px;
vertical-align: top;
}
div.bar span {
display: inline-block;
width: 50px;
vertical-align: baseline;
}
div button {
display: inline-block;
width: 125px;
}
See http://jsfiddle.net/don01001100/3t8v5L1j/3/.
I'm afraid that you can only do that with CSS box-model, such as margin, padding.
This is because the different inline-block elements are aligned at the baseline, but they have different padding / margin settings, so their text is aligned slightly off vertically. If you change the padding and margin of the <button>s and the <span>s to be the same, then it should work.
EDIT1
Actually, now that I think of it, you might be able to manually set values to vertical-align in pixels. Experiment with it (including negative values) to see what you want. It will depend on the paddings and margins of the <span>s and <div>s.
EDIT2
Actually, vertical-align: text-top works pretty well for me:

Show Centered Text Next to Site's Icon

Complete noob here with HTML/CSS.
I'm trying to get something like this : http://imgur.com/Bc72V4M
Here is my code:
<div id="topbar">
<div class="image">
<img src="images/ghwlogo.png">
</div>
<div class="text">
<h1>TEXT TEXT TEXT TEXT TEXT</h1>
</div>
</div>
I've tried floating the div topbar, then display-inline but it never displays horizontally.
I'm so confused. Following tutorials is easy-peasy, but when you need to figure out how to do this yourself, it's completely different.
I think I'm missing a step somewhere. I feel like this should be really easy but it's not.
img {
display: inline;
vertical-align: middle;
}
.subhead {
display: inline;
vertical-align: middle;
}
<div>
<img src="http://dummyimage.com/100x100/000/fff"/>
<h1 class='subhead'>
TEXT
</h1>
</div>
I removed some HTML; I only add more when I can't think of how to get the effect with just CSS. You can add some back, but you may have to set display: inline on some inner elements then.
Generally, a few different ways of putting elements horizontally:
Floating: Removes it from standard flow layout, and may interfere with the root element's total height. Was previously the preferred method of placement but I feel like there are better alternatives.
Display Inline: Treats an element a bit like text. Cannot have a custom height or various other attributes.
Display Inline-Block: Often a "fix-all" for me when I want something laid out horizontally, but to have other styling aspects like height, border, etc.
Position Absolute: You can make a higher element a "relative element" for absolute positioning by setting position: relative on it. Like floating this takes it out of layout, but it can even overlap elements; useful for certain things. Don't rely on absolute pixel amounts too much.
In my case, once things are laid out horizontally, vertical alignment is the next issue. Remember that adding content could make this block very very tall, so you can't just say "vertical-align to the bottom of the thing". Think of all elements in the div as simply letters in a paragraph; for the smaller ones, you're telling it how to align that one letter. For the biggest ones, you're telling it where that "letter" is aligned compared to the others. So, it's important to set vertical alignment how you want it on the image as well.
EDIT: updated answer per #Katana314 answer. I've maintained the OP's markup.
#topbar {
width: 100%;
overflow: hidden;
}
.image {
display: inline-block;
vertical-align: middle;
border: 5px solid black;
height: 100px;
width: 100px;
}
.text {
display: inline-block;
vertical-align: middle;
}
Fiddle: https://jsfiddle.net/dgautsch/che0dtfk/
You could make the image and the text a separate div and then have both of them under the inline-block attribute. The text div would need to have a position: absolute attribute, though, for formatting purposes.
After viewing the Fiddle, you can adjust the left position attribute accordingly to generate space. Here is the link: https://jsfiddle.net/kuLLd866/.
HTML:
<body>
<div class="image">
<img src="http://gfx2.poged.com/poged/game_logo_default_fix.png?2492">
</div>
<div class="imagetext">
<h1>Text text text</h1>
</div>
</body>
CSS:
.image {
display: inline-block;
}
.imagetext {
position: absolute;
top: 50px;
display: inline-block;
}

Empty div vs div with text having inline-block property

Want to know the reason for this behavior.
CSS
div {
display: inline-block;
margin-right: 2px;
width: 20px;
background-color: red;
}
Empty div
<div style="height:20px;"></div>
<div style="height:40px;"></div>
<div style="height:60px;"></div>
<div style="height:80px;"></div>
behavior: element increases from bottom to top (height)
div with text
<div style="height:20px;">20</div>
<div style="height:40px;">30</div>
<div style="height:60px;">40</div>
<div style="height:80px;">50</div>
behavior: element increases from top to bottom (height)
see it in action: http://jsfiddle.net/8GGYm/
Basically it got to do with the way that vertical-align: is calculated. So if you put vertical-aling:bottom; attribute in the css then you will notice it will be the same with and without text.
you can read the this for more details.
When the div has no content, padding is not drawn in the box (i.e. when when 0, if there is content, the browser calculates where the padding would be). so there is a little difference in calculating with and without text.
Hope this is helpfull.
please see here: http://jsfiddle.net/dd24z/. By default text is vertical-align: top, but you can change that behavior:
div {
display: inline-block;
margin-right: 2px;
width: 20px;
background-color: red;
vertical-align: bottom;
}
http://www.w3.org/TR/2008/REC-CSS2-20080411/visudet.html#line-height
'vertical-align': baseline
Align the baseline of the box with the baseline of the parent box. If the box doesn't have a baseline, align the bottom of the box with the parent's baseline.
Add
vertical-align: bottom;
to your CSS. Hope it works as you want.
I guess this can be explained by the text alignment, independently from divs.
Text, when placed in a div, is vertically aligned to top-left by default. Those divs without text align beside each other (inline-block) expanding the page downwards. If you add another div, you'll see the second header going further down.
<h1>Empty div</h1>
Some text
<div style="height:20px;"></div>
<div style="height:40px;"></div>
<div style="height:60px;"></div>
<div style="height:80px;"></div>
continuing here
<h2>Div with text</h2>
Some text
<div style="height:20px;">20</div>
<div style="height:40px;">40</div>
<div style="height:60px;">60</div>
<div style="height:80px;">80</div>
continuing here
...
div {
display: inline-block;
margin-right: 2px;
width: 20px;
background-color: red;
}
Fiddle
In the above fiddle, you can see that the text line is the "guideline".
Maybe this is the explanation: once the divs have text in them, they will align it with the surrounding text and, if inexistent, then they align their bottom line.
I'm sorry, maybe not very clear but I hope you understand my view.