---
url: https://nsh.dev/ru/elements/avatar
description: "Компоненты Avatar и AvatarGroup: изображение пользователя или запасной вариант, пока оно загружается, если загрузка не удалась или если изображения нет, причём состояние загрузки обрабатывается нативно; а также ряд аватаров, который показывает первые несколько и обозначает остальные."
demo: https://nsh.dev/play/index.html#el-avatar
---

# Avatar

Аватар показывает изображение человека: участника команды, автора комментария, аккаунт в шапке. Пока изображение не загрузилось, а также когда загрузка не удалась или изображения нет, он показывает запасной вариант: инициалы `name` человека или собственное содержимое приложения (иконку). Аватар сам управляет состоянием загрузки изображения, которое определяется нативно по событиям load и error самого изображения, без JavaScript, а также отвечает за то, что получают программы чтения с экрана: изображение с подписью в виде имени человека. Внешний вид определяет приложение: у `Avatar` нет собственного размера, формы, цветов или шрифта. `AvatarGroup` показывает первые несколько аватаров ряда и счётчик остальных («+5»).

```rust
use nsh_base::{avatar, theme};
use nsh_core::prelude::*;

fn author(name: &'static str, picture: &'static str) -> impl IntoElement {
    avatar()
        .src(picture)
        .name(name)
        .size(px(40.0))
        .image_style(|s| s.rounded_full())
        .fallback_style(|s| {
            s.rounded_full()
                .items_center()
                .justify_center()
                .bg(move || theme().muted)
                .text_color(move || theme().muted_foreground)
                .text_sm()
        })
}
```

```tsx
import { mount } from "nsh";
import { Avatar } from "nsh/base";

function App() {
  return (
    <Avatar
      src="https://example.com/ada.png"
      name="Ada Lovelace"
      class="size-10"
      imageClass="rounded-full"
      fallbackClass="items-center justify-center rounded-full bg-muted text-sm text-muted-foreground"
    />
  );
}

mount(App);
```

