Skip to content

Svelte Scoped

Помещает сгенерированный CSS для утилитных стилей каждого компонента Svelte непосредственно в блок <style> компонента Svelte вместо глобального CSS-файла.

Этот компонент:

svelte
<div class="mb-1" />

преобразуется в:

svelte
<div class="uno-ei382o" />

<style>
  :global(.uno-ei382o) {
    margin-bottom: 0.25rem;
  }
</style>

Когда использовать

Случай использованияОписаниеПакет для использования
Небольшие приложенияИметь 1 глобальный CSS-файл более удобно. Используйте обычный плагин Vite для Svelte/SvelteKit.unocss/vite
Крупные приложенияSvelte Scoped может помочь избежать постоянно растущего глобального CSS-файла.@unocss/svelte-scoped/vite
Библиотека компонентовСгенерированные стили помещаются непосредственно в собранные компоненты без необходимости использовать UnoCSS в конвейере сборки потребляющего приложения.@unocss/svelte-scoped/preprocess

Как это работает

Обычная настройка UnoCSS/Tailwind CSS помещает утилитные стили в глобальный CSS-файл с правильным порядком. В отличие от этого, Svelte Scoped распределяет ваши стили по многим произвольно упорядоченным CSS-файлам компонентов Svelte. Однако он должен сохранять утилитные стили глобальными, чтобы они могли быть контекстно-осведомленными для таких вещей, как справа-налево и других случаев, перечисленных ниже. Это представляет сложность, которая решается с помощью обертки Svelte :global(), чтобы отказаться от метода хэширования CSS по умолчанию и вместо этого использовать хэш на основе имени файла + имени(н) класса для компиляции уникальных имен классов, которые можно сделать глобальными без конфликтов стилей.

Использование

Поскольку Svelte Scoped переписывает ваши утилитные имена классов, вы ограничены в том, где их можно писать:

Поддерживаемый синтаксисПример
Атрибут класса<div class="mb-1" />
Директива класса<div class:mb-1={condition} />
Сокращение директивы класса<div class:logo />
Проп класса<Button class="mb-1" />

Svelte Scoped разработан как прямая замена для проекта, использующего утилитные стили. Как таковой, выражения, найденные внутри атрибутов класса, также поддерживаются (например, <div class="mb-1 {foo ? 'mr-1' : 'mr-2'}" />) но мы рекомендуем использовать синтаксис директивы класса в дальнейшем. Обратите также внимание, что если вы использовали имена классов другими способами, например, помещая их в блок <script> или используя режим attributify, вам нужно будет предпринять дополнительные шаги перед использованием Svelte Scoped. Вы можете использовать опцию safelist и также ознакомиться с разделом пресеты для получения дополнительных советов.

Контекстно-осведомленный

Несмотря на то, что стили распределены по компонентам Svelte вашего приложения, они все еще являются глобальными классами и будут работать в отношении элементов, найденных за пределами их конкретных компонентов. Вот несколько примеров:

Зависимость от родителя

Классы, зависящие от атрибутов, найденных в родительском компоненте:

svelte
<div class="dark:mb-2 rtl:right-0"></div>

превращаются в:

svelte
<div class="uno-3hashz"></div>

<style>
  :global(.dark .uno-3hashz) {
    margin-bottom: 0.5rem;
  }
  :global([dir="rtl"] .uno-3hashz) {
    right: 0rem;
  }
</style>

Влияние дочерних элементов

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

svelte
<div class="space-x-1">
  <div>Status: online</div>
  <Button>FAQ</Button>
  <Button>Login</Button>
</div>

превращается в:

svelte
<div class="uno-7haszz">
  <div>Status: online</div>
  <Button>FAQ</Button>
  <Button>Login</Button>
</div>

<style>
  :global(.uno-7haszz > :not([hidden]) ~ :not([hidden])) {
    --un-space-x-reverse: 0;
    margin-left: calc(0.25rem * calc(1 - var(--un-space-x-reverse)));
    margin-right: calc(0.25rem * var(--un-space-x-reverse));
  }
</style>

Передача классов дочерним компонентам

Вы можете добавить проп class к компоненту, чтобы разрешить передачу пользовательских классов в любом месте, где этот компонент используется.

svelte
<Button class="px-2 py-1">Login</Button>

превращается в:

svelte
<Button class="uno-4hshza">Login</Button>

<style>
  :global(.uno-4hshza) {
    padding-left:0.5rem;
    padding-right:0.5rem;
    padding-top:0.25rem;
    padding-bottom:0.25rem;
  }
</style>

Простой способ реализовать класс в принимающем компоненте - разместить их на элементе с использованием {$$props.class}, например, div class="{$$props.class} foo bar" />.

Директивы применения

Вы можете использовать директивы применения внутри ваших блоков <style> с помощью --at-apply или @apply, или пользовательского значения, установленного с помощью опции applyVariables.

Svelte Scoped даже правильно обрабатывает контекстно-зависимые классы, такие как dark:text-white, которые обычный пакет @unocss/transformer-directives не может правильно обработать, потому что он не был специально разработан для блоков стилей Svelte. Например, с Svelte Scoped этот компонент:

