Как делать11 октября 2026 г.10 мин чтения
Вёрстка: HTML и CSSШаг 5 из 7

Tailwind CSS: утилиты, адаптивность и тема

Коротко

Tailwind CSS — набор маленьких классов-утилит (p-6, flex, text-lg), из которых стиль собирается прямо в разметке. Сборщик просматривает файлы проекта и генерирует CSS только для классов, которые реально встречаются. В версии 4 настройка живёт в CSS: @import "tailwindcss" подключает фреймворк, @theme задаёт цвета, шрифты и брейкпоинты как переменные, а префиксы md:, hover: и dark: включают стиль только на нужной ширине экрана, в нужном состоянии или в тёмной теме.

Пошаговый урокУровень: НачальныйTailwind CSSПрактика: ~45–90 мин

После материала вы сможете

  • подключить Tailwind CSS 4 к проекту на Vite и объяснить, почему в итоговом CSS только использованные классы
  • сверстать адаптивную сетку карточек от мобильной версии к десктопу с брейкпоинтами md: и lg:
  • оформить состояния hover:, focus-visible:, disabled: и group-hover: и проверить их с клавиатуры
  • вынести цвета и шрифт в @theme и включить тёмный режим через dark: с переключателем и сохранением выбора

Проверено на

Tailwind CSS 4.3Vite 8.3Node.js 24 LTS (24.18)Next.js 16.4

Сверено с документацией: 11 октября 2026 г.

Содержание
  1. 01Утилитарный подход: плюсы и цена
  2. 02Установка Tailwind CSS v4 (Vite, PostCSS, Next.js)
  3. 03Базовые утилиты: отступы, типографика, цвета, flex и grid
  4. 04Адаптивность: брейкпоинты sm, md, lg
  5. 05Состояния: hover, focus-visible, disabled, group
  6. 06Тема: @theme, CSS-переменные и тёмный режим
  7. 07Когда выносить в компонент, а не в @apply
  8. 08Проверка и упражнения

Утилитарный подход: плюсы и цена

В классическом CSS вы придумываете имя (.pricing-card), а потом описываете его в отдельном файле. В Tailwind имён почти нет: элемент получает набор однозначных классов — rounded-2xl скругляет углы, p-6 задаёт внутренний отступ, bg-white — фон. Каждый класс делает одну вещь, а значения берутся из общей шкалы: отступы кратны 0.25rem, цвета — из палитры, размеры шрифта — из типографской шкалы.

Что даёт

  • Не нужно придумывать имена классов и переключаться между HTML и CSS
  • Изменение класса затрагивает только этот элемент — соседние страницы не ломаются
  • Значения из шкалы держат дизайн последовательным, в отличие от «магических чисел» в style
  • Состояния и адаптивность пишутся теми же классами — inline-стили так не умеют
  • CSS не растёт с каждой новой страницей: классы переиспользуются

Чего стоит

  • Длинные строки классов в разметке — к ним нужно привыкнуть
  • Повторяющиеся элементы нужно выносить в компоненты, иначе правки придётся делать в нескольких местах
  • Имена классов нельзя собирать из кусочков в рантайме
  • Команде нужен общий словарь утилит и единая тема

Почему CSS не раздувается: Tailwind — не готовая таблица стилей, а генератор. При сборке он просматривает файлы проекта, ищет всё, что похоже на имя класса, и генерирует CSS только для найденного. В нашем проекте итоговый CSS весит 14,18 КБ (3,68 КБ в gzip), и в нём нет, например, bg-red-500 — этот класс нигде не встречается.

Установка Tailwind CSS v4 (Vite, PostCSS, Next.js)

Практика урока — блок тарифов вымышленного сервиса Kite CRM: три карточки, которые на телефоне идут столбиком, на планшете — по две, на десктопе — в ряд, плюс тёмная тема с переключателем. Проект — Vite с шаблоном vanilla, без фреймворка: так видно, что делает именно Tailwind. Установка по официальной инструкции:

Terminal
npm create vite@latest pricing -- --template vanilla
cd pricing
npm install
npm install tailwindcss @tailwindcss/vite
Новый проект Vite и пакеты Tailwind; файлы-примеры шаблона (counter.js и стили) можно удалить
vite.config.js
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [tailwindcss()],
});
Плагин Tailwind для Vite

