← HTML & CSS/Адаптивные макеты#48 из 383← ПредыдущийСледующий →+20 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

Адаптивные макеты

Создание макетов, которые работают на экранах от 320px до 2560px — главная задача верстальщика. В этом уроке разберём готовые паттерны: адаптивные сетки, карточки, сайдбар-макеты, Holy Grail и адаптивные таблицы. Все решения построены на CSS Grid и Flexbox — без хаков и JavaScript.

Адаптивная сетка карточек с auto-fit

Самый мощный паттерн адаптивности — сетка, которая сама решает, сколько колонок помещается.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

Как это работает:

  • auto-fit — «впихни столько колонок, сколько влезает»
  • minmax(280px, 1fr) — каждая колонка не уже 280px, но может растягиваться
  • На экране 320px → 1 колонка
  • На экране 640px → 2 колонки
  • На экране 960px → 3 колонки
  • Ни одного медиа-запроса!
  • auto-fit vs auto-fill

    /* auto-fit: оставшееся пространство распределяется между элементами */
    .grid-fit {
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    }
    
    /* auto-fill: создаёт пустые колонки, элементы не растягиваются */
    .grid-fill {
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    }

    Если элементов мало:

  • auto-fit — растянет карточки на всю ширину
  • auto-fill — оставит пустое место справа
  • Для карточек товаров обычно нужен auto-fill (карточки одного размера), для контентных блоков — auto-fit.

    Адаптивная карточка

    .card {
      display: flex;
      flex-direction: column;
      background: white;
      border-radius: 12px;
      overflow: hidden;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
      transition: box-shadow 0.2s;
    }
    
    .card:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
    
    .card img {
      width: 100%;
      aspect-ratio: 16 / 9;
      object-fit: cover;
    }
    
    .card-body {
      padding: 16px;
      flex: 1;                   /* Растягивается — кнопка всегда внизу */
      display: flex;
      flex-direction: column;
    }
    
    .card-body .btn {
      margin-top: auto;          /* Прижимается к низу карточки */
    }

    Ключевые приёмы:

  • aspect-ratio — одинаковые пропорции у всех картинок
  • flex: 1 + margin-top: auto — кнопка всегда прижата к низу
  • overflow: hidden — картинка не вылезает за скругления
  • Макет с сайдбаром

    Вариант 1: Grid с минимальной шириной

    .layout {
      display: grid;
      grid-template-columns: minmax(200px, 300px) 1fr;
      gap: 24px;
    }
    
    @media (max-width: 768px) {
      .layout {
        grid-template-columns: 1fr;
      }
    }

    Вариант 2: без медиа-запросов (трюк с auto-fit)

    .layout {
      display: flex;
      flex-wrap: wrap;
      gap: 24px;
    }
    
    .sidebar {
      flex: 1 1 250px;   /* Растёт от 250px, но может быть шире */
      max-width: 300px;
    }
    
    .main {
      flex: 1 1 600px;   /* Растёт от 600px — если не влезает, переносится */
    }
    
    @media (max-width: 768px) {
      .sidebar {
        max-width: 100%;
      }
    }

    Когда контейнер уже, чем 250 + 600 = 850px, .main переносится на новую строку → становится на 100% ширины.

    Holy Grail Layout

    Классический макет: шапка, подвал, основной контент, левый и правый сайдбар.

    .page {
      display: grid;
      min-height: 100dvh;
      grid-template:
        "header  header  header"  auto
        "left    main    right"   1fr
        "footer  footer  footer"  auto
        / 200px  1fr     200px;
    }
    
    .header  { grid-area: header; }
    .left    { grid-area: left; }
    .main    { grid-area: main; }
    .right   { grid-area: right; }
    .footer  { grid-area: footer; }
    
    @media (max-width: 1024px) {
      .page {
        grid-template:
          "header"  auto
          "main"    1fr
          "left"    auto
          "right"   auto
          "footer"  auto
          / 1fr;
      }
    }

    На мобильном все области выстраиваются в одну колонку, а основной контент идёт первым (до сайдбаров).

    Адаптивная сетка с фиксированной первой карточкой

    Паттерн «featured + grid»: первый элемент занимает всю ширину или две колонки.

    .featured-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 20px;
    }
    
    .featured-grid .featured {
      grid-column: 1 / -1;             /* Вся ширина */
    }
    
    @media (min-width: 768px) {
      .featured-grid .featured {
        grid-column: span 2;           /* Две колонки на планшете+ */
        grid-row: span 2;
      }
    }

    Адаптивные таблицы

    Таблицы — одна из самых сложных задач адаптивности. Вот три стратегии.

    Стратегия 1: горизонтальный скролл

    .table-wrapper {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
    }
    
    table {
      min-width: 600px;   /* Таблица не сжимается, скроллится */
      width: 100%;
      border-collapse: collapse;
    }

    Простейшее решение. Пользователь свайпает таблицу горизонтально.

    Стратегия 2: карточки на мобильном

    @media (max-width: 768px) {
      table, thead, tbody, th, td, tr {
        display: block;
      }
    
      thead {
        display: none;  /* Скрываем заголовки */
      }
    
      tr {
        margin-bottom: 16px;
        border: 1px solid #e2e8f0;
        border-radius: 8px;
        padding: 12px;
      }
    
      td {
        display: flex;
        justify-content: space-between;
        padding: 6px 0;
        border: none;
      }
    
      td::before {
        content: attr(data-label);   /* Подставляем заголовок из data-атрибута */
        font-weight: 600;
        margin-right: 16px;
      }
    }
    <table>
      <thead>
        <tr>
          <th>Имя</th><th>Email</th><th>Роль</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td data-label="Имя">Анна</td>
          <td data-label="Email">anna@mail.ru</td>
          <td data-label="Роль">Админ</td>
        </tr>
      </tbody>
    </table>

    Стратегия 3: скрытие колонок

    .col-secondary {
      display: table-cell;
    }
    
    @media (max-width: 768px) {
      .col-secondary {
        display: none;   /* Менее важные колонки скрываются */
      }
    }

    Адаптивная сетка — полный пример

    .products {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
      gap: clamp(12px, 2vw, 24px);          /* Fluid отступы */
      padding: clamp(16px, 3vw, 48px);
    }
    
    .product-card {
      display: flex;
      flex-direction: column;
      border-radius: 12px;
      overflow: hidden;
      background: white;
      border: 1px solid #e2e8f0;
    }
    
    .product-card img {
      width: 100%;
      aspect-ratio: 4 / 3;
      object-fit: cover;
    }
    
    .product-card .info {
      padding: clamp(12px, 2vw, 20px);
      flex: 1;
      display: flex;
      flex-direction: column;
    }
    
    .product-card .price {
      font-size: clamp(1.125rem, 1rem + 0.5vw, 1.5rem);
      font-weight: 700;
      margin-top: auto;
    }

    Эта сетка:

  • Автоматически меняет количество колонок
  • Использует fluid-отступы
  • Карточки одинаковой высоты (grid выравнивает строки)
  • Кнопка/цена всегда внизу благодаря flex
  • Итоговая шпаргалка

    | Задача | Решение |

    |--------|---------|

    | Адаптивная сетка карточек | repeat(auto-fit, minmax(280px, 1fr)) |

    | Сайдбар + контент | Grid + 1fr или Flex + flex-wrap |

    | Holy Grail | grid-template-areas |

    | Кнопка внизу карточки | flex: 1 + margin-top: auto |

    | Адаптивная таблица | Горизонтальный скролл или карточки |

    | Fluid отступы | clamp() в gap/padding |

    Примеры

    Адаптивная сетка карточек с auto-fit и сайдбар-макет

    <!DOCTYPE html>
    <html lang="ru">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <style>
        * { margin: 0; box-sizing: border-box; }
        body {
          font-family: system-ui, sans-serif;
          background: #f1f5f9;
          color: #1e293b;
        }
    
        /* Макет с сайдбаром */
        .page {
          display: grid;
          grid-template-columns: 1fr;
          gap: 24px;
          max-width: 1280px;
          margin: 0 auto;
          padding: clamp(16px, 3vw, 48px);
        }
    
        @media (min-width: 960px) {
          .page {
            grid-template-columns: 240px 1fr;
          }
        }
    
        .sidebar {
          background: white;
          border-radius: 12px;
          padding: 20px;
          border: 1px solid #e2e8f0;
          align-self: start;
        }
    
        .sidebar h3 {
          font-size: 0.875rem;
          text-transform: uppercase;
          letter-spacing: 0.05em;
          color: #64748b;
          margin-bottom: 12px;
        }
    
        .sidebar ul {
          list-style: none;
          padding: 0;
          margin: 0;
        }
    
        .sidebar li {
          padding: 8px 0;
          border-bottom: 1px solid #f1f5f9;
        }
    
        /* Адаптивная сетка карточек */
        .cards {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
          gap: clamp(12px, 2vw, 20px);
        }
    
        .card {
          background: white;
          border-radius: 12px;
          overflow: hidden;
          border: 1px solid #e2e8f0;
          display: flex;
          flex-direction: column;
          transition: box-shadow 0.2s;
        }
    
        .card:hover {
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
        }
    
        .card-img {
          width: 100%;
          aspect-ratio: 16 / 9;
          object-fit: cover;
          background: linear-gradient(135deg, #dbeafe, #c7d2fe);
        }
    
        .card-body {
          padding: 16px;
          flex: 1;
          display: flex;
          flex-direction: column;
        }
    
        .card-body h3 {
          font-size: 1.1rem;
          margin-bottom: 8px;
        }
    
        .card-body p {
          color: #64748b;
          font-size: 0.9rem;
          margin-bottom: 16px;
        }
    
        .card-body .btn {
          margin-top: auto;
          display: inline-block;
          padding: 8px 16px;
          background: #3b82f6;
          color: white;
          border: none;
          border-radius: 6px;
          font-size: 0.875rem;
          cursor: pointer;
          text-align: center;
        }
      </style>
    </head>
    <body>
      <div class="page">
        <aside class="sidebar">
          <h3>Категории</h3>
          <ul>
            <li>Все товары</li>
            <li>Электроника</li>
            <li>Одежда</li>
            <li>Книги</li>
          </ul>
        </aside>
    
        <main class="cards">
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 1</h3>
              <p>Описание товара с основными характеристиками</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 2</h3>
              <p>Ещё один товар с кратким описанием</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 3</h3>
              <p>Третий товар каталога</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 4</h3>
              <p>Описание четвёртого товара</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 5</h3>
              <p>Пятый товар в сетке</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 6</h3>
              <p>Шестой товар каталога</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
        </main>
      </div>
    </body>
    </html>

    Адаптивные макеты

    Создание макетов, которые работают на экранах от 320px до 2560px — главная задача верстальщика. В этом уроке разберём готовые паттерны: адаптивные сетки, карточки, сайдбар-макеты, Holy Grail и адаптивные таблицы. Все решения построены на CSS Grid и Flexbox — без хаков и JavaScript.

    Адаптивная сетка карточек с auto-fit

    Самый мощный паттерн адаптивности — сетка, которая сама решает, сколько колонок помещается.

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
      gap: 24px;
    }

    Как это работает:

  • auto-fit — «впихни столько колонок, сколько влезает»
  • minmax(280px, 1fr) — каждая колонка не уже 280px, но может растягиваться
  • На экране 320px → 1 колонка
  • На экране 640px → 2 колонки
  • На экране 960px → 3 колонки
  • Ни одного медиа-запроса!
  • auto-fit vs auto-fill

    /* auto-fit: оставшееся пространство распределяется между элементами */
    .grid-fit {
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    }
    
    /* auto-fill: создаёт пустые колонки, элементы не растягиваются */
    .grid-fill {
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    }

    Если элементов мало:

  • auto-fit — растянет карточки на всю ширину
  • auto-fill — оставит пустое место справа
  • Для карточек товаров обычно нужен auto-fill (карточки одного размера), для контентных блоков — auto-fit.

    Адаптивная карточка

    .card {
      display: flex;
      flex-direction: column;
      background: white;
      border-radius: 12px;
      overflow: hidden;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
      transition: box-shadow 0.2s;
    }
    
    .card:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
    
    .card img {
      width: 100%;
      aspect-ratio: 16 / 9;
      object-fit: cover;
    }
    
    .card-body {
      padding: 16px;
      flex: 1;                   /* Растягивается — кнопка всегда внизу */
      display: flex;
      flex-direction: column;
    }
    
    .card-body .btn {
      margin-top: auto;          /* Прижимается к низу карточки */
    }

    Ключевые приёмы:

  • aspect-ratio — одинаковые пропорции у всех картинок
  • flex: 1 + margin-top: auto — кнопка всегда прижата к низу
  • overflow: hidden — картинка не вылезает за скругления
  • Макет с сайдбаром

    Вариант 1: Grid с минимальной шириной

    .layout {
      display: grid;
      grid-template-columns: minmax(200px, 300px) 1fr;
      gap: 24px;
    }
    
    @media (max-width: 768px) {
      .layout {
        grid-template-columns: 1fr;
      }
    }

    Вариант 2: без медиа-запросов (трюк с auto-fit)

    .layout {
      display: flex;
      flex-wrap: wrap;
      gap: 24px;
    }
    
    .sidebar {
      flex: 1 1 250px;   /* Растёт от 250px, но может быть шире */
      max-width: 300px;
    }
    
    .main {
      flex: 1 1 600px;   /* Растёт от 600px — если не влезает, переносится */
    }
    
    @media (max-width: 768px) {
      .sidebar {
        max-width: 100%;
      }
    }

    Когда контейнер уже, чем 250 + 600 = 850px, .main переносится на новую строку → становится на 100% ширины.

    Holy Grail Layout

    Классический макет: шапка, подвал, основной контент, левый и правый сайдбар.

    .page {
      display: grid;
      min-height: 100dvh;
      grid-template:
        "header  header  header"  auto
        "left    main    right"   1fr
        "footer  footer  footer"  auto
        / 200px  1fr     200px;
    }
    
    .header  { grid-area: header; }
    .left    { grid-area: left; }
    .main    { grid-area: main; }
    .right   { grid-area: right; }
    .footer  { grid-area: footer; }
    
    @media (max-width: 1024px) {
      .page {
        grid-template:
          "header"  auto
          "main"    1fr
          "left"    auto
          "right"   auto
          "footer"  auto
          / 1fr;
      }
    }

    На мобильном все области выстраиваются в одну колонку, а основной контент идёт первым (до сайдбаров).

    Адаптивная сетка с фиксированной первой карточкой

    Паттерн «featured + grid»: первый элемент занимает всю ширину или две колонки.

    .featured-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 20px;
    }
    
    .featured-grid .featured {
      grid-column: 1 / -1;             /* Вся ширина */
    }
    
    @media (min-width: 768px) {
      .featured-grid .featured {
        grid-column: span 2;           /* Две колонки на планшете+ */
        grid-row: span 2;
      }
    }

    Адаптивные таблицы

    Таблицы — одна из самых сложных задач адаптивности. Вот три стратегии.

    Стратегия 1: горизонтальный скролл

    .table-wrapper {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
    }
    
    table {
      min-width: 600px;   /* Таблица не сжимается, скроллится */
      width: 100%;
      border-collapse: collapse;
    }

    Простейшее решение. Пользователь свайпает таблицу горизонтально.

    Стратегия 2: карточки на мобильном

    @media (max-width: 768px) {
      table, thead, tbody, th, td, tr {
        display: block;
      }
    
      thead {
        display: none;  /* Скрываем заголовки */
      }
    
      tr {
        margin-bottom: 16px;
        border: 1px solid #e2e8f0;
        border-radius: 8px;
        padding: 12px;
      }
    
      td {
        display: flex;
        justify-content: space-between;
        padding: 6px 0;
        border: none;
      }
    
      td::before {
        content: attr(data-label);   /* Подставляем заголовок из data-атрибута */
        font-weight: 600;
        margin-right: 16px;
      }
    }
    <table>
      <thead>
        <tr>
          <th>Имя</th><th>Email</th><th>Роль</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td data-label="Имя">Анна</td>
          <td data-label="Email">anna@mail.ru</td>
          <td data-label="Роль">Админ</td>
        </tr>
      </tbody>
    </table>

    Стратегия 3: скрытие колонок

    .col-secondary {
      display: table-cell;
    }
    
    @media (max-width: 768px) {
      .col-secondary {
        display: none;   /* Менее важные колонки скрываются */
      }
    }

    Адаптивная сетка — полный пример

    .products {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
      gap: clamp(12px, 2vw, 24px);          /* Fluid отступы */
      padding: clamp(16px, 3vw, 48px);
    }
    
    .product-card {
      display: flex;
      flex-direction: column;
      border-radius: 12px;
      overflow: hidden;
      background: white;
      border: 1px solid #e2e8f0;
    }
    
    .product-card img {
      width: 100%;
      aspect-ratio: 4 / 3;
      object-fit: cover;
    }
    
    .product-card .info {
      padding: clamp(12px, 2vw, 20px);
      flex: 1;
      display: flex;
      flex-direction: column;
    }
    
    .product-card .price {
      font-size: clamp(1.125rem, 1rem + 0.5vw, 1.5rem);
      font-weight: 700;
      margin-top: auto;
    }

    Эта сетка:

  • Автоматически меняет количество колонок
  • Использует fluid-отступы
  • Карточки одинаковой высоты (grid выравнивает строки)
  • Кнопка/цена всегда внизу благодаря flex
  • Итоговая шпаргалка

    | Задача | Решение |

    |--------|---------|

    | Адаптивная сетка карточек | repeat(auto-fit, minmax(280px, 1fr)) |

    | Сайдбар + контент | Grid + 1fr или Flex + flex-wrap |

    | Holy Grail | grid-template-areas |

    | Кнопка внизу карточки | flex: 1 + margin-top: auto |

    | Адаптивная таблица | Горизонтальный скролл или карточки |

    | Fluid отступы | clamp() в gap/padding |

    Примеры

    Адаптивная сетка карточек с auto-fit и сайдбар-макет

    <!DOCTYPE html>
    <html lang="ru">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <style>
        * { margin: 0; box-sizing: border-box; }
        body {
          font-family: system-ui, sans-serif;
          background: #f1f5f9;
          color: #1e293b;
        }
    
        /* Макет с сайдбаром */
        .page {
          display: grid;
          grid-template-columns: 1fr;
          gap: 24px;
          max-width: 1280px;
          margin: 0 auto;
          padding: clamp(16px, 3vw, 48px);
        }
    
        @media (min-width: 960px) {
          .page {
            grid-template-columns: 240px 1fr;
          }
        }
    
        .sidebar {
          background: white;
          border-radius: 12px;
          padding: 20px;
          border: 1px solid #e2e8f0;
          align-self: start;
        }
    
        .sidebar h3 {
          font-size: 0.875rem;
          text-transform: uppercase;
          letter-spacing: 0.05em;
          color: #64748b;
          margin-bottom: 12px;
        }
    
        .sidebar ul {
          list-style: none;
          padding: 0;
          margin: 0;
        }
    
        .sidebar li {
          padding: 8px 0;
          border-bottom: 1px solid #f1f5f9;
        }
    
        /* Адаптивная сетка карточек */
        .cards {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
          gap: clamp(12px, 2vw, 20px);
        }
    
        .card {
          background: white;
          border-radius: 12px;
          overflow: hidden;
          border: 1px solid #e2e8f0;
          display: flex;
          flex-direction: column;
          transition: box-shadow 0.2s;
        }
    
        .card:hover {
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
        }
    
        .card-img {
          width: 100%;
          aspect-ratio: 16 / 9;
          object-fit: cover;
          background: linear-gradient(135deg, #dbeafe, #c7d2fe);
        }
    
        .card-body {
          padding: 16px;
          flex: 1;
          display: flex;
          flex-direction: column;
        }
    
        .card-body h3 {
          font-size: 1.1rem;
          margin-bottom: 8px;
        }
    
        .card-body p {
          color: #64748b;
          font-size: 0.9rem;
          margin-bottom: 16px;
        }
    
        .card-body .btn {
          margin-top: auto;
          display: inline-block;
          padding: 8px 16px;
          background: #3b82f6;
          color: white;
          border: none;
          border-radius: 6px;
          font-size: 0.875rem;
          cursor: pointer;
          text-align: center;
        }
      </style>
    </head>
    <body>
      <div class="page">
        <aside class="sidebar">
          <h3>Категории</h3>
          <ul>
            <li>Все товары</li>
            <li>Электроника</li>
            <li>Одежда</li>
            <li>Книги</li>
          </ul>
        </aside>
    
        <main class="cards">
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 1</h3>
              <p>Описание товара с основными характеристиками</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 2</h3>
              <p>Ещё один товар с кратким описанием</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 3</h3>
              <p>Третий товар каталога</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 4</h3>
              <p>Описание четвёртого товара</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 5</h3>
              <p>Пятый товар в сетке</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
          <div class="card">
            <div class="card-img"></div>
            <div class="card-body">
              <h3>Товар 6</h3>
              <p>Шестой товар каталога</p>
              <button class="btn">Подробнее</button>
            </div>
          </div>
        </main>
      </div>
    </body>
    </html>

    Задание

    Создай адаптивную сетку карточек, которая автоматически подстраивается под ширину экрана без медиа-запросов. Каждая карточка должна быть не уже 260px и растягиваться равномерно. Используй `auto-fit` и `minmax()`. Отступы между карточками должны быть fluid (от 12px до 24px).

    Подсказка

    Для сетки: `display: grid`, `repeat(auto-fit, minmax(260px, 1fr))`, `gap: clamp(12px, 2vw, 24px)`. Карточки — `flex-direction: column`. Для картинки `aspect-ratio: 16 / 9`. Для body карточки `flex: 1`, а для цены `margin-top: auto` чтобы прижать её к низу.

    Загружаем среду выполнения...
    Загружаем AI-помощника...