Карточный вид содержимого вэб страниц - один из довольно популярных уже долгое время.

Недавно встала задача таковые web карточки сверстать на CMS генерируемых страничках, где - естественно - количество таковых "карт" непостоянно.

Итак, за дело! И нам нужно:

  • Естественно - адаптивность на различную ширину вьюпорта (видимая область)

  • Начать мыслить с узких смартфоновых широт, где всё складывается в единый столбец

  • Определить минимальную ширину карточки, так же и максимум

  • Думаем об эстетике, понимая, что экраны сегодня могут варьироваться и до "телевизорных"

  • Оглядываемся в сторону браузерной поддержки при реализации адаптивности с эстетичностью современными средствами

Туториалов и статей в сети на эту тему множество, и конечно же, Ваш покорный тоже воспользовался рядом для вдохновения и джамп-старта.

Контекст:

В данном случае - страница настранивается с бэк-енд админки (Processwire CMS) и потенциально может иметь боковую панель (произвольной ширины), может и не иметь. А возможно в дальнейшем и вторую панель кому захочется прикрутить (old school) на широких экранах.

Главная секция (main content) состоит из наших конструкторских чудо-карточек, о ней то речь и пойдёт.


Важно(!) Ввиду вышеупмянутого, говоря о ширине вьюпорта, за основу будем брать не всея веб-документа, а только "контейнер", что непосредственно содержит наши карточки. Чем шире .cardsContainer тем больше карточек встанут в ряд, с установленным лимитом в 4.
В итоге, до 4х карточек должны симпатично выстраиваться в ряд(ы) + последние карточки - если не заполняют весь ряд (хвост) - выстраиваются пропорционально слева направо.


Тут решил воспользоваться javascript с ResizeObserver API

В плане поддержки браузерами, с ним не столь "шоколадно" как скажем, у css flexbox или grid, но - в принципе - на сегодня уже прилично (инфа на caniuse).
В идеале, схожие задачи решаются средствами таблиц стилей, и имея в прицеле "контейнер", можем обратиться к css Container Quieries, который кстати располагает меньшей браузер-поддержкой. Пока этот фактор ещё где-то играет роль, но - благо дело - дальше время работает на нас разрабов..

Да, конечно есть и полифиллы, но, мне кажется, в этом случае js с ResizeObserver API - выглядят несколько "чище".

В общем, ResizeObserver следит за изменениями ширины .cardsContainer.

В плане стилей: Хотя css grid "рулит" для подобных изощрений с контент блоками в несколько рядов, мы задействуем flexbox, пока он ещё служит делу. Вкупе с небольшими js вкраплениями - цель достижима(!)

Итак, html-php разметка на месте, и далее задаём основные/начальные стили. Примечательный момент: data* атрибут [data-col-num='col_x'] задаём динамически в скрипте, сообразно условному количеству столбцов (colsNum) - высчитывая текущую ширину .card контейнера. Там же задаём для него и стиль justifyContent, исходя из той же colsNum переменной.

Код в файле комментирован и понять логику не должно составить труда.
Уверенности ради, скриптовую логику хорошо бы обернуть в window.onload, хотя и скрипты подключаются последними в древе.

Метод throttle - чтобы помочь в сэкономии ресурсов памяти, хотя, можно и заменить методом debounce.

Ещё, быть может, полезно бы включить и полифильчик на наш ResizeObserver - всё таки, классические вэб-сайты с серверным рендерингом вроде как должны отображаться в браузерах почти всех мастей и возрастов. В коммерции в этом знают толк. Но, оставлю таковое на допил любителю :))

P.S.: Ну и конечно же буду рад позитивным комментам, свежим идеям и конструктивной критике :)

Линк на гист.
Всем добра и спасибки!

Комментарии (10)


  1. dom1n1k
    28.12.2023 11:04
    +2

    В подобных статьях первым делом хочется прочитать, чем автора не устроил нативный css grid? Потому как там карточки делаются в несколько строк кода и работают абсолютно плавно без необходимости что-то троттлить. Я вполне допускаю, что у вас были какие-то специфические на то причины. Но пока что вся затея выглядит как типичный молотковый поход, когда все проблемы похожи на гвозди.


    1. NickyX3
      28.12.2023 11:04

      Да тут и flex хватит вполне


      1. uzlander Автор
        28.12.2023 11:04

        Начал было с флексбокса, но итоговая эстетика - не приглянулась, во всяком случае - расстояние между "картами" съезжало и по мне, это бросалось


        1. NickyX3
          28.12.2023 11:04

          Рассояния между елементами во флексе спокойно рулятся через row-gap, column-gap и просто gap


    1. uzlander Автор
      28.12.2023 11:04

      Да, по большому счёту оно так. Просто с гридами, всё равно где-то придётся писать media-queries беря за основу весь viewport и делать калькуляцию карточек в условиях, когда layout страницы настраивается из админки, возможны и боковые колонки, да ито нет определённости в ширине/соразмерности сайдбара(ов). А каждая карточка есть пост/статья, их количество растёт, там же и пагинация и количество статей на страницу задаётся тоже явно, в админке. Css grid - конечно серьёзный инструментарий (возможно нужно побольше практики), но, в моём случае, оптимальным увидел сдвиг внимания на "контейнер" карточек, решил поэкспериментировать с ResizeObserver, не зря ведь придумали ))


      1. dom1n1k
        28.12.2023 11:04
        +2

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


      1. NickyX3
        28.12.2023 11:04

        с ResizeObserver, не зря ведь придумали

        Единственное применение его мы придумали только для Responsive DOM, когда верстка такова, что приходится некоторые элементы таскать по DOM в зависимости от медиа. У нас, к примеру, на сайте есть две отдельных строки навигации в десктопной версии, которые в мобильной версии спрятаны как один список под "бутерброд" (вот тут мы переносим вторую строку к первой и полностью меняем им вид в колонку). Ну или перенос условного меню третьего уровня (привет внутрисервисное меню управления пользовательскими данными) из "третьей" строки на мобилах в правую колонку на десктопе


  1. TsarS
    28.12.2023 11:04

    Это что-то вроде Grid List в Angular Material?


  1. IgorAlentyev
    28.12.2023 11:04
    +1

    Выглядит как изобретение велосипеда который ещё и криво работает, в чем практическая польза такой реализации перед дефолтными гридами или флексами?

    У вас ещё и высота карточек разная, это прям совсем плохо


  1. VlMv
    28.12.2023 11:04

    Хм, выглядит так, как будто решается в одну строчку в CSS. grid: repeat(auto-fill, minmax(a, b) в контейнере. Но я могу и ошибаться, конечно.