1

I know this is supposed to be the fundamental reason why CSS exists but I contend that CSS fails miserably at it. It is your job to prove me wrong.

Take this example:

<html>
<head>
    <title>div test</title>
    <style>
        html {
            font: bold 20px Arial;
            color: white;
        }

        #container {
            border: 1px dotted black;
            width: 90%;
        }

        .blue {
            background-color: blue;
            opacity:0.5;
            float: left;
        }

        .red {
            background-color: red;      
            opacity:0.5;
        }
    </style>
</head>
<body>
    <div id="container">
        <div class="blue">Here is some text</div><div class="red">&nbsp</div>
    </div>
</body>
</html>

And make it so

  1. the red and blue div share the same line
  2. the red and blue div do not overlap
  3. the red and blue divs combined width is 100% of #container
  4. the blue div automatically occupies as much space as it needs to accommodate the text that is inside of it, no more or less.
  5. the red div automatically grows/shrinks to occupy the remaining space in #container so that #3 and #4 are both satisfied

I've been trying to do this - what should be - incredibly simple thing for about 3 hours now with no success. The only way that I can do it is by intertwining style and content and adjusting the width of each div based on the amount of text that is in the blue div.

  • 1
    As far as I can see, this is only possible using a `table` or `display: table-*`. The latter doesn't work in IE6 – Pekka Mar 03 '11 at 18:28

3 Answers3

1

From the code you posted with your description it seems like your code should work. I verified it here:

http://jsfiddle.net/3nSwT/1/

(played with the colors just for clarification)

What's wrong with that scenario that you want fixed?

EDIT:

This code works as you expect. I think. :)

http://jsfiddle.net/3nSwT/3/

dmackerman
  • 2,938
  • 5
  • 26
  • 43
  • 1
    That only looks like it's working because you have removed the opacity property from the divs. If you add it back in, you can see that the blue and red divs are overlapping (causing the red div to turn purple). It only appears to be working because the red div is being drawn on top of the blue. – John M Naglick Mar 03 '11 at 18:31
  • They still overlap. For whatever reason, he doesn't want that. – sdleihssirhc Mar 03 '11 at 18:32
  • @sdleihssirhc: I have good reasons for not wanting it, this is just an example to illustrate what I'm asking :) – John M Naglick Mar 03 '11 at 18:34
  • Ahh, I see. Put display:inline on the blue div and it works. http://jsfiddle.net/3nSwT/3/ – dmackerman Mar 03 '11 at 18:34
  • I thought the blue had to be empty, and just resize automatically, depending on how much text is in the red? – sdleihssirhc Mar 03 '11 at 18:37
  • @dmackerman: This fails #3 - if you make the 2nd div into an inline element, it does not grow to occupy the remaining width of the container. – John M Naglick Mar 03 '11 at 18:40
1

Here is a table based approach that I think does what you want.

<div id="container">
    <table><tr>
        <td class="red">Here is some text in the red div.</td>
        <td  class="blue">
        Some text in blue div. Some text in blue div. Some text in blue div. 
         Some text in blue div.     
        </td>
     </tr>
 </table>

 td.red { white-space: nowrap; width: 1%;   background: red;   }
 td.blue { background: blue; }

The only slight kludge is forcing the width of the red column to 1% so it always takes up just exactly the necessary space.

If you can drop IE6 support, and need everything to be "semantic", you can turn the construct into a series of display: table-* div elements:

    <div class="table"><div class="tr">
    <div class="td red">Here is some text in the red div.</div>
    <div class="td blue">
    Some text in blue div. Some text in blue div. Some text in blue div. 
    Some text in blue div.     
    </div>
  </div>

.table { display: table }
.tr { display: table-row }
.td { display: table-cell }

But I personally find the resulting div soup horrible, and the <table> tag a much cleaner and nicer solution, even though it's not the semantically correct choice.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • You don't need the `table-row` or the `table` CSS rules, do you? If you just use `display:table-cell` doesn't it work? Also, if you use something like `*display:inline; zoom:1` then wouldn't it also work in IE6/7? – sdleihssirhc Mar 03 '11 at 18:40
  • @sdleihssirhc AFAIK, you need a `table` and `table-row` wrapper for the construction to be valid. I don't know about the latter, sounds interesting though – Pekka Mar 03 '11 at 18:42
1

This used to be hard, but is now fairly simple using the method Pekka alluded to. To be more specific:

Remove the float from .blue and add these lines:

#container {
    border: 1px dotted black;
    width: 90%;
    display: table;
}

.red, .blue {
    display: table-cell;
}

and this matches all your criteria, including the implicit criteria that when you resize the window to smaller than the #container width, it starts wrapping text to the size of the box, and that if you put longer text in one side versus the other, browsers will resize accordingly.

Works even in IE8. It's part of CSS2.1, and IE8 implemented that pretty thoroughly, but ignored CSS3. IE7 and IE6 need hacks. See http://www.gunlaug.no/contents/wd_additions_22.html for more info on this method and others, including hacks for IE6/7. This is the only part that I would consider tricky.

One other gotcha for IE8 - make sure you have a standards doctype in your HTML. If you don't, this WILL fail. My new favorite is the HTML5 doctype - <!doctype html>

Using this method rather than old-fashioned table opens up the ability to re-use the same HTML for a mobile site and have .red and .blue appear below each other if needed.

Community
  • 1
  • 1
Chad Lundgren
  • 378
  • 2
  • 7