Использование стилей повторно
Управление дублированием и создание повторно используемых абстракций.
Tailwind поощряет утилитарный подход, где проекты реализуются с использованием только утилитарных классов низкого уровня. Это мощный способ избежать преждевременной абстракции и связанных с ней проблем.
Но, конечно, по мере роста проекта вы неизбежно обнаружите, что повторяете общие комбинации утилит, чтобы повторно создавать один и тот же дизайн во многих разных местах.
Например, в шаблоне ниже вы можете увидеть, что утилитарные классы для каждого изображения аватара повторяются пять раз:
<div>
<div class="flex items-center space-x-2 text-base">
<h4 class="font-semibold text-slate-900">Contributors</h4>
<span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700">204</span>
</div>
<div class="mt-3 flex -space-x-2 overflow-hidden">
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80" alt=""/>
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
</div>
<div class="mt-3 text-sm font-medium">
<a href="#" class="text-blue-500">+ 198 others</a>
</div>
</div> Не паникуйте! В этом руководстве вы узнаете о различных стратегиях повторного использования стилей в своем проекте, а также о лучших практиках для каждого случая.
Использование функций редактора и языка
Во многих случаях такое дублирование даже не является реальной проблемой, поскольку все находится в одном месте или вообще не существует, потому что вы итерируете массив элементов и записываете разметку только один раз.
Если стили, которые нужно повторно использовать, необходимы только в одном файле, редактирование с несколькими курсорами и циклы являются простейшим способом управления дублированием.
Редактирование с несколькими курсорами
Когда дублирование локализовано в группе элементов в одном файле, самый простой способ справиться с этим — использовать редактирование с несколькими курсорами, чтобы быстро выбрать и изменить список классов для каждого элемента сразу:
<nav class="flex justify-center space-x-4"> <a href="/dashboard" class="font-medium px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Home</a> <a href="/team" class="font-medium px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Team</a> <a href="/projects" class="font-medium px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Projects</a> <a href="/reports" class="font-medium px-3 py-2 text-slate-700 rounded-lg hover:bg-slate-100 hover:text-slate-900">Reports</a> </nav>
Вы будете удивлены, насколько часто это оказывается лучшим решением. Если вы можете быстро изменить все дублированные списки классов одновременно, нет смысла вводить какую-либо дополнительную абстракцию.
Циклы
Прежде чем предположить, что вам нужно извлечь компонент или создать пользовательский класс, убедитесь, что вы действительно используете его более одного раза в своем шаблоне.
Во многих случаях элемент дизайна, который отображается более одного раза на отображаемой странице, фактически создается только один раз, потому что фактическая разметка отображается в цикле.
Например, дублированные аватары в начале этого руководства, почти наверняка, будут отображаться в цикле в реальном проекте:
<div>
<div class="flex items-center space-x-2 text-base">
<h4 class="font-semibold text-slate-900">Contributors</h4>
<span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-700">204</span>
</div>
<div class="mt-3 flex -space-x-2 overflow-hidden">
{#each contributors as user}
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="{user.avatarUrl}" alt="{user.handle}"/>
{/each}
</div>
<div class="mt-3 text-sm font-medium">
<a href="#" class="text-blue-500">+ 198 others</a>
</div>
</div> Вы даже можете переписать пример навигации с помощью цикла или map по своему усмотрению:
<nav className="flex sm:justify-center space-x-4">
{[
['Home', '/dashboard'],
['Team', '/team'],
['Projects', '/projects'],
['Reports', '/reports'],
].map(([title, url]) => (
<a href={url} className="rounded-lg px-3 py-2 text-slate-700 font-medium hover:bg-slate-100 hover:text-slate-900">{title}</a>
))}
</nav> Когда элементы отображаются в цикле, фактический список классов записывается только один раз, поэтому нет реальной проблемы дублирования, которую нужно решить.
Извлечение компонентов и частичных шаблонов
Если вам нужно повторно использовать некоторые стили в нескольких файлах, лучшей стратегией является создание компонента, если вы используете фреймворк front-end, например, React, Svelte или Vue, или частичного шаблона, если вы используете язык шаблонов, например, Blade, ERB, Twig или Nunjucks.
<template>
<div>
<img class="rounded" :src="img" :alt="imgAlt">
<div class="mt-2">
<div>
<div class="text-xs text-slate-600 uppercase font-bold tracking-wider">{{ eyebrow }}</div>
<div class="font-bold text-slate-700 leading-snug">
<a :href="url" class="hover:underline">{{ title }}</a>
</div>
<div class="mt-2 text-sm text-slate-600">{{ pricing }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['img', 'imgAlt', 'eyebrow', 'title', 'pricing', 'url']
}
</script>Теперь вы можете использовать этот компонент в любом месте, сохраняя при этом единый источник истины для стилей, чтобы их можно было легко обновлять вместе в одном месте.
Сравнение со стилями CSS абстракций
Если компонент — это не единственный HTML-элемент, то информация, необходимая для его определения, не может быть захвачена только в CSS. Для чего-либо даже отдаленно сложного, структура HTML столь же важна, как и CSS.
Не полагайтесь на классы CSS для извлечения сложных компонентов
<!-- Even with custom CSS, you still need to duplicate this HTML structure -->
<div class="chat-notification">
<div class="chat-notification-logo-wrapper">
<img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
</div>
<div class="chat-notification-content">
<h4 class="chat-notification-title">ChitChat</h4>
<p class="chat-notification-message">You have a new message!</p>
</div>
</div>
<style>
.chat-notification { /* ... */ }
.chat-notification-logo-wrapper { /* ... */ }
.chat-notification-logo { /* ... */ }
.chat-notification-content { /* ... */ }
.chat-notification-title { /* ... */ }
.chat-notification-message { /* ... */ }
</style> Даже если вы создадите классы для разных элементов в компоненте, вам все равно придется дублировать HTML каждый раз, когда вы захотите использовать этот компонент. Конечно, вы можете обновить размер шрифта для каждого экземпляра в одном месте, но что если вам нужно преобразовать заголовок в ссылку?
Компоненты и частичные шаблоны решают эту проблему намного лучше, чем только абстракции CSS, поскольку компонент может содержать HTML и стили. Изменение размера шрифта для каждого экземпляра столь же просто, как и с CSS, но теперь вы также можете преобразовать все заголовки в ссылки в одном месте.
Создайте частичный шаблон или компонент JavaScript
function Notification({ imageUrl, imageAlt, title, message }) {
return (
<div className="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4">
<div className="shrink-0">
<img className="h-12 w-12" src={imageUrl.src} alt={imageAlt}>
</div>
<div>
<div className="text-xl font-medium text-black">{title}</div>
<p className="text-slate-500">{message}</p>
</div>
</div>
)
}Когда вы создаете компоненты и частичные шаблоны, нет необходимости использовать что-либо, кроме утилитарных классов, потому что у вас уже есть единый источник истины для стилей.
Извлечение классов с помощью @apply
Если вы используете традиционный язык шаблонов, например, ERB или Twig, создание частичного шаблона для чего-то столь же простого, как кнопка, может показаться излишним по сравнению с простым классом CSS, например btn.
Хотя настоятельно рекомендуется создавать соответствующие частичные шаблоны для более сложных компонентов, вы можете использовать директиву Tailwind @apply для извлечения повторяющихся утилитарных шаблонов в пользовательские классы CSS, когда частичный шаблон кажется излишним.
Вот как может выглядеть класс btn-primary с использованием @apply для его составления из существующих утилит:
<!-- Before extracting a custom class --> <button class="py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75"> Save changes </button> <!-- After extracting a custom class --> <button class="btn-primary"> Save changes </button>
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}
}Узнайте больше о @apply и @layer в документации Функции и директивы.
Избегание преждевременной абстракции
В любом случае, не используйте @apply только для того, чтобы сделать вещи «чище». Да, HTML-шаблоны, заполненные классами Tailwind, довольно уродливы. Изменения в проекте с множеством пользовательских стилей CSS еще хуже.
Если вы начнете использовать @apply для всего, вы фактически просто напишете CSS снова и откажетесь от всех преимуществ работы и поддержки Tailwind, например:
- Вам постоянно нужно придумывать имена классов — ничего не замедлит вас и не израсходует вашу энергию, как придумывание имени класса для чего-то, что не заслуживает названия.
- Вам нужно переключаться между несколькими файлами, чтобы внести изменения — что является гораздо более серьезной проблемой в плане работы, чем вы думаете, прежде чем все объединить.
- Изменение стилей становится пугающим — CSS глобальный, вы уверены, что можете изменить значение min-width в этом классе, не сломав что-то в другой части сайта?
- Ваш CSS-сборка станет больше — упс.
Если вы собираетесь использовать @apply, используйте его для очень небольших, легко повторно используемых вещей, таких как кнопки и элементы управления формами — и даже тогда, только если вы не используете фреймворк, например React, где компонент будет лучшим выбором.
© 2022 Tailwind Labs Inc.
https://tailwindcss.com/docs/reusing-styles