Skip to content
← К сниппетам
CSSTailwind CSS

Паттерны CSS и Tailwind: вёрстка, типографика, эффекты

Двенадцать рецептов CSS и Tailwind: плавная типографика на clamp(), адаптивные сетки без media-запросов, обрезка по строкам, скелетоны загрузки, кастомные скроллбары, градиентный текст, тёмная тема классом и переменные темы.

Большинство этих приёмов заменяют то, что раньше требовало media-запроса, обёртки или JavaScript. В этом и сквозная мысль: современный CSS вобрал в себя изрядную часть вёрстки, и оставшаяся работа — знать, какой примитив взять.

Размеры без брейкпоинтов

clamp(min, preferred, max) плавно масштабирует значение между двумя границами, убирая ступенчатость типографики на брейкпоинтах. Важная деталь — средний аргумент: чистое значение в vw выглядит правильно ровно до момента, когда кто-то включит зум или увеличит базовый размер шрифта, — после этого текст перестаёт реагировать и на то, и на другое. Смешивание составляющей в rem с составляющей в vw сохраняет привязку и к настройкам пользователя, и к ширине вьюпорта — поэтому шкала здесь записана как rem + vw, а не как один vw.

grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) делает то же самое для вёрстки. Сетка перестраивается сама на той ширине, которая нужна содержимому: ни брейкпоинтов для поддержки, ни чисел, которые придётся править при смене дизайна карточки.

У обрезки текста два разных ответа

Однострочная обрезка — это text-overflow: ellipsis вместе с white-space: nowrap и overflow: hidden; нужны все три, иначе не работает ничего. Многострочная — это -webkit-line-clamp, который вопреки префиксу давно специфицирован и поддерживается актуальными браузерами. Это не варианты одного приёма: однострочный не умеет обрезать по трём строкам, а clamp вообще не работает без display: -webkit-box.

Скелетоны и скроллбары — про воспринимаемую скорость

Скелетон ничего не ускоряет, он делает ожидание понятным: вёрстка перестаёт прыгать при появлении контента, потому что место уже зарезервировано. Стоит сочетать с prefers-reduced-motion — мерцающая анимация ровно то, что эта настройка призвана гасить.

У кастомных скроллбаров теперь два синтаксиса: старые псевдоэлементы ::-webkit-scrollbar и стандартные свойства scrollbar-width / scrollbar-color. Писать оба — не избыточность: покрытие браузеров различается, а будущее у стандартных.

Tailwind: переменные темы и стратегия тёмного режима

Стратегия тёмной темы через класс означает, что всем управляет класс .dark на <html>, — именно это делает возможным ручной переключатель: стратегия через media-запрос следует за системой и не может быть переопределена пользователем. В связке с CSS-переменными для палитры обе темы остаются в одном месте, вместо того чтобы рассыпаться вариантами dark: по всем компонентам.

CSSCSS

Центрирование чего угодно через flexbox

Переиспользуемый класс, который идеально центрирует единственного потомка по горизонтали и вертикали.

Как это работает: display: flex вместе с align-items: center и justify-content: center центрирует flex-элемент по обеим осям независимо от его размера.

.center {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100%;
}
<div class="center">
  <div class="card">I'm centered</div>
</div>
CSSCSS

Кастомный scrollbar через CSS

Стилизует полосу прокрутки под дизайн-систему без JavaScript — тонкий трек, скруглённый ползунок, hover-состояние. Включает вариант для скрытия scrollbar с сохранением прокрутки.

Как это работает: ::-webkit-scrollbar-* псевдоэлементы работают в Chrome, Safari, Edge и Opera. Firefox использует стандартный scrollbar-color / scrollbar-width. Для полного покрытия нужны оба подхода.

/* Кастомный скроллбар (Chromium + Safari + Edge) */
.custom-scrollbar {
  scrollbar-width: thin;                  /* Firefox */
  scrollbar-color: #9ca3af transparent;   /* Firefox: thumb track */
}

.custom-scrollbar::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

.custom-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}

.custom-scrollbar::-webkit-scrollbar-thumb {
  background-color: #9ca3af;
  border-radius: 999px;
}

.custom-scrollbar::-webkit-scrollbar-thumb:hover {
  background-color: #6b7280;
}

/* Скрыть скроллбар, но оставить прокрутку */
.hide-scrollbar {
  scrollbar-width: none;         /* Firefox */
  -ms-overflow-style: none;      /* IE / Edge legacy */
}

.hide-scrollbar::-webkit-scrollbar {
  display: none;
}
<!-- Example usage -->
<div class="custom-scrollbar" style="height: 300px; overflow-y: auto;">
  <!-- длинный контент -->
</div>
CSSCSS

Fluid Typography с clamp()

