Новичок
- Статус
- Оффлайн
- Регистрация
- 2 Окт 2026
- Сообщения
- 1
- Реакции
- 0
Недавно столкнулся с классической, на первый взгляд, задачей: вывести на внутреннем портале огромную таблицу данных (около 15 000 строк) с динамической фильтрацией. Казалось бы, 2024 год на дворе, но браузеры всё так же «выпадают в осадок», если пытаться скормить им такой объём в лоб через стандартный table. Делюсь опытом, как разрулил это на стыке PHP и CSS без привлечения тяжелых JS-фреймворков.
Однако, даже с гридами 15 тысяч DOM-узлов — это перебор. Память течет, скролл лагает. Решение пришло со стороны виртуализации, но реализованной максимально просто. Вместо того чтобы выплевывать весь массив из PHP, я внедрил постраничную подгрузку через Intersection Observer API, но с одной хитростью в CSS.
Проблема семантики и производительности
Первая ошибка, которую совершают многие — использование display: table для сложных макетов. Когда у вас тысячи ячеек, браузер тратит колоссальное время на расчет геометрии каждой колонки, ориентируясь на содержимое. Я перешел на CSS Grid. Это дает контроль над отрисовкой: можно жестко задать grid-template-columns, и браузеру не придется пересчитывать ширину всей таблицы при загрузке каждой новой строки.Однако, даже с гридами 15 тысяч DOM-узлов — это перебор. Память течет, скролл лагает. Решение пришло со стороны виртуализации, но реализованной максимально просто. Вместо того чтобы выплевывать весь массив из PHP, я внедрил постраничную подгрузку через Intersection Observer API, но с одной хитростью в CSS.
CSS-хак для стабильного скролла
Чтобы полоса прокрутки не прыгала при подгрузке новых данных, я использовал свойство contain-intrinsic-size вместе с content-visibility: auto. Это позволяет браузеру пропускать рендеринг элементов, которые находятся за пределами вьюпорта, при этом сохраняя их «виртуальное» место в разметке. Контейнер таблицы не схлопывается, и пользователь не теряет фокус.Оптимизация на стороне бэкенда (PHP)
На стороне PHP основной затык был в потреблении памяти при формировании JSON-ответа. Стандартный PDO::fetchAll() на таких объемах — это гарантированный Out of Memory. Переписал логику на использование генераторов (yield). Это позволило стримить данные из базы порциями, не забивая RAM сервера. Кстати, если вам интересно, как эффективно работать с памятью в высоконагруженных скриптах, советую глянуть
Гости не видят ссылку
Войти или зарегистрироваться
архитектурных паттернов для обработки очередей, там много пересекающихся моментов по части ресурсов.Практические выводы
- Забудьте про <table> для данных свыше 2000 строк. Только div с display: grid. Это в разы ускоряет начальный рендеринг (First Contentful Paint).
- Используйте content-visibility. Это реально «серебряная пуля» для длинных списков в современных браузерах (Chrome 85+, Edge).
- Никаких тяжелых вычислений в цикле вывода PHP. Все преобразования дат, форматирование валют и прочее должны быть сделаны на уровне SQL-запроса или кэшированы.
