22
votes

Shrink wrapping a div to some text is pretty straightforward. But if the text wraps to a second line (or more) due to a max-width (as an example) then the size of the DIV does not shrink to the newly wrapped text. It is still expanded to the break point (the max-width value in this case), causing a fair amount of margin on the right side of the DIV. This is problematic when wanting to center this DIV so that the wrapped text appears centered. It will not because the DIV does not shrink to multiple lines of text that wrap. One solution is to use justified text, but that isn't always practical and the results can be hideous with large gaps between words.

I understand there's no solution to shrink the DIV to wrapped text in pure CSS. So my question is, how would one achieve this with Javascript?

This jsfiddle illustrates it: jsfiddle. The two words just barely wrap due to the max-width, yet the DIV does not then shrink to the newly wrapped text, leaving a nasty right-hand margin. I'd like to eliminate this and have the DIV resize to the wrapped text presumably using Javascript (since I don't believe a solution exists in pure CSS).

.shrunken {text-align: left; display: inline-block; font-size: 24px; background-color: #ddd; max-width: 130px;}

<div class="shrunken">Shrink Shrink</div>
4
some image demonstration or code sample (jsfiddle?) would be useful to understand and build on what you mean.basarat
What's the problem that this doesn't solve? jsfiddle.net/uS6cf/1isherwood
why doesn't the div shrink when the text has to wrap (your max-width example)? just for the sake of more info on this question, how are you shrinking your div?Hurricane Hamilton
@isherwood That actually illustrates the problem perfectly. The two words force a break, but the DIV is still at its max-width of 130px, while the largest word is less 130px, creating the margin on the left and right. I want the DIV to shrink to the largest wrapped line of text. Using 'Shrink Shrink' for the text in your example makes it more noticeable.onlinespending

4 Answers

7
votes

It's not the prettiest solution but it should do the trick. The logic is to count the length of each word and use that to work out what the longest line is that will fit before being forced to wrap; then apply that width to the div. Fiddle here: http://jsfiddle.net/uS6cf/50/

Sample html...

<div class="wrapper">
    <div class="shrunken">testing testing</div>
</div>

<div class="wrapper">
    <div class="shrunken fixed">testing testing</div>
</div>

<div class="wrapper">
    <div class="shrunken">testing</div>
</div>

<div class="wrapper">
    <div class="shrunken fixed">testing</div>
</div>

<div class="wrapper">
    <div class="shrunken" >testing 123 testing </div>
</div>

<div class="wrapper">
    <div class="shrunken fixed" >testing 123 testing </div>
</div>

And the javacript (relying on jQuery)

$.fn.fixWidth = function () {
    $(this).each(function () {
        var el = $(this);
        // This function gets the length of some text
        // by adding a span to the container then getting it's length.
        var getLength = function (txt) {
            var span = new $("<span />");
            if (txt == ' ')
                span.html('&nbsp;');
            else
                span.text(txt);
            el.append(span);
            var len = span.width();
            span.remove();
            return len;
        };
        var words = el.text().split(' ');
        var lengthOfSpace = getLength(' ');
        var lengthOfLine = 0;
        var maxElementWidth = el.width();
        var maxLineLengthSoFar = 0;
        for (var i = 0; i < words.length; i++) {
            // Duplicate spaces will create empty entries.
            if (words[i] == '')
                continue;
            // Get the length of the current word
            var curWord = getLength(words[i]);
            // Determine if adding this word to the current line will make it break
            if ((lengthOfLine + (i == 0 ? 0 : lengthOfSpace) + curWord) > maxElementWidth) {
                // If it will, see if the line we've built is the longest so far
                if (lengthOfLine > maxLineLengthSoFar) {
                    maxLineLengthSoFar = lengthOfLine;
                    lengthOfLine = 0;
                }
            }
            else // No break yet, keep building the line
                lengthOfLine += (i == 0 ? 0 : lengthOfSpace) + curWord;
        }
        // If there are no line breaks maxLineLengthSoFar will be 0 still. 
        // In this case we don't actually need to set the width as the container 
        // will already be as small as possible.
        if (maxLineLengthSoFar != 0)
            el.css({ width: maxLineLengthSoFar + "px" });
    });
};

$(function () {
    $(".fixed").fixWidth();
});
2
votes

I little late, but I think this CSS code can be useful for other users with the same problem:

div {
  width: -moz-min-content;
  width: -webkit-min-content;
  width: min-content;
}
0
votes

I guess this is what you are thinking about, it can be done in css:

div {
    border: black solid thin;
    max-width: 100px;
    overflow: auto;
}

You can see it here: http://jsfiddle.net/5epS4/

-1
votes

Try this: https://jsfiddle.net/9snc5gfx/1/

.shrunken {
   width: min-content;
   word-break: normal;
}