Pasek przewijania w aplikacjach — co to jest, jak utworzyć i skonfigurować

Autor: IT Sectr Opublikowano: 2026-07-25 Czas czytania: 9 min

Pasek przewijania (marquee) — to efekt wizualny, w którym tekst automatycznie przewija się poziomo w ograniczonym obszarze, umożliwiając wyświetlanie długich linii w kompaktowym kontenerze. Historycznie termin pochodzi od HTML-znacznika <marquee>, popularnego w sieci w latach 90. XX wieku. We współczesnym developmentcie mobilnym scrolling text jest używany w odtwarzaczach, tickerach informacyjnych i paskach stanu. Według Apple Human Interface Guidelines i Google Material Design, pasek przewijania jest dopuszczalny tylko w ograniczonych scenariuszach, gdzie statyczne przycięcie z wielokropkiem pogarsza UX.

Najważniejsze

  • Pasek przewijania — automatyczne poziome przewijanie długiego tekstu w ograniczonym kontenerze.
  • Na Androidzie implementuje się przez android:ellipsize="marquee" w TextView.
  • Na iOS efekt tworzy się ręcznie przez Core Animation lub SwiftUI z animacją offset.
  • W sieci HTML-znacznik <marquee> jest przestarzały; używa się CSS-animacji z translateX.
  • Dla accessibility wymagane jest wsparcie prefers-reduced-motion.

Co to jest pasek przewijania?

Pasek przewijania — to efekt UI, w którym tekst przesuwa się poziomo wewnątrz stałego obszaru, cyklicznie przewijając się, aby użytkownik mógł przeczytać całą treść nie mieszczącą się w kontenerze. W przeciwieństwie do ellipsize, który ukrywa część tekstu, marquee pokazuje cały tekst, ale w ruchu.

Termin marquee (ang. — „namiot”, „billboard reklamowy”) utrwalił się dzięki HTML-znacznikowi <marquee>, który został dodany we wczesnych wersjach przeglądarek Netscape i Internet Explorer. Znacznik pozwalał tworzyć przewijający się tekst bez JavaScript i CSS, ale nigdy nie był częścią standardu HTML. Nowoczesne przeglądarki nadal go obsługują dla zachowania wstecznej kompatybilności, ale jego użycie nie jest zalecane.

W developmentcie mobilnym pasek przewijania rozwiązuje problem długich podpisów w kompaktowych kontenerach: nazwy utworów w odtwarzaczu, tickery kursów walut, paski informacyjne na ekranach telewizyjnych. Jednak ze względu na animację obciąża accessibility i może irytować użytkowników — dlatego stosuje się go punktowo.

Według badań Nielsen Norman Group (2023), ruchomy tekst zmniejsza szybkość czytania o 15-20% i zwiększa obciążenie poznawcze. Używaj paska przewijania tylko wtedy, gdy statyczne przycięcie (ellipsize) jest rzeczywiście nie do zaakceptowania.

Pasek przewijania na Android przez TextView

Na Androidzie pasek przewijania implementuje się za pomocą wbudowanego mechanizmu TextView poprzez atrybut android:ellipsize="marquee". Jest to jedyny tryb ellipsize, który nie obcina tekstu, a animuje jego przewijanie.

Do aktywacji marquee muszą być spełnione trzy warunki: singleLine="true" (lub maxLines="1"), ellipsize="marquee" i setSelected(true) w kodzie. Bez wywołania setSelected() animacja nie zostanie uruchomiona.

xml
<!-- XML layout -->
<TextView
    android:id="@+id/marquee_text"
    android:layout_width="150dp"
    android:layout_height="wrap_content"
    android:singleLine="true"
    android:ellipsize="marquee"
    android:marqueeRepeatLimit="marquee_forever" />

// Kotlin: aktywuj marquee
textView.setSelected(true)
textView.isSingleLine = true

Atrybut marqueeRepeatLimit określa liczbę powtórzeń animacji: marquee_forever (nieskończenie) lub konkretną liczbę. Domyślnie — marquee_forever. Jeśli tekst jest krótszy niż szerokość kontenera, animacja nie zostaje uruchomiona — TextView wyświetla statyczny tekst.

