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.
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 {}
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:
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.
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.
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With