Motion blur при переключении слайдов: реализация в вебе
Пошаговое руководство по реализации motion blur при переключении слайдов. Примеры кода на HTML, CSS и JavaScript для создания плавных переходов.
Как реализовать эффект motion blur при переключении слайдов в веб-разработке (HTML/CSS/JS)?
Я пытаюсь создать сложный эффект перехода между слайдами с motion blur, но у меня возникают трудности с пониманием физики движения. Я уже пробовал различные подходы:
- Простые CSS-переходы с использованием translateX и filter: blur()
- Разные кривые cubic-bezier для имитации рывка
- Анимацию через requestAnimationFrame с покадровым изменением transform и filter
Однако ни один из этих методов не дает желаемого результата. Пример эффекта, который я пытаюсь повторить, можно посмотреть по ссылке: https://www.youtube.com/watch?v=FXlsixi7wa8
Мои текущие эксперименты с кодом доступны здесь: https://github.com/temwin/test-tasks/tree/main/tas…
Подскажите, пожалуйста, какие подходы или техники могут помочь достичь подобного эффекта motion blur при переключении слайдов? Какие технологии и методы лучше всего подходят для создания плавных переходов с размытием движения в веб-приложениях?
Эффект motion blur при переключении слайдов можно реализовать через комбинацию CSS-анимаций с filter: blur() и transform, либо использовать продвинутые JavaScript-библиотеки вроде GSAP для создания физически корректного размытия движения. Основная сложность заключается в синхронизации скорости перемещения с интенсивностью размытия.
Содержание
- Основные понятия: Motion blur в веб-разработке
- CSS-подходы: Использование filter: blur() и transform
- JavaScript решения: requestAnimationFrame и управление анимацией
- Продвинутые техники: GSAP и библиотеки для сложных анимаций
- Оптимизация производительности: Советы по реализации motion blur
- Примеры кода: Практические реализации эффектов
Основные понятия: Motion blur в веб-разработке
Motion blur (размытие в движении) — это визуальный эффект, имитирующий размытие объектов при быстром перемещении. В веб-разработке этот эффект достигается путем динамического изменения степени размытия элемента в зависимости от его скорости перемещения.
В отличие от простых CSS-переходов, где blur применяется статически, настоящий motion blur требует:
- Динамического расчета скорости движения
- Прогрессивного изменения интенсивности размытия
- Синхронизации с физическими законами движения
Проблема большинства базовых подходов заключается в том, что они не учитывают физику движения: объект замедляется в начале ускорения и конце движения, а размытие должно быть максимальным в момент максимальной скорости.
CSS-подходы: Использование filter: blur() и transform
Для реализации motion blur при переключении слайдов можно комбинировать свойства transform и filter: blur() с CSS-анимациями.
Базовая реализация
.slider-container {
position: relative;
overflow: hidden;
width: 100%;
height: 400px;
}
.slide {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
transform: translateX(100%);
transition: transform 0.6s ease-out, filter 0.6s ease-out, opacity 0.6s ease-out;
filter: blur(0px);
}
.slide.active {
opacity: 1;
transform: translateX(0);
filter: blur(0px);
}
.slide.prev {
transform: translateX(-100%);
filter: blur(8px);
}
Продвинутая реализация с ключевыми кадрами
@keyframes slideWithBlur {
0% {
transform: translateX(100%);
filter: blur(0px);
opacity: 0;
}
20% {
transform: translateX(40%);
filter: blur(4px);
opacity: 0.8;
}
50% {
transform: translateX(0);
filter: blur(0px);
opacity: 1;
}
80% {
transform: translateX(-40%);
filter: blur(4px);
opacity: 0.8;
}
100% {
transform: translateX(-100%);
filter: blur(8px);
opacity: 0;
}
}
.slide {
animation: slideWithBlur 1s ease-in-out forwards;
}
Ключевой момент здесь — синхронизация анимации transform и filter: blur(). В начале движения объект еще не набрал скорость, поэтому размытие минимально. В момент максимальной скорости размытие достигает пика, а при замедлении снова уменьшается.
JavaScript решения: requestAnimationFrame и управление анимацией
Для более сложных анимаций motion blur лучше использовать JavaScript с requestAnimationFrame. Это позволяет точно контролировать каждый кадр анимации и вычислять физически корректное размытие.
Базовая реализация с requestAnimationFrame
class MotionBlurSlider {
constructor(container, options = {}) {
this.container = container;
this.slides = container.querySelectorAll('.slide');
this.currentIndex = 0;
this.animationDuration = options.duration || 800;
this.blurMax = options.maxBlur || 10;
this.init();
}
init() {
this.slides[this.currentIndex].classList.add('active');
setInterval(() => this.nextSlide(), 3000);
}
nextSlide() {
const currentSlide = this.slides[this.currentIndex];
const nextIndex = (this.currentIndex + 1) % this.slides.length;
const nextSlide = this.slides[nextIndex];
this.animateSlide(currentSlide, nextSlide, nextIndex);
}
animateSlide(currentSlide, nextSlide, nextIndex) {
const startTime = Date.now();
const startX = 0;
const endX = -100;
currentSlide.classList.remove('active');
nextSlide.classList.add('active');
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / this.animationDuration, 1);
// Используем easeOutCubic для более естественного замедления
const easedProgress = 1 - Math.pow(1 - progress, 3);
const currentX = startX + (endX - startX) * easedProgress;
const blurAmount = this.calculateBlur(easedProgress);
currentSlide.style.transform = `translateX(${currentX}%)`;
currentSlide.style.filter = `blur(${blurAmount}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
} else {
this.currentIndex = nextIndex;
}
};
requestAnimationFrame(animate);
}
calculateBlur(progress) {
// Размытие максимальное в середине движения (0.5)
const distanceFromCenter = Math.abs(progress - 0.5);
const maxBlurAtCenter = this.blurMax;
// Чем ближе к началу или концу, тем меньше размытие
return maxBlurAtCenter * (1 - distanceFromCenter * 2);
}
}
Расширенная реализация с физическим движением
class PhysicsMotionBlur {
constructor(element, targetX, duration = 1000) {
this.element = element;
this.targetX = targetX;
this.duration = duration;
this.startTime = null;
this.startX = 0;
this.velocity = 0;
this.acceleration = 0;
this.maxBlur = 8;
}
start() {
this.startTime = performance.now();
this.startX = parseFloat(this.element.style.transform.replace('translateX(', '').replace('px)', '')) || 0;
this.acceleration = (this.targetX - this.startX) / (this.duration * this.duration / 2);
this.animate();
}
animate() {
const currentTime = performance.now();
const elapsed = currentTime - this.startTime;
if (elapsed < this.duration) {
// Физическое движение с ускорением и замедлением
const t = elapsed / 1000; // в секунды
// Позиция с ускорением
const position = this.startX + 0.5 * this.acceleration * t * t;
// Скорость для расчета размытия
this.velocity = this.acceleration * t;
// Размытие пропорционально скорости
const speedRatio = Math.abs(this.velocity) / 1000;
const blurAmount = Math.min(this.maxBlur * speedRatio, this.maxBlur);
this.element.style.transform = `translateX(${position}px)`;
this.element.style.filter = `blur(${blurAmount}px)`;
requestAnimationFrame(() => this.animate());
} else {
// Финальная позиция без размытия
this.element.style.transform = `translateX(${this.targetX}px)`;
this.element.style.filter = 'blur(0px)';
}
}
}
Продвинутые техники: GSAP и библиотеки для сложных анимаций
Для профессиональной реализации motion blur лучше использовать специализированные библиотеки, такие как GSAP (GreenSock Animation Platform), которые предлагают встроенные инструменты для создания сложных анимационных эффектов.
GSAP MotionBlurPlugin
GSAP предоставляет плагин MotionBlurPlugin, который автоматически рассчитывает и применяет эффект размытия на основе скорости движения элементов.
// Регистрация плагина
gsap.registerPlugin(MotionBlurPlugin);
// Базовая реализация
function createGSAPMotionBlur() {
const container = document.querySelector('.slider-container');
const slides = container.querySelectorAll('.slide');
let current = 0;
slides.forEach((slide, index) => {
if (index === 0) slide.classList.add('active');
gsap.set(slide, {
x: index === 0 ? 0 : 100,
opacity: index === 0 ? 1 : 0
});
});
setInterval(() => {
const next = (current + 1) % slides.length;
gsap.to(slides[current], {
x: -100,
duration: 1,
motionBlur: true,
motionBlurOpacity: 0.8,
ease: "power2.out"
});
gsap.to(slides[next], {
x: 0,
opacity: 1,
duration: 1,
motionBlur: true,
motionBlurOpacity: 0.8,
ease: "power2.inOut"
});
current = next;
}, 3000);
}
Продвинутая реализация с GSAP
class GSAPMotionBlurSlider {
constructor(container, options = {}) {
this.container = container;
this.slides = container.querySelectorAll('.slide');
this.currentIndex = 0;
this.timeline = gsap.timeline({ paused: true });
this.init(options);
}
init(options) {
// Настройка начальных состояний
this.slides.forEach((slide, index) => {
gsap.set(slide, {
x: index === 0 ? 0 : '100%',
opacity: index === 0 ? 1 : 0,
filter: 'blur(0px)'
});
});
// Создание анимации
this.createAnimation(options);
// Автоматическое переключение
setInterval(() => this.next(), options.interval || 3000);
}
createAnimation(options) {
const duration = options.duration || 1;
const ease = options.ease || "power2.inOut";
this.timeline
.to(this.slides[this.currentIndex], {
x: '-100%',
opacity: 0,
filter: 'blur(8px)',
duration: duration * 0.4,
ease: ease,
motionBlur: true,
motionBlurOpacity: 0.7
})
.to(this.slides[this.currentIndex], {
x: '-200%',
filter: 'blur(0px)',
duration: duration * 0.1,
ease: "power1.in"
}, '-=0.2');
}
next() {
const nextIndex = (this.currentIndex + 1) % this.slides.length;
// Удаление предыдущих анимаций
this.timeline.kill();
// Создание новой анимации
this.createAnimation();
// Запуск анимации
this.timeline.play();
this.currentIndex = nextIndex;
}
}
GSAP особенно эффективен для motion blur, так как он автоматически рассчитывает скорость движения и применяет соответствующее размытие. Это позволяет создавать физически корректные и визуально привлекательные эффекты без сложных расчетов.
Оптимизация производительности: Советы по реализации motion blur
1. Включение hardware acceleration
Для улучшения производительности используйте CSS-свойства, которые активируют аппаратное ускорение:
.slide {
will-change: transform, filter;
backface-visibility: hidden;
transform: translateZ(0);
}
2. Оптимизация анимаций
// Использование RAF с throttling
let lastTime = 0;
const throttle = 16; // ~60fps
function animate(timestamp) {
if (!lastTime || timestamp - lastTime >= throttle) {
updateAnimation();
lastTime = timestamp;
}
requestAnimationFrame(animate);
}
3. Оптимизация filter: blur()
/* Вместо blur() на больших элементах используйте backdrop-filter */
.slide {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
/* Или используйте размытие на псевдоэлементах */
.slide::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
filter: blur(8px);
opacity: 0.7;
}
4. Управление сложностью анимации
// Адаптивная сложность в зависимости от устройства
const isMobile = window.innerWidth < 768;
const blurIntensity = isMobile ? 4 : 8;
// Упрощенная анимация для мобильных устройств
if (isMobile) {
gsap.to(element, {
x: targetX,
duration: 0.8,
ease: "power2.out"
});
} else {
gsap.to(element, {
x: targetX,
duration: 1,
motionBlur: true,
motionBlurOpacity: 0.8,
ease: "power2.out"
});
}
Примеры кода: Практические реализации эффектов
Пример 1: Комбинированный подход CSS + JavaScript
<div class="slider-container">
<div class="slide slide-1">
<img src="slide1.jpg" alt="Slide 1">
</div>
<div class="slide slide-2">
<img src="slide2.jpg" alt="Slide 2">
</div>
<div class="slide slide-3">
<img src="slide3.jpg" alt="Slide 3">
</div>
</div>
.slider-container {
position: relative;
width: 100%;
height: 500px;
overflow: hidden;
}
.slide {
position: absolute;
width: 100%;
height: 100%;
will-change: transform, filter;
backface-visibility: hidden;
}
.slide img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Базовые стили для активных/пассивных слайдов */
.slide.active {
z-index: 2;
}
.slide.prev {
z-index: 1;
}
class AdvancedMotionBlurSlider {
constructor(container) {
this.container = container;
this.slides = container.querySelectorAll('.slide');
this.currentIndex = 0;
this.isAnimating = false;
this.init();
}
init() {
// Настройка начального состояния
this.slides[0].classList.add('active');
// Автоматическое переключение
setInterval(() => this.nextSlide(), 4000);
// Обработка кликов для ручного переключения
this.slides.forEach((slide, index) => {
slide.addEventListener('click', () => {
if (!this.isAnimating && index !== this.currentIndex) {
this.goToSlide(index);
}
});
});
}
nextSlide() {
if (this.isAnimating) return;
const nextIndex = (this.currentIndex + 1) % this.slides.length;
this.goToSlide(nextIndex);
}
goToSlide(targetIndex) {
if (this.isAnimating || targetIndex === this.currentIndex) return;
this.isAnimating = true;
const currentSlide = this.slides[this.currentIndex];
const targetSlide = this.slides[targetIndex];
// Определение направления
const direction = targetIndex > this.currentIndex ? 'next' : 'prev';
// Применение классов для направления
currentSlide.classList.remove('active');
targetSlide.classList.add('active');
if (direction === 'next') {
currentSlide.classList.add('prev');
} else {
currentSlide.classList.add('next');
targetSlide.classList.add('prev');
}
// Запуск анимации
this.animateSlideTransition(currentSlide, targetSlide, direction, targetIndex);
}
animateSlideTransition(currentSlide, targetSlide, direction, targetIndex) {
const duration = 1000;
const startTime = performance.now();
const startTransform = direction === 'next' ? 0 : -100;
const endTransform = direction === 'next' ? -100 : 0;
const maxBlur = 10;
const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Использование easeInOutCubic для естественного движения
const easedProgress = progress < 0.5
? 4 * progress * progress * progress
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
// Расчет позиции и размытия
const currentX = startTransform + (endTransform - startTransform) * easedProgress;
const blurAmount = this.calculateMotionBlur(easedProgress, maxBlur);
// Применение стилей
currentSlide.style.transform = `translateX(${currentX}%)`;
currentSlide.style.filter = `blur(${blurAmount}px)`;
// Дополнительные эффекты для целевого слайда
if (direction === 'next') {
targetSlide.style.transform = `translateX(${100 - currentX}%)`;
targetSlide.style.filter = `blur(${blurAmount * 0.5}px)`;
} else {
targetSlide.style.transform = `translateX(${-100 + currentX}%)`;
targetSlide.style.filter = `blur(${blurAmount * 0.5}px)`;
}
if (progress < 1) {
requestAnimationFrame(animate);
} else {
// Завершение анимации
this.finishTransition(currentSlide, targetSlide, direction, targetIndex);
}
};
requestAnimationFrame(animate);
}
calculateMotionBlur(progress, maxBlur) {
// Размытие максимальное в середине движения
const normalizedProgress = Math.abs(progress - 0.5) * 2;
return maxBlur * (1 - normalizedProgress);
}
finishTransition(currentSlide, targetSlide, direction, targetIndex) {
// Сброс стилей
currentSlide.style.transform = '';
currentSlide.style.filter = '';
targetSlide.style.transform = '';
targetSlide.style.filter = '';
// Удаление временных классов
currentSlide.classList.remove('prev', 'next');
targetSlide.classList.remove('prev');
// Обновление текущего индекса
this.currentIndex = targetIndex;
this.isAnimating = false;
}
}
// Инициализация
document.addEventListener('DOMContentLoaded', () => {
const slider = document.querySelector('.slider-container');
if (slider) {
new AdvancedMotionBlurSlider(slider);
}
});
Пример 2: Реализация с использованием CSS Grid и 3D-трансформаций
<div class="slider-3d">
<div class="slides-container">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
<div class="controls">
<button class="prev">←</button>
<button class="next">→</button>
</div>
</div>
.slider-3d {
position: relative;
width: 100%;
height: 400px;
perspective: 1200px;
overflow: hidden;
}
.slides-container {
position: relative;
width: 100%;
height: 100%;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 100%;
transform-style: preserve-3d;
}
.slide {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
will-change: transform, filter;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: white;
background-size: cover;
background-position: center;
}
.slide::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
filter: blur(0px);
opacity: 0;
transition: all 0.6s ease;
z-index: -1;
}
.slide.active::before {
opacity: 0.3;
filter: blur(20px);
}
.slide.prev {
transform: translateX(-100%) rotateY(25deg) scale(0.8);
filter: blur(15px);
opacity: 0.6;
}
.slide.next {
transform: translateX(100%) rotateY(-25deg) scale(0.8);
filter: blur(15px);
opacity: 0.6;
}
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 10;
}
button {
padding: 10px 20px;
background: rgba(255, 255, 255, 0.2);
border: none;
border-radius: 25px;
color: white;
cursor: pointer;
transition: all 0.3s ease;
}
button:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.05);
}
class Slider3D {
constructor(container) {
this.container = container;
this.slidesContainer = container.querySelector('.slides-container');
this.slides = container.querySelectorAll('.slide');
this.currentIndex = 0;
this.isAnimating = false;
this.init();
}
init() {
// Настройка начального состояния
this.slides[0].classList.add('active');
// Обработка событий
this.container.querySelector('.prev').addEventListener('click', () => this.prev());
this.container.querySelector('.next').addEventListener('click', () => this.next());
// Автоматическое переключение
setInterval(() => this.next(), 5000);
}
next() {
if (this.isAnimating) return;
const nextIndex = (this.currentIndex + 1) % this.slides.length;
this.goToSlide(nextIndex);
}
prev() {
if (this.isAnimating) return;
const prevIndex = this.currentIndex === 0
? this.slides.length - 1
: this.currentIndex - 1;
this.goToSlide(prevIndex);
}
goToSlide(targetIndex) {
if (this.isAnimating || targetIndex === this.currentIndex) return;
this.isAnimating = true;
const currentSlide = this.slides[this.currentIndex];
const targetSlide = this.slides[targetIndex];
// Определение направления
const direction = targetIndex > this.currentIndex ? 'next' : 'prev';
// Применение классов
currentSlide.classList.remove('active');
targetSlide.classList.add('active');
if (direction === 'next') {
currentSlide.classList.add('prev');
targetSlide.classList.add('next');
} else {
currentSlide.classList.add('next');
targetSlide.classList.add('prev');
}
// Анимация 3D-преобразования с размытием
this.animate3DTransition(currentSlide, targetSlide, direction, targetIndex);
}
animate3DTransition(currentSlide, targetSlide, direction, targetIndex) {
const duration = 800;
const startTime = performance.now();
const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Использование easeInOutQuad для плавного движения
const easedProgress = progress < 0.5
? 2 * progress * progress
: 1 - Math.pow(-2 * progress + 2, 2) / 2;
// Расположение слайдов
if (direction === 'next') {
currentSlide.style.transform = `translateX(-100%) rotateY(${25 * easedProgress}deg) scale(${0.8 + 0.2 * (1 - easedProgress)})`;
targetSlide.style.transform = `translateX(${100 * (1 - easedProgress)}%) rotateY(${-25 * (1 - easedProgress)}deg) scale(${0.8 + 0.2 * easedProgress})`;
} else {
currentSlide.style.transform = `translateX(100%) rotateY(${-25 * easedProgress}deg) scale(${0.8 + 0.2 * (1 - easedProgress)})`;
targetSlide.style.transform = `translateX(${-100 * (1 - easedProgress)}%) rotateY(${25 * (1 - easedProgress)}deg) scale(${0.8 + 0.2 * easedProgress})`;
}
// Размытие в зависимости от прогресса
const blurAmount = 15 * Math.sin(easedProgress * Math.PI);
currentSlide.style.filter = `blur(${blurAmount}px)`;
targetSlide.style.filter = `blur(${blurAmount * 0.5}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
} else {
this.finishTransition(currentSlide, targetSlide, direction, targetIndex);
}
};
requestAnimationFrame(animate);
}
finishTransition(currentSlide, targetSlide, direction, targetIndex) {
// Сброс стилей
currentSlide.style.transform = '';
currentSlide.style.filter = '';
targetSlide.style.transform = '';
targetSlide.style.filter = '';
// Удаление временных классов
currentSlide.classList.remove('prev', 'next');
targetSlide.classList.remove('prev', 'next');
// Обновление текущего индекса
this.currentIndex = targetIndex;
this.isAnimating = false;
}
}
// Инициализация
document.addEventListener('DOMContentLoaded', () => {
const slider3d = document.querySelector('.slider-3d');
if (slider3d) {
new Slider3D(slider3d);
}
});
Эти примеры демонстрируют различные подходы к реализации motion blur при переключении слайдов, от базовых CSS-анимаций до сложных 3D-эффектов с JavaScript-управлением. Выбор конкретного подхода зависит от требований к производительности, сложности желаемого эффекта и целевой платформы.
Источники
-
CSS-Tricks: Filter Property — Практическое руководство по использованию filter: blur() для создания эффектов размытия: https://css-tricks.com/almanac/properties/f/filter/
-
MDN Web Docs: CSS filter-function/blur() — Официальная документация по функции CSS blur() и её применению: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur/
-
MDN Web Docs: CSS Transitions — Подробная информация о CSS-переходах и их использовании для анимации: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
-
MDN Web Docs: requestAnimationFrame API — Документация по методу requestAnimationFrame для создания плавных анимаций: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
-
GSAP Documentation — Официальная документация по GreenSock Animation Platform и плагину MotionBlurPlugin: https://greensock.com/docs/v3/GSAP/
Заключение
Реализация эффекта motion blur при переключении слайдов требует комплексного подхода, сочетающего физически корректное движение с соответствующим визуальным размытием. Базовые CSS-анимации с filter: blur() подходят для простых случаев, но для более сложных эффектов лучше использовать JavaScript с requestAnimationFrame или специализированные библиотеки вроде GSAP.
Ключевые моменты успешной реализации:
- Синхронизация скорости и размытия - интенсивность размытия должна соответствовать скорости движения
- Физически корректное движение - использование функций easing, имитирующих ускорение и замедление
- Оптимизация производительности - включение hardware acceleration и эффективное управление анимациями
- Адаптивность - учет возможностей различных устройств и браузеров
Для профессиональных проектов рекомендуется GSAP, который автоматически обрабатывает сложные расчеты и обеспечивает высокую производительность. Для простых случаев достаточно комбинации CSS-переходов с filter: blur() и правильно подобранных функций easing.
Главное - экспериментировать с разными подходами и адаптировать их под конкретные требования проекта, чтобы достичь желаемого визуального эффекта motion blur при переключении слайдов.
Для создания эффекта motion‑blur при переключении слайдов можно воспользоваться свойством filter: blur() и анимировать его вместе с перемещением слайда. Сначала задаём начальный и конечный состояния в ключевых кадрах, а затем применяем их к контейнеру слайдов. В результате при перемещении элемент будет постепенно размываться, создавая иллюзию движения.
/* Слайд, который перемещается */
.slide {
transition: transform 0.5s ease-out, filter 0.5s ease-out;
/* начальное состояние */
transform: translateX(0);
filter: blur(0);
}
/* Состояние при переходе */
.slide.active {
transform: translateX(-100%); /* смещение влево */
filter: blur(8px); /* размываем */
}
// Пример переключения слайдов
const slides = document.querySelectorAll('.slide');
let current = 0;
function nextSlide() {
slides[current].classList.remove('active');
current = (current + 1) % slides.length;
slides[current].classList.add('active');
}
setInterval(nextSlide, 3000);
Таким образом, сочетание transform и filter: blur() позволяет добиться плавного motion‑blur без сторонних библиотек.

