Модальные окна и оверлеи являются ключевыми элементами интерфейса для взаимодействия с пользователем. В контексте SvelteKit их реализация требует понимания реактивности, управления состоянием и правильного использования компонентов библиотек UI.
В SvelteKit модальное окно обычно реализуется как отдельный компонент. Основные элементы структуры:
<script>
export let isOpen = false;
export let onCl ose = () => {};
</script>
{#if isOpen}
<div class="overlay" on:click={onClose}></div>
<div class="modal">
<slot></slot>
<button on:click={onClose}>Закрыть</button>
</div>
{/if}
<style>
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 10;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 2rem;
border-radius: 8px;
z-index: 11;
max-width: 500px;
width: 90%;
}
</style>
Ключевые моменты реализации:
isOpen управляет видимостью модального окна.slot позволяет вставлять произвольный контент внутрь
модального окна.В больших приложениях управление состоянием модальных окон часто
централизуется через store:
// modalStore.js
import { writable } from 'svelte/store';
export const modalState = writable({
isOpen: false,
content: null
});
Компонент модального окна подписывается на store и отображает контент динамически:
<script>
import { modalState } from './modalStore';
import { onDestroy } from 'svelte';
let unsubscribe;
let isOpen = false;
let content = null;
unsubscribe = modalState.subscribe(value => {
isOpen = value.isOpen;
content = value.content;
});
onDestroy(() => unsubscribe());
</script>
{#if isOpen}
<div class="overlay" on:click={() => modalState.set({ isOpen: false, content: null })}></div>
<div class="modal">
{#if content}
{#await content()}
<p>Загрузка...</p>
{:then data}
<div>{data}</div>
{:catch error}
<p>Ошибка: {error.message}</p>
{/await}
{/if}
<button on:click={() => modalState.set({ isOpen: false, content: null })}>Закрыть</button>
</div>
{/if}
Использование store позволяет открывать любое модальное
окно из любой части приложения без передачи props через несколько
уровней компонентов.
SvelteKit и Svelte предоставляют встроенные переходы и анимации, которые делают появление модальных окон плавным:
<script>
import { fade, fly } from 'svelte/transition';
export let isOpen = false;
</script>
{#if isOpen}
<div class="overlay" on:click={() => isOpen = false} transition:fade></div>
<div class="modal" transition:fly="{{ y: -50, duration: 300 }}">
<slot></slot>
<button on:click={() => isOpen = false}>Закрыть</button>
</div>
{/if}
Примечания:
fade применяется к оверлею для плавного
затемнения.fly создаёт эффект вылета/появления окна с заданной
координатой и длительностью.Для отображения различных форм, сообщений или карточек внутри одного
модального окна используется концепция dynamic content.
Контент передаётся через функцию или компонент:
// modalContent.js
export function getUserForm() {
return import('./UserForm.svelte').then(m => m.default);
}
// Где открывается модальное окно
import { modalState } from './modalStore';
import { getUserForm } from './modalContent';
function openUserForm() {
modalState.set({
isOpen: true,
content: getUserForm
});
}
Такой подход позволяет уменьшить количество отдельных компонентов модальных окон и управлять ими централизованно.
Для повышения UX важно блокировать взаимодействие с остальной частью страницы при открытом модальном окне:
overlay с высокой
z-index.document.body.style.overflow = 'hidden' при открытии и
восстанавливать после закрытия.Escape клавиши для закрытия
окна:<script>
import { onMount, onDestroy } from 'svelte';
export let isOpen = false;
export let onCl ose = () => {};
function handleKey(event) {
if (event.key === 'Escape') onClose();
}
onMount(() => window.addEventListener('keydown', handleKey));
onDestroy(() => window.removeEventListener('keydown', handleKey));
</script>
Популярные библиотеки для SvelteKit, такие как Svelte Material UI (SMUI), Skeleton, Flowbite Svelte, предоставляют готовые модальные компоненты с встроенными стилями и анимациями. Использование их упрощает разработку:
<script>
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@smui/dialog';
let open = false;
</script>
<Dialog bind:open>
<DialogTitle>Подтверждение</DialogTitle>
<DialogContent>Вы уверены, что хотите удалить этот элемент?</DialogContent>
<DialogActions>
<button on:click={() => open = false}>Отмена</button>
<button on:click={confirmDelete}>Удалить</button>
</DialogActions>
</Dialog>
Преимущества использования UI-библиотек:
Для сложных интерфейсов с вложенными модальными окнами рекомендуется:
modalStack) через
store.// modalStack.js
import { writable } from 'svelte/store';
export const modalStack = writable([]);
Добавление и удаление окна осуществляется через push/pop, что позволяет реализовать динамические цепочки модальных окон без конфликтов.
aria-modal="true" и
role="dialog" на модальном окне.Эта структура позволяет создавать модальные окна и оверлеи любого уровня сложности в SvelteKit, от простых диалогов до динамических форм с централизованным управлением состоянием, а также обеспечивает плавные анимации и соответствие стандартам доступности.