После того как мы кратко познакомились с htmx и всё таки решили пойти в крестовый поход против javascript, vite, react, ангуляра и здравого смысла, пора задуматься какие же задачи мы можем решить с помощью htmx а какие - нет.

Htmx решает одну задачу: обновляет определенную часть интерфейса куском HTML который вернул сервер. Можно настраивать когда обновлять, что именно менять и как это встраивать в DOM, но суть именно такая. Сам по себе htmx никак не отвечает за стили и не диктует, как оформлять интерфейс. Этот вопрос я предлагаю закрывать через… daisyUI!

daisyUI - слой поверх tailwind который даёт готовые классы-компоненты. Честно, уважаемые читатели, я пробовал довольно много решений которые должны “просто работать”:

  1. Вайбкодить весь сырой css без какой-либо библиотеки - оказалось что тут не всё так просто и задачки занимали ОЧЕНЬ много времени даже простые даже если как-то структурировать css. И много токенов уходило на “поддержку” этих стилей
  2. Вайбкодить весь сырой css с помощью “очистителей” то есть чтото типа a-more-modern-css-reset - разницы с первым пунктом особо не заметил.
  3. CSS first библиотеки а-ля “picocss”, решения в которых весь css написан за тебя то есть твой </button> выглядит уже совсем не как дефолтный. У LLMок, по моему опыту, начинаются трудности поскольку бОльшая часть css находится вне проекта и, соответственно, вне контекста.
  4. Tailwind CDN - честно, я практически переставал понимать десятки классов которые клод пихал в атрибуты… это тоже становилось довольно тяжело

Напомню что я преследовал оч конкретную цель - вайбкодинг фронта для:

  • админок
  • внутренних панелей
  • MVP

И вот тут я пришёл к daisyUI! Это заранее написанные и сгруппированные tailwind классы, на нашей стороне количество стилей ну МИНИМАЛЬНО. На актуальном daisyUI v5 это выглядит примерно так.

Чистый Tailwind:

<div class="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
  <h2 class="text-xl font-semibold text-gray-900">Delete post</h2>
  <p class="mt-2 text-sm text-gray-500">
    This action is irreversible.
  </p>
  <div class="mt-4 flex justify-end gap-2">
    <button class="inline-flex h-10 items-center justify-center rounded-md border border-gray-200 px-4 text-sm font-medium transition hover:bg-gray-100">
      Cancel
    </button>
    <button class="inline-flex h-10 items-center justify-center rounded-md bg-red-600 px-4 text-sm font-medium text-white transition hover:opacity-90">
      Delete
    </button>
  </div>
</div>

daisyUI:

<div class="card bg-base-100 shadow-sm border border-base-300">
  <div class="card-body">
    <h2 class="card-title">Delete post</h2>
    <p>This action is irreversible.</p>
    <div class="card-actions justify-end">
      <button class="btn">Cancel</button>
      <button class="btn btn-error">Delete</button>
    </div>
  </div>
</div>

Для моего юзкейса это важно не потому, что daisyUI какой-то “магический фреймворк красоты”, а потому что он снижает LOC и снижает шансы что LLMка случайно сгенерит свалку из десятков 27 utility-классов половину из которых потом забудет. Сами авторы daisyUI поддерживают актуальную LLM-first документацию где чё использовать!

Честно, даже не хочется расписывать особо технические плюсы минусы. Я не фронтендер и сам эти стили не читаю… Самое главное МНЕ что такое решение просто работает и позволяет не тратить большое кол-во токенов на поддержку этого чудища. Если замечаю что становится подозрительно много стилей промчу что-то вроде “изучи доку daisyUI и подумай не нарушаем ли мы базовые принципы”. Кода стилей становится существенно меньше)0))

Давайте поговорим про ощутимые минусы. Всё вот это “удобно, zero-build, кайф” очень отрезвляется ситуацией в которой кто-то заходит на сайтик и видит какую-то сломанную дичь… Почему? Потому что HTML у нас может приехать нормально с нашего сервера, а вот CSS едет отдельным запросом на внешний CDN.

Типичный zero-build кусок выглядит так:

<link
  href="https://cdn.jsdelivr.net/npm/daisyui@5"
  rel="stylesheet"
  type="text/css"
/>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

То есть страница открывается не одним монолитным “сайт загрузился”, а цепочкой:

  • браузер получает HTML
  • видит ссылку на внешний стайлщит
  • идет в другой домен за CSS
  • ждет пока тот ответит
  • только потом нормально красит интерфейс

И вот этот внешний CDN может тупить, быть временно недоступен. У пользователя может резаться доступ корпоративной сетью, адблоком, провайдером, чем угодно(( Причём с @tailwindcss/browser ситуация сложнее чем с обычным CSS: это не файл со стилями, а JS который сканирует DOM и генерирует CSS прямо браузере — значит даже при доступном CDN стили могут не применится если скрипт упал, не успел отработать до рендера, или ещё чего. Такое происходит(

В этот момент пользователь видит что кнопки расползлись, карточки исчезли, отступы умерли, интерфейс ВСЁ

Чисто технически можно попробовать:

  • Вшивать css себе в свой бэк т.е в свою static директорию.
    • Плюсы: независимость от внешнего CDN, полный контроль над тем что и откуда грузится, LLMке проще работать с локальным файлом
    • Минусы: начинаешь сам отвечать за доставку, кеширование и обновление этих стилей
  • Добавить немного JS который прячет body до загрузки CDN и показывает обратно по onload/onerror, плюс таймаут на случай зависания:
    <style>body { visibility: hidden }</style>
    <script
      src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"
      onload="document.body.style.visibility=''"
      onerror="document.body.style.visibility=''">
    </script>
    <script>setTimeout(() => document.body.style.visibility = '', 3000)</script>
    
    • Плюсы: пользователь не видит сломанный интерфейс, только пустую страницу на момент загрузки
    • Минусы: если CDN совсем умер — 3 секунды белого экрана перед тем как таймаут сработает
  • Реально собирать css с помощью (условно) ноды отдельным процессом
    • Получится уже не чистый zero-build, зато это самый взрослый вариант если проект ВДРУГ вырос

Я ничего этого не использовал потому что нет необходимости эти проблемы решать, я перезагружу страничку итд. Всё работает четко в 90% случаев ну и конкретно для моего юзкейса этого достаточно.

Обязательно попробую какие-то решения выше и отпишу… Вообщем, использовать htmx вместе с daisyUI это некая БАЗА из моего практического опыта