alignment box for inline-block non-replaced elements - css

Please run the demo:
* {
margin: 0;
padding: 0;
}
.body {
font-family: Microsoft Yahei;
font-size: 16px;
background-color: lightblue;
height: 400px;
width: 400px;
line-height: 2;
vertical-align: baseline;
}
.body span {
background-color: pink;
}
.body .inline-block {
display: inline-block;
background: orange;
height: 50px;
}
.inline-block.text {
vertical-align: text-top;
}
<div class="body">
<span>
words-g words words-g
<span class="inline-block text">with inline-block box child</span> words-g w
</span>
</div>
The point is that I set
.inline-block.text {
vertical-align: text-top;
}
According to the specification:
In the following definitions, for inline non-replaced elements, the box used for alignment is the box whose height is the 'line-height' (containing the box's glyphs and the half-leading on each side, see above). For all other elements, the box used for alignment is the margin box.
and in the section 'line-height':
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.).
So,in this case,.inline-block.textis a
block container element whose content is composed of inline-level elements
whose height is 50px and line-height is 32px
also is an inline non-replaced elements
And here is my question:
the box used for alignment is the box whose height is the 'line-height'
What is the above box point at in this case for .inline-block.text?
As the demo shows,I think it is the box with height 50px. However,the box's height is not the line-height which conflicts with the specification above. So,I was confused and don't understand the above sentence in the specification.
And if you think the above box is the box with height 50px,how do you explain the fact that height 50px is not the line-height 32px?
Please notice:
I just want to understand this sentence which is the box used for alignment is the box whose height is the 'line-height',so I can understand the vertical-align better.
I am not asking for a specific solution.
Whatever thanks for your help!

The statement
for inline non-replaced elements, the box used for alignment is the box whose height is the 'line-height'
does not apply to inline-blocks. Inline-blocks are not inline elements. Inline elements are elements with display: inline, and generate inline boxes. Inline-blocks are not inline boxes, but inline-level (the "-level" part is important!) block container boxes. Therefore, the statement
For all other elements, the box used for alignment is the margin box.
applies instead, which results in vertical-align: text-top causing the top outer edge of the inline-block to align with the top of the line box.
Any part of the specification that is said to apply to inline elements does not apply to inline-blocks.

