Печатает... Список заметок

Создание простой карточки товара для интернет-магазина

Универсальная, адаптивная карточка товара — сложный блок, который может содержать много элементов в разных состояниях. Нужно продумывать всё многообразие сочетаний элементов и их состояний

Я думаю подготовить лонгрид про построение «взрослой» карточки, но это будет сильно позже. Сейчас хочу кратко описать примитивную конструкцию и на её примере обозначить вектор мысли относительно проектирования компонента

Задача

Сверстать карточку товара, которая будет содержать в себе:

  • изображение;
  • название товара;
  • краткое описание;
  • цену;
  • кнопку добавления в корзину.

Карточка должна уметь трансформироваться из ячейки сетки в строковый блок без изменения структуры, сменой класса.

Общая структура

Карточка — .product

Содержимое делим на два больших контейнера: __ main и __aside. Первый представляет собой большой элемент-ссылку, ведущую на страницу товара. Второй содержит вспомогательные интерактивные элементы. В примере такой один, кнопка «В корзину», на практике может быть больше, например кнопки добавления в избранное или сохранения в закладках.

Внутри контейнера __main размещаем два дополнительных ящика: один для фотографии товара, второй для названия и описания.

Схематично структура выглядит так:

В разметке эдак:

<div class="product product_grid">
    <a href="/" class="product__main">
        <div class="product__outer-image-container"></div>
        <div class="product__info-container"></div>
    </a>
    <div class="product__aside"></div>
</div>

Основной контейнер

.product__main — основной контейнер, ссылка, содержащая в себе фотографию, название товара и его краткое описание.

Я считаю плохим решением оборачивать фотографию и заголовок в отдельные ссылки. В таком случае площадь кликабельного поля снижается, между линками появляются провалы, переход на страницу товара требует внимательного прицеливания.

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

Изображение

Контейнер удовлетворяет следующим условиям:

  • изображению позволено иметь любые пропорции (минус головная боль контент-менеджеру);
  • оно вставляется через тег <img>, без использования background.

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

Контейнер состоит из трёх секций:

<div class="product__outer-image-container">
    <div class="product__medium-image-container">
        <div class="product__internal-image-container">
            <img src="https://nikolaywerner.ru/files/codepen/product.jpg" alt="" class="product__image">
        </div>
    </div>
</div>

Внешней секции прописываем position: relative и, опционально, ширину.

Средней секции указываем ширину в 100%, нулевую высоту и размер нижнего поля в процентах. padding-bottom: 70%; Так мы получим нижнее поле пропорциональное ширине секции.

Внутренней секции назначаем 100% высоту и ширину и абсолютное позиционирование. Также я предпочитаю делать эту секцию флекс-контейнером и  указывать вертикальное и горизонтальное выравнивание внутри по центру.

Последний элемент — само изображение. Ему важно назначить максимальную ширину и высоту в 100%. Не width и height, а max-width и max-height. Это позволит фотографии, в зависимости от ориентации занять внутри максимально возможное пространство. Имэдж портретной ориентации упрётся в «пол» и «потолок» блока, фото пейзажной ориентации упрётся в «стены».

Итого стили выглядят примерно так:

.product__outer-image-container {
        position: relative;
    }
.product__medium-image-container {
        width: 100%;
        height: 0;
        padding: 0 0 70%;
    }
.product__internal-image-container {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        overflow: hidden;
        position: absolute;
        top: 0;
        left: 0;
    }
.product__image {
        max-width: 100%;
        max-height: 100%;
    }

Изменение способов отображения

Способы отображения: .product_grid — сетка, .product_row — строка.

В первом случае элементы просто выстраиваются в колонку и занимают всю ширину .product

Строчная вёрстка чуть сложнее. В ней наша карточка становится флекс-контейнером. Аналогичным образом изменяется свойство display и у .product__main. Внутри основного контейнера жёстко задана ширина внешней обёртки изображения, а flex: 1; для блока с заголовком и описанием указывает занять оставшееся свободное пространство.

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

Отступы

Отступы между элементами предпочитаю задавать через соседние селекторы.

Допустим, между изображением и контейнером для описания требуется зазор в 12 пикселей. Можно задать верхний отступ для описания, но если вдруг у нас будет карточка без фотки (мало ли), сверху появится паразитный маргин. Если задать нижний отступ для изображения, скорее всего ничего страшного не случится (без названия карточек обычно не бывает), но я всё же предпочитаю соседние селекторы. С их помощью можно точно сказать: «описание, стоящее ровно после фотки — получай верхний маргин».

.product__outer-image-container + .product__info-container {
        margin: 12px 0 0;
    }

И под конец статьи повторю: не стоит слепо копировать данную инструкцию. Описанная карточка не учитывает много деталей, которые могут всплыть в том или ином контексте применения. Речь о некоторых базовых принципах, описанных на примере примитивного варианта компонента. 

Посмотреть пример на кодпене.