Масштабирует размер шрифта плавно между минимальным и максимальным значением в зависимости от ширины viewport — без media queries, только clamp().

Как это работает: clamp(min, preferred, max) зажимает значение между минимумом и максимумом. Средний параметр — линейная функция от ширины viewport (vw). Формула: preferred = minFont + (maxFont - minFont) * (vw - minVw) / (maxVw - minVw).

/* Утилиты fluid typography */
:root {
  /* clamp(min-size, fluid-value, max-size) */
  --text-sm:   clamp(0.75rem,  0.7rem + 0.25vw,  0.875rem);
  --text-base: clamp(0.875rem, 0.8rem + 0.4vw,   1rem);
  --text-lg:   clamp(1rem,     0.9rem + 0.5vw,    1.125rem);
  --text-xl:   clamp(1.125rem, 1rem + 0.6vw,      1.25rem);
  --text-2xl:  clamp(1.25rem,  1rem + 1.25vw,     1.5rem);
  --text-3xl:  clamp(1.5rem,   1rem + 2.5vw,      2.25rem);
  --text-4xl:  clamp(2rem,     1.5rem + 2.5vw,    3rem);
  --text-5xl:  clamp(2.5rem,   2rem + 2.5vw,      4rem);
}

h1 { font-size: var(--text-5xl); }
h2 { font-size: var(--text-4xl); }
h3 { font-size: var(--text-3xl); }
p  { font-size: var(--text-base); }

/* Или напрямую */
.hero-title {
  font-size: clamp(2rem, 5vw + 1rem, 5rem);
  line-height: 1.1;
}

.body-text {
  font-size: clamp(1rem, 0.5vw + 0.875rem, 1.125rem);
  line-height: 1.6;
}
CSSCSS

Градиентный текст (CSS)

Применяет линейный или радиальный градиент к тексту через background-clip: text — без SVG, без JavaScript. Поддерживается всеми современными браузерами.

Как это работает: градиент устанавливается как background на элемент, затем background-clip: text обрезает фон по контуру символов, а color: transparent делает сам текст прозрачным — сквозь него виден градиентный фон.

