I'm messing around with everyone's favorite CSS topic, vertical alignment. I found a little case that makes no sense to me, which probably means I'm failing to understand something about CSS.
I have the following HTML (it's for exploration code, so please excuse the inline styles):
<div style="height: 40px; line-height: 40px; vertical-align: middle; border: 1px solid blue; margin: 1em 2em;">
<span style="background-color: Blue; height: 30px; width: 30px; margin: 5px 1em; display:inline-block;"> </span>
<span>Some text</span>
</div>
This displays a blue box and some text, both vertically centered. But if I replace the with a regular space character, the text in the other span is no longer centered. I created a JSFiddle that demonstrates this.
My question is - why does changing from an to a space character in the first span change the vertical alignment of the second span?
You are confused how the vertical-align property works. It doesn't apply to block-level elements. When it is set on a non-table-cell and non-inline element, the property is actually applied to all the inline text inside that element, not to the element itself.
When you use a regular space, the space isn't actually "rendered" by the browser because it's not really content. Therefore, the entire box becomes the line of text (since you're displaying it as inline-block) and the baseline is set at the very bottom of the parent against the black border at the bottom, which is why the text appears way down there.
When you use a non-breaking space, the space is content and does get render, which moves the baseline for the text up to where the text would actually appear inside the blue box. It's not actually centering the text. It's nowhere near centered on my screen. The baseline has just moved based on the content. You'll notice from this example that it also changes the line-height of the continuing text.
An easy way to fix this is to float the blue box to the left and then manually set a line-height for the rest of the text to follow. See the jsFiddle.
<div style="height: 40px; line-height: 40px; vertical-align: middle; border: 1px solid blue; margin: 1em 2em;">
<span style="background-color: Blue; height: 30px; width: 30px; margin: 5px 1em; float: left;"></span>
<span>Some text that continues on and on and on sothat you can see what is actually happening here blah blah blah blah blah</span>
</div>
The entity stands for non breaking space and is a variant of the space char.
They aren't the same.
In fact the entity prevents an automatic line break
Read more about at wikipedia
Moreover, the white space result as an "empty" span and that will cause that "bad behaviour"
May help?:
http://jsfiddle.net/mFryV/18/
Related
I'm working through a CSS problem at http://www.codecademy.com/courses/web-beginner-en-jNuXw/0/1?curriculum_id=50579fb998b470000202dc8b (actually, just helping a friend learn HTML/CSS) and came across a curious issue. If you erase the content in any of the <p> tags within a <div>, the div shifts upward. For example, delete the word 'Mom' without deleting the <p>. As best as I can figure out, this is because the element is set to vertical-align: baseline and for some reason the baseline is changing. I just can't figure out exactly why it's changing or what is causing it to change.
To be clear, I'm not asking for help to get the div's to align. That's simply a matter of setting their vertical-align to 'top'. I'm just trying to understand how the document flow is calculated. The specific question is: why does the empty div shift upwards?
DEMO: jsFiddle
UPDATE: Here is a new jsFiddle - http://jsfiddle.net/tonicboy/2DtTw/3/ which removes a lot of rules to boil the problem down to a simplified use case. From this, we can see that when a <p> tag has text in it, the baseline of the parent <div> is set at the baseline of the text. When you remove the text, the baseline of the parent <div> is set to the bottom of the <div>. Why is that?
HTML:
<div class="friend" id="best_friend"><p>Arthur</p></div>
<div class="friend"><p>Batmanuel</p></div>
<div class="friend"><p>Captain Liberty</p></div>
<div class="friend"><p>The City</p></div>
<div class="friend"><p>Justice</p></div>
<div class="family"><p></p></div>
<div class="family"><p>Dad</p></div>
<div class="family"><p>Bro</p></div>
<div class="family"><p>Sis</p></div>
<div class="family"><p>Rex</p></div>
<div class="enemy"><p>Baron Violent</p></div>
<div class="enemy"><p>The Breadmaster</p></div>
<div class="enemy"><p>The Deadly Nose</p></div>
<div class="enemy"><p>Dinosaur Neil</p></div>
<div class="enemy" id="archnemesis"><p>Chairface</p></div>
CSS:
div {
position: relative;
display: inline-block;
height: 100px;
width: 100px;
border-radius: 100%;
border: 2px solid black;
margin-left: 5px;
margin-top: 5px;
text-align: center;
}
div p {
position: relative;
margin-top: 40px;
font-size: 12px;
}
.friend {
border: 2px dashed green;
}
.family {
border: 2px dashed blue;
}
.enemy {
border: 2px dashed red;
}
#best_friend {
border: 4px solid #00C957;
}
#archnemesis {
border: 4px solid #cc0000;
}
I think I've mostly figured out the reason, after digging through W3C specs. Here are three key items from the spec which may explain this behavior:
"Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes for the purposes of determining the positions of any elements inside of them, and must be treated as not existing for any other purpose."
When you delete the text, the <p> element is no longer in-flow.
"The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge."
Because there are no in-flow elements within the parent div, the baseline becomes the bottom margin.
Because the div's are set to display: inline-block, their default vertical alignment is 'baseline'
Because the other div's have in-flow elements (the <p> tags), their baseline is set to the text baseline.
And that is why the empty box's bottom margin aligns with the baseline of the <p> tags in the other div's.
The baseline of the element is shifting because the text inside the <p> determs the baseline height:
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.
source: http://www.w3.org/TR/CSS2/visuren.html#block-formatting
The height of each inline-level box in the line box is calculated. For
replaced elements, inline-block elements, and inline-table elements,
this is the height of their margin box; for inline boxes, this is
their 'line-height'.
source: http://www.w3.org/TR/CSS2/visudet.html#line-height
CSS assumes that every font has font metrics that specify a
characteristic height above the baseline and a depth below it. In this
section we use A to mean that height (for a given font at a given
size) and D the depth. We also define AD = A + D, the distance from
the top to the bottom.
source: http://www.w3.org/TR/CSS2/visudet.html#inline-box-height
So with this block being a inline-block and baseline is calculted based on the line-height which is calcuted by different font types. Because this <p> has no font/text the baseline will not be positioned.
place all the line-height: 0; and you will see that the one with no text/font doesn't react like the other does:
jsFiddle
So why are the other two elemets shifting that have text in them?
Well it's because the text excist of two lines of text. The margin of the text is bigger and uses more space, thus the baseline is pushed further
I have a bunch of dynamically generated html (See Fiddle) that basically puts some ugly buttons on an ugly calculator in a grid, but when I try to replace an image with text in a span, the button moves down.
I'm not asking for a critique of the colors, but if someone could help me with the styling re:the alignment, that would be awesome.
Basically
<div><span>Text</span></div>
or
<div><div>Text</div></div>
appears 50% lower than:
<div><img src="url.jpg" /></div>
whereas:
<div>Text</div>
appears slightly above the image buttons in the grid if I don't mess with the font size, but:
<div style="font-size: 12px">Text</div>
moves it right back down to where the span had it.
The issue seems to occur independent of my javascript, as the attached fiddle has the same problem and no js in it (just the generated html and included css).
So yeah, any help other than, it's ugly?
Note: I chose display: inline-block intentionally for the buttons, to provide the autowrapping in the parent container. I'd prefer not to go to a position:fixed or position:absolute if that messes with the wrap around.
The alignment issue you're having is the expected result of using display: inline-block on your .button elements. Using inline-block elements basically makes the element act like a block element, but its bottom aligns as an inline element would. Take this for example:
<p>example example example <img src="something.jpg" /></p>
Which renders like this:
The image is inline with the paragraph. Notice that the bottom of the image aligns with the bottom of the text. This same thing is happening in your Fiddle – the bottom of the span text aligns with the bottom of the images (once you remove the relative positioning). You have inline elements inside inline-block elements, so the bottom alignment is naturally behaving like it would on inline elements.
Inline-block elements are extremely useful, but probably not in this scenario, where you have several distinct buttons, which are in themselves distinct elements. I would suggest doing this:
.button {
border: 1px outset;
background-color: #FACC43;
color: darkgreen;
display: block;
margin : 10px;
margin-right : 0px;
margin-bottom: 0px;
float:left;}
Make the buttons block elements by using display: block and float:left. They'll behave much more predictably as elements that are 30px x 30px on a common alignment.
If for whatever reason your really want to use inline-block, apply vertical-alignment: bottom to the .button style you currently have.
Both solutions I gave you will result in this:
You have quite a bit going on here, so I have simplified your code a bit to illustrate a few ideas to help clarify things.
Consider the following:
<div id="calculator">
<div class="button">Basic</div>
<div class="button"><span style="font-size: 30px;">Tall</span></div>
<div class="button">
<img src="http://placehold.it/28x28">
</div>
<div class="button">
<img src="http://placehold.it/28x28" style="vertical-align: bottom;">
</div>
<div class="button" style="height: 28px; width: 28px;">
<img src="no-image.jpg">
</div>
<div class="button" style="height: 28px; width: 28px;">
<img src="no-image.jpg" alt="alt">
</div>
<div class="button">
<img src="no-image.jpg" alt="alt">
</div>
</div>
and the following CSS (essentially your button style):
.button {
border: 1px outset;
background-color: #FACC43;
color: darkgreen;
display: inline-block;
margin: 10px 0px;
}
and the update fiddle: http://jsfiddle.net/audetwebdesign/j3SRn/
Going from left to right, I show 7 buttons, on inline-blocks.
Button 1, only text, the inline-block shrinks-to-fit, simple enough.
Button 2, increase font size, again, box shrinks-to-fit, and notice that the bottom of the text shares a common baseline with Button 1.
Button 3, 28x28 image, bottom of image is on baseline, notice gap below the image.
Button 4, same as 3 but use vertical-align: bottom and image sits slightly lower, bottom of line box.
Button 5, in this case, the image file is not present, so a 28x28 box is drawn around the non-existent image (0x0 px dimensions) and positioned in the middle of the line, which is why it projects upward.
Button 6, no image, but this time we have alt text, wrapped in a 28x28 box, so the text falls on the baseline and the border box bits around it and projects downward.
Button 7, no image with alt text, no box size, so border shrinks to fit on text that falls on the baseline.
I hope this gives you a flavor of how inline-blocks behave, quite a flexible element.
Can anyone explain the behaviour of the divs here http://jsfiddle.net/Z7z5Q/ ? I wonder, why they are not aligned on one line ? And why adding text to div moves other divs ?
Here is html and css:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<title>My Social Network</title>
</head>
<body>
<!--Add your HTML below!-->
<div class="friend">Some text in more than two line, actually in 3</div>
<div class="family">Some text in two line</div>
<div class="friend" id="best_friend"></div>
<div class="enemy" id="archnemesis"></div>
<div class="friend">Some text</div>
<div class="family"></div>
<div class="friend"></div>
<div class="family"></div>
</body>
</html>
Css:
div {
display: inline-block;
margin-left: 5px;
height:100px;
width:100px;
border-radius: 100%;
border: 2px solid black;
}
.friend {
border: 2px dashed #008000;
}
.family {
border: 2px dashed #0000FF;
}
.enemy {
border: 2px dashed #FF0000;
}
#best_friend {
border:4px solid #00C957;
}
#archnemesis {
border: 4px solid #CC0000;
}
Thanks. Will appreciate links to docs or articles.
The elements are aligned... but not in the way you intended it, obviously ;)
The key to your problem is the property vertical-align.
First remove border-radius in order to better see the boxes.
Then add vertical-align: middle;: problem solved (see fiddle)
Content or not, each box is now aligned relatively to its fixed height (you fixed it to 100px).
What happened in the first place without vertical-align: middle;? Change the value for baseline: you're back to the original problem. This is the default value, the one you do want when displaying text in spans for example or a label and the text of a text field, whatever the padding and margin on both. But with text forced to occupy 2 or 3 lines (boxes are 100px wide whatever their content), the baseline is very different from what you'd expect, it's the baseline of the content aka the last line of text.
Same with empty div: as they lack content to align with, their baseline is their bottom side (not so sure about this one, but that's what seems to happen).
Add a single character or a non-breakable space in some empty div: their baseline is now completely different from an empty div. See other fiddle
The same phenomenon happens with a tall image lost in a paragraph of text; you can align it with vertical-align but the difference is that it's easier to see what's happening. Here you haven't a single occurence of "normal" text so spotting it is a bit harder.
Why float: left; does work here? It'll take each box, all of the same height, and align it relative to the box, not to its content. But then you've to manage clearing and 1px more on a box can break the alignment of all the following boxes...
inline-block is an attribute with a number of curiosities. In this example, you can plainly see that removing height: 100px from the div CSS rules will result in the elements having their text aligned, which isn't so obvious with the flashy circle-shaped dashed multicolored borders. So to fix this, you would apply vertical-align: top. (source)
The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
(from a great answer from another thread)
In comparison, floats align at the top by default.
align on one line
div {vertical-align: middle;}
Adding a float:left; will solve this problem see here: http://jsfiddle.net/Z7z5Q/5/
Also adding vertical-align:top; will solve it as well: http://jsfiddle.net/Z7z5Q/7/
This is because inline-block behaves weird with white spaces in html.
I'm trying to understand why the line-height CSS property places the text vertically in the middle of this button:
.btn-order {
width: 220px;
height: 58px;
font-size: 24px;
padding: 0;
text-align: center;
vertical-align: middle;
line-height: 58px;
border: 1px solid black;
}
<div class="btn-order">Complete Order</div>
The line-height property is essentially setting a 29px (29 + 29 = 58) text line above and below your text, "Complete Order". If you added another line of text below this you will find it 58px below this text. You are putting line-height here only to center your text in the middle.
Here is a good slide show to help you understand this concept more... line-height
And here is an example using your code of what I am talking about: http://jsfiddle.net/YawDF/14/
By setting the line-height to 58px you are telling the browser to leave half this above and below the text line, creating a '58px' gap between each line and only a '29px' gap above the first line.
SIDE NOTE: Your use of vertical-align: middle is useless in the code you are showing. This can be taken out all together.
it is by design. If the CSS parser (i.e. the browser) doesn't know how tall is your text, he can't vertical align your text correctly.
Note there is a default value of line-height property.
line-height defines the height of text which make the paragraph looks neat so vertical-align works with respect to line-height when you increase the line height it increases the height and the you can more clearly see the effects of vertical-alignment of text
think this as a notebook which we children use to learn English -writing in nursery class
The text you generate is inside its own line box and vertical-align is used for placement inside that box. However, that box has nothing to do with the div you have wrapped around the text. You set the height of the div to 58px but that does not affect the height of the line text box. That is why you need line-height to match the height of the div.
Whenever a paragraph is inserted in a division the distance between the first line and the top border of the div is half of the line-height i.e if the default line- height is 1px then the distance between the first line and the top-border of the div is 0.5px.
If you have a division with height:58px the distance between the line and the top-border of the div is 29px and the distance between the line and the border of the bottom div would be=(total div height-distance b/w the line and the top border) which is 58px-29px=29px.This results in the line being vertically aligned at the center.
Also,there is no need to use vertical align:middle(for text containing not more than one line) if you're using line-height to centrally align the text.
How can I do this using CSS and HTML?
Bordered text surrounded by colored border
Bordered text's border minimally surrounds text
Bordered text has maximum width
Bordered text's border doesn't overlap neighboring elements
When rendered, it should look something like this:
For the border I'm using:
padding: 1.0em;
border-style: solid;
border-width: 2px;
background-color: #FFFFCC;
border-color:#E8E800;
If I apply the CSS to a <p>, then the border is as wide as the browser window. I want the border to only be as wide as the text (variable depending on the text size), so setting an absolute width using width doesn't work. I tried display:inline but that causes spacing issues with neighboring elements. I also tried applying the above CSS to a <span> contained within a <p>, but that doesn't work when the text is too long and wraps.
Have you tried experimenting with the CSS property called float? Specifying float: left causes the width of the containing element to adjust to the text - seems like a secondary effect but it works.
If you don't want the containing elements lining up, you can add <br /> tags or you can add "clear: both;" to the style.
I definitely think it's achievable - you just need to find the right combination of attributes/values.
You can get the highlighted paragraphs to minimally surround the text by making the highlighted paragraphs float left as block elements (<p> is by default). Then, get the paragraphs to clear:left to prevent them from stacking up horizontally.
The CSS:
.pars {
/* this is used to prevent the last floating element
from causing issues below the paragraph (.pars) container */
width: 100%;
overflow: visible;
}
.pars p {
clear: left;
margin: 0 0 0.5em 0;
}
.pars .highlighted {
float: left;
padding: 1.0em;
border-style: solid;
border-width: 2px;
background-color: #FFFFCC;
border-color:#E8E800;
}
Your HTML:
<div class="pars">
<p>Some paragraph text</p>
<p class="highlighted">Some bordered text</p>
<p class="highlighted">Some more bordered text</p>
<p>Some very long bordered text blah blah blah
blah blah blah blah blah blah blah blah blah blah</p>
</div>
Just add
p.highlighted {
float: left;
}
p {
clear: both;
}
This will cause the highlighted paragraphs to only be as wide as required by their text, and will ensure that existing paragraphs never overlap horizontally with the highlighted ones.
sounds like a table to me... oh, I can see the comments and down votes coming already. "tables are only for tabular data"... Yeah, I know but they are also a qnd way of doing exactly what steve wants to do.
what about display:inline-block?