Урок 12. Решения

📁 Раздел: Состояния и темы ⏱️ Время изучения: ~50 мин 🎯 Сложность: Средняя

⚡ Кратко

Три решения: строка с появляющейся кнопкой, чекбокс-карточка и поле с доступной ошибкой.

Решение задания 1

  • Договор-2026.pdf

  • Смета.xlsx

<ul class="max-w-md divide-y divide-slate-100 rounded-lg border border-slate-200">
  <li class="group flex items-center gap-3 px-4 py-3 transition-colors hover:bg-slate-50">
    <div class="size-8 shrink-0 rounded bg-slate-200"></div>
    <p class="min-w-0 flex-1 truncate text-sm text-slate-800">Договор-2026.pdf</p>
    <button class="rounded-md px-2 py-1 text-xs text-rose-600 opacity-0 transition-opacity
                   group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-rose-500">
      Удалить
    </button>
  </li>
  <li class="group flex items-center gap-3 px-4 py-3 transition-colors hover:bg-slate-50">
    <div class="size-8 shrink-0 rounded bg-slate-200"></div>
    <p class="min-w-0 flex-1 truncate text-sm text-slate-800">Смета.xlsx</p>
    <button class="rounded-md px-2 py-1 text-xs text-rose-600 opacity-0 transition-opacity
                   group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-rose-500">
      Удалить
    </button>
  </li>
</ul>

Почему так: opacity-0 вместо hidden — потому что скрытый через display: none элемент недоступен клавиатуре. Пара group-hover:opacity-100 и focus-visible:opacity-100 закрывает оба способа взаимодействия.

Решение задания 2

<label class="relative block max-w-xs cursor-pointer rounded-xl border border-slate-200 bg-white p-4 transition-colors
              has-checked:border-emerald-500 has-checked:bg-emerald-50">
  <input type="checkbox" class="peer sr-only" checked>
  <span class="absolute top-3 right-3 hidden size-5 items-center justify-center rounded-full bg-emerald-500 text-xs text-white peer-checked:flex">✓</span>
  <p class="text-sm font-semibold text-slate-900">Подписка на отчёты</p>
  <p class="mt-1 text-xs text-slate-600">Раз в неделю на почту</p>
</label>

Почему так: два механизма работают вместе: has-checked: красит саму карточку, а peer-checked: показывает галочку. Оба читают состояние одного и того же скрытого чекбокса.

Решение задания 3

✉

Введите адрес целиком, например name@example.com

<div class="max-w-sm">
  <label for="err-mail" class="mb-1 block text-sm font-medium text-slate-700">Почта</label>
  <div class="group flex items-center gap-2 rounded-md border border-slate-300 px-3 py-2
              has-aria-invalid:border-rose-500 has-aria-invalid:bg-rose-50">
    <span class="text-slate-400 group-has-aria-invalid:text-rose-500">✉</span>
    <input id="err-mail" aria-invalid="true" aria-describedby="err-mail-hint" value="petrov@"
           class="w-full text-sm text-slate-900 focus:outline-none">
  </div>
  <p id="err-mail-hint" class="mt-1 text-xs text-rose-600">Введите адрес целиком, например name@example.com</p>
</div>

Почему так: aria-invalid — это не «класс для красноты», а сообщение для вспомогательных технологий. Атрибут aria-describedby связывает поле с текстом ошибки: скринридер прочитает подсказку вслух. Цвет — лишь дублирующий сигнал.