3 inline-block divs with exactly 33% width not fitting in parent - html

This is a common problem but I can't figure out why it happens.
I have a parent div and inside that div I have 3 divs with width set to 33% (exactly, not 33.3%!) and display: inline-block.
In Chrome it works well, but in Mozilla and Opera it does not (I didn't test it in IE yet). I thought the problem might be in the algorithm browsers use to calculate pixel sizing from percentages. But when I checked the DOM metrics, I found that the parent's width is 864px and the child's is 285px (that's correct: 864 * .33 = 285.12). But why doesn't it fit in the parent? 285 * 3 = 855, that's 9px less than parent's width!
Oh, yes, padding, margin and border for all divs set to 0 and DOM metrics confirm that.

Whitespace in the HTML source code
In the HTML source code, When you have lines of text or images, or elements that are inline-block, if there is any whitespace between them (blank spaces, tabs, or new lines), a single blank space character will be added between them when the page is rendered. For example, in the following HTML, a blank space will appear between each of the four pieces of content:
one
two
<img src="three.png"/>
<span style="display: inline-block;">four<span>
This is very helpful for lines of text, and for small images or HTML elements that appear inside a line of text. But it becomes a problem when inline-block is used for layout purposes, rather than as way to add content inside a paragraph of text.
Removing the extra space
The safest, cross-browser way to avoid the extra 4px or so of space that's added between inline-block elements, is to remove any whitespace in the HTML source code between the HTML tags.
For instance, if you have a ul with 3 floated li tags:
<-- No space, tabs, or line breaks between </li> and <li> -->
<ul>
<li>...</li><li>...</li><li>...</li>
</ul>
Unfortunately, this hurts the maintainability of the website. Besides making the code unreadable, it severely compromises the separation of data and formatting.
If another programmer comes along later and decides to put each li tag on a separate line in the source code (unaware of why the tags were on the same line, or possibly running it through HTML Tidy and not even having a chance to notice any related HTML comments), suddenly the website has a formatting bug that may be difficult to identify.
Consider floating elements instead
The whitespace behavior strongly suggests that it may be inappropriate to use inline-block for general-layout purposes, to use it for anything other than adding content inside the flow of a paragraph of text.
Plus, in some cases inline-block content is very difficult to fully style and align, especially on older browsers.
Quick summary of other solutions
Put the close tag on the same line as the next open tag, with no white space between them.
Use HTML comments to fill all of the whitespace between the close tag and the next open tag (as #Arbel suggested).
Add a negative left margin to each element (usually -3px or -4px, based on the font-size). I don't recommend this particular approach.
Set the font-size for the container element to 0 or 0.01em. This doesn't work in Safari 5 (not sure about later versions), and it may interfere with Responsive Design websites, or any website that uses a font-size unit other than px.
Remove whitespace-only text nodes from the container using JavaScript or jQuery. This doesn't work in IE8 and earlier, as text nodes are not created in those browsers when there's only whitespace between elements, though space is still added between the elements.
Set letter-spacing and word-spacing for the container (as #PhillipWills suggested). Further info. This requires standardizing em sizes on the website, which may not be a reasonable option for all websites.
Add text-space-collapse: discard; to the container (previously called white-space-collapse). Unfortunately, this CSS3 style is not yet supported by any browsers, and the standard hasn't been fully defined.

If you don't want to mess up the HTML formatting e.g. having all the elements with inline-block written in one line for future readability and also get rid of the extra white space that is added between them, you can "comment" the white space.
For example in your code this will solve the problem, it will even work with 33.3% instead of 33%:
.parent {
width: 100%;
}
.child{
display: inline-block;
width: 33.3%;
}
/\
<div class="parent">
<div class="child">bla-bla1</div><!--
--><div class="child">bla-bla2</div><!--
--><div class="child">bla-bla3</div>
</div>

A space is added between the inner divs. There is some CSS voodoo to correct this problem:
div {
letter-spacing: -.31em;
word-spacing: -.43em;
}
div div {
letter-spacing: normal;
word-spacing: normal;
}
Of course, you'll probably prefer to use classes or something to differentiate between parent and children.

Add float:left;
.parent{
width: 100%
}
.child{
float:left;
display: inline-block;
width: 33%
}
http://jsfiddle.net/H6Whc/1/

Has anyone tried display: table? If that's not a good idea, why not? This works in all modern browsers and I tested it down to IE9.
.parent{
display: table;
width: 100%;
}
.containers {
box-sizing: border-box;
border: 1px solid #000;
height: 50px;
width: 33.3%;
display: table-cell;
}

This is a mentioned by a number of comments and by #Avin, but removing display: inline-block and replacing it with float: left works.
.parent{
width: 100%
}
.child{
float:left;
width: 33%
}

This is a common problem, but it can be sorted out very easily by assigning the display: table CSS property to the parent div.

Related

How can I work around this IE11 layout bug related to table-cell, text-decoration, and padding?

It seems I've stumbled on an annoying Internet Explorer 11 layout bug. (Ugh, I thought these days were behind us.)
In the following example, the padding on the right table cell disappears when you hover over it in IE11:
http://jsfiddle.net/xx4Z4/
This seems to arise because of an incredibly specific CSS scenario:
The element uses display: table-cell
The element uses percentage-based padding, e.g., padding: 0 5%
A subelement adds text-decoration: underline when the parent element is hovered over
If you change any of those three things, the problem goes away.
This seems to be an IE11 bug, but I'm wondering: Can anyone think of a workaround for this problem without abandoning display: table-cell and percentage-based padding?
Again a IE11 problem that seems so unusual. I see that the percentage padding is not even calculated and is not applied in the layout. However the text is still padded according to the padding percentage. So i would assume the text is positioned with the padding but after the positioning the percentage padding is "disabled".
I can't tell you why this happens. But if you really want to fix these you might want to use these quick fixes.
Use margin
Because the percentage bug only occurs on the padding of a table-cell, you can actually use a margin on the span itself.
span
{
margin-left: 10%;
}
and ofcourse reset the padding of the sides:
div.table-cell {
display: table-cell;
padding: 20px 0;
}
This "solution" is not as dynamic as with percentage padding on the table-cell itself.
Why not?
It's because the percentage takes is value from it's parent element, the table-cell. Where as the table-cell did take it's percentage value based on the tabel. Now when you would just use left-margin: 5%;. It would be half of the space as it should be. This is because it take the 10% on the table-cell width. Where the table-cell width is table width devided by its cells(table width / table cell).
So to fix that i did 5 times the amount of cells (5 * 2 in this case), which would result in the right percentage.
However this is not dynamic when you want to add more cells.
jsFiddle
Use border
Use border which its position is "reserved" before the padding is resetted.
Reserved border
span
{
border-bottom: 1px solid transparent;
}
Change property that doesn't need re-calculation of position; color
div.table-cell-bug:hover span
{
border-bottom-color: black;
}
Now note that there will still be no padding in the layout. As soon as a property is assigned which has not been calculated before the padding did reset(the same time the text position is determed) the positions will be re-calculated.
jsFiddle
I hope one of these quick fixes work for you.
I see you sended a bug report to MS. Keep us up-to-date when you get a reply, i would appreciate it :)
Strange, no one mentioned to set table-layout:fixed; It's really important, otherwise the padding/width won't be calculated correctly on IE (and some other weird side-effects, depending on the use case), especially when you are using images inside it.
<style>
.table { display:table; table-layout:fixed; }
.table-cell { display:table-cell; }
</style>
<div class="table">
<div class="table-cell"></div>
<div class="table-cell"></div>
<div class="table-cell"></div>
</div>
Adding invisible top and bottom borders seems to fix the problem.
a {
border: solid rgba(0,0,0,0);
border-width: thin 0;
}
This prevents the anchors from moving on hover or focus.
I use rgba(0,0,0,0) instead of transparent for better compatibility with old IE which displays transparent in colour while rgba is rendered invalid and not displayed at all.
We had a similar scenario where none of the solutions above worked.
Instead we animate the width of our affected div after the page has loaded:
if (!!navigator.userAgent.match(/Trident\/7\./)){
$("#karina-rosner2").animate({'width': '20.1%'},1);
$("#karina-rosner2").animate({'width': '20%'},1);
}
This forces IE11 to recalculate the div's relative padding value and solved our problem well.
This can be "helpfully" solved by setting the paddding css-rules like this ->
element:hover,
element:active,
element:focus {
// padding example
padding-left: 1.5%;
}
Rememeber to set this only for IE since it can make all normal browser behave like a disco.
EDIT: Flexbox works for IE 10 and above so this "solution" is only needed for ie 9 and below.
These are all really good answers, and the media query option works well to identify only IE which has this problem with display:table-cell
What I did that I found worked well was employ vertical-align as a great way to direct the text contained within the display:table-cell element to where I wanted it to reside. Usually vertical-align doesn't do much to formatting, UNLESS it is in a table.
Here is my simplified HTML:
<li id="table-cell-element">
<a href="#">
<img src="event.png"/>
<small>Register for Event</small>
</a>
</li>
And here is the CSS:
#media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
li {vertical-align:middle; display:table-cell; width:15%; font-size:1.2em; line-height:1.2em; padding:2%; margin:0;}
li a {display:inline-block;}
li img {display:inline-block; vertical-align:middle; padding-right:5px; float:left; max-with:30px;}
small {display:block; font-size:60%; font-weight:bold; color:#333;}
}
You may also have to adjust the li a:hover {line-height} depending on what is in your CSS for those elements
Also, if you want this to work for IE 9 and below I suggest using conditional comments that add an "ie" class to the <html> tag and then create an IE9 style sheet. Thankfully the styling required for IE9 is relatively the same. But I only tested through IE9 and I am uncertain of your results for IE8 and IE7.

Space under <img> tag

I have this annoying space under my picture for no reason.
I'm using www.getskeleton.com as the framework.
HTML code
<div class="four columns bottom">
<div class="box">
<img src="images/picture.png" title="" alt="">
</div>
</div>
CSS code
.box{
border: 1px solid #bfbfbf; /* ---- Border OUTSIDE*/
}
Although I'm sure this has since been resolved, I believe none of these answers are correct (or at least, the link from the "accepted" answer is dead).
The way to deal with this spacing issue (and why it isn't set in util libraries like normalize I'm not sure) is vertical alignment of the image. This'll solve it for HTML pages when using the HTML 5 doctype. Oddly, when using e.g., HTML 4.01 doctype, images will not exhibit this errant space below behaviour.
The fix:
img {
vertical-align: top;
}
I hope that helps someone who may have run into this problem.
Edit: Some extra info I noticed after writing this and subsequently researching why normalize doesn't set alignment on the img tag; the default alignment for images is vertical-align: baseline; - that's the behaviour which introduces the space underneath. Normalize's author believes this behaviour is consistent cross-browser, and so has decided not to 'normalize' this. I suppose that makes sense if you wanted text sitting next to an image to align properly with any subsequent lines of text. Some people also prefer to use vertical-align: middle as opposed to top to address this issue - so you can vary this as you wish.
However, regarding baseline alignment, in the case where I had an image that was so big that it was higher than the line-height, I'd probably be floating it or some other behaviour anyway... but there you go.
I've used the vertical-align stuff for a while now without any incident. But as always, do ensure you test for any repercussions for images no longer being aligned to the baseline.
Try this:
.box img {
display: block;
padding: 0px;
margin: 0px;
}
Try this: .box { font-size: 0; }
Your image need to be floated. Try this:
#yourimage{
float: left;}
As mentioned, more information would help a lot but i have no doubt that it is padding that is causing the border to go out of the image, reason put very simply being
margin pushes outside the element
padding pushes inside the element
as it were.
Fix then:
.box {
padding-bottom: 0px;
}
//to be sure that the image doesn't have any padding, even though OP said the .box img fix didn't help
.box img {
margin-bottom: 0px;
}
It's an age old quirk - the whitespace from your line formatting is causing the gap. Add
<br /> after the image.
Try this
.box{
display:flex
}

Horizontal line inline-block IE7

I would like to put 3 horizontal line in a row.
Does anyone know how to put an horizontal line displaying in inline-block in IE7 ?
Here is my CSS:
hr.small {
width: 28.9%;
margin-right: 6px;
display: inline-block;
vertical-align: top;
zoom: 1;
*display: inline;
height: 3px;
border: 0px;
color: #7c8690;
background-color: #7c8690;
}
but it doesnt works.
here is the JSFiddle Link: http://jsfiddle.net/sRuz3/6/
If anyone has a solution.
Thanks a lot.
Here you go: http://jsfiddle.net/eq3Z2/
It works in IE7 also.
Granted, they aren't HRs. They are DIVs. Trying to render the HR as an inline element
is tripping up IE7 but I don't know of a workaround.
Does it have to be inline-block? Can you not simply float them and set a height if necessary?
Edit - Example:
hr.small {
float:left;
width: 28.9%;
margin-right: 6px; /* Choice: Use border instead or halve the margin for IE7 and lowwer (double margin float bug). */
height: 3px;
background-color: #7c8690;
}
Edit again - Question:
Is this going in a fluid layout and how big is the container? You are setting a dynamic width but a fixed margin, this will cause issues in small scale and introduce unwanted white space to the far right in large scale. If it is a fixed area then consider using a fixed width.
It seems there's a solution if you can wrap the hrs in divs.
Set the div's to display:inline (we could use spans instead but hrs are not valid in spans)¹ and also give the divs hasLayout via zoom:1
See http://jsfiddle.net/YqKDJ/1/
¹ As an aside, there's a reason why hrs are not valid in spans and it's relevant here. An hr is not primarily a way of drawing a horizontal line - it has a specific semantic meaning of "Thematic break". It makes no sense to have two or more hr elements with no content betwwen them - there's nothing for the second thematic break to break from. If you want multiple horizontal lines for presentational purposes, you should use CSS to create them, along the lines of #Cynthia's answer.

