Css for an element that allows break-word on child divs, but that can also expand to take the width of its children
Asked Answered
K

5

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.

Knoxville answered 29/9, 2011 at 23:35 Comment(3)
I'm looking for a css only solution, or proof that such a solution is not possible.Knoxville
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 JSFiddleLou
Give a picture of what you want.Archway
K
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';
  }
}
Knoxville answered 3/11, 2011 at 23:6 Comment(2)
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.Amberly
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.Recommend
A
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/

Amberly answered 1/11, 2011 at 0:56 Comment(3)
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.Knoxville
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.Knoxville
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.Founder
B
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
      }
Birl answered 22/10, 2011 at 19:4 Comment(2)
Here's the fiddle: 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.Teleview
I can't control the user generated content, which includes the table. I added an <img> tag above as an example of another element that overflows the parent.Knoxville
C
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%;
}
Congruency answered 29/10, 2011 at 14:59 Comment(2)
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.Knoxville
then post a picture of your intended layoutCongruency
F
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%;
}
Founder answered 3/11, 2011 at 18:26 Comment(1)
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.Knoxville
K
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';
  }
}
Knoxville answered 3/11, 2011 at 23:6 Comment(2)
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.Amberly
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.Recommend

© 2022 - 2024 — McMap. All rights reserved.