views:

1045

answers:

10

In IE6, IE7 and FF2 the .outer div below is stretching out to the right edge of the document. Here is a complete test case:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <style>
  .outer { position:absolute; border:1px solid red; }
  .outer .floater { float:right; }
  </style>
</head>
<body>
  <div class="outer">
      <div class="floater">Lorem ipsum</div>
  </div>
</body>

As I understand position:absolute, the outer div should be removed from the flow of the document and (without a width specified) should take up the minimal amount of space needed to display its contents. However float:right on any child breaks this.

Expected output (IE8, FF3+, Chrome 2+, Safari 4, Opera 9+):

Expected output - IE8, FF3+, Chrome 2+, Safari 4, Opera 9+

Actual output (IE6, IE7, FF2):

Actual output - IE6, IE7, FF2

How do I get the outer div to not stretch? This is only happening in IE6, IE7 and Firefox 2.

Requirements:

  • .outer cannot have a width set (it must be left as "auto")
  • .outer must remain absolutely positioned
  • .floater must remain floated to the right


Update:

I've reproduced the behavior as a "real world" example using jQuery dialog. The characteristics are the same:

  1. There is an absolutely positioned div (i.e. the dialog container, jQuery-UI creates this)
  2. The div from 1) has width="auto"
  3. There is an element inside this dialog that is floated to the right.

See it here. Again, IE6, IE7 and FF2 are the only problematic browsers.

This replicates the conditions inside my application. I tried boiling down the problem to what you see above this Update, but I'm getting the sense that people could use a real-world example where my requirements make sense. I hope I've done this.

A: 

You need this to stop it overflowing the edge of the page:

body {margin:0;padding:0}

However it will still take up the whole width of the page, it just won't overflow

James
Yes, I don't care about overflowing the page. I only care about *not* stretching the absolutely positioned element.
Roatin Marth
Is it **absolutely** necessary for `.floater` to be `float:right`? Will you be putting content to the left side of it? I only ask, because changing it to `float:left` instead fixes everything, and any other `<div>` tags you need to be in .outer can also be floated left..
James
@James: yes, the `.floater` must be `float:right`. That's pretty much the crux of the problem.
Roatin Marth
A: 

float should have a width in this case, and from another point of view you should have top:0;left:0; for the positioned element they should not kept like this. note: this is logic only for the design if you wont the code please ask :)

Ibrahim AbuRajab
Good call on a width for the floater. However it makes no difference (parent still stretches).
Roatin Marth
A: 

Hi. Hope this helps. :)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <style>
  .outer { overflow:hidden; clear:right; position:absolute; border:1px solid red; }
  .outer .floater { float:right; }
  </style>
</head>
<body>
  <div class="outer">
      <div class="floater">Lorem ipsum</div>
  </div>
</body>

It's really simple, you only must set the overflow and clear properties to every object that has floated childs.

If the parent is also floated, you only need to set your object to float.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <style>
  .outer { overflow:hidden; clear:right; position:absolute; border:1px solid red; }
  .outer .floater { float:right; }
  .outer .floater .child { float:right; }
  </style>
</head>
<body>
  <div class="outer">
      <div class="floater">Lorem ipsum 
                <span class="child">HI!</span>
      </div>
  </div>
</body>

If got any questions, just ask!

Regards & GL. ;)

Raul Illana
Did you try this sample yourself and it worked? Because I added `overflow:hidden; clear:right;` to `.outer` and the outcome is the same: the floater still causes the parent to stretch all the way out.
Roatin Marth
A: 

If you change float:right to clear:right, you will get the requested output in your example, but it will not work as expected if you actually have content outside the floater div.

awe
If I change `float` to `clear` then the floater won't float.
Roatin Marth
A: 

The css2 spec has some information about how a user agent “should” compute width, but reality is not the spec: http://www.w3.org/TR/CSS2/visudet.html#Computing%5Fwidths%5Fand%5Fmargins.