Ważna cecha: setSelected(true) działa tylko gdy TextView ma focus lub znajduje się w trybie selected. W RecyclerView może to powodować problemy — animacja uruchamia się tylko dla jednego elementu. Rozwiązanie — użyj niestandardowego MarqueeTextView, który nadpisuje isFocused() i zawsze zwraca true.

Począwszy od Android 9 (API 28), Google poprawiła zachowanie marquee — animacja stała się płynniejsza i nie zawiesza się podczas scrollowania listy. Jednak na starszych urządzeniach marquee może szarpać, zwłaszcza przy wysokiej gęstości pikseli.

Implementacja scrolling text na iOS

W iOS nie ma wbudowanego odpowiednika android:ellipsize="marquee". Pasek przewijania implementuje się ręcznie przez Core Animation lub za pomocą animacji SwiftUI. Najczęstsze podejście — animacja layer.position w połączeniu z kontenerem clipping.

W UIKit pasek przewijania opiera się na trzech elementach: kontener UILabel z clipsToBounds = true, sam tekst i CABasicAnimation do przesuwania tekstu po X z nieskończonym powtórzeniem i autoreverses = false, aby pasek przewijał się w jedną stronę i wracał skokowo.

swift
func startMarquee(for label: UILabel) {
    label.clipsToBounds = true
    label.numberOfLines = 1

    let textWidth = (label.text as? NSString)?
        .size(withAttributes: [.font: label.font as any]).width ?? 0

    guard textWidth > label.bounds.width else { return }

    let animation = CABasicAnimation(keyPath: "position.x")
    animation.fromValue = label.layer.position.x + label.bounds.width / 2
    animation.toValue = label.layer.position.x - textWidth - label.bounds.width / 2
    animation.duration = CFTimeInterval(textWidth / 60)
    animation.repeatCount = .infinity
    animation.autoreverses = false
    label.layer.add(animation, forKey: "marquee")
}

Obliczenie duration = textWidth / 60 daje prędkość około 60 pikseli na sekundę — komfortowe tempo do czytania. Jeśli prędkość przekracza 120 px/s, tekst staje się nieczytelny. Jeśli poniżej 30 px/s — animacja wygląda ospale. Zmieniaj speed w zależności od konkretnego scenariusza.

W SwiftUI pasek przewijania implementuje się prościej — przez modyfikator offset() z powtarzalną animacją i .animation(.linear(duration:).repeatForever(autoreverses: false)). SwiftUI automatycznie zarządza cyklem życia animacji, ale wymaga GeometryReader do określenia szerokości tekstu.

CSS-animacja zamiast znacznika marquee

W sieci przestarzały znacznik <marquee> nie jest zalecany do użycia, choć przeglądarki nadal go obsługują. Nowoczesna implementacja paska przewijania — CSS-animacja z klatkami kluczowymi i transform: translateX.

Zalety podejścia CSS: pełna kontrola nad prędkością, pauzą i krzywą animacji, obsługa prefers-reduced-motion dla accessibility, brak semantycznie niepoprawnego znacznika.

css
.marquee {
    overflow: hidden;
    white-space: nowrap;
    width: 300px;
}
.marquee-content {
    display: inline-block;
    animation: marquee 10s linear infinite;
}
@keyframes marquee {
    0%   { transform: translateX(0); }
    100% { transform: translateX(-100%); }
}

/* Pause on hover */
.marquee-content:hover {
    animation-play-state: paused;
}

Kluczowa sztuczka: display: inline-block u kontentu gwarantuje, że szerokość elementu jest równa szerokości tekstu, a translateX(-100%) przesuwa go dokładnie o tę szerokość w lewo. Jeśli content ma display: block, translateX(-100%) będzie równy szerokości kontenera, a nie tekstu, i animacja się zepsuje.

Dla accessibility dodaj @media (prefers-reduced-motion: reduce) { .marquee-content { animation: none; } } — użytkownicy z zaburzeniami przedsionkowymi zobaczą statyczny tekst z możliwością scrollowania.

Kiedy używać, a kiedy unikać

Pasek przewijania jest uzasadniony w scenariuszach, gdzie użytkownik nie może samodzielnie rozszerzyć kontenera, a pełny tekst jest krytyczny: bieżący utwór w odtwarzaczu na zablokowanym ekranie, pasek informacyjny na panelu telewizyjnym, pasek przewijania w aplikacji taksówkowej (status zamówienia).

