I'm trying to add padding to an element inside a display:flex element. When the padding is defined as a percent, it doesn't display in Firefox, though it does when defined in px. Both cases work as expected in Chrome.
div {
background: #233540;
}
div > div {
color: #80A1B6;
}
.parent {
display: flex;
}
.padded {
padding-bottom: 10%;
}
<div class="parent">
<div class="padded">
asdf
</div>
</div>
Chrome:
Firefox:
Edit:
This may be because of Mozilla's decision to interpret vertical percentages with respect to the height of the parent container. Seems crazy to me. https://bugzilla.mozilla.org/show_bug.cgi?id=851379
Edit 2:
Yes, it appears that the spec actually defines vertical padding and margin as being resolved against the container's height, so perhaps Chrome is the one not honoring the spec?
https://drafts.csswg.org/css-flexbox/#item-margins
See https://lists.w3.org/Archives/Public/www-style/2015Sep/0038.html
Grid/Flex Percentages
The group tried to work through how vertical percentage margins
and paddings are defined.
Note: Top and bottom margins in CSS have traditionally
resolved against the containing block width instead of its
height, which has some useful effects but is generally
surprising. Existing layout modes must of course continue
to do so.
Previous group resolution had been for option 2 (below), but
Google felt they had new information regarding abspos
behavior that merited reconsideration.
The discussion came down to three potential solutions:
Option 1: Always resolve percents against the width.
Option 2: Grid and flex resolve against height, and
abspos items always resolve against the width.
Option 3: Grid and flex, including their abspos items,
resolve against the height. Abspos elsewhere
continue to resolve against the width.
In a straw poll the group was pretty evenly divided between
options 1 and 3.
Microsoft would object to option 1 and Google to option 3,
so the discussion reached an impasse and will be continued
privately during the F2F in hopes of reaching a conclusion.
See https://lists.w3.org/Archives/Public/www-style/2015Sep/0113.html,
Flexbox % Follow-Up
[...] there was still no conclusion.
The current Flexbox spec warns about this:
Percentage margins and paddings on flex items can be resolved
against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height)
the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current
state of the world (no consensus among implementations, and no
consensus within the CSSWG). It is the CSSWG’s intention that browsers
will converge on one of the behaviors, at which time the spec will be
amended to require that.
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in
different browsers.
However, more recently the CSS WG resolved (with some controversy):
Both flexbox and grid items top and bottom margin and padding percent resolves against the available inline direction.
See the updated editor's draft.
For me this does the trick: adding display: table to the div. Don't know if that causes other problems though.
div {
background: #233540;
display: table;
}
div > div {
color: #80A1B6;
}
.parent {
display: flex;
}
.padded {
padding-bottom: 10%;
}
<div class="parent">
<div class="padded">
asdf
</div>
</div>
Try this:
.padded {
padding-bottom: 10vw;
}
The current draft spec says
Percentage margins and paddings on flex items, like those on block boxes, are resolved against the inline size of their containing block, e.g. left/right/top/bottom percentages all resolve against their containing block’s width in horizontal writing modes.
So, Firefox is now incorrect according to the latest draft.
CSSWG discussion: https://github.com/w3c/csswg-drafts/issues/2085
Spec changelog reference: https://drafts.csswg.org/css-flexbox/#change-2017-margin-padding-percent
Current spec on flex item margins: https://drafts.csswg.org/css-flexbox/#item-margins
Related
As you can see in this simple example:
<div id="minheight">
<p id="margin">Paragraph with a margin</p>
</div>
<div id="sibling">Sibling div</div>
#minheight {
min-height: 100px;
background: red;
}
#sibling {
background: blue;
}
http://jsfiddle.net/peterbriers/B43th
There is a difference between Chrome (35) and Firefox (29) in how it handles the collapsing margins on a block with a min-height that is larger than the child's margin.
I tried to fully understand the specifications: http://www.w3.org/TR/CSS2/box.html#collapsing-margins , but I'm still unsure which browser handles this correctly. I would say Chrome is in the wrong, but Safari (7) does it the Chrome way too.
Which browser is correct, and how can I file a bug for the one that isn't doing it the right way?
BTW: I'm not asking any fix by adding new block formatting context (adding overflow property)...
OK, so this seems to be a very peculiar case.
If you change min-height to height, the gap disappears in Chrome. Not only does Safari behave the same as Chrome, but so does IE. Firefox's behavior is unique to itself, and its behavior does not change when you make that adjustment to your CSS. This should come as a surprise, as you would not expect min-height and height to behave any differently in your given scenario.
However, the spec has something interesting to say about min-height with respect to margin collapsing:
The following algorithm describes how the two properties influence the used value of the 'height' property:
[...]
These steps do not affect the real computed values of the above properties. The change of used 'height' has no effect on margin collapsing except as specifically required by rules for 'min-height' or 'max-height' in "Collapsing margins" (8.3.1).
Because you have not specified a fixed value for the height property on the same element that has a min-height, the computed value for height remains the default auto, even though the used value is floored to min-height.
Therefore the following text from section 8.3.1 applies, and the margins between the block box and its child should collapse as a result, irrespective of min-height:
Two margins are adjoining if and only if:
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
...
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
Note that it goes on to list some scenarios in which margins may or may not collapse:
Note the above rules imply that:
...
The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.
... but it does not state what happens when the block box has height: auto and a non-zero min-height.
Based on this, it would be safe to assume that the spec should be interpreted as I am doing. Therefore it looks like Firefox is not behaving quite correctly, and all other browsers are following the spec to the letter, despite what one might expect from the behavior of height and min-height.
You can file a bug for Firefox here, although it looks like the developers have already made themselves aware of this issue.
A display: table-row div with height: 75px is nested inside a display: table div with height: 100px
The height of the child is 100px initially with position: static
By changing the positioning of the child element to absolute and then back to static, the height of the child permanently changes from 100px to 75px.
It only occurs if the parent element is a table and the child is a table-row and apparently it's only in WebKit; firefox/IE change back to 100px height but Chrome/Safari don't.
<div id="div1">
<div id="div2">
Hello, world!
</div>
</div>
#div1
{
display: table;
height: 100px;
}
#div2
{
display: table-row;
height: 75px;
}
Here's the jsfiddle with the example and output of the positioning type/height.
I originally noticed it by messing with CSS properties in the Chrome developer tools, so it's not something specific to jsfiddle or jQuery.
Why does the height permanently change?
The root of the problem lies in the fact that the table and table-row elements have specified heights, but the table height is greater than the table-row height. Since there are no other rows, this will result in undefined behavior. From the spec:
CSS 2.1 does not define how extra space is distributed when the 'height' property causes the table to be taller than it otherwise would be.
The following is what appears to be happening, at least based on my own observations:
Unless I'm misreading it, every browser seems to be ignoring the paragraph in the spec that specifies how to compute the height of a table-row element, and taking the table height instead.
When you absolutely position the table-row, its computed height changes to the specified 75px, because absolute positioning turns it into a block box and therefore its dimensions are calculated accordingly.
When you return the element to its static position, it reverts to a table-row (as it should), but Chrome/Safari, for some reason, keeps the 75px from when you made it a block box, while other browsers recalculate the height according to the table, again ignoring its specified height.
As this is technically undefined behavior, whether any of the browsers can be said to have buggy or incorrect behavior is debatable. However, I'm going to go out on a limb and say that this could be related to Chrome's tendency to mess up badly at reflows and repaints, since you'd expect a browser to revert all properties and repaint the layout correctly when you undo a single property change — something Chrome is notoriously bad at.
Alternatively, as mentioned in the comments, this may have something to do with anonymous table objects. The spec does not say that an empty table needs to have an anonymous row and cell, but it looks like Chrome could be creating one to replace the table-row when you first position it, but forgetting to remove it after you put it back in.
For example, if you add some bare text as a child of your table, which the browser will then wrap in an anonymous row box per the spec:
<div id="div1">
Anonymous row
<div id="div2">
<p>Hello World!</p>
</div>
</div>
Every browser will consistently report the height of #div2 as 75px. Presumably, the remaining space is taken up by the anonymous row box, but unfortunately I'm not familiar enough with the CSS table model to comment further.
This simple table with one absolutely-positioned column renders differently in Firefox (and IE) than in Chrome (and other Webkit-based browsers):
http://jsfiddle.net/WZ6x8/
<div>
<table>
<tr>
<th class="absolute"> </th>
<th> </th>
</tr>
</table>
</div>
* {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
table-layout:fixed;
}
th {
border: 1px solid black;
width: 100px;
}
.absolute {
left: 0;
position: absolute;
}
div {
margin-left: 100px;
}
Why is there a difference? Which browser is wrong (according to the standard)? How can this be fixed to work on all browsers, without removing the line border-collapse: collapse?
Edit: as noted by #urzeit, "If you specify top: 0; the output in firefox is the same as in chrome." However, there are two issues: first, with multiple rows, top: 0; collapses them all into one; second, the right edge of the absolutely-positioned column extends one pixel too far. You can see both issues at http://jsfiddle.net/WZ6x8/3.
This is caused by rounding issues which are often inconsistent across browsers, and are probably the same ones that plague things like background offsets, percentage calculations and so on.
In a nutshell, the reason why rounding issues come into play is found in section 17.6.2 which, as you may have guessed, describes the collapsing border model:
Borders are centered on the grid lines between the cells. User agents must find a consistent rule for rounding off in the case of an odd number of discrete units (screen pixels, printer dots).
And:
The top border width of the table is computed by examining all cells who collapse their top borders with the top border of the table. The top border width of the table is equal to half of the maximum collapsed top border. The bottom border width is computed by examining all cells whose bottom borders collapse with the bottom of the table. The bottom border width is equal to half of the maximum collapsed bottom border.
Since the border width is 1 pixel, which is an odd number, rounding issues occur when attempting to halve that value. So the question of which browser is wrong — or if any of them are — is debatable.
Unfortunately, because this is a rounding issue, it's not possible to work around this using pure CSS unless through inconceivably elaborate hackery, and very difficult to do so using a script as browsers tend to be inconsistent when reporting decimal/fractional offset values as well (in particular, Firefox, IE and Chrome all report wildly different values for offsetTop of your table-cell and its next sibling).
While I can't offer a solution to your problem, hopefully at least I've helped you understand why browsers are behaving the way they do.
Here's the nitty gritty if you're interested in why the issue ultimately lies in the way the collapsing border model is defined.
Section 9.7 states that if an element is absolutely positioned, then its display is set to block, even if it would otherwise be a table-cell. In all browsers, the computed display for that th is in fact block, so no problem there.
As you've correctly pointed out, the containing block of your table cell is the initial containing block. This removes it from its usual containing block which would otherwise be the table. Section 10.6.4 does add that that if your cell does not have any specified height, top or bottom offsets, i.e. they are all auto, then it should remain in its static vertical position and measurements made accordingly. (Likewise the horizontal position is accounted for in section 10.3.7, however since you've given it left: 0 and width: 100px, it gets shifted to the left edge and its width is as specified, excluding the borders.)
But what is this static vertical position? Because it would ordinarily be display: table-cell if it wasn't absolutely-positioned, the static position, and its corresponding measurements, is determined by its position in the table.
Your given table layout is covered by the following subsections of section 17:
17.5 Visual layout of table contents
17.5.2.1 Fixed table layout
17.6.2 The collapsing border model
Section 17 contains elaborate descriptions on how tables, captions, table-rows and table-cells should be laid out. A lot of it is based on HTML, and certain sections are left vague and/or undefined for various reasons. Fixed table layout is pretty well-defined though, and in this case it is not even relevant.
Section 17.5 says this near the bottom:
The edges of the rows, columns, row groups and column groups in the collapsing borders model coincide with the hypothetical grid lines on which the borders of the cells are centered. (And thus, in this model, the rows together exactly cover the table, leaving no gaps; ditto for the columns.)
And:
Note. Positioning and floating of table cells can cause them not to be table cells anymore, according to the rules in section 9.7. When floating is used, the rules on anonymous table objects may cause an anonymous cell object to be created as well.
Which, of course, has been explained just above.
But if an absolutely-positioned table cell is no longer a cell, what happens?
A "missing cell" is a cell in the row/column grid that is not occupied by an element or pseudo-element. Missing cells are rendered as if an anonymous table-cell box occupied their position in the grid.
So while the actual th box is absolutely positioned, it leaves an anonymous "ghost" cell in its place in order for the table to be rendered properly. This anonymous table-cell is empty and does not inherit the styles from the actual table-cell, so it has no intrinsic width.
However, because the actual table-cell's vertical position is static, it is still affected by how the table is rendered, which brings us to section 17.6.2 on the collapsing border model.
multiple rows - Try this css..
<style>
.absolute {
left: 0;
margin-top: -1px;
border-right:0px;
position: absolute;
}
#media screen and (-webkit-min-device-pixel-ratio:0)
{
.absolute {
margin-top: 0px;
}
}
</style>
Chrome And Firefox Demo Screenshot.
The reason this is happening is because you've specified the entry as absolute, meaning firefox's browser style where it sets the "top" css property to 1px is being used. If you want to avoid this you might be able to use a css reset file which blows away browser-specific default formatting.
As for your issue with setting top:0 resulting in the cells collapsing into each other, that is the correct behavior. Absolute renders in the space of the closest positioned CSS element. Think of it as if the element is no longer in its usual place in the DOM. If the two cells specified as absolute have the same closest positioned parent element (in this case the body) then they would both render relative to the same place with each having the top:0 property which means they would overlap.
I don't think either is wrong, you're just running into the (common) issue of browser styles.
In short ,
There are two problem to me in this problem
a) The first problem is overlapping of left <th> with right <th>
The correct browser is one which overlapp the <th> because
you are firstly giving the outer div margin-right:100px;
the <th> with aboslute property should fit this area, but the extra border of 1px increase the width by 2px(left border + right border) .Hence the overlap is correct
b) The second problem is of top margin for the left element
It can be removed by adding
th{
top:0px;
}
This is because of browser effect to html page
I was writing the layout of an app using the box-flex property (in Chrome) and I have found a strange behaviour, in my opinion, that I am wondering if might be a bug or that I just ignore the reason for those workings.
The code looks like this: http://jsfiddle.net/5tuCh/
There is a weird "div" resize when resizing the "textarea" so that the dimension of the "div" minus the "textarea" is equal to the dimension of the second "div", in order to satisfy "box-flex:1.0" I guess. Now if the reason for box-flex was making it easier to arrange the layout, this behaviour makes it unusable in this case.
Might it be that I am missing something?
Thanks.
This is in fact correct behaviour. From MDN:
The containing box allocates the available extra space in proportion
to the flex value of each of the content elements.
In your example, div.text boxes actually render with a height, meaning that any space beyond that would be spread evenly (or, rather, according to the flex ratio) between the elements. Setting height:0 on these elements would force behavior that I believe you're after (fiddle: http://jsfiddle.net/5tuCh/16/); I also had to remove the height:100% declaration on your textarea to prevent it from collapsing inside an element with zero height. I'd speculate that you may accomplish the textarea to take up full height of the parent element by setting its box-flex property as well.
Update:
OP's having issues with textarea behaviour could possibly be addressed by the following style:
textarea {
position:absolute;
top:10px;right:10px;bottom:10px;left:10px;
resize:none;
}
The parent element, of course, has to have position:relative set, which would result in the textarea taking up all available space in the container (w/10px spacing between the borders). Not sure if that's what you were after though. Fiddle: http://jsfiddle.net/5tuCh/36/
I've seen numerous people mentions that you shouldn't use widths and padding or margins on the same element with CSS. Why is that?
Because some browsers treat the width as the total width of the element including the padding and the margins, and others treat the width as the base width to which the padding and margins are added. As a result your design will look different in different browsers.
For more information, see the W3C page on Box Model and quirksmode's take.
A lot of people still cling to notions about faulty box-models in IE and reckon that if you start messing around with element widths, padding and margins, you're going to get into trouble.
That's pretty outdated advice - assuming you're using a correct doctype, all fairly modern browsers (including IE6+) will work to the same box model, and you shouldn't really have too many issues related to it.
This being CSS, you will obviously have a million other cross-browser issues, but the infamous IE box-model is becoming a thing of the past.
I've never come across a problem caused by using width, padding and/or margin together.
So long as you have a valid DOCTYPE and are not in Quirks Mode, you will have a predictable box model and therefor should use whichever is most appropriate out of margin/padding to represent what you are trying to do.
Note:
Margin applies outside of borders, padding applies inside of borders.
Width means inner width of the container, the Total width = margin+border+padding+width (remembering that the first three are added for both left and right hand side).
Are you stating that padding and/or margin values shouldn't co-exist with a DOM element that also has a width value assigned to it? If so, that is only true if you do not want to write CSS that is compatible with both IE as well as browsers which implement web standards (e.g. Firefox). It would be difficult to achieve the layout you're looking for usually without some margin or padding value. But I suggest that you write CSS that is compatible for both browsers. If this is not what you are asking, then please correct me :)
The reason may be the famous box model problem.
Summary: IE renders width different then the standard rendering if padding and margin used with width or height.
I can think of 2 reasons:
1) the old "box model" of IE is really flaky, so when you have an element with the style { width: 300px; padding: 30px; margin: 20px;} it's outline might not actually match up to the expected 400px (300 px size, plus 2 30px padding, plus 2 20 px margin. I think its actual width would be 340, as it rolls the padding into the width calculation.
which brings is to...
2) Some people find the calculations a little confusing.
That said, I personally use widths along with padding and margins and have no problems with it. If you limit yourself to not using widths when using paddings/margins, that means you are peppering your code with a lot of non-semantic cruft. It does mean you have to be aware of what the various browsers are going to do with the element, but this is why we browsertest.
One important point to note is that it can make using percentage widths almost impossible. Take this for example, if you want your "content" div to take the full width, but have a 10px padding:
#content {
width: 100%;
padding: 0 10px;
}
That works in the (sensible, but incorrect) IE model, but in standards compliant browsers your div will occupy a width of 100% + 20px which is no good. The solution is to use another "inner" container.
<div id="content">
<div class="inner">
content here.
</div>
</div>
#content {
width: 100%;
}
#content .inner {
padding: 0 10px;
}
It's a bit annoying have the extra markup, but it makes a lot of things easier in the long run.