Вся остальная настройка — в CSS. Первая строка @import "tailwindcss" подключает слои фреймворка: тему с переменными по умолчанию, базовые стили (Preflight) и утилиты. Файла tailwind.config.js и директив @tailwind base из третьей версии больше нет. Итоговый style.css проекта, который разберём в разделе о теме:

src/style.css
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

@theme {
  --font-display: Georgia, "Times New Roman", serif;
  --color-brand-500: oklch(0.62 0.17 255);
  --color-brand-600: oklch(0.54 0.19 260);
  --color-brand-700: oklch(0.47 0.18 262);
}
Весь CSS проекта: подключение, вариант dark по классу и токены темы

Vite

Пакет
@tailwindcss/vite
Подключение
Плагин в vite.config

PostCSS (webpack и другие)

Пакет
@tailwindcss/postcss + postcss
Подключение
Плагин в postcss.config.mjs

Next.js

Пакет
@tailwindcss/postcss по документации
Подключение
create-next-app 16.4 подключает Tailwind сам; в app/globals.css тот же @import "tailwindcss"

Мы проверили, что та же тема работает и в Next.js 16.4: style.css урока подставили в app/globals.css проекта из create-next-app, и сборка сгенерировала те же классы. В этом проекте Tailwind подключён через загрузчик @tailwindcss/turbopack в next.config.ts, а цвета oklch Next.js дополнительно продублировал запасными hex-значениями.

Базовые утилиты: отступы, типографика, цвета, flex и grid

Вся разметка страницы. Скрипт в <head> выбирает тему до отрисовки — вернёмся к нему в разделе о тёмном режиме. Остальное — обычный HTML с классами:

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Kite CRM — Pricing</title>
    <script>
      document.documentElement.classList.toggle(
        "dark",
        localStorage.theme === "dark" ||
          (!("theme" in localStorage) &&
            window.matchMedia("(prefers-color-scheme: dark)").matches),
      );
    </script>
    <script type="module" src="/src/main.js"></script>
  </head>
  <body class="bg-slate-50 text-slate-900 antialiased dark:bg-slate-950 dark:text-slate-100">
    <main class="mx-auto max-w-6xl px-4 py-12 sm:px-6 lg:py-20">
      <header class="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
        <div>
          <h1 class="font-display text-3xl font-bold sm:text-4xl">Pricing</h1>
          <p class="mt-2 text-slate-600 dark:text-slate-400">
            Pick a plan for your team. Switch any time.
          </p>
        </div>
        <button
          id="theme-toggle"
          type="button"
          class="self-start rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium hover:bg-slate-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-600 sm:self-auto dark:border-slate-700 dark:hover:bg-slate-800"
        >
          Dark theme
        </button>
      </header>

      <ul class="mt-10 grid gap-6 md:grid-cols-2 lg:grid-cols-3">
        <li class="flex flex-col rounded-2xl border border-slate-200 bg-white p-6 dark:border-slate-800 dark:bg-slate-900">
          <h2 class="text-lg font-semibold">Free</h2>
          <p class="mt-4 flex items-baseline gap-1">
            <span class="text-4xl font-bold">$0</span>
            <span class="text-sm text-slate-500 dark:text-slate-400">/ month</span>
          </p>
          <ul class="mt-6 mb-8 space-y-2 text-sm text-slate-600 dark:text-slate-300">
            <li>1 user</li>
            <li>100 leads</li>
          </ul>
          <button
            type="button"
            disabled
            class="mt-auto rounded-lg border border-slate-300 px-4 py-2.5 font-semibold disabled:cursor-not-allowed disabled:opacity-60 dark:border-slate-700"
          >
            Current plan
          </button>
        </li>

        <li class="group relative flex flex-col rounded-2xl bg-white p-6 shadow-lg ring-2 ring-brand-600 transition hover:-translate-y-1 hover:shadow-xl dark:bg-slate-900">
          <span class="absolute -top-3 left-6 rounded-full bg-brand-600 px-3 py-1 text-xs font-semibold text-white">
            Popular
          </span>
          <h2 class="text-lg font-semibold group-hover:text-brand-600 dark:group-hover:text-brand-500">Team</h2>
          <p class="mt-4 flex items-baseline gap-1">
            <span class="text-4xl font-bold">$12</span>
            <span class="text-sm text-slate-500 dark:text-slate-400">/ user / month</span>
          </p>
          <ul class="mt-6 mb-8 space-y-2 text-sm text-slate-600 dark:text-slate-300">
            <li>Up to 20 users</li>
            <li>Unlimited leads</li>
            <li>Telegram notifications</li>
          </ul>
          <a
            href="#signup"
            class="mt-auto rounded-lg bg-brand-600 px-4 py-2.5 text-center font-semibold text-white hover:bg-brand-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-600"
          >
            Start free trial
          </a>
        </li>

        <li class="group flex flex-col rounded-2xl border border-slate-200 bg-white p-6 transition hover:-translate-y-1 hover:shadow-lg md:col-span-2 lg:col-span-1 dark:border-slate-800 dark:bg-slate-900">
          <h2 class="text-lg font-semibold group-hover:text-brand-600 dark:group-hover:text-brand-500">Business</h2>
          <p class="mt-4 flex items-baseline gap-1">
            <span class="text-4xl font-bold">$29</span>
            <span class="text-sm text-slate-500 dark:text-slate-400">/ user / month</span>
          </p>
          <ul class="mt-6 mb-8 space-y-2 text-sm text-slate-600 dark:text-slate-300">
            <li>Unlimited users</li>
            <li>Roles and audit log</li>
            <li>1C integration</li>
          </ul>
          <a
            href="#contact"
            class="mt-auto rounded-lg border border-slate-300 px-4 py-2.5 text-center font-semibold hover:border-brand-600 hover:text-brand-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-600 dark:border-slate-700"
          >
            Contact sales
          </a>
        </li>
      </ul>
    </main>
  </body>
