Reputation: 832
I am working on a text effect but the transition is not completely to my liking.
I am replacing a single word in a line of centered text, I make the old word fade out and the new one fade in, but the surrounding text "jumps". I have been trying for a while to figure out how to make it slide to it's new spot somehow by using an animation on margins or width, but I cannot seem to figure it out.
Here is a JSfiddle of what I have right now http://jsfiddle.net/DEk7m/3/
What I am trying to achieve is something similar to what is seen in the big title here: https://gumroad.com/
And here is the code:
HTML:
<h1 id="changingtext">This is <span>changing</span> text</h1>
CSS:
h1 {
text-align: center;
font-family: helvetica, arial, sans-serif;
}
JavaScript (using jQuery):
$(function() {
var t1 = new Array("changing", "dynamic", "cool");
var i = 0;
var tid = setInterval(
function() {
$("#changingtext span").animate({'opacity': 0}, 1000, function () {
$(this).text(t1[i]);
}).animate({'opacity': 1}, 1000);
if(i < t1.length -1)
i++;
else i = 0;
}, 3000 );
});
many thanks!
Upvotes: 7
Views: 2165
Reputation: 206028
SEE ANOTHER ANSWER COVERING THE SAME QUESTION
BON! No need for setInterval
when you deal with .animate()
An even better approach without the first change gap/jump
and with dynamically calculated span
widths:
CSS:
h1 span{
/* To prevent a jumpy misaligned SPAN due to widths change. */
vertical-align:top;
}
jQ:
$(function() {
var t=["changing", "dynamic", "cool"],
$h1 = $("#changingtext"),
$sp = $h1.find("span"),
i=0,
widths=[];
$.each(t, function(i, v){
var el = $('<span />', {text:v}).appendTo($h1);
widths.push(el.width());
el.remove();
});
$sp.css({opacity:0});
(function loop(){
i = ++i%t.length;
$sp.text(t[i]).animate({width:widths[i]}, 1000, function(){
$(this).animate({opacity:1},1000).delay(3000).animate({opacity: 0}, 1000, loop);
});
})();
});
This code group
$.each(t, function(i, v){
var el = $('<span />', {text:v}).appendTo($h1);
widths.push(el.width());
el.remove();
});
stores inside our widths[]
array all the needed widths we need.
We'll treat the widths[]
iterations same as you already do for t[]
than we create a recursive self-invoking function
(no need for setInterval
!) where we'll test for i
to become 0
using a simple Modulo Operator (Reminder) %
i = ++i%t.length;
The function "looping" is simply achieved recalling that function inside the last chained animation callback.
Upvotes: 3
Reputation: 6596
Ok here is a working example i quickly made for you: fiddle
As you can see I am using another element that is hidden and contains the next string for calculating the correct width - all u need now is just
Fading out >>> Animating the width >>> Text >>> Fade in.
The text is not jumping while fading out because the outer words are floated to the left/right.
Have fun....
var words1 = new Array( "dynamic", "changing", "cool");
var i1 = 0;
$("#next1").text($("#outer1").text()).hide();
$("#outer1").width($("#next1").width());
var tid1 = setInterval(
function() {
var word_in1;
if (typeof words1[i1+1] !='undefined') { word_in1 = words1[i1+1] } else { word_in1 =
words1[0]; }
var by_char_next1 = $("#next1").text('This is '+ word_in1 + ' text').width();
$("#changingtext1").fadeOut(1000, function(){
$("#outer1").animate({'width': by_char_next1 },1000,function(){
$("#changingtext1").text(words1[i1]).fadeIn(1000);
});
});
if (i1 < words1.length-1) i1++;
else i1 = 0;
}, 3000 );
#outer1,
#changingtext1
{
padding:0;
margin:0;
font-size: 40px;
font-weight: bold;
font-family: helvetica, arial, sans-serif;
}
#next1{
padding:0;
margin:0;
font-size: 40px;
font-weight: bold;
font-family: helvetica, arial, sans-serif;
}
<center>
<div id='outer1' align='center'>
<span style='float:left;'>This is</span>
<span id="changingtext1">changing</span>
<span style='float:right;'>text</span>
</div>
<br />
<span id='next1'></span>
</center>
Upvotes: 0
Reputation: 1464
Width is missing in your demo, Have a look at this,
HTML
<body>
<h1><span id="chkWidth" style="display: none;"></span></h1>
<h1 id="changingtext">This is <span>changing</span> text</h1>
</body>
Script
$(function() {
var t1 = new Array("changing", "dynamic", "cool");
var i = 0;
var width;
var tid = setInterval(
function() {
$("#changingtext span").animate({'opacity': 0}, 1000, function () {
$(this).text(t1[i]);
width = $('#chkWidth').text(t1[i]).width();
$(this).animate({'opacity': 1, 'width': width}, 1000);
});
if(i < t1.length -1)
i++;
else i = 0;
}, 3000 );
});
Hope this will help you.
Upvotes: 5
Reputation: 20820
You can set up an object array to include the ideal width for each instance that comes next.
var t1 = [ ['changing', '130px'], ['dynamic', '80px'], ['cool','150px'] ],
i = 0;
var tid = setInterval( function() {
$("#changingtext span")
.animate({
'opacity': 0,
'width': t1[i][1] },
500,
function() {
$(this).text( t1[i][0] );
})
.animate({'opacity': 1}, 1000);
if(i < t1.length -1)
i++;
else
i = 0;
}, 3000 );
This is a bit of a static and cumbersome way but it should set you off on the right direction.
You could probably figure out the sizes of the spans dynamically by printing the words as a span
list, measuring their width and adding their widths to the array.
Upvotes: 1