Cannot make 3 column layout work within list for IE7

I am trying to create a liquid 3 column area within a list item. To achieve this, I use the standard method of having 3 elements, of which the first two are the sides, floated left and right, and the 3rd is the content, which should sit between the two. The following HTML works fine in Firefox, but doesn't render correctly in IE7 - the content is rendered below the two floated elements. Any ideas what the problem is?
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
*
{
margin: 0;
padding: 0;
border: 0;
}
span
{
display:block;
}
.corner
{
width: 12px;
height: 12px;
}
.tl
{
float: left;
}
.tr
{
float: right;
}
.fill
{
margin: 0px 12px;
}
</style>
</head>
<body>
<ul>
<li>
<span class="tl corner">a</span>
<span class="tr corner">b</span>
<span class="fill">text text text</span>
</li>
</ul>
</body>
</html>
Note that replacing the spans with divs results in the same effect. I've also tried various DocTypes with no luck. And it works fine outside of the list, hence the problem appears to be intrinsic to using the list.
The way IE sees it, you're trying to jam in the lines one after the other, but the first two have already taken up their space, FLOATing away, which leaves the last SPAN in the LI to fight for the next level, which in IE looks like the next level below.
Since the last SPAN is not floated, that's also why it gets knocked to the next level.
Also, SPANs are inline styles, not block level elements. You should replace SPAN with DIV is you still want to try and style this in a LI element.
You should also use a full DOCTYPE so the browsers will know how to render the page. Otherwise they will default to quirks mode, ugly and all over the place.
But the better tactic is to create this float of 3 columns outside of the LI and in a DIV setting.
Have a read of CSSplay or Max Design on creating 3 column layouts.
It's a bit difficult to say anything without seeing the markup, but why don't you just put the two elements which should float inside the content element? You would have to adjust with some padding on the content element, but that should do the job. Then again, not quite sure what you mean. If you supply us with a bit more markup, it would be easier to tell.
The center block should have margins to either side allowing room for the floated blocks.
The answer is to wrap the spans in a block level element (say, a div), with overflow set to hidden. Example came from a more in depth look at the 2nd CSSplay example.

