defuss-shadcn / Website / News / news-ticker
News TickerBLK
Displays a compact stream of linked news headlines - a seamless CSS marquee that pauses on hover and focus, and stops for reduced motion. Part of the News blocks.
On this page (7)
§Default
Hover or focus a headline and the strip pauses. The list runs twice in the track - the copy is inert and aria-hidden, so each headline is read and tabbed once.
§Breaking
data-variant='breaking': a red label with a pulsing dot. --mk-news-ticker-duration sets the speed (here 25s).
§Static and small
data-variant='static': no motion, the row scrolls by hand - what everyone gets under prefers-reduced-motion. data-size='sm' slims the strip.
§Market
data-variant='market': symbols, prices and changes in mono - .mk-news-ticker-trend with data-trend='up' / 'down' draws the arrow and the colour.
§Inverse with badges
data-variant='inverse': a dark band. Each headline can lead with a Badge for its desk.
§Pill
data-variant='pill': a rounded, floating strip - announcements above a landing page.
§CSS view file
/* -- News Ticker (website) ------------------------------------------ A compact stream of linked headlines. The list runs twice in one track (the copy is inert + aria-hidden) and the track slides by half its width, so the loop is seamless - pure CSS. Hover or focus pauses it; under reduced motion it stops and the row scrolls by hand instead. */@layer components { .mk-news-ticker { --_duration: var(--mk-news-ticker-duration, 40s); display: flex; align-items: stretch; box-sizing: border-box; width: 100%; min-width: 0; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); color: var(--card-foreground); font-size: 0.875rem; } .mk-news-ticker-label { display: inline-flex; flex: none; align-items: center; gap: 0.375rem; padding-inline: 0.875rem; background: var(--primary); color: var(--primary-foreground); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; } .mk-news-ticker-viewport { flex: 1; min-width: 0; overflow: hidden; mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent); } .mk-news-ticker-track { display: flex; width: max-content; animation: mk-news-ticker-scroll var(--_duration) linear infinite; } .mk-news-ticker:is(:hover, :focus-within) .mk-news-ticker-track { animation-play-state: paused; } .mk-news-ticker-items { display: flex; flex: none; margin: 0; padding: 0; list-style: none; & li { display: flex; align-items: center; /* a separator dot between headlines (and after the last, for the loop) */ &::after { content: ""; width: 0.25rem; height: 0.25rem; border-radius: 50%; background: var(--muted-foreground); opacity: 0.6; } } & a { display: inline-flex; align-items: baseline; gap: 0.5rem; padding: 0.625rem 1.25rem; color: inherit; font-weight: 500; text-decoration: none; white-space: nowrap; &:hover { text-decoration: underline; text-underline-offset: 0.2em; } &:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; border-radius: var(--radius-sm); } } & time { color: var(--muted-foreground); font-size: 0.75rem; font-variant-numeric: tabular-nums; } } /* breaking: a red label with a pulsing dot */ .mk-news-ticker[data-variant="breaking"] { border-color: oklch(0.58 0.22 27 / 0.45); & .mk-news-ticker-label { background: oklch(0.58 0.22 27); color: #fff; &::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: currentColor; animation: mk-news-ticker-pulse 1.6s ease-in-out infinite; } } } /* static: no motion at all - the row scrolls by hand */ .mk-news-ticker[data-variant="static"], .mk-news-ticker[data-variant="static"] .mk-news-ticker-viewport { mask-image: none; } .mk-news-ticker[data-variant="static"] { & .mk-news-ticker-viewport { overflow-x: auto; overscroll-behavior-inline: contain; scrollbar-width: thin; } & .mk-news-ticker-track { animation: none; } & .mk-news-ticker-items[aria-hidden="true"] { display: none; } } /* a change readout (market, scores): green up, red down */ .mk-news-ticker-trend { display: inline-flex; align-items: center; gap: 0.125rem; font-size: 0.75rem; font-weight: 600; font-variant-numeric: tabular-nums; &[data-trend="up"] { color: oklch(0.6 0.16 150); &::before { content: "▲"; font-size: 0.625em; } } &[data-trend="down"] { color: oklch(0.6 0.2 27); &::before { content: "▼"; font-size: 0.625em; } } } /* market: a stock strip - symbol, price, change; mono numbers */ .mk-news-ticker[data-variant="market"] { & .mk-news-ticker-label { background: var(--foreground); color: var(--background); } & .mk-news-ticker-items a { gap: 0.625rem; font-family: var(--font-mono); font-size: 0.8125rem; } & .mk-news-ticker-items b { font-weight: 700; letter-spacing: 0.02em; } } /* inverse: a dark band */ .mk-news-ticker[data-variant="inverse"] { border-color: transparent; background: var(--foreground); color: var(--background); & .mk-news-ticker-label { background: var(--primary); color: var(--primary-foreground); box-shadow: 0.75rem 0 1rem -0.5rem rgb(0 0 0 / 0.5); } & .mk-news-ticker-items time { color: color-mix(in oklch, var(--background) 65%, transparent); } & .mk-news-ticker-items li::after { background: var(--background); } } /* pill: a rounded floating strip with a badge label */ .mk-news-ticker[data-variant="pill"] { padding: 0.25rem; border-radius: 999px; box-shadow: var(--shadow-md); & .mk-news-ticker-label { border-radius: 999px; padding-block: 0.25rem; } & .mk-news-ticker-items a { padding-block: 0.375rem; } } /* sizes */ .mk-news-ticker[data-size="sm"] { font-size: 0.8125rem; & .mk-news-ticker-items a { padding-block: 0.375rem; } & .mk-news-ticker-label { padding-inline: 0.625rem; font-size: 0.6875rem; } } @keyframes mk-news-ticker-scroll { to { translate: -50% 0; } } @keyframes mk-news-ticker-pulse { 50% { opacity: 0.3; } } /* -- Accessibility ------------------------------------------- */ @media (prefers-reduced-motion: reduce) { .mk-news-ticker { & .mk-news-ticker-viewport { overflow-x: auto; mask-image: none; } & .mk-news-ticker-track { animation: none; } & .mk-news-ticker-items[aria-hidden="true"] { display: none; } & .mk-news-ticker-label::before { animation: none; } } } @media (prefers-contrast: more) { .mk-news-ticker { border-color: var(--foreground); } .mk-news-ticker-items time { color: var(--foreground); } } @media (forced-colors: active) { .mk-news-ticker-label { forced-color-adjust: none; background: Highlight; color: HighlightText; } .mk-news-ticker-items a { color: LinkText; } }}Comments, ideas or improvements? Edit this page's source on GitHub