/* Базовый горизонтальный градиент */
.gradient-text {
  background: linear-gradient(90deg, #f97316, #ec4899);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Диагональный с тремя остановками */
.gradient-text--diagonal {
  background: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Анимированный (двигается) */
.gradient-text--animated {
  background: linear-gradient(90deg, #f97316, #ec4899, #6366f1, #f97316);
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: gradient-shift 4s linear infinite;
}

@keyframes gradient-shift {
  0%   { background-position: 0% center; }
  100% { background-position: 300% center; }
}
<!-- Example usage -->
<h1 class="gradient-text">Привет, мир</h1>
<h2 class="gradient-text--animated">Animated Gradient</h2>
CSSCSS

CSS Grid auto-fit — адаптивная сетка без media queries

Создаёт автоматически адаптируемую сетку колонок через auto-fit и minmax — карточки сами перестраиваются при изменении ширины контейнера без единого breakpoint.

Как это работает: repeat(auto-fit, minmax(min, 1fr)) заставляет CSS Grid автоматически добавлять и убирать колонки. auto-fit схлопывает пустые треки, auto-fill оставляет их. minmax(240px, 1fr) — каждая колонка минимум 240px, максимум — равная доля свободного места.

/* Базовая адаптивная сетка */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}

/* Вариант с минимумом 3 колонок на больших экранах */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 1.5rem;
}

/* Фотогалерея: равные квадратные ячейки */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  grid-auto-rows: 160px;
  gap: 4px;
}

.photo-grid img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<!-- Example usage -->
<div class="auto-grid">
  <div class="card">Карточка 1</div>
  <div class="card">Карточка 2</div>
  <div class="card">Карточка 3</div>
  <!-- автоматически переносится на следующую строку -->
</div>
CSSCSS

Многострочный text-overflow с ellipsis

Обрезает текст после N строк с многоточием через -webkit-line-clamp — работает во всех современных браузерах без JavaScript.

Как это работает: -webkit-line-clamp в связке с display: -webkit-box и -webkit-box-orient: vertical ограничивает блок заданным числом строк. Несмотря на префикс -webkit-, поддерживается всеми современными браузерами включая Firefox.

/* Одна строка */
.truncate-1 {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* N строк (меняй --lines) */
.line-clamp {
  --lines: 3;
  display: -webkit-box;
  -webkit-line-clamp: var(--lines);
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Готовые утилиты */
.line-clamp-2 { --lines: 2; }
.line-clamp-3 { --lines: 3; }
.line-clamp-4 { --lines: 4; }
<!-- Example usage -->
<p class="line-clamp" style="--lines: 2">
  Очень длинный текст, который будет обрезан после второй строки
  с многоточием в конце, без какого-либо JavaScript...
</p>
CSSCSS

Skeleton Loading анимация (CSS)

Shimmer-эффект для скелетонов загрузки — пульсирующий градиент имитирует загрузку контента. Без JavaScript, только CSS-анимация на кастомных свойствах.

Как это работает: @keyframes shimmer двигает градиент слева направо через элемент. Использование background-size: 200% позволяет градиенту выходить за края — это создаёт эффект бегущего света. will-change: background-position помогает GPU-ускорению.

/* Базовый skeleton-блок */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--skeleton-base, #e5e7eb) 25%,
    var(--skeleton-shine, #f3f4f6) 50%,
    var(--skeleton-base, #e5e7eb) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: 4px;
}

@keyframes shimmer {
  0%   { background-position: 200% center; }
  100% { background-position: -200% center; }
}

/* Тёмная тема */
@media (prefers-color-scheme: dark) {
  .skeleton {
    --skeleton-base: #374151;
    --skeleton-shine: #4b5563;
  }
}

/* Готовые фигуры */
.skeleton-text   { height: 0.875rem; border-radius: 2px; }
.skeleton-title  { height: 1.25rem;  border-radius: 2px; }
.skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; }
.skeleton-card   { height: 120px; border-radius: 8px; }
<!-- Example usage — карточка в состоянии загрузки -->
<div style="display: flex; gap: 12px; align-items: center">
  <div class="skeleton skeleton-avatar"></div>
  <div style="flex: 1; display: flex; flex-direction: column; gap: 8px">
    <div class="skeleton skeleton-title" style="width: 60%"></div>
    <div class="skeleton skeleton-text" style="width: 90%"></div>
    <div class="skeleton skeleton-text" style="width: 75%"></div>
  </div>
</div>
CSSCSS

Обрезание однострочного текста с многоточием

Обрезает текст, не помещающийся в одну строку, и добавляет "…" в конце — классический способ обрезки текста только средствами CSS.

Как это работает: работает только для ОДНОЙ строки — white-space: nowrap запрещает перенос, overflow: hidden обрезает лишнее, а text-overflow: ellipsis заменяет обрезанную часть на "…". Для нескольких строк используйте line-clamp.

.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
<p class="truncate" style="max-width: 200px;">
  This sentence is way too long to fit on one line and will be truncated
</p>
Tailwind CSS

Tailwind CSS анимации — keyframes и transition

Создание кастомных анимаций через `animate-*` и `@keyframes` в Tailwind — от микро-взаимодействий до переходов между страницами без выхода из конфига.

Как это работает: определите keyframes и animation в tailwind.config.js. Каждый ключ получает класс animate-{name}. Комбинируйте с transition-*, hover: и group-hover: для интерактивных микро-анимаций.

// tailwind.config.js
export default {
  theme: {
    extend: {
      keyframes: {
        'fade-in': {
          '0%': { opacity: '0', transform: 'translateY(10px)' },
          '100%': { opacity: '1', transform: 'translateY(0)' },
        },
        'scale-in': {
          '0%': { transform: 'scale(0.95)', opacity: '0' },
          '100%': { transform: 'scale(1)', opacity: '1' },
        },
        'slide-up': {
          '0%': { transform: 'translateY(100%)' },
          '100%': { transform: 'translateY(0)' },
        },
        'pulse-soft': {
          '0%, 100%': { opacity: '1' },
          '50%': { opacity: '0.5' },
        },
      },
      animation: {
        'fade-in': 'fade-in 0.3s ease-out',
        'scale-in': 'scale-in 0.2s ease-out',
        'slide-up': 'slide-up 0.4s ease-out',
        'pulse-soft': 'pulse-soft 2s ease-in-out infinite',
      },
    },
  },
}
<!-- Использование классов анимации -->
<div class="animate-fade-in">
  <h1>Появляется со слайдом</h1>
</div>

<div class="animate-scale-in">Фон модалки</div>

<!-- Ступенчатая анимация детей -->
<div class="space-y-4">
  <div class="animate-fade-in" style="animation-delay: 0ms">Элемент 1</div>
  <div class="animate-fade-in" style="animation-delay: 100ms">Элемент 2</div>
  <div class="animate-fade-in" style="animation-delay: 200ms">Элемент 3</div>
</div>

<!-- Hover микро-взаимодействия -->
<button class="transition-all duration-200 hover:scale-105 hover:shadow-lg active:scale-95">
  Наведи
</button>

<!-- Group hover раскрытие -->
<div class="group relative">
  <p>Наведите сюда</p>
  <div class="opacity-0 group-hover:opacity-100 transition-opacity duration-200">
    Скрытый контент
  </div>
</div>
Tailwind CSS

Tailwind CSS кастомная тема через CSS переменные

Расширение стандартной темы Tailwind кастомными цветами, шрифтами, отступами и брейкпоинтами — все значения через CSS-переменные для смены темы в рантайме.

Как это работает: определите CSS-переменные в @layer base и укажите их в tailwind.config.js через theme.extend. Это держит токены дизайна в одном месте и позволяет менять тему в рантайме (просто переопределите значения переменных).

/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --color-primary: #2563eb;
    --color-primary-light: #60a5fa;
    --color-secondary: #7c3aed;
    --color-accent: #f59e0b;
    --color-surface: #ffffff;
    --color-surface-muted: #f8fafc;
    --color-border: #e2e8f0;
    --font-sans: 'Inter', system-ui, sans-serif;
    --font-display: 'Playfair Display', serif;
    --spacing-page: 2rem;
  }

  .dark {
    --color-primary: #60a5fa;
    --color-primary-light: #93c5fd;
    --color-surface: #0f172a;
    --color-surface-muted: #1e293b;
    --color-border: #334155;
  }
}
// tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        primary: {
          DEFAULT: 'var(--color-primary)',
          light: 'var(--color-primary-light)',
        },
        secondary: 'var(--color-secondary)',
        accent: 'var(--color-accent)',
        surface: {
          DEFAULT: 'var(--color-surface)',
          muted: 'var(--color-surface-muted)',
        },
      },
      fontFamily: {
        sans: ['var(--font-sans)'],
        display: ['var(--font-display)'],
      },
      spacing: {
        page: 'var(--spacing-page)',
      },
    },
  },
}
<!-- Использование в шаблонах -->
<div class="bg-surface text-primary font-sans">
  <h1 class="font-display text-3xl">Кастомная тема</h1>