</html>
Страница тарифов целиком

Отступы

Утилиты из примера
p-6, px-4, mt-10, mx-auto
CSS
padding, margin; шаг шкалы — 0.25rem, p-6 = 1.5rem

Ширина

Утилиты из примера
max-w-6xl
CSS
max-width из шкалы контейнеров

Типографика

Утилиты из примера
text-4xl, font-bold, text-sm
CSS
font-size с подобранной line-height, font-weight

Цвета

Утилиты из примера
bg-white, text-slate-600, border-slate-200
CSS
background-color, color, border-color из палитры

Flex

Утилиты из примера
flex flex-col, items-baseline, gap-1
CSS
display: flex, направление, выравнивание, промежутки

Grid

Утилиты из примера
grid gap-6, md:grid-cols-2
CSS
display: grid, колонки repeat(2, minmax(0, 1fr))

Скругление и тень

Утилиты из примера
rounded-2xl, shadow-lg, ring-2
CSS
border-radius, box-shadow

Обратите внимание на mt-auto у кнопок: карточка — flex-колонка, и автоматический отступ сверху прижимает кнопку к низу. Поэтому кнопки во всех карточках стоят на одной линии, хотя пунктов в списках разное количество. Это тот же flexbox из урока о раскладке, только записанный классами.

Адаптивность: брейкпоинты sm, md, lg

Любую утилиту можно включить только начиная с определённой ширины экрана — для этого перед классом ставят префикс брейкпоинта и двоеточие. Tailwind работает по принципу mobile-first: класс без префикса действует везде, а md:grid-cols-2 — от 48rem и шире. Документация предупреждает о частой ошибке: sm: не означает «на маленьких экранах». Мобильную версию пишут без префиксов, а префиксами добавляют изменения для более широких экранов.

sm

Минимальная ширина
40rem (640px)
Media query
@media (width >= 40rem)

md

Минимальная ширина
48rem (768px)
Media query
@media (width >= 48rem)

lg

Минимальная ширина
64rem (1024px)
Media query
@media (width >= 64rem)

xl

Минимальная ширина
80rem (1280px)
Media query
@media (width >= 80rem)

2xl

