In the following example, the <div> is smaller then its content.
Why? And how do I fix it?
.switcher {
border: 1px dashed green;
}
.switcher a {
padding: 30px;
background: orange;
}
<div class=switcher>
<a href=#>first</a>
<a href=#>second</a>
</div>
From the specs:
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.
Although padding can be applied to all sides of an inline element, but only left and right padding will have an effect on the surrounding content.
The <a> tag is an inline element by default. You can set it to inline-block, so that both horizontal and vertical padding will be respected. As an inline-block element is placed as an inline element (on the same line as adjacent content), but it behaves as a block element.
.switcher {
border: 1px dashed green;
}
.switcher a {
padding: 30px;
background: orange;
display: inline-block; /*new*/
}
<div class=switcher>
<a href=#>first</a>
<a href=#>second</a>
</div>
You can contain the the a elements by placing a overflow: hidden or overflow: auto to the switcher class
You can make <a> tags display block ... as anchor tags are not by default similar as <div> p h1 h2
<a> tag and span tag are inline tags. these elements remain inline until you apply some property to display as block.
so both display: inline-block and display: block will work.
Related
a:link,
a:visited {
background-color: #f44336;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
a:hover,
a:active {
background-color: red;
}
This is a link
In the above code if I set "display" to "inline" the link gets pushed towards upside. Why is it so?
First of all, your question is not a duplicate of Why is this inline-block element pushed downward? and the answer here (unlike that question) has nothing to do with vertical alignment. Nor will studying "Section 8 Box Model" of the CSS 2.2 spec enlighten you.
To understand what's happening here you need to understand about heights. The height of block containers and the height of line boxes, and how they interact.
Block containers, which includes among others display:block and display:inline-block elements have a height that's either the sum of the height of its block level box children, if it has any, or the sum of the line-heights of its stack of line boxes otherwise.
In the case of your example, the <body> element, which is a display:block block container has only inline-level children, regardless of whether the <a> element is display:inline or display:inline-block so its height is the height of the sum of the line boxes. Furthermore, unless the viewport is very narrow, we can simplify things further by assuming that all the text in the <a> element will fit on one line, and so the height of the <body> element is the height of the one and only line box that it contains. We have this:
You'll note that I haven't depicted the boundaries of the <a> element above. That's because its placement depends on whether it is display:inline or display:inline-block.
We now need to look at how line-heights are calculated from the content. For display:inline elements we have this in the section 10.6.1 Inline, non-replaced elements of the spec.
The height of the content area should be based on the font, but this
specification does not specify how. A UA may, e.g., use the em-box or
the maximum ascender and descender of the font.
and
The vertical padding, border and margin of an inline, non-replaced box
start at the top and bottom of the content area, and has nothing to do
with the 'line-height'. But only the 'line-height' is used when
calculating the height of the line box.
Put those together, and what it means is that the height of the line box in this circumstance is the height of the text, and that the padding you have: padding: 14px 25px; doesn't affect the height of the line box at all, when the <a> element is display:inline. If it doesn't affect the height of the line box, then it doesn't affect the height of the <body> element either. But the background of the text and its padding still get painted. So we have this:
display:inline-block is different. Here the 10.6.6 Complicated cases spec says:
For 'inline-block' elements, the margin box is used when calculating
the height of the line box.
So the line box contains the whole of the inline-block element, not just the content, but the padding, borders and margins as well. In this case we have
And we can see if we put them alongside one another, that the text is lower for display:inline-block, than for display:inline.
Block-level elements are vertically aligned depending on the upper side of the box.
Inline-level elements are vertically aligned in respect to the text baseline. That is why for block-level elements your top padding is taken into account, but not for inline-level elements.
I would recommend reading about the box model in the spec.
a:link,
a:visited {
background-color: #f44336;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
a:hover,
a:active {
background-color: red;
}
This is a link
In a nutshell:
An inline element has no line break before or after it, and it tolerates HTML elements next to it.
A block element has some whitespace above and below it and does not tolerate any HTML elements next to it.
An inline-block element is placed as an inline element (on the same line as adjacent content), but it behaves as a block element.
Please go through this article for more insights.
You should preferably use display: inline-block in this case.
a:link,
a:visited {
background-color: #f44336;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
a:hover,
a:active {
background-color: red;
}
This is a link
HTML:
<div id='container'>
<p>This is some text contained within a small-ish box. I'm using it as an example of how placing your floated elements in different orders in your HTML can affect your layouts. For example, take a look at this great photo placeholder that should be sitting on the right.</p>
<img src='image.gif'>
</div>
CSS:
#container {
width: 280px;
margin: 0 auto;
padding: 10px;
background-color: #aaa;
border: 1px solid #999;
}
p {
width: 100px;
}
img {
float: right;
}
Result: https://jsfiddle.net/y9Lqjm1f/
Why if the paragraph's width is small enough does the floated right element not appear at the top of the container div?
Because the img element is placed below the p element which follows the normal flow as a block element.
img's separate flow, which results from it having a float style applied, only begins below the p.
If you added another p below the img it would follow normal layout flow as if the img did not exist, like so: https://jsfiddle.net/mkarajohn/y9Lqjm1f/1/
In short, in order for the img to appear to the top, it has to be placed first in the markup, like so: https://jsfiddle.net/mkarajohn/y9Lqjm1f/2/
Also see this about float and block elements
In general:
Floated elements respect previous block elements' layout flow, meaning they appear below the previous block element
Block elements following the floated element disregard the floated element, and keep their normal layout flow as if the floated element did not exist.
p and img tags are block level elements. They create new line for next element. So, float: right; property in img apply in new line.
You can use display: inline-block; for both p and img tags.
codepen
I have a simple HTML vertical menu, with such a structure:
<div id="menu">
<div class="item">
...
</div>
</div>
I've set the .item div to be rendered as text elements, so they're ordered next to each other:
#menu div.item {
margin: 0px;
padding: 0px;
display: inline;
}
This kinda works:
However, I want to apply a :hover effect on each link, such as vertical black borders will come from sides and connect with the bottom dashed border:
So I did the following:
#menu div.item a{
padding: 5px;
border-width: 0px 1px 0px 1px;
border-color: transparent;
border-style: dashed;
}
#menu div.item a:hover{
border-color: black;
background: #B3D2FF;
}
But the link seems to be bigger than it's parent element. I didn't think this was possible:
What's wrong? Why doesn't the parent DIV stretch to be able to contain whatever's inside?
(not) Working fiddle.
Rest of the CSS:
#menu {
text-align: center;
margin: 0px;
padding:0px;
background-color: #CEE2FF;
border-bottom: 1px dashed #1868FF;
}
Add the following css:
#menu div.item a {
display: inline-block;
}
Before this code, the a tags are not being displayed as blocks and the container doesn't want to be friends with them.
The padding 5px you used on the a tag will be partially applied but only left-right in respect to other sibling inline elements.
You're trying to set padding to inline elements, which is visually not the desired. The padding on inline elements will refer to the textual line, but not in respect to the containing block-level parent.
Remember that padding can be set to block-level elements such as
<div>, <h1>, <p> etc...
One fix is to use some simple math and set line-height to your a
The other is to set your inline anchors as display-block elements,
doing that way your elements will act contextually as inline elements while being allowed to take block-level elements properties.
https://developer.mozilla.org/en-US/docs/Web/CSS/display
http://www.w3.org/TR/CSS2/propidx.html
Also setting just like that an inline any element to be inline-block is not the best choice and is not fully compatible with older browsers.
display-inline for span, a, b, i, s, q, u will work in all browsers,
but generally speaking span is the perfect one to be used in that case cause even if an inline element by properties is similar to div.
https://developer.mozilla.org/en-US/docs/HTML/Block-level_elements
https://developer.mozilla.org/en-US/docs/HTML/Inline_elements
From CSS 2.1 section 10.6.1 Inline, non-replaced elements
The vertical padding, border and margin of an inline, non-replaced box
start at the top and bottom of the content area, and has nothing to do
with the 'line-height'. But only the 'line-height' is used when
calculating the height of the line box.
The height of the block div is the height of the stack of line boxes, which in this case is the height of the one and only line box. Which means that if you want to contain the <a> with padding, you need to set the line-height of the <a> element.
Add to your CSS
#menu div.item a{
line-height:30px;
vertical-align:top;
}
Like this: http://jsfiddle.net/Z63gs/4/
You can try putting overflow:hidden; on your #menu item. http://jsfiddle.net/Z63gs/1/
This will just hide the extra fluff. I think your padding is making the <a> elements larger than you would like.
Elliot's answer is much cleaner than this.
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
Why isn't the image centered in the li? The dimensions of it is 25x25px.
#information-list li {
height: 50px;
line-height: 50px;
padding: 0 10px;
border-bottom: 1px solid #c1c0bf;
}
#information-list li img {
vertical-align: middle;
margin-right: 10px;
}
<ul id="information-list" class="flat-list">
<li>
<img src="images/test.png" />
<strong>Foo</strong>
</li>
...
Try this instead:
#information-list li {
height: 50px;
line-height: 50px;
padding: 0 10px 0 20px;
border-bottom: 1px solid #c1c0bf;
background:transparent url(images/test.png) no-repeat left center;
}
<ul id="information-list" class="flat-list">
<li>
<strong>Foo</strong>
</li>
...
It is vertically centered for me (tested your css/markup in Chrome/Firefox/IE)
Do you have a valid doctype?
You can read about vertical-align, and how it works here.
As commented by animuson, here is how you should use inline elements and vertical-align.
Essentially, you need to vertically align both inline elements, and you did it on one only.
You should also try to keep line-height properties on blocks that contain text.
Here's a JSFiddle example - I also included some proof that it is in fact centered
CSS
#information-list li {
padding: 0 10px;
border-bottom: 1px solid #c1c0bf;
}
#information-list li img,
#information-list li span{
vertical-align:middle;
}
#information-list li span{
font-weight: bold;
line-height: 50px;
}
HTML
<ul id="information-list" class="flat-list">
<li>
<img src="images/test.png" />
<span>Foo</span>
</li>
...
Here's a screenshot
W3C will give us a bit of insight.
www.w3.org - 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.).
The height and depth of the font above and below the baseline are assumed to be metrics that are contained in the font. (For more details, see CSS level 3.)
On a non-replaced inline element, 'line-height' specifies the height that is used in the calculation of the line box height.
www.w3.org - vertical-align:
This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element.
Note. Values of this property have different meanings in the context of tables. Please consult the section on table height algorithms for details.
The following values only have meaning with respect to a parent inline element, or to the strut of a parent block container element.
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.
The default blocks
The HTML you provided consists of 4 blocks which have these display properties by default.
<ul> - treated as a block
<li> - treated as list-item
<img> - is treated as an inline-block (placed as inline, but formatted as a block)
<strong> - treated as inline
Try to remember them. Though they have little impact on this particular scenario, it is good to know the defaults and what they do and what they are for.
See also
9.2.2.1 Anonymous inline boxes
Any text that is directly contained inside a block container element (not inside an inline element) must be treated as an anonymous inline element.