Индикатор загрузки и оверлей для Angular | ng-hub-ui-loading
Компонент загрузки для Angular с индикаторами spinner, dots, bars, pulse и ring в режимах inline, overlay и fullscreen, а также сервис для блокирующих оверлеев на уровне приложения.
Последнее обновление 16 сент. 2026 г.
Обзор
Почему команды ищут эту библиотеку
Используйте ng-hub-ui-loading, когда раздел, контейнер или всё приложение должны показать, что идёт работа, и при этом каждому представлению не нужно собирать собственный спиннер и подложку.
Установка
npm install ng-hub-ui-loadingПерейти к
Идеально для
- загрузка маршрутов и данных
- оверлеи при отправке форм
- блокирующие операции уровня приложения
- брендированные заставки
- полосы загрузки страницы под панелью навигации
О библиотеке loading
ng-hub-ui-loading — это standalone-компонент Angular, отрисовывающий неопределённое состояние загрузки в трёх режимах: `inline` как блок в потоке документа, `overlay` с абсолютным позиционированием поверх родительского контейнера и `fullscreen` с фиксацией во вьюпорте. В комплекте пять индикаторов на чистом CSS — spinner, dots, bars, pulse и ring — в трёх размерах, необязательное сообщение и необязательное изображение бренда с анимацией `none`, `spin` или `pulse`. `HubLoadingService` программно управляет глобальным полноэкранным оверлеем и ведёт счётчик ссылок на параллельных вызывающих, поэтому одновременные запросы никогда не снимают оверлей друг у друга. Каждый цвет, размер и длительность — это пользовательское свойство `--hub-loading-*`, дополненное Sass-миксином `hub-loading-theme()` для сплошной перестилизации; компонент доступен по умолчанию благодаря `role=status`, `aria-live=polite` и `aria-busy` и учитывает `prefers-reduced-motion`. Рядом с ним `hub-loading-bar` сообщает, что в пути сама страница, — тонкая полоска под панелью навигации, отрисованная в потоке документа, прикреплённая к позиционированной панели навигации или зафиксированная на viewport на расстоянии `--hub-loading-bar-offset`. `HubLoadingBarService` так же считает вызывающих, выдерживает льготный период, чтобы быстро завершённая работа не мигала полосой, и продвигается к концу, до которого сам никогда не доходит: показать 100 % вправе только `complete()`. `provideHubLoadingBarRouter()` и `hubLoadingBarInterceptor` подключают её к навигации и к HTTP, ничего не зная друг о друге.
Руководства по возможностям
Блок inline
`inline` — режим по умолчанию, потому что ещё пустая область должна заранее резервировать место, которое займёт её содержимое: блок участвует в обычном потоке документа, поэтому при появлении настоящего содержимого ничего не подпрыгивает. `message` отрисовывается под индикатором, а всё спроецированное между тегами — под сообщением: там место для действия отмены или для пометки, что операция затянулась дольше обычного. Хост несёт `role="status"`, `aria-live="polite"` и `aria-busy="true"`, поэтому программа чтения с экрана подхватывает сообщение при его появлении, не прерывая то, что уже читает.
Примеры:
Основы блока inline
Блок inline в трёх полезных формах: только индикатор, индикатор с сообщением и сообщение с действием отмены, спроецированным снизу.
The block is announced as role="status" with aria-live="polite", so a screen reader reads the message when it appears without interrupting whatever is being read.
Код
Import:
Template:
Component:
Индикаторы и акценты
Библиотека несёт пять индикаторов на чистом CSS — `spinner`, `dots`, `bars`, `pulse` и `ring` — и потому не тянет за собой ни изображений, ни иконочного шрифта. Три ступени размера предустанавливают `--hub-loading-size`, но сам токен остаётся переопределяемым отдельно, если вёрстке нужен размер, которого эти ступени не покрывают. `color` — не обычный CSS-цвет: значение проходит через `resolveHubAccent()`, который читает голое имя вроде `primary` как токен дизайн-системы, следующий теме, тогда как hex, литерал `oklch()` или ссылка `var(...)` берутся как есть.
Примеры:
Варианты, размеры и акценты
Пять поставляемых индикаторов, три ступени размера и три вида, которые может принимать акцент, — семантическое имя, литерал CSS-цвета и ссылка `var(...)`.
Variants
spinnerdotsbarspulseringSizes
size="sm"size="md"size="lg" Each step is a preset for the --hub-loading-size token. Override that token directly when a layout needs a size the three steps do not cover.
Accents
color="primary"color="success"color="danger"color="#7c3aed"color="var(--hub-sys-color-warning)" A bare name resolves to var(--hub-sys-color-<name>) and tracks the active theme. A hex, an oklch() or a var(...) is used verbatim.
Код
Import:
Template:
Component:
Overlay и fullscreen
`overlay` накрывает одну область, а не страницу. Он позиционируется абсолютно, поэтому то, что окажется накрытым, решает ближайший позиционированный предок — задайте этому контейнеру `position: relative`, иначе overlay ускользнёт вверх, к тому предку, который случайно оказался позиционированным. Такое ограничение оставляет остальной экран прокручиваемым и рабочим. `fullscreen` зафиксирован относительно viewport и именно его `HubLoadingService` монтирует в `document.body`, вне любого поддерева компонентов, так что ни `overflow`, ни контекст наложения предка не смогут его обрезать. Оба режима рисуют полупрозрачную завесу, если только `backdrop` не выключен.
Примеры:
Overlay контейнера
Overlay, запертый в одной карточке её же `position: relative`, тогда как остальная страница остаётся прокручиваемой. Переключите `backdrop`, чтобы увидеть разницу между фоновым обновлением и работой, обесценивающей то, что на экране.
Order #4821
3 items · delivered 14 Aug 2026
- Subtotal
- 212.00 €
- Shipping
- 9.90 €
- VAT (21%)
- 26.70 €
- Total
- 248.60 €
Turn the backdrop off to keep the content readable underneath — useful when the work is a background refresh rather than something that invalidates what is on screen.
Код
Import:
Template:
Component:
Сервис fullscreen
`HubLoadingService` под управлением из TypeScript. Два перекрывающихся запроса показывают, зачем нужен счётчик ссылок: первый `hide()` оставляет overlay на месте, потому что второй вызывающий всё ещё держит ссылку, а `update()` переписывает сообщение на лету.
hideAll() after 5 seconds no matter what. Nothing yet.
Код
Import:
Template:
Component:
Брендирование и темизация
`image` заменяет встроенный индикатор вашим знаком, анимируемым через `none`, `spin` или `pulse`: `spin` читается хорошо только на радиально симметричном знаке, а `pulse` сохраняет текстовый логотип прямым и разборчивым. Всё визуальное живёт в токенах `--hub-loading-*`, объявленных на `:where(.hub-loading)`, так что задать их может любой предок — акцент, размер, скорость, толщину штриха, зазор, размер изображения, цвет текста, а также тон и размытие backdrop. Sass-миксин `hub-loading-theme()` выставляет всю лестницу токенов одним вызовом, а `provideHubLoading()` переопределяет значения по умолчанию для целого приложения, не трогая ни один шаблон.
Примеры:
Изображение бренда
Фирменный знак вместо встроенного индикатора, показанный с каждой из трёх анимаций изображения, чтобы был виден компромисс между `spin`, `pulse` и `none`.
imageAnimation="none"imageAnimation="spin"imageAnimation="pulse" Any URL works — an asset path, an imported file or, as here, an inline data URI. Size the mark with --hub-loading-image-size rather than size, which drives the built-in indicators.
Код
Import:
Template:
Component:
Темизация через CSS-переменные
Живая темизация через токены `--hub-loading-*`, заданные на элементе-обёртке, включая тон и размытие backdrop, которые работают только в режимах `overlay` и `fullscreen`.
Overlay preview
The backdrop tint and blur only apply in overlay and fullscreen modes. The tint is mixed from --hub-sys-surface-page, so it veils this text with the theme's own surface instead of a fixed colour — drop it to zero and the card stays fully legible underneath.
The same overrides written once, in Sass, are in the CSS tab — that is what hub-loading-theme() is for.
Код
Import:
Template:
Component:
Полоса загрузки страницы
`hub-loading-bar` — тонкая полоска, сообщающая, что в пути сама страница; та самая, что идёт под панелью навигации. Достоверной её делают три решения. Она считает вызывающих: навигация и три запроса, которые отправляет страница, — это четыре ссылки, и полоса завершается с последней, а не с первой. Она ждёт, прежде чем что-либо рисовать: работа, уложившаяся в льготный период, не показывает полосу вовсе, потому что маршрут на 40 мс с мигнувшим индикатором читается как сбой, а не как скорость. И её продвижение замедляется по мере заполнения и останавливается, не дойдя до конца: реального процента здесь не знает никто, поэтому 100 % вправе показать только `complete()` — только он знает, что это правда. Размещайте её через `mode="overlay"` внутри позиционированной панели навигации либо через `mode="fixed"` и `--hub-loading-bar-offset`, когда сама панель зафиксирована.
Примеры:
Полоса загрузки страницы
Полоса, подвешенная к макету панели навигации. Три маршрута показывают три поведения: обычный продвигается, медленный даёт увидеть замедление, а сорокамиллисекундный не рисует полосу вовсе.
Orders
This page arrived without you watching a spinner.
Код
Import:
Template:
Component:
Известный и неизвестный прогресс
Привязка `progress` передаёт полосу вызывающему и публикует `aria-valuenow`; `indeterminate` вместо этого водит фрагмент и значение скрывает. Третье состояние, `null`, убирает полосу.
Known percentage
[progress]="null"A real value, so the bar announces it. Reaching 100% is the caller's call, not the trickle's.
No percentage at all
indeterminateA sweep instead of a fill, for a stream or a job that reports no stages. No value is announced, because there is none.
Both bars are mode="inline", so each reserves its own row and nothing on the card moves when a bar appears or goes away.
Код
Import:
Template:
Component:
Подключение роутера и HTTP
Зачем полосе считать вызывающих: навигация плюс три запроса — четыре ссылки, и полоса завершается с последней. Код показывает `provideHubLoadingBarRouter()`, перехватчик и способ исключения.
Nothing yet.
Код
Import:
Template:
Component:
Пробег справа налево
Та же полоса `indeterminate` под `dir="ltr"` и под `dir="rtl"`. Пробег разворачивается вместе с текстом — им управляет `--hub-loading-bar-sweep-direction`, так что ничего не нужно привязывать или дублировать под локаль.
Loading results…
dir="ltr"Sweeps left to right, with the text.
جارٍ تحميل النتائج…
dir="rtl"يمسح من اليمين إلى اليسار، مع اتجاه النص.
The flip comes from [dir='rtl'] .hub-loading-bar, .hub-loading-bar[dir='rtl'], so the attribute counts wherever it sits — on <html>, on the region that changes direction, or on the <hub-loading-bar> element itself. The determinate fill needs no such treatment: it grows along the inline axis, which already reverses on its own.
Код
Import:
Template:
Component:
Ключевые возможности
Последние изменения
Version 22.2.1 - 9/16/26, 12:00 AM
changed: Repository, issue and README links follow the move to the hub-env organization. Issues for every Hub UI package are now gathered in hub-env/hub-ui, and the repository and bugs fields of the manifest point at the new addresses. No code, types or styles change.
Version 22.2.0 - 9/8/26, 12:00 AM
changed: <hub-loading> and <hub-loading-bar> keep their stylesheets to themselves. Both shipped with ViewEncapsulation.None, and neither reason recorded for it held any more. Retheming from a global stylesheet is answered by the tokens, not by the encapsulation mode: they are declared on the host at zero specificity, a custom property inherits down to every element inside, and a rule written against .hub-loading still reaches the host because the class is on the host element. And the overlay HubLoadingService mounts on document.body is a real component instance created through createComponent(), so it carries its own stylesheet with it. See BREAKING_CHANGES.md.
changed: The bar's RTL rule is written as :host-context([dir='rtl']). It was a hand-written pair of selectors, one for the attribute on an ancestor and one for the attribute on the bar itself, because dir is inherited and both spellings are legitimate. :host-context() is exactly that pair, and under emulated encapsulation Angular now compiles it, which it never did while the component was unencapsulated. Same behaviour, one selector.
added: ng-hub-ui-ds is declared as an optional peer dependency (>=22.0.0). Both stylesheets have always resolved their defaults through the --hub-sys-* / --hub-ref-* ladder and the manifest said nothing about it, so a consumer reading the package on npm could not tell that installing the token package is what hands the indicator and the bar the family palette and its dark mode. It stays optional: every token carries a literal fallback and the library renders without it.
Version 22.1.1 - 9/6/26, 12:00 AM
added: Both READMEs now document the BEM classes of the loading bar and add a Right-to-left section explaining that the indeterminate sweep reverses under dir="rtl" so it travels with the text. Both have worked since 22.1.0 with nothing in the documentation to find them by, which is the same as not having them.
changed: rxjs is now declared as a peer dependency, because hubLoadingBarInterceptor imports finalize from it on the published path and a strict installer such as pnpm with hoisting turned off had no reason to resolve it. Nothing changes under npm or yarn, where rxjs arrives hoisted as a peer of @angular/core.
fixed: The Angular badge and the opening line of both READMEs say 21+, the range package.json has always declared. Claiming 22+ turned away an application on Angular 21 that the library supports.
fixed: HubLoadingService.isLoading is described as what it computes, the reference counter rather than the mounted overlay. The README contradicted itself, since its own SSR section already explained that on the server the counter runs while the mount is skipped.
fixed: FUNCTIONALITIES.md marks the ariaLabel of hub-loading as covered, which the Inline playground control has made true since the page shipped, and adds the RTL row of the bar so the file stops omitting behaviour the stylesheet has.
fixed: Calling HubLoadingService.hide(), HubLoadingBarService.complete() or HubLoadingBarService.inc() from inside an effect() no longer subscribes that effect to the internal state of the service. Each of those paths read a tracked signal to decide what to do next, the counter, whether the bar is on screen, the current fill, so the effect woke up on state it does not own: a show() from anywhere else re-ran it and retired a reference it never registered, and inc() re-entered itself on every step. The untracked read that already guarded the bar counter now covers the three places that were left out.
Version 22.1.0 - 9/5/26, 12:00 AM
added: hub-loading-bar: the thin page-progress strip that sits under the navbar, in three placements — inline in the flow, overlay against a positioned ancestor, or fixed to the viewport at --hub-loading-bar-offset.
added: HubLoadingBarService, with reference-counted start() / complete(), an anti-flicker grace period so fast work never paints a bar at all — set delay to 0 to opt out and reveal synchronously — and a trickle that decelerates as it fills and stops short of the end, since only complete() may show 100%.
added: provideHubLoadingBarRouter(), which runs the bar for the length of a navigation, including one a guard rejects, and hubLoadingBarInterceptor with withoutHubLoadingBar() to keep polls and heartbeats out of the count.
added: Determinate mode through the progress input, which publishes aria-valuenow, and an indeterminate sweep. Both withhold the value while the number is invented, which is how ARIA marks a progressbar of unknown position.
added: provideHubLoadingBar(), the HUB_LOADING_BAR_CONFIG token, the exported hubLoadingBarTrickle() curve, thirteen --hub-loading-bar-* tokens and the hub-loading-bar-theme() Sass mixin.
Version 22.0.0 - 8/24/26, 12:00 AM
added: Initial release of hub-loading: one component covering the inline block, the container overlay and the fullscreen layer, with role="status", aria-live="polite" and aria-busy set on the host.
added: Five pure-CSS indicators — spinner, dots, bars, pulse and ring — in three size steps, with no image or font dependency.
added: Accent resolution through resolveHubAccent() from ng-hub-ui-utils: a bare name becomes a --hub-sys-color-* token and follows the theme, while a hex, an oklch() or a var(...) is used verbatim.
added: Optional image input with none, spin and pulse animations, replacing the built-in indicator with a brand mark.
added: HubLoadingService for the fullscreen overlay, with a reference counter so concurrent callers cannot unblock the screen out from under each other, plus update() to re-dress the live overlay and hideAll() to force the count to zero. SSR-safe: a no-op without a DOM.
added: provideHubLoading() and the HUB_LOADING_CONFIG token, supplying application-wide defaults to both the component and the service.
added: Theming through the --hub-loading-* token ladder and the hub-loading-theme() Sass mixin, shipped at ng-hub-ui-loading/styles.
Связанные библиотеки
Часто задаваемые вопросы
Как показать спиннер или оверлей загрузки в Angular?
Установите ng-hub-ui-loading и отображайте `<hub-loading>`, пока идёт работа. По умолчанию это блок в потоке документа; поставьте `mode` в `overlay`, чтобы закрыть окружающий контейнер, или в `fullscreen`, чтобы заблокировать окно просмотра. Для оверлея на всё приложение внедрите `HubLoadingService` и вызывайте `show()` и `hide()` вокруг операции.
Что выбрать: спиннер, скелет или полосу прогресса?
Берите ng-hub-ui-skeleton, когда уже знаете форму будущего содержимого: заглушка резервирует место и избавляет от скачка вёрстки. Берите ng-hub-ui-loading, когда ожидание неопределённо или экран нужно заблокировать — отправляется форма, готовится отчёт. Когда можно сообщить о реальном ходе выполнения, ng-hub-ui-metrics рисует определённые полосы, шкалы и кольца.
Как изменить цвет индикатора загрузки в Angular?
Задайте входное свойство `color`: оно принимает семантическое имя, шестнадцатеричный литерал, значение `oklch()` или ссылку `var(...)` на один из ваших токенов. Для постоянного изменения каждый цвет, размер и длительность — это пользовательское свойство `--hub-loading-*`, которое можно переопределить из своей таблицы стилей, а Sass-миксин `hub-loading-theme()` перекрашивает весь компонент в одном месте. Входное свойство `image` заменяет индикатор логотипом, когда состояние загрузки должно нести бренд.
Доступен ли компонент загрузки Angular и безопасен ли он для SSR?
Да. Хост — это живая область: `role=status`, `aria-live=polite` и `aria-busy`, с входным свойством `ariaLabel` для озвучиваемого текста, а все анимации отключаются при `prefers-reduced-motion`. На сервере нет DOM, куда монтироваться, поэтому `HubLoadingService` хранит только счётчик, и серверный рендеринг остаётся безопасным.
Как добавить полосу загрузки страницы под панелью навигации в Angular?
Отобразите `<hub-loading-bar mode="overlay" placement="bottom">` внутри панели навигации с `position: relative` или используйте `mode="fixed"` вместе с `--hub-loading-bar-offset`, когда панель тоже зафиксирована. Затем добавьте `provideHubLoadingBarRouter()`, чтобы полоса жила столько, сколько длится каждая навигация, включая ту, которую отклонил guard, и `hubLoadingBarInterceptor`, чтобы она покрывала и запросы, которые страница отправляет по прибытии. Полоса считает ссылки своих вызывающих, поэтому оба механизма сочетаются, не зная друг о друге, а `withoutHubLoadingBar()` держит фоновые опросы вне счёта.