Paska przewijania nie należy używać w tabelach, listach, formularzach i dialogach — wszędzie tam, gdzie użytkownik aktywnie współdziała z interfejsem. Animacja rozprasza, wydłuża czas szukania elementu i powoduje dyskomfort. Według WebAIM (2024), 1 na 3 użytkowników z zaburzeniami przedsionkowymi zgłasza dyskomfort podczas oglądania animowanego tekstu.

Zasada kciuka: jeśli tekst można skrócić lub umieścić w następnym wierszu — zrób to. Pasek przewijania to ostateczność, a nie uniwersalne rozwiązanie dla długich podpisów.

Accessibility: animacja i reduced motion

Pasek przewijania to jedna z najbardziej problemowych animacji UI z punktu widzenia accessibility. Ruchomy tekst może powodować zawroty głowy, nudności i dezorientację u osób z zaburzeniami przedsionkowymi. Zgodnie z WCAG 2.2, każda animacja trwająca dłużej niż 5 sekund musi mieć mechanizm pauzy lub wyłączenia.

Na iOS użyj właściwości UIAccessibility.isReduceMotionEnabled do sprawdzenia ustawienia systemowego. Jeśli reduceMotion jest włączona — nie uruchamiaj animacji, pokaż statyczny tekst z ellipsize.

Na Androidzie sprawdzaj animację systemową przez Settings.Global.ANIMATOR_DURATION_SCALE. Jeśli globalna animacja jest wyłączona (duration scale = 0), pasek przewijania nie powinien być włączany.

W sieci użyj funkcji medialnej prefers-reduced-motion: @media (prefers-reduced-motion: reduce) { .marquee-content { animation: none; } }. To standardowa możliwość CSS, obsługiwana przez wszystkie nowoczesne przeglądarki. Sprawdź w DevTools: włącz emulację prefers-reduced-motion i upewnij się, że animacja się wyłącza.

Często zadawane pytania

Czym różni się Marquee od Ellipsize?

Ellipsize obcina tekst i wstawia wielokropek, ukrywając część treści. Marquee przewija cały tekst, ale w ruchu. Wybór zależy od priorytetu: pokazać wszystko (marquee) czy zachować statykę (ellipsize).

Jak przyspieszyć lub spowolnić pasek przewijania na Androidzie?

Wbudowany android:ellipsize="marquee" nie pozwala zmieniać prędkości — jest ona określana przez systemowy ScrollSpeed. Do niestandardowej prędkości użyj Animation lub ValueAnimator ręcznie.

Dlaczego marquee nie działa w RecyclerView?

Z powodu ponownego wykorzystania widoków setSelected(true) jest resetowane. Rozwiązanie: utwórz niestandardowy MarqueeTextView, który nadpisuje isFocused() i zwraca true, lub użyj niestandardowej animacji w Adapter.onViewAttachedToWindow().

Czy można zrobić pionowy pasek przewijania?

Tak, przez translateY zamiast translateX. Pionowy marquee jest używany do napisów końcowych (credits) lub pasków informacyjnych w pionowych pasmach. Zasada jest ta sama, ale zmienia się oś animacji.

Jak zatrzymać pasek przewijania przy fokusie?

W CSS: :hover { animation-play-state: paused; }. Na Androidzie: śledź focus przez OnFocusChangeListener i resetuj setSelected(false). Na iOS: usuń animację przez layer.removeAnimation(forKey:).

Podsumowanie

  • Pasek przewijania — poziome przewijanie tekstu, pokazujące całą treść poprzez animację.
  • Na Androidzie wbudowany android:ellipsize="marquee" wymaga setSelected(true) i singleLine="true".
  • Na iOS implementacja odbywa się przez CABasicAnimation ze ścieżką position.x.
  • W sieci znacznik <marquee> jest przestarzały; używaj CSS @keyframes z translateX.
  • Stosuj marquee tylko gdy ellipsize jest nieodpowiedni — w odtwarzaczach, tickerach, paskach stanu.
  • Koniecznie wyłączaj animację przy prefers-reduced-motion na wszystkich platformach.
  • Prędkość animacji: ~60 px/s — komfortowa do czytania, powyżej 120 px/s — nieczytelna.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również