Lopende tekst (marquee) — is een visueel effect waarbij tekst automatisch horizontaal scrollt binnen een beperkt gebied, zodat lange regels in een compacte container kunnen worden weergegeven. Historisch komt de term van de HTML-tag <marquee>, populair in het web van de jaren 1990. In moderne mobiele ontwikkeling wordt scrolling text gebruikt in spelers, nieuwstickers en statusbalken. Volgens Apple Human Interface Guidelines en Google Material Design is lopende tekst alleen toegestaan in beperkte scenario's waar statisch afkappen met weglatingstekens de UX verslechtert.
Belangrijkste punten
Lopende tekst — is een UI-effect waarbij tekst horizontaal beweegt binnen een vast gebied, cyclisch scrollend zodat de gebruiker alle inhoud kan lezen die niet in de container past. In tegenstelling tot ellipsize, dat een deel van de tekst verbergt, toont marquee de volledige tekst, maar in beweging.
De term marquee (Engels — „luifel”, „reclamebord”) is ontstaan dankzij de HTML-tag <marquee>, die werd toegevoegd in vroege versies van Netscape en Internet Explorer. De tag maakte het mogelijk scrollende tekst te maken zonder JavaScript en CSS, maar was nooit onderdeel van de HTML-standaard. Moderne browsers blijven het ondersteunen voor achterwaartse compatibiliteit, maar het gebruik wordt afgeraden.
In mobiele ontwikkeling lost lopende tekst het probleem van lange labels in compacte containers op: muziektitels in de speler, valutakoersstickers, nieuwsregels op tv-schermen. Echter, vanwege de animatie belast het accessibility en kan het gebruikers irriteren — daarom wordt het gericht toegepast.
Volgens onderzoek van Nielsen Norman Group (2023) vermindert bewegende tekst de leessnelheid met 15-20% en verhoogt het de cognitieve belasting. Gebruik lopende tekst alleen wanneer statisch afkappen (ellipsize) echt onaanvaardbaar is.
Op Android wordt lopende tekst geïmplementeerd via het ingebouwde mechanisme van TextView met het attribuut android:ellipsize="marquee". Dit is de enige ellipsize-modus die tekst niet afkapt, maar de scroll ervan animeert.
Voor het activeren van marquee moeten drie voorwaarden worden vervuld: singleLine="true" (of maxLines="1"), ellipsize="marquee" en setSelected(true) in de code. Zonder setSelected() start de animatie niet.
<!-- 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: activeer marquee
textView.setSelected(true)
textView.isSingleLine = true
Het attribuut marqueeRepeatLimit bepaalt het aantal herhalingen van de animatie: marquee_forever (oneindig) of een specifiek getal. Standaard — marquee_forever. Als de tekst korter is dan de breedte van de container, start de animatie niet — TextView toont statische tekst.
Belangrijk kenmerk: setSelected(true) werkt alleen wanneer TextView focus heeft of in de geselecteerde modus staat. In RecyclerView kan dit problemen veroorzaken — de animatie start alleen voor één element. Oplossing — gebruik een aangepaste MarqueeTextView die isFocused() overschrijft en altijd true retourneert.
Vanaf Android 9 (API 28) heeft Google het gedrag van marquee verbeterd — de animatie werd vloeiender en loopt niet vast bij het scrollen van de lijst. Op oudere apparaten kan marquee echter schokkerig zijn, vooral bij hoge pixeldichtheid.
In iOS is er geen ingebouwd equivalent van android:ellipsize="marquee". Lopende tekst wordt handmatig geïmplementeerd via Core Animation of met SwiftUI-animatie. De meest voorkomende aanpak — animatie van layer.position in combinatie met een clipping-container.
In UIKit wordt lopende tekst opgebouwd uit drie elementen: een UILabel-container met clipsToBounds = true, de tekst zelf, en een CABasicAnimation om de tekst over X te verschuiven met oneindige herhaling en autoreverses = false, zodat de balk in één richting scrollt en met een sprong terugkeert.
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")
}
Berekening van duration = textWidth / 60 geeft een snelheid van ongeveer 60 pixels per seconde — een comfortabel tempo om te lezen. Als de snelheid hoger is dan 120 px/s, wordt de tekst onleesbaar. Onder 30 px/s — ziet de animatie er traag uit. Pas speed aan op het specifieke scenario.
In SwiftUI wordt lopende tekst eenvoudiger geïmplementeerd — via de offset()-modifier met herhaalbare animatie en .animation(.linear(duration:).repeatForever(autoreverses: false)). SwiftUI beheert automatisch de levenscyclus van de animatie, maar vereist GeometryReader om de tekstbreedte te bepalen.
In het web wordt de verouderde tag <marquee> niet aanbevolen, hoewel browsers het nog steeds ondersteunen. De moderne implementatie van lopende tekst — CSS-animatie met keyframes en transform: translateX.
Voordelen van de CSS-aanpak: volledige controle over snelheid, pauze en animatiecurve, ondersteuning voor prefers-reduced-motion voor accessibility, geen semantisch incorrecte tag.
.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;
}
De belangrijkste truc: display: inline-block op de inhoud zorgt ervoor dat de breedte van het element gelijk is aan de breedte van de tekst, en translateX(-100%) verschuift het exact met die breedte naar links. Als de inhoud display: block heeft, is translateX(-100%) gelijk aan de breedte van de container, niet van de tekst, en werkt de animatie niet goed.
Voeg voor accessibility @media (prefers-reduced-motion: reduce) { .marquee-content { animation: none; } } toe — gebruikers met vestibulaire stoornissen zien statische tekst met scrollmogelijkheid.
Lopende tekst is gerechtvaardigd in scenario's waarin de gebruiker de container niet zelf kan vergroten en de volledige tekst cruciaal is: het huidige nummer in de speler op het vergrendelde scherm, de nieuwsbalk op een tv-paneel, lopende tekst in een taxi-app (bestelstatus).
Lopende tekst mag niet worden gebruikt in tabellen, lijsten, formulieren en dialoogvensters — overal waar de gebruiker actief met de interface werkt. Animatie leidt af, verlengt de zoektijd van een element en veroorzaakt ongemak. Volgens WebAIM (2024) meldt 1 op de 3 gebruikers met vestibulaire stoornissen ongemak bij het bekijken van geanimeerde tekst.
Vuistregel: als de tekst kan worden ingekort of op de volgende regel kan worden geplaatst — doe dat. Lopende tekst is een laatste redmiddel, geen universele oplossing voor lange labels.
Lopende tekst is een van de meest problematische UI-animaties vanuit accessibility-oogpunt. Bewegende tekst kan duizeligheid, misselijkheid en desoriëntatie veroorzaken bij mensen met vestibulaire stoornissen. Volgens WCAG 2.2 moet elke animatie die langer dan 5 seconden duurt een pauze- of uitschakelmechanisme hebben.
Op iOS gebruik je de eigenschap UIAccessibility.isReduceMotionEnabled om de systeeminstelling te controleren. Als reduceMotion is ingeschakeld — start de animatie niet, toon statische tekst met ellipsize.
Op Android controleer je de systeemanimatie via Settings.Global.ANIMATOR_DURATION_SCALE. Als de globale animatie is uitgeschakeld (duration scale = 0), mag lopende tekst niet worden ingeschakeld.
In het web gebruik je de mediafunctie prefers-reduced-motion: @media (prefers-reduced-motion: reduce) { .marquee-content { animation: none; } }. Dit is een standaard CSS-mogelijkheid die door alle moderne browsers wordt ondersteund. Controleer in DevTools: schakel emulatie van prefers-reduced-motion in en zorg dat de animatie wordt uitgeschakeld.
Veelgestelde vragen
Ellipsize kapt tekst af en plaatst weglatingstekens, waardoor een deel van de inhoud wordt verborgen. Marquee scrollt de volledige tekst, maar in beweging. De keuze hangt af van de prioriteit: alles tonen (marquee) of statisch blijven (ellipsize).
De ingebouwde android:ellipsize="marquee" staat niet toe de snelheid te wijzigen — deze wordt bepaald door de systeem-ScrollSpeed. Voor aangepaste snelheid gebruik je handmatig Animation of ValueAnimator.
Door het hergebruik van views wordt setSelected(true) gereset. Oplossing: maak een aangepaste MarqueeTextView die isFocused() overschrijft en true retourneert, of gebruik een aangepaste animatie in Adapter.onViewAttachedToWindow().
Ja, via translateY in plaats van translateX. Verticale marquee wordt gebruikt voor credits of nieuwsregels in verticale banden. Het principe is hetzelfde, maar de animatie-as verandert.
In CSS: :hover { animation-play-state: paused; }. Op Android: volg focus via OnFocusChangeListener en reset setSelected(false). Op iOS: verwijder de animatie via layer.removeAnimation(forKey:).
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook