Перейти к содержимому

20. Продвинутые паттерны

Иллюстрация к уроку

В финальном уроке разберём продвинутые CSS-фичи через Tailwind: container queries, logical properties, has() селектор, scroll-driven animations и паттерны, которые выделят тебя как сильного frontend-разработчика.

Container Queries — стили на основе размера родительского контейнера, а не вьюпорта. Идеальны для переиспользуемых компонентов.

В Tailwind v3 — через плагин:

Окно терминала
npm install @tailwindcss/container-queries

В Tailwind v4 — встроены из коробки.

<!-- Отмечаем контейнер -->
<div class="@container">
<!-- Стили зависят от ширины контейнера, не вьюпорта -->
<div class="flex flex-col @md:flex-row @lg:grid @lg:grid-cols-3 gap-4">
<div>Карточка</div>
<div>Карточка</div>
<div>Карточка</div>
</div>
</div>

Брейкпоинты контейнера:

КлассШирина контейнера
@xs320px
@sm384px
@md448px
@lg512px
@xl576px
@2xl672px

Именованные контейнеры:

<div class="@container/sidebar">
<div class="@md/sidebar:flex">Зависит от ширины sidebar</div>
</div>

Logical properties заменяют физические (left/right) на логические (start/end), что важно для RTL-языков (арабский, иврит):

<!-- Физические (работают только для LTR) -->
<div class="ml-4 mr-8 pl-6 pr-2 text-left border-l-4">
<!-- Логические (работают для LTR и RTL) -->
<div class="ms-4 me-8 ps-6 pe-2 text-start border-s-4">

Маппинг:

ФизическийЛогическийLTRRTL
ml-4ms-4margin-leftmargin-right
mr-4me-4margin-rightmargin-left
pl-4ps-4padding-leftpadding-right
pr-4pe-4padding-rightpadding-left
text-lefttext-startleftright
border-lborder-sborder-leftborder-right
rounded-lrounded-sradius-leftradius-right
left-0start-0left: 0right: 0

:has() — «родительский селектор», проверяет наличие дочерних элементов:

<!-- Стилизуем форму, когда внутри есть невалидный инпут -->
<div class="[&:has(input:invalid)]:border-red-500 border-2 rounded-xl p-4">
<input type="email" required>
</div>
<!-- Карточка с кнопкой — показываем кнопку при hover на всю карточку -->
<div class="group [&:has(button:focus)]:ring-2 [&:has(button:focus)]:ring-blue-500">
<p>Контент</p>
<button>Действие</button>
</div>
<!-- Горизонтальная прокрутка с привязкой -->
<div class="flex overflow-x-auto snap-x snap-mandatory gap-4 p-4">
<div class="snap-center shrink-0 w-80 h-48 bg-blue-500 rounded-2xl">Слайд 1</div>
<div class="snap-center shrink-0 w-80 h-48 bg-purple-500 rounded-2xl">Слайд 2</div>
<div class="snap-center shrink-0 w-80 h-48 bg-pink-500 rounded-2xl">Слайд 3</div>
</div>
<!-- Типы привязки -->
<div class="snap-start">Привязка к началу</div>
<div class="snap-center">Привязка к центру</div>
<div class="snap-end">Привязка к концу</div>
<div class="aspect-video">16:9 — видео</div>
<div class="aspect-square">1:1 — квадрат</div>
<div class="aspect-[4/3]">4:3 — фото</div>
<div class="aspect-[21/9]">21:9 — ультраширокий</div>
<!-- Заполнить контейнер, обрезая -->
<img class="w-full h-48 object-cover rounded-2xl" src="photo.jpg">
<!-- Вместить целиком -->
<img class="w-full h-48 object-contain" src="logo.png">
<!-- Фокус на центре -->
<img class="object-cover object-center" src="photo.jpg">
<img class="object-cover object-top" src="portrait.jpg">
<!-- Стеклянный эффект -->
<div class="backdrop-blur-md bg-white/30 border border-white/20 rounded-2xl p-6">
Контент с размытым фоном
</div>
<!-- Навигация с glass-эффектом -->
<nav class="fixed top-0 w-full backdrop-blur-lg bg-white/70 border-b border-gray-200/50 z-50">
Прозрачная навигация
</nav>
<!-- Текст поверх изображения -->
<div class="relative">
<img src="bg.jpg" class="w-full h-64 object-cover">
<div class="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent">
<h2 class="absolute bottom-4 left-4 text-white text-2xl font-bold">Заголовок</h2>
</div>
</div>
<!-- Mix-blend-mode -->
<div class="mix-blend-multiply">Наложение</div>
<div class="mix-blend-screen">Экран</div>
<div class="mix-blend-overlay">Оверлей</div>
<header class="sticky top-0 z-50 backdrop-blur-lg bg-white/80 border-b border-gray-200/50
transition-all duration-300">
<nav class="max-w-5xl mx-auto px-6 py-3 flex items-center justify-between">
<span class="font-bold">Logo</span>
<div class="flex gap-6">
<a href="#">Ссылка</a>
</div>
</nav>
</header>
<!-- Однострочный текст с ... -->
<p class="truncate">Очень длинный текст который обрезается...</p>
<!-- Многострочный текст с ... (2 строки) -->
<p class="line-clamp-2">Длинный текст обрезается через 2 строки и показывается многоточие...</p>
<p class="line-clamp-3">3 строки</p>