</div>
Tailwind CSS

Tailwind CSS dark mode со стратегией class

Включение тёмной темы по кнопке вместо системных настроек — стратегия class даёт полный контроль через переключатель с сохранением в localStorage.

Как это работает: установите darkMode: "class" в tailwind.config.js и переключайте класс dark на <html>. Все варианты dark: активируются, когда родитель имеет этот класс. Это даёт полный контроль — идеально для переключателя темы.

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  darkMode: 'class',
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
}
<!-- Классы тёмной темы -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
  <h1 class="text-gray-900 dark:text-white">Заголовок</h1>
  <p class="text-gray-600 dark:text-gray-400">Контент с адаптивными цветами</p>
  <button class="bg-blue-600 dark:bg-blue-500 text-white px-4 py-2 rounded-lg
                 hover:bg-blue-700 dark:hover:bg-blue-400 transition-colors">
    Отправить
  </button>
</div>

<!-- Кнопка переключения -->
<button onclick="toggleDarkMode()">
  <span class="dark:hidden">☀️ Светлая</span>
  <span class="hidden dark:inline">🌙 Тёмная</span>
</button>
// Переключение темы с сохранением в localStorage
function toggleDarkMode() {
  const html = document.documentElement
  const isDark = html.classList.toggle('dark')
  localStorage.setItem('theme', isDark ? 'dark' : 'light')
}

// При загрузке страницы
const saved = localStorage.getItem('theme')
if (saved === 'dark' || (!saved && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
  document.documentElement.classList.add('dark')
}
Tailwind CSS

Tailwind CSS адаптивная сетка карточек

Адаптивная сетка карточек на Tailwind CSS — от 1 колонки на мобильных до 4 на десктопе — без медиа-запросов.

Как это работает: responsive grid-утилиты Tailwind (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4) декларативно задают брейкпоинты. Карточки используют gap для отступов, aspect-video для единообразных медиа и truncate для переполнения текста.

<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-6">
  <div v-for="item in items" :key="item.id"
       class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden hover:shadow-md transition-shadow">
    <div class="aspect-video bg-gray-100 dark:bg-gray-700">
      <img :src="item.image" :alt="item.title" class="w-full h-full object-cover">
    </div>
    <div class="p-4 space-y-2">
      <span class="text-xs font-medium text-blue-600 dark:text-blue-400 uppercase tracking-wide">
        {{ item.category }}
      </span>
      <h3 class="font-semibold text-gray-900 dark:text-white truncate">
        {{ item.title }}
      </h3>
      <p class="text-sm text-gray-500 dark:text-gray-400 line-clamp-2">
        {{ item.description }}
      </p>
    </div>
  </div>
</div>
/* Опционально: утилита line-clamp если Tailwind v3 */
.line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
# В Tailwind v4 line-clamp через @utility или
# используйте нативный CSS выше
// CONNECT

Контактная информация

Оставьте заявку или напишите напрямую в телеграм. Я отвечу в течение 24 часов.

Укажите email или Telegram, чтобы я мог вам ответить.