Spec-Zone.ru › Tailwind CSS

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

Управление дублированием и создание повторно используемых абстракций.

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.

VacationCard.vue
<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

Notification.jsx
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 для его составления из существующих утилит:

HTML
<!-- 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>
CSS
@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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API