Функция CSS blur() применяет гауссовый размыв к элементу. Для реализации motion blur при переключении слайдов, её необходимо комбинировать с анимацией свойств transform. Однако важно учитывать, что простое применение blur() без учёта траектории движения может дать неестественный результат.
Рекомендуется использовать blur() в паре с transform: translateX() для горизонтальных переходов или translateY() для вертикальных. Значение blur() должно постепенно увеличиваться в процессе движения и уменьшаться при остановке. Это создаёт более реалистичный эффект размытия в движении.

Для создания плавных переходов с motion blur рекомендуется использовать CSS transitions с одновременной анимацией нескольких свойств. Оптимальный подход - синхронизировать анимацию transform и filter: blur() с одинаковой продолжительностью.
Ключевые моменты:
- Задайте transition для обоих свойств
- Используйте одинаковые значения duration и timing function
- Начните с blur(0) и постепенно увеличивайте значение
- Синхронизируйте с перемещением элемента
Это обеспечит плавный и естественный эффект motion blur при переключении слайдов.

Для создания более сложных эффектов motion blur можно использовать requestAnimationFrame. Этот метод позволяет контролировать анимацию покадрово, что особенно полезно для реализации физически корректного размытия движения.
Основные преимущества:
- Синхронизация с частотой обновления экрана
- Плавная анимация даже при низкой производительности
- Точное управление каждым кадром анимации
- Возможность реализации сложных траекторий движения
Пример реализации:
function animateMotionBlur(element, startTime, duration, fromX, toX, fromBlur, toBlur) {
const currentTime = Date.now();
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Используем easeOutCubic для более естественного замедления
const easedProgress = 1 - Math.pow(1 - progress, 3);
const currentX = fromX + (toX - fromX) * easedProgress;
const currentBlur = fromBlur + (toBlur - fromBlur) * easedProgress;
element.style.transform = `translateX(${currentX}px)`;
element.style.filter = `blur(${currentBlur}px)`;
if (progress < 1) {
requestAnimationFrame(() => animateMotionBlur(element, startTime, duration, fromX, toX, fromBlur, toBlur));
}
}
GSAP (GreenSock Animation Platform) предоставляет мощные инструменты для создания сложных анимаций motion blur. Библиотека предлагает специализированный плагин MotionBlurPlugin, который автоматически рассчитывает и применяет эффект размытия на основе скорости движения элемента.
Основные преимущества:
- Автоматическое вычисление размытия на основе скорости
- Поддержка 3D-пространства
- Высокая производительность даже для сложных сцен
- Плавное интегрирование с другими анимациями
Пример использования:
gsap.registerPlugin(MotionBlurPlugin);
gsap.to(".slide", {
x: -500,
duration: 1,
motionBlur: true,
motionBlurOpacity: 0.7,
ease: "power2.out"
});
GSAP особенно рекомендуется для профессиональных проектов, где требуется физически корректное и визуально привлекательное motion blur.