Минимальная ширина
96rem (1536px)
Media query
@media (width >= 96rem)
  1. Телефон: grid gap-6

    Без префиксов сетка из одной колонки — карточки идут друг под другом. Шапка — flex flex-col: заголовок и кнопка темы в столбик.

  2. От 640px: sm:flex-row

    Шапка становится строкой, кнопка темы уходит вправо (sm:justify-between, sm:self-auto).

  3. От 768px: md:grid-cols-2

    Две колонки. Третья карточка растягивается на всю ширину через md:col-span-2, чтобы не висеть одна в половине ряда.

  4. От 1024px: lg:grid-cols-3

    Три колонки, и lg:col-span-1 возвращает третьей карточке обычную ширину. Вертикальные поля страницы увеличиваются через lg:py-20.

Проверка в headless Edge после сборки: при ширине 375px сетка из одной колонки, при 800px — из двух, при 1280px — из трёх, и ни на одной ширине нет горизонтальной прокрутки. Для диапазонов есть варианты max-*: md:max-lg:flex действует только между 768 и 1024px. А если компонент должен подстраиваться под ширину родителя, а не экрана, используют контейнерные запросы: класс @container у родителя и префиксы @md: у детей.

Состояния: hover, focus-visible, disabled, group

Состояния записываются так же, как брейкпоинты: префикс-вариант перед утилитой. hover:bg-brand-700 ничего не делает, пока курсор не наведён на элемент. Варианты можно комбинировать: dark:hover:bg-slate-800 — фон при наведении, но только в тёмной теме.

hover:

Где в примере
hover:bg-brand-700, hover:-translate-y-1
Когда срабатывает
Наведение мыши; в v4 — только на устройствах, которые поддерживают hover

focus-visible:

Где в примере
focus-visible:outline-2 focus-visible:outline-brand-600
Когда срабатывает
Фокус с клавиатуры; при клике мышью рамка не появляется

disabled:

Где в примере
disabled:opacity-60 disabled:cursor-not-allowed
Когда срабатывает
У кнопки есть атрибут disabled

group + group-hover:

Где в примере
group на карточке, group-hover:text-brand-600 на заголовке
Когда срабатывает
Наведение на родителя меняет стиль потомка

Важная деталь четвёртой версии: hover: оборачивается в @media (hover: hover). На телефоне касание больше не «залипает» в состоянии наведения, но и полагаться на hover нельзя: документация советует считать его улучшением, а не единственным способом что-то показать. Вот как выглядит сгенерированный CSS — фрагменты реальной сборки без минификации:

dist/assets/index.css
@layer theme {
  :root, :host {
    /* … the default theme variables that are in use … */
    --font-display: Georgia, "Times New Roman", serif;
    --color-brand-500: oklch(62% .17 255);
    --color-brand-600: oklch(54% .19 260);
    --color-brand-700: oklch(47% .18 262);
  }
}

