I'm noticing discrepancies between browsers in how the width of a TH tag is interpreted, specifically whether or not padding is included in the width calculation.
I am building a reusable library for quickly generating and styling tables (for tabular data, of course). This means that I have full control over the code I generate, but that I need to actually solve the problem versus finding a hack for a particular instance.
Simplest Description of the Problem
A TH in IE9 and FF is sized based on its padding + width (as expected). Chrome and Safari include the padding in the width, leading to undesirable results.
For example, if the cell is set to 16px wide + 4px of padding, IE9 correctly displays the cell as 20px wide. Chrome displays it as 16px wide.
Here is a JS Fiddle showing the differences: http://jsfiddle.net/CZnau/
You can see how the last cell is sized differently between browsers.
Notes
I am aware of box-sizing and even though the default is to not include the padding in width calculation of a cell, setting box-sizing: content-box explicitly does not fix the problem.
The fiddle shows a fixed layout table. I wish to use table-layout: fixed to handle display correctly in other scenarios. Specifically, my actual implementation uses text-overflow, wrapping management, and variable width layouts. In my testing using a fixed layout is the only reliable way to make all my requirements play together nicely. Plus, fixed layout tables potentially render more quickly.
I have tried setting the width explicitly on each TD, but this does not fix the issue (perhaps it conflicts with the fixed layout table?)
In case you want more details around why I need a fixed layout table, try this fiddle with and without table-layout: fixed and note the differences. With a fixed layout, the table is correctly sized to 100% and truncates text elegantly, even with a variable width cell.
http://jsfiddle.net/6GPmY/
Firefox doesn't support box-sizing: content-box; yet, not even in their Aurora Version.
Until then you can use -moz-box-sizing:
th, td {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 8px;
}
jsFiddle Demo
Related
I'm trying to understand the effect that margin has on two elements. I have the following HTML, see the dabblet:
<p>some text</p>
<pre>some code</pre>
I have the following CSS:
body { color: white; }
p { background: red; margin-bottom: 50px; padding: 20px; }
pre { background: purple; margin-top: 40px; padding: 20px; }
So I've given the paragraph tag a bottom margin of 50px, and I've given the pre tag a top margin 40px. I was expecting therefore to find 90px vertical distance between them, but only have 50px.
I understand that the margins are collapsing, and that if I want to fix this then I need to add display: inline-block to the pre tag. But that causes the width of the pre tag to collapse.
Again, I know that I can fix the width problem by adding width: 100% to my pre tag, but I've got padding on the pre tag (20px), so this causes my elements to be too wide. I know that I can use box-sizing to deal with that, but what an almightly pain in the crotch it is to have to mess about with width, display and box-sizing just to have the desired amount of vertical space between two elements. So I simply refuse to do any of that.
Instead, I've decided that I'm just going to add margin-top: 90px to my pre tag, which will guarantee that I've got the 90px space that I want.
My question is: Are there any browsers out there that don't collapse margins in the way the others do? Will I inadvertently end up with 140px space (90px from the top-margin of the pre tag + 50px from the bottom margin of the paragraph tag)? In other words, are margins collapsed reliably and consistently across all browsers, or is there a browser out there that does it's own thing?
It's hard to give a definitive answer to this question because it's very broad. "All browsers" is a lot of browsers. There could always be some fringe browsers you never heard of that handle this differently. It all depends on how the browser's CSS rendering engine was written.
That said, any browser that wants to be taken seriously will try to adhere the W3C specs, which have the following to say about margin collapsing:
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
Adjoining vertical margins collapse, except:
Margins of the root element's box do not collapse.
If the top and bottom margins of an element with clearance are adjoining, its margins collapse with the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block.
Horizontal margins never collapse.
Source: Box Model (w3.org)
I figured it'd be a nice addition to just put your code to the test in as many browsers as possible. I made a test page page of your html (slightly modified), with an absolutely positioned 50px high block that should fit right in between the collapsed margin, to make it easier to spot a difference:
http://files.litso.com/playground/margin.html
Then I ran this through browsershots.org to get screenshots of how browsers would display this piece of HTML:
http://browsershots.org/http://files.litso.com/playground/margin.html#
(I have no idea how long this will stay cached, but I guess you could always just run it again)
Interestingly, the positioning of the blue block is a few pixels off in a bunch of the screenshots. You can still tell the margins are collapsed correctly, but I do wonder what exactly the problem is with the positioning.
The only browsers that don't seem to collapse the margin correctly are Dillo 3.0.2 and Links 2.7 on Debian 6.0, neither of which seem to listen to padding or margin properties at all (nor to the absolute positioning for that matter). They would mess up your layout no matter what, and you shouldn't worry about it. People use browsers like these for a specific reason, and seeing your page exactly as you intended it to be seen is not one of them.
TL;DR: Yes, it's safe to say that all browsers collapse these elements reliably and consistently.
I noticed something odd with my CSS earlier. As you can see in my image below, I have a td element with padding set to 0. However, if you look to the left, you can see the green-tinted areas where there's about 10px of padding on the top and bottom, even thought Chrome says there is no padding. I didn't write the CSS, but I discovered that setting the box-sizing property to border-box is what seems to be causing this. But I can't really figure out how to get rid of it.
So where is this phantom padding coming from, and how can I get rid of it while still using border-box sizing?
EDIT: Here is a Fiddle that should demonstrate the behavior (at least in the latest version of Chrome). I can't figure out how to get rid of the padding unless I do something like table * { box-sizing: content-box; }, which I don't want to do.
I'm trying to accomplish something specific around platform constraints I'm under.
I created a somewhat self-explanatory jsfiddle of the problem at http://jsfiddle.net/MrV5M/4/
The specific problem:
On Chrome, the right border of the input box is cut off.
On Safari, the width of the content class cell exceeds the container so it spills over the border.
On IE9, the label doesn't float to the left of the content div
The main reason I care about Safari is because I'm working on a JQuery Mobile/PhoneGap app which is also a web app. I'm only supporting modern browsers, but this is driving me nuts. Normally I'd just use a table for the container, but the text-overflow: ellipsis styles on the content div don't work when inside a table. (Basically, I'm trying to keep the content to a single line and have ellipsis without enforcing a fixed width or calculating a width with Javascript)
Anyone have the l33t CSS skills to make this work? I sure don't... :)
Just add this CSS to your Stylesheet, and get peace of mind on your issue :D
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
You may not like this answer. I made some adjustments in the css which fixes Chrome and IE9 issues. Take a look,
http://jsfiddle.net/MrV5M/11/
There are many ways to do what you are trying to do, but if you insist on using 'flex' stuff which is largely un-supported (even in the majors see here), you'll need to add the vendor prefixes to flex.
e.g... -webkit-flex, -moz-flex
Also, I don't think you need to be setting widths on elements that have the flex property.. not positive though.
So your browser issues:
-IE doesn't support flex at all so you're label won't float unless you use a float.
-The reason your input/content is spilling over the container and getting cut off is not really anything to do with flex.. but the way css works.. setting an element to 100% width means setting it to the width of its parent. But by default, css doesn't count the padding/border-width as part of that width. So you end up getting 100% width plus the L/R padding and border. But, since you are only supporting modern browsers.. box-sizing:border-box; to the rescue. Google it for details, but putting it on your input element should do the trick.
I have an issue that terrorizes me in my sleep, unrelentingly . If you have an attainable solution and care to share it, please do; I'd like to have a normal night of sleep again.
On my latest project, there are multiple times when I will need to have 4 or 5 elements floated next to one another. Each element must be sized using percentages (%) but must also have border-right: 1px solid #000.
Once upon a time, I would normally size each element with percentages, then create a child element that would have all of the styling properties that the parent probably should have had, including the border-right. This solution isn't ideal, however, because it involves a lot of unnecessary markup.
A co-worker then directed me to another solution. When an element has a width that is sized using %s, and also needs to have border-right: 1px solid #000, apply margin-right: -1px as an offset. And while it works, it created another issue for me (which is why we're here, together, in union).
When zooming out in any of the major browsers (ctrl mousescroll, ctrl -), the floated elements that have been the focus-of-discussion tend to dance around a bit; the last element toggles between breaking to the next line and then snapping back. Please refer to the image below:
The reason this should be addressed is because the scope of the project has the potential of serving people from many different demographics (especially those who may need to scroll in, or out for that matter, to make the text larger or smaller). A very broad project, indeed.
How can I reach my goal highlighted in the example above?
How can I have 4 or 5 or more (or less) bordered elements floated next to one another, sized proportionally using %s, WITHOUT them breaking form?
You can use the experimental box model CSS3 declaration to have the borders detract from the elements width instead of adding on to it. This should prevent the problem. Quirksmode has a nice write up on it. It is supported by IE8/9 and current versions of webkit, opera and ff.
li {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
The basic issue here, I think, is that you're 'misusing' the width property - width is supposed to control inner boxes, not the size of outer boxes. That is, your borders are supposed to be added on to your boxes, not included in the calculated width.
The result is that you don't have many choices beyond either:
Using Javascript to do some fancy recalculation,
Seeing if you can trigger quirks mode and use the IE5 box model (NOT a good idea),
Replacing borders several background images in lots of stacked divs (not nice), or,
Floating 20% width containers, then putting width:auto divs (not width:100%) with borders in the parent floats.
I know solution 4 sounds horrible, and means non-semantic markup, but it's a common kludge and one that other developers will probably understand (too) well.
This may sound horrible, but why not use a background image to create the border?
.box_20_percent {
width:20%;
float:left;
padding:0;
background-image:url([one_pixel_colored_image]);
background-repeat:repeat-y;
background-position:right
}
This should leave the "border" out of the resize calculation altogether.
If you declare the border-width and negative margin in ems instead of pixels, there is no wrapping/jumping. I realize this may be cold comfort since it would compromise your design somewhat, but it works!
I'm trying to create a site which uses laterally-stacked "blades" of content. The element containing them is moved laterally inside a div with overflow-x: hidden to create the desired sidescrolling effect. This seems to be working fine: The element containing the "blades" is set to display: table; width: 100%; table-layout: fixed and each blade is styled as follows: display: table-cell; width: 601px; border-right: 1px solid white; padding: 10px. Finally, the nav element has width 621px, with no horizontal padding or margins.
It all seems simple enough, but I'm getting a very odd cross-browser bug: Firefox and IE9 agree on how the page looks, but Chrome has a different opinion. I've figured out what Chrome is doing, but I haven't been able to figure out why it's doing it.
The doctype's set and everything else seems to be working fine. Except for background-colors, the rules above are all I've defined in the stylesheet, and there are no inline styles. Here are some screenshots which illustrate the problem behavior.
Here's the page in Firefox - as desired, the right edge of the navigation bar aligns with the right edge of the content box.
Same in IE9.
In Chrome, the padding is subtracted from the width, creating the overhang shown above. I never set border-box anywhere in the stylesheet, nor do I see it in the computed rules in Chrome - it just says that the width is 581px, whereas it's 601px in the other two browsers.
[Note: I saw that there were other posts on padding issues, but none where Firefox and IE9 agreed and Chrome did something different.]
Edit Here's a JSFiddle link: http://jsfiddle.net/aCeAw/
This is just a bug in Chrome. When it computes column widths for table-layout: fixed, it incorrectly ignores cell padding. See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=652941 complete with spec quotes, and the almost-5-year-old WebKit bug report at https://bugs.webkit.org/show_bug.cgi?id=13339.
You may be able to work around this by using width styles on display: table-column elements, as discussed in the Mozilla bug report above. Alternately, you could add a first row with 0 height and no paddings, but the cell widths you want... I realize both of those mess with the actual site markup, which may not be an option in your case, of course.