svelte
<div />

<style>
  div {
    --at-apply: rtl:ml-2;
  }
</style>

будет преобразован в:

svelte
<div />

<style>
  :global([dir=\\"rtl\\"]) div {
    margin-right: 0.5rem;
  }
</style>

Чтобы rtl:ml-2 работал правильно, селектор [dir="rtl"] обернут в :global(), чтобы компилятор Svelte не удалял его автоматически, так как у компонента нет элемента с этим атрибутом. Однако div не может быть включен в обертку :global(), потому что этот стиль тогда будет влиять на каждый div в вашем приложении.

Другие директивы блока стилей

Использование theme() также поддерживается, но @screen не поддерживается.

Плагин Vite

В приложениях Svelte или SvelteKit внедряет сгенерированные стили непосредственно в ваши компоненты Svelte, помещая минимально необходимые стили в глобальную таблицу стилей. Посмотрите пример SvelteKit в Stackblitz:

Open in StackBlitz

Установка

bash
pnpm add -D unocss @unocss/svelte-scoped
bash
yarn add -D unocss @unocss/svelte-scoped
bash
npm install -D unocss @unocss/svelte-scoped
bash
bun add -D unocss @unocss/svelte-scoped

Добавление плагина

Добавьте @unocss/svelte-scoped/vite в вашу конфигурацию Vite:

ts
import { sveltekit } from '@sveltejs/kit/vite'
import UnoCSS from '@unocss/svelte-scoped/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    UnoCSS({
      // injectReset: '@unocss/reset/normalize.css', // смотрите определение типа для всех включенных параметров сброса или как передать свой собственный
      // ...другие параметры Svelte Scoped
    }),
    sveltekit(),
  ],
})

Добавление файла конфигурации

Настройте ваш файл uno.config.ts, как описано ниже.

Глобальные стили

Хотя почти все стили помещаются в отдельные компоненты, есть несколько, которые должны быть помещены в глобальную таблицу стилей: префлайты, список безопасных классов и необязательный сброс (если вы используете опцию injectReset).

Добавьте заполнитель %unocss-svelte-scoped.global% в тег <head>. В Svelte это index.html. В SvelteKit это будет в app.html перед %sveltekit.head%:

html
<head>
  <!-- ... -->
  <title>SvelteKit using UnoCSS Svelte Scoped</title>
  %unocss-svelte-scoped.global%
  %sveltekit.head%
</head>

Если вы используете SvelteKit, вам также необходимо добавить следующее в хук transformPageChunk в вашем файле src/hooks.server.js:

js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
  const response = await resolve(event, {
    transformPageChunk: ({ html }) =>
      html.replace(
        '%unocss-svelte-scoped.global%',
        'unocss_svelte_scoped_global_styles'
      ),
  })
  return response
}

Это преобразование должно быть в файле, путь которого включает hooks и server (например, src/hooks.server.js, src/hooks.server.ts), так как svelte-scoped будет искать в вашем файле серверных хуков, чтобы заменить unocss_svelte_scoped_global_styles на ваши глобальные стили. Убедитесь, что не импортируйте это преобразование из другого файла, такого как sequence из @sveltejs/kit/hooks.

В обычном Svelte проекте Vite's transformIndexHtml хука автоматически сделает это.

Svelte Preprocessor

Используйте утилитные стили для создания библиотеки компонентов, которая не зависит от включения сопровождающего CSS файла, используя препроцессор для размещения сгенерированных стилей непосредственно в построенные компоненты. Проверьте Stackblitz пример SvelteKit Library

Open in StackBlitz

Установка

bash
pnpm add -D unocss @unocss/svelte-scoped
bash
yarn add -D unocss @unocss/svelte-scoped
bash
npm install -D unocss @unocss/svelte-scoped
bash
bun add -D unocss @unocss/svelte-scoped

Добавление препроцессора

Добавьте @unocss/svelte-scoped/preprocess в вашу конфигурацию Svelte:

ts
import adapter from '@sveltejs/adapter-auto'
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import UnoCSS from '@unocss/svelte-scoped/preprocess'

const config = {
  preprocess: [
    vitePreprocess(),
    UnoCSS({
      // ... опции препроцессора
    }),
  ],
  // другие настройки Svelte
}

Не объединяйте имена классов в разработке

При использовании Svelte Scoped в обычном приложении плагин Vite автоматически определяет режим dev или build. В режиме разработки классы будут оставаться отдельными и хешироваться на месте для удобства включения/выключения в инструментах разработчика вашего браузера. class="mb-1 mr-1" превратится в нечто вроде class="_mb-1_9hwi32 _mr-1_84jfy4. В производственном режиме они будут скомпилированы в одно имя класса, используя ваш желаемый префикс, по умолчанию uno-, и хеш на основе имени файла + имен классов, например, class="uno-84dke3.

Если вы хотите такое же поведение при использовании препроцессора, вы должны вручную установить опцию combine в зависимости от окружения. Один из способов сделать это - установить cross-env и обновить ваш скрипт разработки следующим образом:

