Рядок, що біжить, на сайті: де marquee-анімація ламає верстку та увагу
Рядок, що біжить, майже завжди починається з одного рядка CSS — і майже завжди закінчується скаргою «на телефоні смикається, а на десктопі з'їжджає занадто швидко».
Причина в тому, що marquee-анімація задає зсув у пікселях за фіксований час: ширина контенту на різних екранах різна, а тривалість одна, тому швидкість плавання змінюється в рази.
Плюс класичний @keyframes зі translateX(-100%) дає ривок на стику циклу — текст «стрибає» в початкову точку, і око це ловить миттєво.
Друга група проблем — конфлікт із прокруткою. Рядок, який рухається поверх блоку, що скролиться, перехоплює жести на тач-пристроях, а overflow: hidden на батьківському елементі обрізає випадні елементи й ламає сітку при ресайзі.
Якщо анімація запущена на властивості, що викликає перерахунок розкладки, браузер перемальовує шар кожен кадр — на слабких пристроях це просідання частоти та нагрівання, а на довгих сторінках ще й боротьба за основний потік із лінивим завантаженням зображень.
Окремо — доступність і увага. Текст, що безкінечно рухається, заважає читати сусідній контент, збиває фокус при навігації з клавіатури й не зупиняється за системним налаштуванням «зменшити рух».
Користувач із вестибулярними особливостями просто йде зі сторінки, а пошукові системи бачать дублювання тексту, якщо рядок продубльовано для безшовності.
Розбираємо, як це закривається: розрахунок швидкості від ширини контенту, безшовний цикл без ривка, пауза за наведенням і системними налаштуваннями, винесення анімації на композиційний шар — щоб рядок залишався плавним і не забирав ресурси в решти сторінки.
Реалізація marquee анімації: CSS, JavaScript і режими руху
Рухомий рядок на чистому CSS збирається на @keyframes з translateX(-50%) і дубльованим контентом: копія стрічки стає впритул до оригіналу, і цикл замикається без ривка.
Такий варіант не торкається головного потоку — анімація йде в композитинг, а will-change: transform знімає зайві перемальовування.
Плавність задається не тривалістю, а узгодженістю: linear без пауз дає рівномірний рух, а animation-play-state: paused на :hover зупиняє стрічку без перерахунку позиції.
Коли контент надходить ззовні або стрічка збирається динамічно, marquee css поступається місцем рухомому рядку на JavaScript.
Тут позиція рахується через requestAnimationFrame, а не через setInterval: кадри синхронізуються з частотою оновлення екрана, і на слабких пристроях не накопичується дрейф.
Швидкість тримаємо в пікселях за секунду і переводимо в зсув за минулим часом — при просіданні кадрів стрічка не «смикається», а просто йде рівніше.
Режими руху та їхня ціна
Безперервне прокручування — базовий режим: одна швидкість, один цикл, передбачуване навантаження. Пінг-понг (стрічка доходить до краю і розвертається) вимагає зміни напрямку на межі — якщо не згладити, на розвороті видно мікрорівок.
Пауза за наведенням і за фокусом з клавіатури — обов'язкова для доступності: рух вимикається через prefers-reduced-motion, а стрічка залишається читабельною статично.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
CSS @keyframes + дубль стрічки |
Статичний набір логотипів, простий тикер | Контент фіксований на етапі верстки, складно змінювати швидкість на льоту |
JavaScript + requestAnimationFrame |
Динамічні дані, різна швидкість, пауза за подіями | Потрібен контроль за очищенням кадрів при розмонтуванні |
| Гібрид: CSS-анімація, керована змінними | Потрібна плавність CSS і гнучкість налаштувань | Вимагає акуратної синхронізації CSS-змінних зі станом |
Що дає на виході
На довгій стрічці з десятків елементів перехід на композитинг і requestAnimationFrame прибирає просідання кадрів при прокручуванні сторінки: рух перестає конкурувати з головним потоком.
Стрічка зі сотні логотипів зберігає рівний хід, а пауза за наведенням і вимкнення за prefers-reduced-motion закривають вимоги доступності без окремої реалізації.
Для керування кадрами і синхронізації з розміткою в проєктах використовуємо requestAnimationFrame — він дає передбачуваний таймінг замість таймерів.
Як ми впроваджуємо біжучий рядок: від аудиту до передачі
Впровадження marquee-анімації починається з аудиту поточної верстки: дивимося, з чого зібраний блок, чи є фіксовані ширини, як поводиться контейнер при переповненні та чи не конфліктує нова стрічка з наявними трансформаціями й overflow.
На цьому етапі фіксуємо, де анімація допустима за вимогами доступності, а де її доведеться вимикати або замінювати статичним блоком — це дешевше, ніж переробляти після релізу.
Далі проєктуємо схему руху: обираємо між CSS-анімацією з дублюванням контенту для безшовного циклу та керуванням через TypeScript, коли потрібні пауза при наведенні, адаптивна швидкість або синхронізація з прокруткою.
Окремо рахуємо довжину треку й кількість копій, щоб на широких екранах не з'являлося пустот, а на вузьких стрічка не «смикалася» через перерахунок ширини.
- Аудит верстки й контенту — розбір структури блоку, перевірка переповнень і конфліктів зі стилями.
- Проєктування схеми анімації — вибір підходу, розрахунок довжини треку та кількості дублів контенту.
- Налаштування біжучого рядка — прив'язка швидкості до ширини контейнера, пауза при наведенні та фокусі.
- Урахування доступності — вимкнення руху при
prefers-reduced-motion, збереження читабельності тексту. - Перевірка на пристроях — прогін на мобільних, планшетах і десктопі, включно зі зміною орієнтації екрана.
- Оптимізація відмалювання — винесення анімації на композиторний шар, щоб стрічка не викликала перерахунок макета.
- Передача й документація — параметри налаштування, інструкція з правки швидкості та складу стрічки.
Така послідовність прибирає типові збої: ривки на слабких пристроях, обрив стрічки при зміні ширини вікна та «залипання» анімації після повернення на вкладку. Замість правок за фактом скарг замовник отримує передбачувану поведінку блоку на всьому парку пристроїв. Опишіть задачу — повернемося з оцінкою та планом робіт.
Чим CSS-анімація відрізняється від JavaScript-реалізації рухомого рядка?
CSS-анімація рухомого рядка живе цілком у браузерному рушії відображення: ви задаєте ключові кадри та animation-play-state, а зсув елементів обчислює композитор, минаючи основний потік.
Поки рядок не змінює вміст, сторінка не перераховує розмітку й не перемальовує шари — за десятка таких блоків на сторінці це помітно за стабільністю прокручування.
Обмеження те саме: CSS не знає, скільки місця займає контент, тому безшовний цикл будується на дублюванні доріжки та translateX(-50%), а пауза при наведенні чи фокусі робиться лише через :hover і :focus-within.
JavaScript-реалізація керує анімацією з коду: позиція обчислюється в requestAnimationFrame, зсув записується в transform, а швидкість, напрямок і точка старту — звичайні змінні.
Це дає те, чого немає в CSS: зупинку на конкретному елементі, синхронізацію кількох доріжок, підлаштування швидкості під довжину тексту після завантаження даних, паузу при переході вкладки у фон через visibilitychange.
Плата — цикл на основному потоці: якщо поруч іде важка робота, кадри просідають, а при неакуратному записі в left або top замість transform браузер перераховує розмітку на кожному кадрі.
Вибір реалізації рухомого рядка впирається в сценарій. Статичний набір логотипів або текстовий тикер без інтерактиву — CSS: менше коду, нульове навантаження на потік, працює при вимкнених скриптах.
Стрічка з даними з API, різною довжиною елементів, зупинкою по кліку та зв'язкою з іншими блоками — JavaScript, бо керування анімацією потребує доступу до стану, а не лише до стилів.
Гібрид закриває обидва випадки: розмітку та базовий рух задає CSS, а скрипт втручається точково — ставить animation-play-state: paused при наведенні, перераховує тривалість після підвантаження контенту, вимикає рух при prefers-reduced-motion. Так основний цикл залишається на композиторі, а логіка — в коді.
Кейс: як біжучий рядок перестав смикатися й навантажувати сторінку
Клієнт звернувся з типовою скаргою: біжучий рядок на головній «смикається» на слабких ноутбуках і старих телефонах, а при відкритті вкладки у фоні браузер навантажує процесор до помітного нагрівання.
Вимірювання підтвердили діагноз: анімація йшла через setInterval з перерахунком позиції в JavaScript, кожні 16 мс читався offsetWidth і записувався style.left — це спричиняло примусову синхронізацію розкладки на кожному кадрі.
На слабкому пристрої інтервал не встигав відпрацювати, кадри пропускалися, і стрічка візуально ривками наздоганяла позицію.
Що змінили
Перевели рух на композиторний шар: анімація через transform: translate3d() з ключовими кадрами CSS, а JS залишили тільки на керування — паузу при наведенні, підстроювання швидкості та перезапуск.
Тривалість задається змінною, а не перерахунком у циклі, тому браузер веде стрічку сам, без участі основного потоку. Дублювання контенту для безшовності зробили через aria-hidden-копію, щоб скринрідер не читав текст двічі.
Додали prefers-reduced-motion: при системному налаштуванні «менше руху» стрічка зупиняється й перетворюється на звичайну прокручувану область. Пауза за visibilitychange глушить анімацію в неактивній вкладці — це прибрало нагрівання та зайві витрати батареї.
| Було | Стало |
|---|---|
| Перерахунок позиції в JS кожен кадр | CSS-анімація на композиторі |
| Ривки на слабких пристроях | Рівний рух, стабільна швидкість |
| Нагрівання та витрати батареї у фоні | Анімація стає на паузу поза вкладкою |
| Текст читається двічі | Копія прихована від скринрідерів |
Результат
Після правок частота кадрів на слабкому пристрої вирівнялася й перестала просідати, навантаження на процесор у спокої знизилося приблизно втричі, а у фоновій вкладці — практично до нуля.
Швидкість стрічки тепер однакова на всіх пристроях, бо її задає час проходження, а не частота перемальовування. Правки зайняли один робочий цикл і не потребували змінювати розмітку сторінки.
Підхід спирається на стандартні механізми браузера, тому не ламається при оновленнях. Деталі реалізації звіряли з документацією MDN Web Docs щодо CSS-анімацій і композитингу.
Сумніви перед впровадженням: сумісність, відкат і доступи
Що якщо рухомий рядок конфліктує з поточною версткою? Marquee-анімація майже завжди ізолюється в окремий шар: контейнер з overflow: hidden, трек на трансформаціях, дублювання контенту для безшовного циклу.
Такий блок не чіпає сітку сторінки, не впливає на потік документа і не ламає існуючі компоненти — сумісність анімації перевіряється точково, без перезбирання макета.
Як відкочуються зміни, якщо щось піде не так? Кожна правка йде окремим комітом з описом, стилі та скрипт виносяться в ізольовані файли, а не розмазуються по проєкту.
Відкат змін — це повернення одного коміту, а не ручне розплутування чужого коду: попередня версія блоку повертається за хвилини.
Хто і як отримує доступи для розробки? Ми працюємо через окремі облікові записи з мінімально потрібними правами, без доступу до платіжних і персональних даних. Доступи для розробки видаються на час робіт і відкликаються після завершення — це фіксується в передачі.
Анімація буде гальмувати на слабких пристроях?
Рух будується на трансформаціях і requestAnimationFrame, а не на перерахунку позиції в кожному кадрі. При prefers-reduced-motion рухомий рядок зупиняється автоматично — це вимога доступності, а не опція. На слабких пристроях навантаження залишається в межах одного композитного шару.
Після здачі замовник отримує на руки:
- вихідний код блоку з коментарями та структурою файлів;
- конфігурацію швидкості, напрямку та паузи при наведенні;
- схему підключення до поточного шаблону та збірки;
- правила доступності та поведінку при reduced-motion;
- інструкцію з правки тексту та додавання нових елементів;
- чеклист перевірки після оновлення контенту;
- опис процедури відкату до попередньої версії.
Опишіть вашу задачу та поточний стек — повернемося з оцінкою та планом робіт по рухомому рядку.
Терміни впровадження рядка, що біжить, за етапами
Терміни залежать не від самої marquee анімації — її механіка займає години, — а від того, скільки часу йде на узгодження контенту, доступи до середовища та перевірку на реальних даних.
Нижче — орієнтовний план розробки, який ми уточнюємо після розбору задачі: цифри показують порядок робіт і точки, де зазвичай виникає очікування на боці замовника.
Паралельно йде робота з контентом: якщо рядок тягне дані із зовнішнього джерела, додається час на узгодження формату та обробку збоїв.
На етапі перевірки ми окремо дивимося, як поводиться marquee анімація, коли тексту більше за ширину екрана в рази, і коли його майже немає — це два найчастіші випадки, де прототип виглядає добре, а на проді ламається верстка.
Загальний орієнтир для типової задачі — від тижня до двох з половиною, якщо не потрібна інтеграція із сторонніми системами. Точні терміни впровадження називаємо після того, як побачимо вашу сторінку і зрозуміємо, звідки береться текст. Опишіть задачу — повернемося з оцінкою та планом за етапами.