I guess you are confusing about the reference of the alignment (it aligns relatively to what?).
I will try to explain this with easy words. When using vertical-align with an element a you align it relatively to its parent element b whataver is the height of a (b is the reference). Using correct words it's like this:
The vertical-align property can be used in two contexts:
To vertically align an inline element's box inside its containing line
box. For example, it could be used to vertically position an <img> in
a line of text.ref
So the a element is the inline element's box and the b element is the containing line box and the height of b is defined by it's line-height as you already read in the specification.
Now let's consider your code and add properties step by step.
Initially let's remove the inline-block
.body {
font-family: Microsoft Yahei;
font-size: 16px;
background-color: lightblue;
}
.body span {
background-color: pink;
}
.body .inline-block {
background: orange;
}
.inline-block.text {
vertical-align: text-top;
}
<div class="body">
<span>
words-g
<span class="inline-block text">inline-block</span> words-g w
</span>
</div>
As you can see the inner span has the same height/line-height as the outer span and both are using the same font-family. So logically we see nothing when using text-top as vertical alignment.
Now let's add line-height:2 to the container:
.body {
font-family: Microsoft Yahei;
font-size: 16px;
background-color: lightblue;
line-height:2;
}
.body span {
background-color: pink;
}
.body .inline-block {
background: orange;
}
.inline-block.text {
vertical-align: text-top;
}
<div class="body">
<span>
words-g
<span class="inline-block text">inline-block</span> words-g w
</span>
</div>
In this situation, both span will inherit the line-height:2 thus the computed value will be 32px (2 * font-size) and this will make the top reference different from text-top. To remind about this, here is a figure I shared with your beforeref:
And if we read the definition about the value text-top of vertical-align:
Aligns the top of the element with the top of the parent element's
font.
So the top of the inner span will align with the text-top of the outer span, that's why it moved to the bottom. Then the height of the main container .body will not be equal to 32px but it will be bigger because it will consider the movement of inner span (we will have 37px).
Now let's add inline-block to the inner element:
.body {
font-family: Microsoft Yahei;
font-size: 16px;
background-color: lightblue;
line-height:2;
}
.body span {
background-color: pink;
}
.body .inline-block {
background: orange;
}
.inline-block.text {
vertical-align: text-top;
display:inline-block;
}
<div class="body">
<span>
words-g
<span class="inline-block text">inline-block</span> words-g w
</span>
</div>
The first thing you will notice is that the text didn't move BUT the orange background is covering a bigger height. This is because our element will behave as block container and this height is the line-height of the text (32px) which is also the distance between the top and bottom in the image above (Initially it was covering from text-bottom to text-top).
It's also like the blue background of the .body element since this one is a block element. Try to make the .body element inline and see what will happen.
Now you can also add a specific height to the element and nothing will change because we align relatively to the parent element. You can also play with all the vaues of vertical-align to see the different behaviors:
.body {
font-family: Microsoft Yahei;
font-size: 16px;
background-color: lightblue;
line-height:2;
margin:5px;
}
.body span {
background-color: pink;
}
.body .inline-block {
background: orange;
}
.inline-block.text {
display:inline-block;
height:50px;
}
<div class="body">
<span>
Align the
<span class="inline-block text" style="
vertical-align: text-top;">top of this</span> with text-top
</span>
</div>
<div class="body">
<span>
Align the
<span class="inline-block text" style="
vertical-align: top;">top of this</span> with top
</span>
</div>
<div class="body">
<span>
align the
<span class="inline-block text" style="
vertical-align: text-bottom;">bottom of this</span> with text-bottom
</span>
</div>
<div class="body">
<span>
align the
<span class="inline-block text" style="
vertical-align: bottom;">bottom of this</span> with bottom
</span>
</div>

Related

How do I prevent multiline text from filling the entire width of the parent element

Suppose I have a container element that has a set width. I have a content element with a display inline-block that can contain some text. This text could be so big that it has to be filled over several lines. The problem with this is that default behaviour for multiline text is that it grows the element to the complete width of the parent element.
Imagine the following example:
HTML:
<div class="container">
<div class="content">
Firstreallongword11 Secondalsolongword22 Thirdwordthatisconsiderablylonger
</div>
</div>
CSS:
.container {
width: 260px;
border: solid blue 1px;
}
.content {
display: inline-block;
background: red;
}
Because these are long words, they will be positioned over multiple lines. What I would expect for the .content element, is that it would grow to the maximum width of the largest word on one single row.
But as you can see, because it consists of multiple lines, the element grows to the max width of .container .
FIDDLE
What I want to achieve is, .content gaining the width of the largest item on a single row, as it would with one single lin:
FIDDLE
Is there any way to achieve this with pure css/html?
The simple answer is: No, you can't do that with pure CSS.
But here is a solution anyway, which is a bit of a hack: It uses display: table-cell; for the .content element, and a rather small width value (which will adjust to the actual value of the longest word and acts like a min-width setting in this case):
.container {
width: 260px;
border: solid blue 1px;
}
.content {
display: table-cell;
width: 100px;
background: red;
}
<div class="container">
<div class="content">
Firstreallongword11 Secondalsolongword22 Thirdwordthatisconsiderablylonger
</div>
</div>

Why CSS text-align property centers block-level content?

