The effects in the previous lesson, jQuery Effects, are ready-made animations. When you need something else – a progress bar filling up, a box moving across the screen, a number counting up – you use the general-purpose jQuery animate() method. In fact, fadeIn() and slideDown() are built on top of it.
The jQuery animate() syntax
.animate() takes an object of CSS properties and their target values. jQuery then changes each property step by step from its current value to the target over the duration you give.
// properties, duration, easing, callback
$('#box').animate({ left: '200px', opacity: 0.5 }, 800, 'linear', () => {
$('#status').text('Arrived!');
});
// properties, options object (more settings available)
$('#box').animate(
{ left: '200px', opacity: 0.5 },
{
duration: 800,
easing: 'swing',
complete: () => $('#status').text('Arrived!')
}
);Write property names in camelCase (marginLeft) or quote the CSS name ('margin-left'). The duration, easing and callback work just like in the effects methods.
What can jQuery animate?
Only properties with a single number can be animated: width, height, opacity, left, top, margins, paddings, font-size, border-width, and also scrollTop and scrollLeft. Colours (background-color) and transform cannot be animated by jQuery alone; colours need a plugin, and for transforms you should use CSS transitions instead.
- Units: write them as strings, such as
'240px','75%'or'2rem'. Plain numbers getpxonly for the same short list of properties as.css()in jQuery 4, so including the unit is the safe habit. - Relative values:
'+=50px'and'-=50px'animate from the current value, which is ideal for “move a bit further” buttons. - Shortcuts:
'show','hide'and'toggle'animate a property to or from zero and handledisplayfor you, e.g.{ height: 'toggle' }. - Positioning:
leftandtoponly move an element that hasposition: relative,absoluteorfixedin your CSS.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>A progress bar and a moving box</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
.track { height: 18px; background: #e5e7eb; border-radius: 9px; overflow: hidden; max-width: 400px; }
#bar { width: 0; height: 100%; background: #16a34a; }
#stage { position: relative; height: 60px; max-width: 400px; margin-top: 16px; border: 1px dashed #bbb; }
#auto { position: absolute; left: 0; top: 10px; width: 40px; height: 40px; background: #f59e0b; border-radius: 6px; text-align: center; line-height: 40px; }
button { margin: 4px 2px; }
</style>
</head>
<body>
<p>Upload progress: <span id="pct">0%</span></p>
<div class="track"><div id="bar"></div></div>
<button id="fill" type="button">Fill to 75%</button>
<button id="empty" type="button">Empty</button>
<div id="stage"><div id="auto">🛺</div></div>
<button id="right" type="button">Move right</button>
<button id="left" type="button">Move left</button>
<button id="stopbtn" type="button">Stop</button>
<p id="status" role="status"></p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const $bar = $('#bar');
function fillTo(target) {
$bar.stop().animate({ width: target + '%' }, {
duration: 1200,
easing: 'linear',
// step runs on every frame: keep the label in sync
step: (now) => $('#pct').text(Math.round(now) + '%')
});
}
$('#fill').on('click', () => fillTo(75));
$('#empty').on('click', () => fillTo(0));
const $auto = $('#auto');
$('#right').on('click', () => {
$auto.animate({ left: '+=80px' }, 500, () => $('#status').text('Moved right.'));
});
$('#left').on('click', () => {
$auto.animate({ left: '-=80px' }, 500, () => $('#status').text('Moved left.'));
});
$('#stopbtn').on('click', () => {
$auto.stop(true); // stop now and clear any queued moves
$('#status').text('Stopped at left = ' + $auto.css('left'));
});
</script>
</body>
</html>Click “Move right” several times quickly: each click adds an animation to the queue, so the auto-rickshaw keeps going until all of them have played. “Stop” calls .stop(true), which halts it on the spot and clears the queue. In fillTo(), .stop() before .animate() makes the newest click win straight away.
Easing
Easing controls how the speed changes during an animation. jQuery includes two: 'swing' (the default), which starts and ends slowly, and 'linear', which moves at a constant speed. Linear suits progress bars and counters; swing feels more natural for movement. Other easings such as “easeOutBounce” come from the separate jQuery UI library, so do not use those names unless it is loaded.
Running animations together or in sequence
Properties inside one .animate() call change together. Separate calls on the same element queue up and run one after another. To run a second animation at the same time as one already running, pass queue: false in the options object. The .stop(), .finish() and .delay() methods from the effects lesson work the same way here.
Animating a number, not an element
.animate() also works on a plain object. Wrap it, animate one of its properties, and use step to show the value. This is a neat way to build a counting-up statistic without a separate library.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Counting up with step</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
#count { font-size: 2rem; font-weight: bold; color: #1d4ed8; }
</style>
</head>
<body>
<p>Happy customers in Coimbatore: <span id="count">0</span></p>
<button id="start" type="button">Start counter</button>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$('#start').on('click', () => {
$({ value: 0 }).animate({ value: 3600 }, {
duration: 1500,
easing: 'swing',
step: (now) => $('#count').text(Math.round(now).toLocaleString('en-IN')),
complete: () => $('#count').text((3600).toLocaleString('en-IN') + '+')
});
});
</script>
</body>
</html>Smooth scrolling
A classic use of .animate() is scrolling the page to a section: $('html').animate({ scrollTop: $('#contact').offset().top }, 500). .offset().top gives the section’s distance from the top of the document. Today the same effect often needs no JavaScript at all: html { scroll-behavior: smooth; } in CSS makes ordinary #contact links glide. Put that rule inside a @media (prefers-reduced-motion: no-preference) block so people who prefer reduced motion jump straight to the section instead.
Performance and accessibility
Animating width, left or margin makes the browser recalculate the layout on every frame, which can stutter on low-end phones. For smooth movement, toggle a class and let a CSS transition animate transform and opacity, which browsers can handle without layout work. The post CSS animation performance tips explains why. Use jQuery animate() for small touches, values that CSS cannot reach (like scrollTop) and existing code.
Tip: Like other effects, .animate() respects jQuery.fx.off. Turn it on when the user has asked for reduced motion, and your animations will jump to their final state instead of moving.