"dev": "cross-env NODE_ENV=development vite dev"

Затем настройте ваш svelte.config.js:

diff
+const prod = process.env.NODE_ENV !== 'development'
const config = {
  preprocess: [
    vitePreprocess(),
    UnoCSS({
+      combine: prod,
    }),
  ],
}

Добавление файла конфигурации

Настройте ваш файл uno.config.ts, как описано ниже.

Префлайты

При использовании препроцессора у вас есть возможность включать префлайты в конкретные компоненты, где они необходимы, добавляя uno-preflights в качестве атрибута стиля.

html
<style uno-preflights></style>

Любые специальные префлайты, начинающиеся с точки, такие как .prose :where(a):not(:where(.not-prose, .not-prose *)), будут обернуты в :global(), чтобы избежать их автоматического удаления компилятором Svelte.

Добавление префлайтов в отдельные компоненты не требуется, если ваши классы не зависят от префлайтов или ваши построенные компоненты используются только в приложениях, которые уже включают префлайты.

Безопасный список

При использовании препроцессора у вас есть возможность включать классы из безопасного списка в компонент, добавляя uno-safelist в качестве атрибута стиля.

html
<style uno-safelist></style>

Ваши стили из безопасного списка будут обернуты в :global(), чтобы избежать их автоматического удаления компилятором Svelte.

Конфигурация

Разместите настройки UnoCSS в файле uno.config.ts:

ts
import { defineConfig } from 'unocss'

export default defineConfig({
  // ...опции UnoCSS
})

Экстракторы не поддерживаются из-за различий в обычном глобальном использовании UnoCSS и использовании Svelte Scoped. Пресеты и трансформеры поддерживаются, как описано в следующих разделах. См. Файл конфигурации и Справочник по конфигурации для всех остальных деталей.

Поддержка пресетов

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

ПресетПоддержкаПримечания
@unocss/preset-uno, @unocss/preset-mini, @unocss/preset-wind3, @unocss/preset-icons, @unocss/web-fontsЭти и все плагины сообщества, например unocss-preset-forms, которые полагаются только на правила/варианты/префлайты, будут работать.
@unocss/preset-typographyИз-за того, как этот пресет добавляет наборы правил к вашим префлайтам, вы должны добавить класс prose в ваш безопасный список при использовании этого пресета, иначе префлайты никогда не будут запущены. Все остальные классы из этого пресета, например prose-pink, могут быть ограничены компонентом.
@unocss/preset-rem-to-pxЭтот и все пресеты, подобные ему, которые только модифицируют вывод стилей, будут работать.
@unocss/preset-attributify-Пресет не будет работать. Вместо этого используйте плагин Vite unplugin-attributify-to-class (attributifyToClass({ include: [/\.svelte$/]})) перед плагином Svelte Scoped Vite
@unocss/preset-tagify-Пресеты, добавляющие пользовательские экстракторы, не будут работать. Создайте препроцессор для преобразования <text-red>Hi</text-red> в <span class="text-red">Hi</span>, затем создайте PR для добавления ссылки здесь.

Для других пресетов, если они не полагаются на традиционное использование class="...", вам нужно будет сначала предварительно обработать эти имена классов в атрибут class="...". Если они добавляют пресеты, такие как класс .prose из typography, вам нужно будет поместить классы, которые запускают дополнения пресета, в ваш безопасный список.

Поддержка трансформеров

Трансформеры поддерживаются для ваших CSS-файлов (css|postcss|sass|scss|less|stylus|styl). Чтобы использовать их, добавьте трансформер в опцию cssFileTransformers в вашем vite.config.ts:

ts
import transformerDirectives from '@unocss/transformer-directives'

export default defineConfig({
  plugins: [
    UnoCSS({
      cssFileTransformers: [transformerDirectives()],
    }),
    sveltekit(),
  ],
})

INFO

Трансформеры не поддерживаются в компонентах Svelte из-за особенностей работы Svelte Scoped.

Scoped utility classes unleash creativity

Некоторые советы о том, когда вы можете захотеть использовать локальные стили: если вы дошли до того момента в жизни большого проекта, когда каждый раз, используя класс вроде .md:max-w-[50vw], который, как вы знаете, используется только один раз, вы морщитесь, чувствуя, как растет размер вашего глобального файла стилей, тогда попробуйте этот пакет. Нерешительность использовать именно нужный вам класс подавляет творчество. Конечно, вы могли бы использовать --at-apply: md:max-w-[50vw] в блоке стилей, но это становится утомительным, и стили в контексте полезны. Более того, если вы хотите включить в свой проект большое количество иконок, вы начнете чувствовать тяжесть их добавления в глобальную таблицу стилей. Когда каждый компонент несет на себе вес собственных стилей и иконок, вы можете продолжать расширять свой проект, не анализируя соотношение затрат и выгоды каждого нового добавления.

Лицензия

  • Лицензия MIT © 2022-НАСТОЯЩЕЕ ВРЕМЯ Jacob Bowdoin

Released under the MIT License.