I’ve got 2 questions.
1) Is the text inside the navigation links centered because I set the value of the display property of those links(a tags) to block and now it’s basically the same thing as if I was centering text inside a p element?
2) I set the display property of i elements(font awesome icons) to block too, so why are these elements centered as well? If you change the display property on the i elements to table, then these icons are not being centered. Shouldn’t block value behave the same as table in this case? As far as I know I can only use text-align to align inline and inline-block elements. So why is this working?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Text-align</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<style>
.cf:before,
.cf:after {
content: "";
display: block;
}
.cf:after {
clear: both;
}
body {
margin: 0;
font: 16px/1 sans-serif;
}
nav {
height: 120px;
background-color: #f2f2f2;
padding: 0 5%;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
float: left;
color: #a6a6a6;
border-left: 1px solid #a6a6a6;
}
li:last-child {
border-right: 1px solid #a6a6a6;
}
li:hover {
color: #de5728;
}
a {
display: block;
text-decoration: none;
color: inherit;
font-size: 10px;
text-transform: uppercase;
padding: 37px 0;
width: 136px;
text-align: center;
}
nav a .fa {
display: block;
font-size: 36px;
}
</style>
</head>
<body>
<nav>
<ul class="cf">
<li>
<a href="#">
<i class="fa fa-shield"></i> Domov
</a>
</li>
<li>
<a href="#">
<i class="fa fa-leaf"></i> Portfolio
</a>
</li>
<li>
<a href="#">
<i class="fa fa-bolt"></i> O nas
</a>
</li>
<li>
<a href="#">
<i class="fa fa-trophy"></i> Kontakt
</a>
</li>
</ul>
</nav>
</body>
</html>
Yes. Block containers can have text-align applied, which aligns their content.
Block-level elements in normal flow take up the full width of their containing block, which in your example is the width of the content box of the li elements.
The content box width of the element is calculated according to this equality:
'margin-left' + 'border-left-width' + 'padding-left' +
'width' +
'padding-right' + 'border-right-width' + 'margin-right' =
width of containing block
In your example, the margins and paddings resolve to 0, and the borders to 0 or 1 pixels. The containing block is provided by the <a> element and the remainder of its width is the content box width of the <i> element when it is display:block.
The text-align property is inherited, so the <i> element takes on the alignment and centres its content within the width of its content box, the content for the <i> element being provided by fontawesome via the :before pseudo-element.
Table elements are block-level, but they resolve the equality differently. Instead, the width of their content box is shrink-to-fit, and any remaining width of the containing block is, in your example, given to the right margin instead.
This puts the table over to the left side of its container, and the content (again the generated content from fontawesome) goes tightly inside that. The anonymous table cell created inside the table still inherits the text-align setting, but there's no space either side of the content for it to move in. So it too appears to be on the left side of the floated <li> element whose width is determined by tightly wrapping the <a> element inside it.
Yes. block level (and inline-block with a width) can have text-align:center applied.
the i elements will inherit from their parent, the a tag, and so will also be centered.
Display block and table are very different to each other in that the child elements are rendered differently, i.e children of a table would likely be display:table-cell.
Also, text-align really makes no sense on inline elements.

How to make <div> inline? All <div>, even when their total width more than width of their parent?

I need to make <div> displayed inline and hide them with "overflow: hidden" for their parent.
Width for <div> is set to 20% with "box-sizing" property, so they are exactly 20% of their parent width.
The usual method, using "float: left" doesn't help, because it makes only 5 <div> displayed in one line, and the rest of them shown in new line under the first 5 <div>.
How to make all <div> displayd inline and hide the rest of them if they are too wide to be shown inside of their parent, using "overflow: hidden"?
I have the following document structure:
<body>
<div class="column">
<div class="header">Some text</div>
<ul class="item_list">
<li class="simple">Some text<br></li>
<li class="simple">Some text<br></li>
<li class="simple">Some text<br></li>
...
</ul>
</div>
You can see what I mean here. But I've made it using javascript (setted for <div> "position: absolute" and generated "margin-left" for each elemet) and it causes great problems for future development.
DEMO: http://jsfiddle.net/marcuswhybrow/7YDfE/3/
Use display: inline-block and white-space: nowrap in combination:
<div class="wrapper">
<div class="inline"></div>
<div class="inline"></div>
<div class="inline"></div>
</div>
Then use the appropriate CSS:
div.wrapper {
width: 200px; /* or whatever */
overflow: hidden;
white-space: nowrap;
}
div.inline {
display: inline-block;
}
The demo contains a little jQuery animation to illustrate the effect:
DEMO: http://jsfiddle.net/marcuswhybrow/7YDfE/3/
If the div elements are display: inline then applying white-space: nowrap; to the parent element will prevent their wrapping to new lines.
Since you have a known number of divs, have you tried using absolute positioning instead of floats, and specifying left:20% left:40%, etc.?
If you set the container div's height to a fixed value, and give all the inner elements display: inline-block, this should do the trick. inline-block will make each element align to the left, but keep it's dimensions, while the fixed height container will hide any that overflow to a new line.
This will do what you want with the addition of removing the white space between while allowing nice code formatting. The container gets font-size:0px ftw.
Markup
<div class="wrapper">
<div class="inline">Some text </div>
<div class="inline">Some sample text </div>
<div class="inline">Some Other text </div>
</div>
CSS
div.wrapper {
width: 250px; /* or whatever */
overflow: hidden;
white-space: nowrap;
border: 1px solid red;
font-size:0px;
}
div.inline {
display: inline-block;
width: 80px;
height: 20px;
background-color: black;
color:white;
margin: 0; padding: 0;
border: 1px solid blue;
font-size:12px;
}