I definitely recommend going with a strict DOCTYPE instead of a transitional one, http://www.w3.org/QA/2002/04/valid-dtd-list.html#DTD.

Without specifying a margin for your .outer div, the user agent will determine the width using width: auto, which looks like it varies depending on the user agent.

Why do you not want to specify a width for the parent div?

If you can, specify a width for the parent div, even if it's width: 100%. You may want to also place * { margin: 0; padding: 0; } in the stylesheet to avoid user agent differences in those attributes, especially if you specify width as 100% for .outer.

This may be trivial, but you should be able to shorten the statement .outer .floater to just .floater.

If you need the “shrink-to-fit” effect around the inner floater and need to maintain float-right, then add direction: rtl; to the .floater class; otherwise you should be able to use float-left;

dan_nl
I do not want to specify a width for the parent div because I want it to be elastic (i.e. stretch/shrink according to its contents). You touch on this with your "shrink-to-fit" comment. I will have a look at your other suggestions and report back.
Roatin Marth
Maybe a bit more info on the "total" design you're looking for with some "mock-up" content might help us find something ...atm, there's really no need for the .outer div, get rid of the class .outer and the .outer .floater reference and make it just .floater and the .floater div will float to the right with the "shrink-to-fit" effect you're looking for.
dan_nl
@dan_nl: I've added an "total design" example to the question. The requirements are there for a reason.
Roatin Marth
Hey Roatin, I figured there must be a requirement ;) There's a lot going on in that little dialog ... if you comment out the jqueryui css link and get rid of the .floater class declaration it seems to allow for the auto fit you're looking for. When you put back the jquery css the auto fit issue returns so there's probably a float: right in that style sheet (haven't had time to look at that yet). Do you have to have the .floater { float: right; } declaration?
dan_nl
@dan_nl: thanks for checking it out. Re: your comments: if you get rid of the css link that means the container is not `position:absolute` anymore. This breaks requirement #2 (as an aside: there is no `float:right` in the jquery stylesheet. Rather *I've* got that in for my `.floater` declaration). Secondly if you get rid of the floater then I've broken requirement #3.
Roatin Marth
okay .. I wastrying to step back and focus on the dialog box design and functionality I saw on the test page and startedto break it down so that it would appear the same in FF3 and IE6. The next step was to look at applying the jqueryui classesso they wouldn't "interfere" with the design, but it lookslike the style requirements you have are making it more difficult ... if you can let go of some of them that may give you a solution. In any case, good luck.
dan_nl
A: 

Yeah for absolute positioned elements, width is undefined (as is top and left). Some browsers do elastic table-style width in this case, and some do 100% width, but it's up to the browser. Best to be explicit in this case.

Tables are really the only good way to get elastic width in a cross-browser fashion. A single celled table is just as good as a DIV as long as your remember the cellspacing=0.

<table cellspacing=0 cellpadding=0 style="position:absolute;top:0;right:0">
    <tr><td>Lorem ipsum</td></tr>