How do I keep a DIV from expanding to take up all available width?

In the following HTML, I'd like the frame around the image to be snug -- not to stretch out and take up all the available width in the parent container. I know there are a couple of ways to do this (including horrible things like manually setting its width to a particular number of pixels), but what is the right way?
Edit: One answer suggests I turn off "display:block" -- but this causes the rendering to look malformed in every browser I've tested it in. Is there a way to get a nice-looking rendering with "display:block" off?
Edit: If I add "float: left" to the pictureframe and "clear:both" to the P tag, it looks great. But I don't always want these frames floated to the left. Is there a more direct way to accomplish whatever "float" is doing?
.pictureframe {
display: block;
margin: 5px;
padding: 5px;
border: solid brown 2px;
background-color: #ffeecc;
}
#foo {
border: solid blue 2px;
float: left;
}
img {
display: block;
}
<div id="foo">
<span class="pictureframe">
<img alt=''
src="http://stackoverflow.com/favicon.ico" />
</span>
<p>
Why is the beige rectangle so wide?
</p>
</div>
The right way is to use:
.pictureframe {
display: inline-block;
}
Edit: Floating the element also produces the same effect, this is because floating elements use the same shrink-to-fit algorithm for determining the width.
The beige rectangle is so wide because you have display: block on the span, turning an inline element into a block element. A block element is supposed to take up all available width, an inline element does not. Try removing the display: block from the css.
Adding "float:left" to the span.pictureFrame selector fixes the problem as that's what "float:left" does :) Apart from everything else floating an element to the left will make it occupy only the space required by its contents. Any following block elements (the "p" for example) will float around the "floated" element. If you "clear" the float of the "p" it would follow the normal document flow thus going below span.pictureFrame. In fact you need "clear:left" as the element has been "float:left"-ed.
For a more formal explanation you can check the CSS spec although it is beyond most people's comprehension.
Yes
display:inline-block is your friend.
Also have a look at: display:-moz-inline-block and display:-moz-inline-box.
The only way I've been able to do picture frames reliably across browsers is to set the width dynamically. Here is an example using jQuery:
$(window).load(function(){
$('img').wrap('<div class="pictureFrame"></div>');
$('div.pictureFrame').each(function(i) {
$(this).width($('*:first', this).width());
});
});
This will work even if you don't know the image dimensions ahead of time, because it waits for the images to load (note we're using $(window).load rather than the more common $(document).ready) before adding the picture frame. It's a bit ugly, but it works.
Here is the pictureFrame CSS for this example:
.pictureFrame {
background-color:#FFFFFF;
border:1px solid #CCCCCC;
line-height:0;
padding:5px;
}
I'd love to see a reliable, cross-browser, CSS-only solution to this problem. This solution is something I came up with for a past project after much frustration trying to get it working with only CSS and HTML.