How do you align a block item to the right edge of its parent (with CSS)?

I am aware that you can center a block item by setting the left and right margin to auto.
However, is it possible to align it to the right edge? And how would this be done?
Edit: without using float: right (because it doesn't seem to work, at least not with <ul>'s)
Edit again: Here is a snippet of the code:
<td style='vertical-align: top; text-align: center;'>
<b>Choices:</b><br><br>
<ul id='orderchoices' style='margin-left: auto; margin-right: auto;'>
...
</ul>
</td>
Here is the style for #orderchoices
#orderchoices li {
border: 1px solid #666;
background: #333 url(images/dark_gloss.png) repeat-x;
color: #eee;
margin: 3px;
padding: 5px;
cursor: pointer;
width: 160px;
font-style: italic;
}
I want the ul right-aligned in the td
<div class="outer">
<div class="inner">I'm the inner element!</div>
</div>
<style type="text/css">
.outer { position:relative; }
.inner { position:absolute; right:0px; }
</style>
If your inner element is positioned absolutely within a container that is positioned relatively, you can use top, right, bottom and left to indicate the inner element's distance from the edges of the parent container.
Make sense?
To right align a block element to its parent try using float.
Remember to add an element after to clear the float so the bottom of the parent respects the bottom of the floated element.
<div id="parent">
<div style="float: right">
<div>your stuff here</div>
</div>
<div style="clear:both"></div>
</div>
The 'position: absolute' method can also work, but when an element is positioned this way it is removed from the flow of html, thus its parent does not know the height of the absolute positioned element - hence the reason it might slip off the end of the page. You can overcome that by setting the height on parent but that of course relies on the fact that a) you know the height before hand, b) it won't change

Vertically align text inside an element with a percentage height?

As I have an element with a percentage height I can't use the line-height hack. Does anyone have any ideas on how to solve this?
<div height="100%">
I want to be vertically aligned in the middle
</div>
Here's what you want: http://www.jakpsatweb.cz/css/priklady/vertical-align-valid-solution-en.html
You have to set the height value of div, then set line-height: value_of_div_height. line-height 100% won't work because it will take value of text, not div element. It works with or without vertical-align, as long as height=line-height
div {
height: 200px;
line-height: 200px;
display: block;
}
Alternative method if you want to do with a paragraph inside a div element: http://www.w3.org/Style/Examples/007/center
DIV.container {
min-height: 10em;
display: table-cell;
vertical-align: middle }
...
<DIV class="container">
<P>This small paragraph...
</DIV>
If you set the font-size, and you know the number of lines of text you have.
You can wrap the text in a span. And use the following CSS on the span.
span {
font-size:20px;
margin-top:-10px; //half the font-size (or (font-size*number of lines)/2)
position: relative;
top: 50%;
}

Resources