Saturday, January 30, 2010

CSS Browser Compatibility Tricks 2b

******************************************

Browsers support varying amounts of CSS. Support generally increases as new versions are released.

For old browsers, most CSS problems are noticed in Netscape 4. I have found a site that fully documents every bug that Netscape 4 has with stylesheets. It is a very long read. Generally, I recommend that you ignore Netscape 4, and style for newer browsers instead (Netscape itself is now using version 8). If you need to ensure that Netscape 4 can still view your pages (you don't), it is best to simply put all of your styles in another external file, and use the @import rule to import it, since Netscape 4 cannot import. Netscape 4 will show an unstyled page.

Out of all the current browsers, Internet Explorer's support is generally the worst. It is missing many parts of CSS, and can be a very difficult browser to design for. Most sites will need to cater for older versions of Internet Explorer

In general, the best way to write is using a browser with a high level of CSS support to check your CSS, then after you have something that works nicely, work out what you will have to change to make it work in versions of Internet Explorer that you still need to cater for. For development, I recommend testing in at least Opera and Mozilla/Firefox (both are available on all major platforms). If you have access to them, you should also test in Safari, Chrome or Konqueror, or some other browser based on the KHTML/WebKit engines.

Remember that there is usually more than one way to achieve what you need, such as being able to use both float and position to do columns (you can also use display:table; in most browsers, but not Internet Explorer 7-).

******************************************

Margin Collapsing

=================

Many Web developers run into margin collapsing without realising what it is, or why it is happening. It takes place on virtually every Web page, and in most cases, it creates the desired effect without causing any undesired side effects. However, when it does cause a problem, it usually appears as strange gaps at the top of elements even when they have their top margins set to 0. The typical response is to use an unrelated workaround of some kind, such as positioning everything. Understanding the cause allows more efficient workarounds to be used, especally those that actually deal with the root cause.

Historically, margin collapsing only exists because older browsers like Netscape 3 used to do it before they had CSS, and when CSS was created, it had to describe that behaviour so it could be implemented in CSS.

CSS box model

=============

The first thing you need to understand is the CSS box model. In its simplest form, a box is a block element or tag,like a DIV, for example. In the middle of the box are the contents. If the relevant styles are set, even if there are no contents, the content size comes from the height and width styles (you will need to ensure that your DOCTYPE triggers standards mode rendering for some browsers, particularly Internet Explorer, for them to get this part correct). Then outside the contents, but still inside the box, is the padding. Then outside the padding, but still inside the box, is the border. Outside the border is the margin. "Box" is only a word, you do not really need to think about it yet. It is more important to understand where the various margin, border, padding, and content exist in relation to each other.

content <--- In the middle of the box.

padding <--- Outside the contents, but still inside the box.

border <--- Outside the padding, but still inside the box.

margin <--- Outside the border, but not inside the box.

Almost no elements have padding by default. Some of the rare cases where an element has padding by default would be fieldsets, or in some browsers the padding of the body, and the padding of a DL list. For the sake of this tutorial, it is easiest to assume that no block elements have padding.

Most block elements have a default top and bottom margin, such as paragraphs and headings for example, which may have a top and bottom margin of 1em, which computes to 16 pixels if that is the current font size. This is what creates the gap between two paragraphs. It is also what causes margin collapsing to be so important. This tutorial will assume that paragraphs have a 16 pixel top and bottom margin, but you should be aware that different browsers will have very different default margins, and can also change depending on user settings such as font size.

Take the following HTML:

<div>A</div>

<p>B</p>

<p>C</p>

<div>D</div>

Paragraphs may have 16 pixels top and bottom margins, while DIVs have 0. As a result, the gap between the DIV and paragraph is 16 pixels in each case. The gap between the two paragraphs is also 16 pixels, even though there are two paragraphs, and they may be expected to have 32 pixels between them. This is a margin collapse.

The first and simplest kind of margin collapse

==============================================

Margin collapsing only happens with top and bottom margins, not left and right, and not at all on inline elements. Margin collapsing happens wherever two (or more) top or bottom margins are touching. The basic idea is that when they touch, instead of getting the sum of the two margins, the bigger one is used, and the other is ignored. So in the case of the two paragraphs, the 16 pixel bottom margin of the first one touches the 16 pixel top margin of the second one. Max(16,16) is 16, so the gap between them is 16 pixels.

Three elements

==============

<p>A</p>

<p style="margin-top:100px;margin-bottom:50px;"></p>

<p>B</p>

The middle paragraph has no contents, so it also has no height (since the CSS does not specify a height for it). However, it is still there. The resulting margins are like this:

16 pixels

A

16 pixels

100 pixels

50 pixels

16 pixels

B

16 pixels

The middle paragraph is 0px high, so its margins are touching. So there are 4 margins touching each other. The gap between A and B is max(16,100,50,16), which is 100 pixels.

Negative margins

================

Negative margins are special and are dealt with as follows:

1. Work out what margins are touching.

2. Ignore all negative margins.

3. Perform the collapse as if there were no negative margins.

4. Select the largest of the negative margins, and subtract it from the computed margin from step 3.

<p style="margin-bottom:-5px;">A</p>

<p style="margin-top:100px;margin-bottom:-50px;"></p>

<p>B</p>

Step 1:

16

A

-5

100

-50

16

B

16

Step 2:

Ignoring the negative margins:

16

A

100

16

B

16

Step 3:

The gap between A and B is max(100,16), which is 100 pixels.

Step 4:

Subtracting the largest negative margin:

Max(5,50) is 50.

100 - 50 = 50

So the resulting gap between A and B is 50 pixels.

Nested margins

==============

This is the part that causes most problems for Web developers.

<div style="margin-top:10px">

<div style="margin-top:20px">

A

</div>

</div>

There are two margins touching each other: 10 and 20 pixels. The resulting margin will be max(10,20), which is 20 pixels.

The question is; where does the 20 pixels appear:

1. Before the outer DIV?

2. Before the inner DIV but inside the outer DIV?

(In other words, if the background of the outer DIV is red, and the background of the inner DIV is white, should any red be visible?)

The answer is quite simple; the resulting margin always appears as far out as possible - outside the outermost element whose margin is taking part in the collapse. Even though the margin that gets "used" is the one from the inner DIV, it appears outside the outer DIV. So it seems to appear in the wrong place.

This is the part that causes the most unexpected effects. A developer might make the background of a container white, make the background of a DIV inside it blue, then put a paragraph or heading inside it. The expectation is for the blue to extend all the way to the top of the container, but it does not. The paragraph may have a default top margin of 16 pixels, and that collapses to the outside of the DIV because it touches the 0 pixel top margin of the DIV, pushing the DIV down, and leaving a strange gap at the top of the blue.

The solution to the unwanted gap, is to make sure the margin collapse cannot happen. The way to do that is to make sure the 0 pixel top margin of the DIV and the 16 pixel top margin of the paragraph cannot touch each other. This is where the box model becomes useful. It is possible to remove the margin of the paragraph, but it is also possible to manipulate the DIV to insert something between the paragraph's top margin, and the DIV's 0 pixel top margin. The way to do that is to add a top padding or top border of at least 1 pixel of height onto the DIV, since they sit between the two margins.

Internet Explorer 7

===================

In rare cases, margin collapsing where an inner element has a bottom border and an outer container has a bottom border, can cause the background of an intermediate element to spill into the container in Internet Explorer.

The more problematic bug is caused by Internet Explorer's strange hasLayout behaviour. This is a fundamental bug in Internet Explorer 7- and affects several other things as well, but this article will only deal with margin collapsing. Setting certain styles on an element makes it "have layout" (a concept unique to Internet Explorer, and not compliant with any standards). The most common style that causes a problem is width. When an element hasLayout it suddenly assumes a minimum height of 1em, and if set to something less in Internet Explorer 6, such as 0.5em, it still uses 1em.

An element has layout when one of the following conditions is true:

* It has a width and/or a height specified

* It is an inline-block (display: inline-block)

* It has absolute positioning (position: absolute)

* It is a float (float: left, float: right)

* It is a table element

* It is transformed (style="zoom: 1")

Height usually does not cause a problem, since setting height will prevent collapsing in other browsers anyway. However, triggering hasLayout on a nested element where the parent has prevented margin collapsing using borders or padding, can cause margins to disappear, or to collapse through the parent irrespective of the padding or borders. Generally, hasLayout is a mess, and it is best to avoid it in places where margins are critical.

Positioning

===========

When an element has either position:absolute or position:fixed, it is taken out of the flow, and its margins no longer take part in any collapses at all.

<p>A</p>

<p style="margin-top:100px;margin-bottom:50px;position:absolute;"></p>

<p>B</p>

The gap between A and B is max(16,16), which is 16 pixels.

Floats

======

Float also takes elements out of the flow. The margins of its siblings touch as if it was not there, and they collapse while completely ignoring it, as with positioned elements.

When the float is being positioned, it is initially placed as if it had no top margin at all (so its top margin does not take part in any collapsing), and as if it had no subsequent siblings (so any collapsing between its preceding and subsequent siblings is temporarily ignored). Any margins of preceding elements that are due to take part in a margin collapse have their margins collapsed assuming any siblings following the float do not exist. The float is then placed below that collapsed margin. It is then moved downwards by its own top margin. The float is then ignored, and the normal margin collapse is recalculated assuming the float does not exist, but the subsequent siblings do exist, as described in the paragraph above.

The bottom margin of a float does not take part in any collapsing at all. However, elements that are pushed downwards when they are told to clear the margin of a float (using the clear style), may no longer touch a margin that they normally would, so they will not collapse with it.

If the float contains any non-inline elements that have their own margins, these never collapse with the float's margins.

******************************************

******************************************

No comments:

Post a Comment