</table>
darkporter
I know a table will work. Tables always work ;) Tables are the cat's meow. I love tables. However in this case I would *really* prefer to fix this in css alone. The markup exists in too many places in the codebase for it to be practical to fix it in the html. Thank you for your suggestion, it may be the only browser-proof solution.
Roatin Marth
At the risk of appearing a bit over-zealous, "Tables are really the only good way to get elastic width in a cross-browser fashion." is not correct. I understand why so many people like tables (it's an easy hack), but they're meant for displaying tabular data. Nothing else.
codeinthehole
Please elaborate... how do you get block elements to fit their content without a table? And why do you think tables are only for tabular data?
darkporter
@darkporter: the accepted approach to a get block element to fit its content (i.e. fluid width) while remaining in the flow of the document is to float the element (eg `"left"`). If remaining in the flow of the document is not important, `position:absolute` works perfectly, **except if you float a child as I've done!**. @codeinthehole: in this case a table has the precise properties as a absolutely positioned div, but does *not* suffer from the propblem outlined. Screw the "tables are meant for tabular data" arguments. It's old. It's done. *Tables are the sh--*.
Roatin Marth
Some background: The original w3c spec (from 1994 or whenever) intended tables for data. Then people needed "layout" for their whiz-bang flashy e-commerce sites so tables evolved for that purpose. Then around 2002, CSS's box model became a viable layout model. Both models (table layout and box model) had powers that the other didn't, so the two co-exist until this day. Don't worry too much about the "spec," there's give and take. De facto use feeds back into the spec. @codeinthehole is right in that, the box model is the "preferred" model of the two.
darkporter
A: 

Your .outer div is empty, therefore we get different results. As soon as you add content to it, atleast in my test it seems to work exactly the same (my test was Chrome 3.0 as the 'working as intended', and IE7 as the broken one).


<div class="outer">
  <div class="floater">Lorem ipsum</div>
Lorem ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit ipsum dolor sit amet consequetur elit 
</div>

Since you mentioned the .outer div has content, try removing the float div from it and it still gets very similar output.

Edit

To reproduce your code without stretching (understand here that you'll have different problems to deal after you have this working equally, like margins/padding/vertical stretch) you can introduce a relative 'wrapper'.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <style>

  body { margin: 0; }
  #outer { position: absolute; border:1px solid red; }
  #wrapper { position: relative; }
  #floater { position: absolute; right:0; border: 1px blue solid;  }

  </style>
</head>
<body>

  <div id="outer">

    <div id="wrapper"> 
        <div id="floater">Lorem ipsumX</div> 
    </div>

    Lorem ipsum dolor sit amet consequetur elitipsum dolor sit amet consequetur elit
  </div>
</body>
F.Aquino
Thanks for looking at this. Results: 1) your first example makes no difference :(as I expected, as production code has lots of content after the float but still exhibit the same stretching). 2) your second example (introducing a "relative wrapper") makes no difference :(. The reason it works for you is because you bypassed my requirement that `floater` **remain floated to the right**. You've simply *positioned* it absolutely to the right (`right:0`) which introduces more problems of text-collision. Thanks anyway.
Roatin Marth
+2  A: 

Apologies for the negative answer, but I don't think there's a way around this. The CSS implementation for those older browsers is simply incorrect when it comes to the case you've outlined, and I don't believe there's any way to hack around this via other CSS properties within the constraints you've given us. As a limited fix you could in theory set a max-width on the outer div to limit the degree to which it stretches... but unfortunately max-width isn't supported in all of the 'old' browsers mentioned anyway.

I know it's not what you're wanting to hear, but I think you're going to have to bite the bullet and either change the markup or relax your style requirements (e.g. give up on the float).

Chris
I agree with this. I have looked at this on and off for the last couple weeks since it is such a good problem but I don't think there is a workaround on the way that IE6, IE7 and Firefox 2 handles a floated div inside of an absolutely positioned div with no width set.If it was me I would leave it as it is for the browsers that work and then put a hack for max-width only on the browsers that don't handle it and call it a day.
Bertine
A: 

Since I see in your working example you're using jquery you could calculate the width of the container first, before floating the floater like so:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
  <style>
  .outer { position:absolute; border:1px solid red;}
  </style>
</head>
<body>
  <div class="outer">
    <div class="floater">Lorem ipsum</div>
  </div>

  <script type="text/javascript">
    $(".outer")
      .css("width", $(".outer").width());
    $(".floater")
      .css("float", "right");
  </script>

</body>

Putting a width on the outer div makes it behave in all the other browsers

wannabe_rockgod
A: 

I don't have IE6, IE7, or FF2 to test on, so I'm going to take a stab in the dark on this one. If my memory serves me, you're going to want to float:left on .outer. This will minimize the width of .outer while maintaining your inner div's proportions.

mattbasta