9

I would never think this is possible, but there are a lot of clever people here so I thought I'd ask. I'm looking for a way to have a full-height container whose width depends on how much content there is. I want the text to fill the area taking up the full height while using the smallest possible width. The height is known and hard-coded, the amount of content is not.

I'm working with something like this:

<div>
    <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.
    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
    when an unknown printer took a galley of type and scrambled....</p>
</div>
div {
    background:red url(http://lorempixel.com/600/400/);
    float:left;
    width:600px;
    height:400px;
}
p {
    background:#fff;
    padding:20px;
    margin:20px;
}

Normally content fills the page from top to bottom:

enter image description here

What I'm looking for is sort of the opposite, filling in left-to-right:

enter image description here

With less content, it should look like this:

enter image description here

Using full hard-coded height with width:auto produces this effect:

enter image description here

Is there any way to have the text fill the height with the smallest possible width, without hard-coding a width or having text overflow? It seems impossible and I have no idea how to approach it. Javascript/jQuery solutions welcome.

Wesley Murch
  • 101,186
  • 37
  • 194
  • 228

5 Answers5

3

What I have in mind is a simple jQuery solution: in a while loop, set the condition such that the loop is run whenever the height exceeds the container height. In the loop, you increase the width of <p> pixel by pixel until the height no longer exceeds container height :)

$(document).ready(function() {
    // The 400-80 is because you have to subtract the container padding and the element's own padding
    while($("div > p").height() > 400 - 80) {
        currentWidth = $("div > p").width();
        $("div > p").width(currentWidth + 1);    
    }
});

http://jsfiddle.net/teddyrised/RwczR/4/

I have made some changes to your CSS, too:

div {
    background:red url(http://lorempixel.com/600/400/);
    float:left;
    overflow: hidden;
    width:600px;
    height:400px;
    padding: 20px;
    box-sizing: border-box;
}
p {
    background:#fff;
    padding: 20px;
    width: 1px;
}
Terry
  • 63,248
  • 15
  • 96
  • 118
  • Looks like a great solution, I'm just trying to plug it in to my project right now and failing. EDIT: Ah, I forgot to set the `width: 1px;` first. I ended up going with 10px intervals (good enough). Very nice, small, easy solution. – Wesley Murch Mar 05 '13 at 15:50
  • 1
    Use `.outerHeight(true)` to get full height (with padding and margin). – Pavlo Mar 05 '13 at 15:57
  • @PavloMykhalov That's true, but I generally avoid using margins in this case because of the changes of margin collapse, which complicates calculation. – Terry Mar 05 '13 at 16:04
  • This is awesome, thanks! I love not having to guess the width, and it works great with different font sizes and content (the client can edit the text). I ended up going with the original CSS though since I have to support a couple browsers that don't know about `box-sizing` (guess who). – Wesley Murch Mar 05 '13 at 16:08
1

This is not too difficult to do with JavaScript. I have no idea how to do it without JS (if that's even possible).

You can use another "invisible" div to measure dimensions until it gets to the 320px height while reducing its with by a set amount (even 1 pixel at a time, if you want to be as precise as possible).

var $measurer = $("<div>").css({'position': 'fixed', 'top': '100%'})
    .text($("p").text()).appendTo('body');

var escape = 0;
while ($measurer.height() < 320) {
    console.log($measurer.height());
    $measurer.width(function (_, width) { return width - 1; });
    console.log($measurer.width());
    escape++;
    if (escape > 2000) {
        break;
    }
}
$("p").width($measurer.width());
$measurer.remove();

http://jsfiddle.net/RwczR/2/

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
1

Try this:

var p = $('p');
var height = parseInt(p.height())-40;
p.height('auto');
p.width('auto');
for(var i=p.width(); i--; ) {
    p.width(i);
    if (p.height() > height) {
        p.height(height+20);
        p.width(i-1);
        break;
    }
}
p.height(height);

http://jsfiddle.net/RwczR/6/

jcubic
  • 61,973
  • 54
  • 229
  • 402
1

You can use jQuery/JavaScript and checking the client vs the scroll heights keep increasing the width until it fits the text, similar to the below.

You need to also set overflow: hidden; in the CSS on the p tag for the scrollHeight to give you the actual height including the overflow.

The below code also takes margin and padding into account for both; height and width and adjusts accordingly.

Changing the height of the outer div ajdust accordingly.

$(document).ready(function(){
    var $container = $("div");
    var containerHeight = $container.height();
    var containerWidth = $container.width();

    var $textWrapper = $(">p", $container);

    var paddingMarginHeight = $textWrapper.outerHeight(true) - $textWrapper.innerHeight();
    var paddingMarginWidth = $textWrapper.outerWidth(true) - $textWrapper.innerWidth();

    $textWrapper.innerHeight(containerHeight - paddingMarginHeight);

    //SetMinWidth();
    var maxWidth = containerWidth - paddingMarginWidth;
    var visibleHeight = 0;
    var actualHeight = 0;

    for(i = 50; i <= maxWidth; i++){
        $textWrapper.innerWidth(i);

        visibleHeight = $textWrapper[0].clientHeight;
        actualHeight = $textWrapper[0].scrollHeight;

        if(visibleHeight >= actualHeight){
            break;
            console.log("ouyt");
        }
    }
});

DEMO - Grow width until text is fully visible


Nope
  • 22,147
  • 7
  • 47
  • 72
  • @WesleyMurch: You don't need jQuery off course but it makes it easier to get paddings/margins dynamically. Otherwise this is a dynamic solution. the `50` min width was simply for the demo. You can off course expand on that to also include a `clientWidth`\`scrollWidth` check to ensure the minwidth is covered too. Still very dynamic. – Nope Mar 05 '13 at 15:54
  • Good solution too. I went with the shorter one. Sorry for the delay in my response, I had to test all these answers (didn't expect so many). They're all pretty much the same approach though. – Wesley Murch Mar 05 '13 at 15:56
0

We can give the paragraph an overflow:auto;.

If the paragraph needs a vertical scroll bar, it will create one.

The trick is to keep tightening the width, until the scroll bar is created.

var hasScrollBar = false;
var p = document.getElementById('myParagraph');
while(!hasScrollBar)
{
    if(p.scrollHeight>p.clientHeight)
    {
        //Has Scroll Bar
        //Re-Increase Width by 1 Pixel
        hasScrollBar=true;
        p.style.width=(p.clientWidth+1)+"px";
    }
    else
    {
       //Still no Scroll Bar
       //Decrease Width
       p.style.width=(p.clientWidth-1)+"px";
    }
}
Ali Bassam
  • 9,691
  • 23
  • 67
  • 117