Модальные окна

Модальные окна являются ключевым элементом интерфейсов, позволяя отображать важную информацию, формы или подтверждения действий, блокируя при этом взаимодействие с остальной частью страницы. В SvelteKit модальные компоненты реализуются с использованием реактивных переменных, условного рендеринга и библиотек UI, которые предоставляют готовые стилизованные элементы.

Условный рендеринг модального окна

В Svelte условный рендеринг выполняется через конструкцию {#if ...}{/if}. Основная логика открытия модального окна заключается в хранении состояния isOpen и контроле его изменения:

<script>
  let isOpen = false;

  function openModal() {
    isOpen = true;
  }

  function closeModal() {
    isOpen = false;
  }
</script>

<button on:click={openModal}>Открыть модальное окно</button>

{#if isOpen}
  <div class="modal-backdrop" on:click={closeModal}>
    <div class="modal-content" on:click|stopPropagation>
      <h2>Заголовок модального окна</h2>
      <p>Содержимое модального окна.</p>
      <button on:click={closeModal}>Закрыть</button>
    </div>
  </div>
{/if}

Ключевые моменты:

  • on:click|stopPropagation предотвращает закрытие окна при клике на его содержимое.
  • modal-backdrop служит затемнённым фоном и ловит клики вне окна.

Использование библиотек UI в SvelteKit

Библиотеки компонентов, такие как Svelte Material UI (SMUI), Flowbite-Svelte или Svelte Headless UI, предоставляют готовые модальные компоненты с расширенными возможностями: анимациями, доступностью для клавиатуры и стилями по умолчанию.

Пример модального окна с использованием SMUI:

<script>
  import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@smui/dialog';
  let open = false;
</script>

<Button on:click={() => open = true}>Открыть диалог</Button>

<Dialog bind:open>
  <DialogTitle>Диалоговое окно</DialogTitle>
  <DialogContent>
    <p>Здесь может быть форма или уведомление.</p>
  </DialogContent>
  <DialogActions>
    <Button on:click={() => open = false}>Отмена</Button>
    <Button on:click={() => { /* действие */ open = false }}>Подтвердить</Button>
  </DialogActions>
</Dialog>

Особенности подхода через UI-библиотеки:

  • Автоматическое управление фокусом и клавиатурой.
  • Возможность стилизовать окно через темы или CSS-переменные.
  • Простая интеграция с анимациями открытия/закрытия.

Анимации и переходы модальных окон

SvelteKit предоставляет встроенные функции анимации через директиву transition. Для плавного появления модального окна используют, например, fade или fly:

<script>
  import { fade, fly } from 'svelte/transition';
  let isOpen = false;
</script>

<button on:click={() => isOpen = true}>Открыть</button>

{#if isOpen}
  <div class="backdrop" on:click={() => isOpen = false} transition:fade>
    <div class="modal" on:click|stopPropagation transition:fly={{ y: 20, duration: 300 }}>
      <h2>Модальное окно с анимацией</h2>
      <button on:click={() => isOpen = false}>Закрыть</button>
    </div>
  </div>
{/if}

Рекомендации по анимациям:

  • fade используется для затемнённого фона.
  • fly позволяет окну «вылетать» из точки появления.
  • duration и easing настраиваются индивидуально для плавности.

Управление состоянием модальных окон

В больших приложениях рекомендуется хранить состояние модальных окон в store, чтобы управлять их открытием глобально и передавать данные между компонентами:

// modalStore.js
import { writable } from 'svelte/store';
export const modal = writable({ isOpen: false, content: null });

// App.svelte
<script>
  import { modal } from './modalStore';
  import Modal from './Modal.svelte';
</script>

<Modal />

<button on:click={() => modal.set({ isOpen: true, content: 'Привет, мир!' })}>
  Открыть модальное окно
</button>

Преимущества использования store:

  • Модальное окно может быть единым компонентом на уровне всего приложения.
  • Можно динамически менять содержимое и размеры окна.
  • Упрощается интеграция с роутером и асинхронными действиями.

Доступность (Accessibility)

Правильная реализация модальных окон требует соблюдения стандартов доступности:

  • role="dialog" для контейнера.
  • aria-modal="true" чтобы информировать вспомогательные технологии о блокировке фона.
  • Фокус внутри окна должен быть ограничен элементами модального окна, а возвращение к исходному элементу после закрытия.

Пример с добавлением доступности:

<div class="modal" role="dialog" aria-modal="true">
  <h2 id="modal-title">Доступное модальное окно</h2>
  <p id="modal-desc">Описание содержимого окна.</p>
</div>

Итоговые рекомендации по проектированию модальных окон

  • Использовать готовые компоненты из UI-библиотек для экономии времени и соблюдения стандартов.
  • Всегда учитывать доступность и управление фокусом.
  • Применять анимации для улучшения UX, но без перегрузки интерфейса.
  • Для крупных проектов централизовать состояние через Svelte store.
  • Разделять логику открытия/закрытия и визуальное отображение окна для поддерживаемости кода.

Модальные окна в SvelteKit при правильной организации становятся мощным инструментом для взаимодействия пользователя с приложением, сочетая реактивность, управляемость и визуальную выразительность интерфейса.