10

I'm trying to determine whether it's possible to create css for an element that supports word-wrap:break-word, but that also expands to take the width of its children when breaking is not possible.

<html>
  <style>
  .outer {
    background-color:red;
    word-wrap:break-word;
  }
  </style>
  <div class="outer">
    User generated content:
    <a href="http://www.google.com">http://anannoyinglylongurlthatcausesthepagetogrowtolongunlessIusewordwrapbreakwordasdfasfasdfasdfasdfasdfasdfsadfasdfadsf</a>
    <table>
      <tr>
        <td>asdfasdfadsffdsasdfasdfsadfafsd</td>
        <td>asdfasdfadsffdaasdfassdffaafasds</td>
      </tr>
    </table>
    <img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png"/>
  </div>
</html>

In the above sample, the url breaks properly, but the table and img overflow the red outer div if the window becomes narraower than the table.

If I make the outer div display:inline-block or display:table, the red outer div correctly expands to include the content, but the url doesn't break if the window is narrower than the url.

I only need this to work in WebKit (on Android), and I'm trying to find a CSS only (no Javascript) solution if possible.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
nas
  • 957
  • 1
  • 9
  • 21
  • I'm looking for a css only solution, or proof that such a solution is not possible. – nas Oct 19 '11 at 20:21
  • Not sure if this is what you are looking for but you actually can make sure breaking always occurs with the CSS property word-break. Check out this [JSFiddle](http://jsfiddle.net/sp43f/1/) – skyline3000 Oct 21 '11 at 14:46
  • Give a picture of what you want. – c69 Oct 31 '11 at 20:01

5 Answers5

8

If I understood what you need correctly, all you need is overflow: auto set on .outer. Here's an example: http://jsfiddle.net/hgLbh/1/ (tested on safari & chrome).

Update:

After your scrolling related comment I've tried a few other solutions and I've found something that satisfies even that. I'll say in advance it's dirty, but if you can handle absolutely positioned content and you are willing to duplicate the generated markup I hope it will work (at least on my local safari it does).

The solution is to duplicate your content and wrap the new content in 2 other divs, so the HTML will look something like:

<div class="outer-fixed">
    <div class="just-a-helper-wrapper">
        ... user generated content
    </div>
</div>
<div class="outer">
    ... same user generated content
</div>

And for the CSS:

.outer,
.outer-fixed {
    background-color:red;
    word-wrap:break-word;
    position: absolute;
    left: 0;
    right: 0;
}

.outer-fixed {
    position: fixed;
    right: 0;
}
.outer-fixed * {
    visibility: hidden;
}

I'd like to point out that the just-a-helper-wrapper is required only because outer-fixed * doesn't select text nodes (ie. content that's not in another tag) - for example the string User generated content: from your example would have still been visible. If you don't actually have that kind of content, you can remove it.

Here's the link: http://jsfiddle.net/hgLbh/2/

deviousdodo
  • 9,177
  • 2
  • 29
  • 34
  • Thanks for the suggestion. Unfortunately , scrolling a div doesn't work on mobile webkit. I could use a js library like iScroll to do my own scrolling, but this isn't exactly what I want, since I'd prefer that the entire page scroll rather than just the div. – nas Nov 03 '11 at 21:21
  • 1
    Your update is kind of a cool idea. I was trying to think of some way to do this with duplicated content. I won't use this, but this is deserving of the bounty. – nas Nov 04 '11 at 02:13
  • I agree with Alex (and I'm glad he recognized you for it), your solution showed ingenuity. Of course, there are (search engine) issues with duplicating content, but it is an interesting solution. – ScottS Nov 04 '11 at 20:54
7

Assigning width: 100%; and using table-layout: fixed; forces the td cells to fit the table and will allow for text wrapping.

  table {
        width:100%;
        table-layout:fixed
      }
Kevin M
  • 1,524
  • 17
  • 38
  • Here's the fiddle: http://jsfiddle.net/hgLbh/ @AlexM `display:inline-block;` didn't limit the table's width. The overflowing anchor caused the background to expand, making the non-wrapped table visually not noticeable. – Rob W Oct 22 '11 at 19:23
  • I can't control the user generated content, which includes the table. I added an tag above as an example of another element that overflows the parent. – nas Oct 26 '11 at 00:49
3

I don't know about mobile webkit but this worked in Chrome

http://jsfiddle.net/HerrSerker/duDTz/1/

.outer {
    background-color:red;
    word-wrap:break-word;
    overflow:hidden;
  }

.outer table {
    width: 100%;
    table-layout:fixed
}

.outer * {
    max-width: 100%;
}
yunzen
  • 32,854
  • 11
  • 73
  • 106
  • This solution shrinks the image, and any other content that would otherwise overflow the div, which is not what I want. Thanks for the response. – nas Nov 03 '11 at 21:24
  • then post a picture of your intended layout – yunzen Nov 03 '11 at 22:39
2

It seems to me that draevor has the answer, but I suspect that you don't want a scroll bar showing up in the middle of the screen on the div. If that is so, and depending on your limitations, you might try this to make the div the window:

CSS

html {height: 100%}
body {overflow: auto; height: 100%; margin: 0;}
.outer {
    word-wrap: break-word; 
    background-color: red;
    overflow: auto;
    min-height: 100%;
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • This solution works if you are OK with the outer div growing to take the height of the window, and you aren't using mobile Webkit. Thanks for the response. – nas Nov 03 '11 at 21:23
2

Looking at the CSS spec, it's likely that what I'm trying to do is impossible, although I find the size calculations fairly difficult to decipher. Here are some important bits:

http://www.w3.org/TR/CSS21/visudet.html

The content width of a non-replaced inline element's boxes is that of the rendered content within them

So if I want the background of my containing box to grow to be the width of the children, it appears I need to make sure it's layout is calulated in an inline formatting context:

http://www.w3.org/TR/CSS21/visuren.html#normal-flow

When an inline box exceeds the width of a line box, it is split into several boxes and these boxes are distributed across several line boxes. If an inline box cannot be split (e.g., if the inline box contains a single character, or language specific word breaking rules disallow a break within the inline box, or if the inline box is affected by a white-space value of nowrap or pre), then the inline box overflows the line box.

Great. Hopefully the breaking rules also include emergency wrapping possibilities.

http://www.w3.org/TR/2010/WD-css3-text-20101005/#word-wrap

This property specifies whether the UA may break within a word to prevent overflow when an otherwise-unbreakable string is too long to fit within the line box.

Doesn't really help; let's look at the newer draft spec:

http://www.w3.org/TR/css3-text/#overflow-wrap

Break opportunities not part of ‘overflow-wrap: normal’ line breaking are not considered when calculating ‘min-content’ intrinsic sizes.

This isn't very clear, but if 'min-content' instrinsic sizes has something to do with the same calculations used to determine line-breaking possibilities, I might be out of luck.


I ended up just using Javascript to measure the content and decide whether to show it in block or inline context. Sigh.

var messages = document.body.getElementsByClassName('mail_uncollapsed');

// Show overflowing content by setting element display to inline-block. This
// prevents break-word from being applied to the element, so we only do this
// if the element would overflow anyway.
for (var i = 0; i < messages.length; ++i) {
  var message = messages[i];
  message.style.display = 'block';
  var isOverflowing = message.clientWidth < message.scrollWidth;
  if (isOverflowing) {
    message.style.display = 'inline-block';
  }
}
nas
  • 957
  • 1
  • 9
  • 21
  • 1
    Of course, the javascript solution is simple, but you said in your post that's unacceptable. Anyway, I've updated my answer with a working example (even though it's hackish) without Javascript. – deviousdodo Nov 03 '11 at 23:17
  • In case anyone is wondering, `word-wrap` was recently renamed to `overflow-wrap`, hence the discrepancy between the 2010 draft and the latest draft. Both property names are aliases, and share the same set of values and rendering rules. – BoltClock Feb 27 '12 at 17:52