`Avatar` и `AvatarGroup` берутся из [`nsh/base`](https://nsh.dev/translations/ru/modules/nsh-base.md), крейта `nsh-base` в Rust. В Rust
`avatar()` и `avatar_group()` создают их через отдельный сеттер для каждого свойства (`.src(..)`, `.fallback_delay(..)`), типизированные методы стиля
для самого аватара и `.child(..)` для того, что располагается поверх изображения.

<a id="props"></a>

## Свойства

| Свойство | Rust | Тип | По умолчанию | Описание |
|---|---|---|---|---|
| `src` | `.src(..)` | `string \| ImageAsset` | нет | Изображение в том виде, в котором его принимает `src` компонента [`<Image>`](https://nsh.dev/translations/ru/elements/image.md): URL, URI `asset:/` или `data:`, URL `blob:` (фото, выбранное пользователем: `URL.createObjectURL(file)`) или импортированное изображение. Показывается после загрузки; пустая строка означает отсутствие изображения. |
| `name` | `.name(..)` | `string` | нет | Имя человека: то, что произносят программы чтения с экрана, и инициалы, которые показывает запасной вариант, если приложение не передало `fallback`. |
| `accessibilityLabel` | `.accessibility_label(..)` | `string` | `name` | То, что произносят программы чтения с экрана, вместо `name`. `""` делает аватар декоративным и скрывает его от программ чтения с экрана. |
| `fallbackDelay` | `.fallback_delay(..)` | `number` (мс) | `0` | Сколько запасной вариант ждёт, пока загружается изображение, чтобы быстро загрузившееся изображение показывалось без предварительной вспышки запасного варианта. `Infinity`: запасной вариант не показывается во время загрузки, только при ошибке или отсутствии изображения. |
| `imageClass`, `imageStyle` | `.image_style(\|s\| ..)` | `string`, `StyleProp<ViewStyle>` | нет | Изображение: его вписывание, радиус и анимация. |
| `fallbackClass`, `fallbackStyle` | `.fallback_style(\|s\| ..)` | `string`, `StyleProp<ViewStyle>` | нет | Запасной вариант: его фон, цвет и размер текста и выравнивание содержимого. |
| `fallback` | `.fallback(..)` | `JSX.Element` | инициалы | Содержимое запасного варианта вместо инициалов: иконка, заглушка для человека без имени. |
| `children` | `.child(..)` | `JSX.Element` | нет | То, что показывается поверх изображения: точка присутствия, значок. Программы чтения с экрана озвучивают подпись аватара, а не их (см. [Доступность](#accessibility)). |
| `class`, `style` | методы стиля | `string`, `StyleProp<ViewStyle>` | нет | Сам аватар: его размер и форма. |

| Событие | Rust | Данные | Описание |
|---|---|---|---|
| `onStatusChange` | `.on_status_change(..)` | `{ status: AvatarStatus }` | Состояние изображения изменилось: `"idle"` (без `src`), `"loading"`, `"loaded"` или `"error"`. |

<a id="parts"></a>

## Части

| Часть | Находится внутри | Стилизуется с помощью |
|---|---|---|
| Аватар | | `class`, `style` |
| Запасной вариант | аватар, первым, того же размера; присутствует, пока изображение загружается (после `fallbackDelay`), при ошибке или при отсутствии изображения | `fallbackClass`, `fallbackStyle`; его содержимое: инициалы или `fallback` |
| Изображение | аватар, поверх запасного варианта, заполняет его | `imageClass`, `imageStyle` |
| Содержимое приложения | аватар, последним | собственные элементы (`children`) |

Задайте аватару размер (`class="size-10"`): запасной вариант и изображение заполняют его, поэтому исчезновение запасного варианта не приводит к повторной раскладке. Изображение размещается с самого начала прозрачным и становится непрозрачным после загрузки; после этого запасной вариант исчезает. `transition-opacity` в `imageClass` плавно проявляет изображение (при включённом режиме уменьшенной анимации оно показывается сразу). Скругляйте изображение и запасной вариант (`rounded-full` у каждого), а не обрезайте сам аватар, чтобы точка присутствия, расположенная у его края (`absolute bottom-0 right-0`), оставалась целой.

Инициалы — это первые буквы первых двух слов имени в верхнем регистре («Ada Lovelace» даёт «AL»); из одного слова берутся его первые две буквы («huacnlee» даёт «HU»), а для имени в письменности без регистра букв — его первый символ («王小明» даёт «王»).

<a id="groups"></a>

## Группы

```tsx
import { Text } from "nsh";
import { Avatar, AvatarGroup } from "nsh/base";

<AvatarGroup
  limit={3}
  total={members.length}
  accessibilityLabel={`${members.length} members`}
  class="flex-row"
  overflowClass="-ml-2 size-8 items-center justify-center rounded-full bg-muted ring-2 ring-background"
  overflowAccessibilityLabel={`${members.length - 3} more people`}
  overflow={<Text class="text-xs">{`+${members.length - 3}`}</Text>}
>
  <Each of={members.slice(0, 3)} key={(m) => m.id}>
    {(m, i) => <Avatar src={m().picture} name={m().name} class={i() > 0 ? "-ml-2 size-8" : "size-8"} />}
  </Each>
</AvatarGroup>
```

| Свойство | Rust | Тип | По умолчанию | Описание |
|---|---|---|---|---|
| `limit` | `.limit(..)` | `number` | `3` | Показывается не больше этого числа аватаров, первых по порядку; для остальных представления не создаются. |
| `total` | `.total(..)` | `number` | число дочерних элементов | Сколько человек представляет группа, если приложение передаёт только первых из них. |
| `accessibilityLabel` | `.accessibility_label(..)` | `string` | нет | То, что программы чтения с экрана произносят о группе. |
| `overflowClass`, `overflowStyle` | `.overflow_style(\|s\| ..)` | `string`, `StyleProp<ViewStyle>` | нет | Часть с переполнением, после показанных аватаров. |
| `overflow` | `.overflow(..)` | `JSX.Element` | нет | То, что обозначает непоказанных людей («+5», «⋯»); присутствует, пока в группе больше людей, чем показано аватаров. |
| `overflowAccessibilityLabel` | `.overflow_accessibility_label(..)` | `string` | нет | То, что программы чтения с экрана произносят о переполнении вместо его содержимого: «ещё 5 человек» для «+5». |
| `children` | `.child(..)` | `JSX.Element` | нет | Аватары по порядку. |
| `class`, `style` | методы стиля | `string`, `StyleProp<ViewStyle>` | нет | Ряд: его направление (`flex-row`) и интервалы. |

Перекрытие, кольца и форма переполнения определяются приложением: отрицательный отступ у каждого аватара, кроме первого (`-ml-2`), выстраивает их внахлёст, а кольцо цвета фона разделяет их. Для длинного списка передавайте первых `limit` человек и `total`: создаются только показанные аватары. Число, которое обозначает переполнение, равно `total` за вычетом показанных аватаров; их число — меньшее из количества дочерних элементов и `limit`: `total={8}` при двух дочерних элементах показывает два аватара и «+6».

<a id="accessibility"></a>

## Доступность

- Для программ чтения с экрана аватар — это одно изображение с подписью `accessibilityLabel` или `name`: имя произносится один раз. Запасной вариант и изображение скрыты от них, поэтому инициалы не читаются отдельно. Аватар без них или с `accessibilityLabel=""` считается декоративным и скрывается от программ чтения с экрана, как и должен быть скрыт аватар, стоящий рядом с именем, которое он показывает.
- Группа — это группа с подписью из `accessibilityLabel` («Ada, Grace и ещё 5»); показанные аватары внутри неё — изображения. Переполнение читается как его содержимое («+5») или как `overflowAccessibilityLabel` («ещё 5 человек»), если приложение его задаёт: NSH не добавляет собственных слов.
- Для программ чтения с экрана аватар — один элемент, поэтому то, что показывают его дочерние элементы, не читается отдельно, а кнопка или ссылка среди них на iOS вообще недоступна. Объясняйте, что означает точка присутствия или значок, в `accessibilityLabel` («Ada Lovelace, в сети»), а то, что можно нажимать, размещайте рядом с аватаром, а не внутри него.
- Ни аватар, ни группа не принимают нажатия и фокус клавиатуры: поместите аватар в `Button`, чтобы сделать его интерактивным.

Общие сведения о подписях, ролях и объявлениях см. в разделе [Доступность](https://nsh.dev/translations/ru/docs/accessibility.md).

<a id="platform-notes"></a>

## Особенности платформ

- Каждая платформа загружает изображение собственным загрузчиком изображений и кэшами (см. [Image](https://nsh.dev/translations/ru/elements/image.md)); события load и error меняют состояние аватара в Rust, поэтому загружающееся или не загрузившееся изображение меняет только изображение и запасной вариант, и ничего больше.
- Изображение начинает загружаться, как только у него появляется рамка, поэтому оно остаётся размещённым, пока прозрачно.