@layer utilities {
  /* … */
  .bg-brand-600 {
    background-color: var(--color-brand-600);
  }

  @media (min-width: 48rem) {
    /* … */
    .md\:grid-cols-2 {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (hover: hover) {
    /* … */
    .hover\:bg-brand-700:hover {
      background-color: var(--color-brand-700);
    }
  }

  .dark\:bg-slate-900:where(.dark, .dark *) {
    background-color: var(--color-slate-900);
  }
}
Фрагменты реального CSS после vite build --minify false. В этой сборке условие width >= 48rem записано эквивалентным min-width: 48rem; в минифицированной осталось width>=48rem

Проверка с клавиатуры: первый Tab попадает на кнопку темы, второй — пропускает заблокированную кнопку «Current plan» и попадает на «Start free trial», вокруг которой появляется сплошная рамка 2px. У заблокированной кнопки вычисленные opacity: 0.6 и cursor: not-allowed, а наведение на карточку Team перекрашивает её заголовок в цвет бренда.

Тема: @theme, CSS-переменные и тёмный режим

Дизайн-токены — цвета бренда, шрифты, брейкпоинты — в Tailwind 4 задаются в CSS директивой @theme. Это не обычные CSS-переменные: каждая переменная из известного пространства имён создаёт утилиты. --color-brand-600 даёт классы bg-brand-600, text-brand-600, ring-brand-600 и все остальные цветовые; --font-display — класс font-display. Одновременно Tailwind выводит их как обычные переменные в :root, поэтому значение доступно и в своём CSS через var(--color-brand-600).

--color-*

Что создаёт
Все цветовые утилиты
Пример
--color-brand-600 → bg-brand-600

--font-*

Что создаёт
Семейство шрифта
Пример
--font-display → font-display

--breakpoint-*

Что создаёт
Адаптивные варианты
Пример
--breakpoint-3xl: 120rem → 3xl:

--spacing

Что создаёт
Шкала отступов и размеров
Пример
--spacing: 0.25rem → p-6 = 1.5rem

--radius-*, --shadow-*

Что создаёт
Скругления и тени
Пример
--radius-xl → rounded-xl

Новые переменные расширяют стандартную тему, переопределённые — заменяют значение (например, --breakpoint-sm: 30rem), а --color-*: initial убирает всю стандартную палитру. Используйте @theme для токенов, которым нужны утилиты, и :root — для переменных, которым утилиты не нужны.

По умолчанию dark: срабатывает по системной настройке через prefers-color-scheme. Нам нужен ещё и переключатель на странице, поэтому строка @custom-variant dark (&:where(.dark, .dark *)); в style.css переопределяет вариант: теперь dark: действует, когда у <html> есть класс dark. Скрипт в <head> ставит этот класс до отрисовки — по сохранённому выбору или, если выбора нет, по системной теме. Так страница не мигает светлой темой перед тёмной. Кнопка переключает класс и запоминает выбор:

src/main.js
import "./style.css";

const toggle = document.querySelector("#theme-toggle");
toggle.setAttribute(
  "aria-pressed",
  String(document.documentElement.classList.contains("dark")),
);

toggle.addEventListener("click", () => {
  const isDark = document.documentElement.classList.toggle("dark");
  localStorage.theme = isDark ? "dark" : "light";
  toggle.setAttribute("aria-pressed", String(isDark));
});
Переключатель темы: класс на html, выбор в localStorage, состояние в aria-pressed

Проверено в headless Edge: при системной тёмной теме и пустом localStorage у <html> сразу есть класс dark; клик по кнопке в светлой теме меняет фон страницы со slate-50 на slate-950, записывает localStorage.theme = "dark" и ставит aria-pressed="true", а после перезагрузки тёмная тема сохраняется.

Когда выносить в компонент, а не в @apply

Классы кнопок «Start free trial» и «Contact sales» во многом совпадают. Документация Tailwind называет лучшим решением для повторяющихся стилей компонент: React- или Vue-компонент, шаблон-partial в Blade или Twig, цикл в разметке. Стили и структура тогда лежат в одном месте, и правка делается один раз.

Свой CSS-класс уместен, когда речь об одном простом элементе и компонент ощущается избыточным, или когда нужно оформить чужую разметку — сторонний виджет, HTML из CMS. Такие классы кладут в слой components, а @apply позволяет собрать их из тех же утилит и токенов:

src/style.css
@layer components {
  .btn {
    @apply rounded-lg px-4 py-2.5 text-center font-semibold focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-600;
  }
}
Фрагмент: класс-компонент из утилит; варианты вроде focus-visible работают и внутри @apply
index.html
<a href="#signup" class="btn mt-auto rounded-none bg-brand-600 text-white hover:bg-brand-700">
  Start free trial
</a>
Фрагмент: утилита rounded-none переопределяет скругление из .btn

Мы проверили это в браузере: у ссылки остались отступы 10px 16px и жирность 600 из .btn, а скругление стало 0px — утилита rounded-none победила. Причина — порядок слоёв: Tailwind объявляет theme, base, components, utilities, и утилиты всегда сильнее компонентных классов, независимо от порядка классов в атрибуте.

Повторяется блок из нескольких элементов (карточка, строка таблицы)

Решение
Компонент или partial шаблона

Повторяется в списке

Решение
Цикл в разметке — классы пишутся один раз

Один простой элемент в шаблонизаторе без компонентов

Решение
Класс в @layer components, можно через @apply

Разметку генерирует чужой код (виджет, Markdown из CMS)

Решение
Свой CSS с var(--color-…) или @apply

Два класса спорят за одно свойство (grid и flex)

Решение
Оставить один, выбирать его условием в коде

Проверка и упражнения

Terminal
$ npm run build

vite v8.3.4 building client environment for production...
transforming...
✓ 5 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                  4.74 kB │ gzip: 1.37 kB
dist/assets/index-0MkxrnFc.css  14.18 kB │ gzip: 3.68 kB
dist/assets/index-DApDsg-q.js    0.97 kB │ gzip: 0.51 kB

✓ built in 91ms
Реальный вывод сборки: CSS только из использованных классов
  • Мобильная версия написана без префиксов, а sm:/md:/lg: только добавляют изменения
  • Ни на одной ширине нет горизонтальной прокрутки
  • У всех интерактивных элементов виден фокус с клавиатуры (focus-visible:)
  • Hover — улучшение: без наведения всё по-прежнему понятно и доступно
  • Цвета бренда и шрифты лежат в @theme, а не повторяются произвольными значениями вроде bg-[#2067da]
  • У каждого светлого цвета есть пара в тёмной теме, переключатель запоминает выбор
  • Имена классов в коде полные, без сборки из кусочков
  • Повторяющиеся блоки вынесены в компоненты или циклы
Как проверено6 · пройдено1 · не запускалосьсверено 11 октября 2026 г.
  • запущено, работает

    Проект Vite: vite.config.js, src/style.css, src/main.js, index.html

    Vite 8.3.4 + tailwindcss 4.3.3 + @tailwindcss/vite 4.3.3 (npm view), vite build OK (CSS 14.18 kB / gzip 3.68 kB, вывод в статье реальный); код статьи считан генератором из файлов проекта; структура совпадает с шаблоном create-vite 9.2.1 --template vanilla (проверено отдельным прогоном)

  • запущено, работает

    Сгенерированный CSS

    vite build --minify false: переменные @theme в @layer theme, md:grid-cols-2 в @media, hover: внутри @media (hover: hover), dark: через :where(.dark, .dark *); bg-red-500 и палитра red отсутствуют; фрагменты в статье взяты из файла сборки

  • запущено, работает

    Адаптивность, состояния и тёмная тема в браузере

    playwright-core + headless Edge на vite preview: колонки 1/2/3 при 375/800/1280px, без горизонтальной прокрутки; системная тёмная тема → html.dark; клик переключателя: фон slate-50 → slate-950, localStorage.theme=dark, aria-pressed=true, сохраняется после перезагрузки; Tab → видимая рамка 2px, disabled: opacity 0.6 и not-allowed; group-hover перекрашивает заголовок; скриншоты осмотрены

  • запущено, работает

    @layer components + @apply (.btn) и переопределение rounded-none

    отдельная копия проекта: сборка OK, в браузере у ссылки padding 10px 16px и font-weight 600 из .btn, border-radius 0px от утилиты

  • запущено, работает

    Та же тема в Next.js 16.4

    style.css урока подставлен в app/globals.css проекта create-next-app 16.4 (Tailwind через @tailwindcss/turbopack), временная страница: next build OK, в CSS есть bg-brand-600, dark:bg-slate-900:where(.dark,.dark *), hover в @media (hover:hover), md:px-6; oklch продублированы hex; изменения откатены

  • запущено, работает

    Упражнения: акцентный цвет, семантические токены

    accent: сборка, в CSS --color-accent-500 и .bg-accent-500; токены (код решения = файл проекта tw-tokens): сборка, фон карточек rgb(255,255,255) в светлой и oklch(0.208 0.042 265.755) в тёмной теме

  • не запускалось

    Упражнение «Карточка услуги»

    самостоятельная задача без готового кода в статье

«Запущено» — код выполнен во временном проекте или контейнере, вывод в статье взят из прогона. «Частично» — проверено с заглушками вместо внешних сервисов. «Не запускалось» — нужны устройство, аккаунт или ключ; шаги сверены с официальной документацией. Файлы проверочного проекта и логи запусков сохранены в архиве InterLAB.

Расскажите о задаче — мы изучим запрос и свяжемся с вами

Есть задача?
Обсудим и оценим — бесплатно.

Расскажите о продукте или проблеме. Предложим архитектуру, срок и стоимость первой версии после изучения задачи.

  • Оценка объёма и рисков до старта
  • NDA — по вашему или нашему шаблону
  • Старт работ в течение недели

Не присылайте через форму пароли, ключи доступа и исходный код — безопасную передачу доступа обсудим отдельно.

Нажимая кнопку, вы соглашаетесь с обработкой персональных данных.