Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Place a button when text is overflowing

Tags:

jquery

css

So say i have a <div> with a long text inside and defined height, and when text overflows that div height i want to display ... at the end of the text, so this is easy with a little css, but i want something a bit more advanced.

What i want is to have that ... and a button (Show more), and i kind of made it, but it's quite a dirty hack and i know there should be better solution, anyways please take a look a this fiddle: http://jsfiddle.net/DgBR2/1/

Basically i just floated another div with white background on top of the text, but if i would want to change that text height or something else this would create problems in the future, so i want something better.

like image 457
Linas Avatar asked Nov 06 '12 20:11

Linas


2 Answers

Revised 11/07/2012

Robust Text Overflow Slider

Robust Fiddle

Features:
1. Auto adjusts for font size
2. Auto Adjusts for 'Show More / Show Less' Buttons
3. Easily Change Animation Speed
4. Easily Change 'Show More / Show Less' Button Spacing
5. Easily Choose Which side the 'Show More / Show Less' Displays On
6. Easily Set how many Lines of Text should initially appear

JQuery

//Editable Values

var lines = 5; //Choose how many lines you would like to initially show
var buttonspacing = 7; //Choose Button Spacing
var buttonside = 'right'; //Choose the Side the Button will display on: 'right' or 'left'
var animationspeed = 1000; //Choose Animation Speed (Milliseconds)


//Do not edit below

var lineheight = $('.text').css("line-height").replace("px", "");
startheight = lineheight * lines;
$('.text_container').css({'height' : startheight });

var buttonheight =  $('.button').height();

$('div.container').css({'padding-bottom' : (buttonheight + buttonspacing ) });

if(buttonside == 'right'){
    $('.button').css({'bottom' : (buttonspacing / 2), 'right' : buttonspacing });
}else{
   $('.button').css({'bottom' : (buttonspacing / 2), 'left' : buttonspacing });
}

$('.open').on('click', function(){
        var newheight = $(this).parent('div.container').find('div.text').height();
        $(this).parent('div.container').find('div.text_container').animate({'height' : newheight }, animationspeed );
        $(this).hide().siblings('.close').show();

        });

$('.close').on('click', function(){
    var h = $(this).parent('div.container').find('div.text').height();
    $(this).parent('div.container').find('div.text_container').animate({'height' : startheight }, animationspeed );
    $(this).hide().siblings('.open').show();
    });


$('div.container').each(function(){
    if( $(this).find('div.text').height() >= $(this).find('div.text_container').height() ){
        $(this).find('.button.open').show();

    }
});

HTML

<div class="container">
    <div class="text_container">
        <div class='text'>

           // Text goes Here

        </div>
     </div>
    <div class='button open'>...Show More</div>
    <div class='button close'>...Show Less</div>
</div>

CSS

.button {position:absolute; z-index:5; display:none; cursor:pointer; color:#555555;}
.close {display:none; }
.open {display:none;}

.container{
    width:200px;
    overflow:hidden;
    border:1px solid #cacaca;
    border-radius:5px;
    font-size:12px;
    position:relative;
    margin:auto;
    padding:10px 10px 0px 10px;
    float:left;
    margin:5px;
}

.text_container{
    height:105px;
    overflow:hidden;

}

.text {}
like image 118
VIDesignz Avatar answered Nov 08 '22 18:11

VIDesignz


To make it more robust, you can simply remove the set height, rather than setting a new height. This will allow the container to grow to however big its contents are.

Also, I'd recommend using a separate class like .collapsed or similar, and just toggling that class instead of setting the CSS height value back and forth between some value and auto.

Here's a your edited fiddle: http://jsfiddle.net/DgBR2/9/

new JS:

$(".enlarge").click(function(){
    $(this).siblings('.text').toggleClass('collapsed');   
});

new CSS:

.container{
    width:200px;
    border:1px solid #cacaca;
    font-size:12px;
    position:relative;
    margin:auto;
    padding: 10px 10px 26px;
}

.text.collapsed {
    height: 100px;
    overflow: hidden;
}

.enlarge{
    position:absolute;
    height: 21px;
    bottom: 0;
    left: 0; right: 0; text-align: center;
    color:blue;
}

OK, I'm editing my answer to preserve the animation. This solution is a bit trickier and involves three key things:

  1. Getting the height value of .collapsed-classed elements when your element is NOT collapsed, so that you can collapse the element down to the desired height without using a magic number. You do this by creating a new element and giving it the .collapsed class, then checking the height of that new (but not rendered) element.

  2. Getting the full height of the expanded element when it IS collapsed, so that you can animate it to the new height - because .animate() does not work with the auto value.

  3. Removing the set height value after the animation has completed, so that your text element has no fixed height and will expand/shrink automatically if you later change its content.

Here is your new animation-enabled fiddle: http://jsfiddle.net/DgBR2/13/

And the JS looks like this:

$(".enlarge").click(function(){
    var btn = $(this),
        text = btn.siblings('.text'),
        collapsed = text.hasClass('collapsed'),
        // predict the height that the element SHOULD be: its full (scroll) height if it is currently collapsed, or the value of the 'height' CSS property that it will have when collapsed if it is not currently collapsed
        height = collapsed ? text[0].scrollHeight : $('<div>', {'class': 'text collapsed'}).css('height');


    text.animate({'height': height}, 400, function() {
        // do all further changes after the animation completes
       text.toggleClass('collapsed'); // we use this class for our animation logic, so we need to toggle it correctly
       text.css('height', ''); // we don't want the text element to have a fixed height, so remove whatever height we set earlier
       btn.text(collapsed ? 'Show Less' : '...(Show More)');
    });    

});

A final edit to make it even more modular: remove the expander divs from the markup (as they are not semantic) and add them in the JS. This approach also ensures 1) that text containers whose content does not overflow will not have expander buttons 2) that you can correctly hide/show the expander buttons when you add new text divs or change the content of existing text divs.

I'll just sketch the JS to show how it's changed from the previous iteration:

// PSEUDOCODE
$(document).ready(function() {
    var addExpander = function() {
            if (this.scrollHeight <= collapsedHeight) {
                // remove expander button if it exists
            } else if (this /* contains no expander button */) {
                // add the expander with its click function
            }
        };

    // call it on all collapsed text divs currently in the document
    $('.text.collapsed').each(addExpander);

    // how to call it again after changing a text div's content:
    addExpander.call(/* your changed div */);
});

working demo: http://jsfiddle.net/DgBR2/18/

like image 26
tuff Avatar answered Nov 08 '22 17:11

tuff