Пагінація на сайті: offset, cursor, SEO та prefetch

Пагінація на сайті: offset, cursor, SEO та prefetch

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Пагінація на сайті: offset, cursor, SEO та prefetch
Простий
від 1 дня до 3 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1421
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    984
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1248
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    999

Пагінація на сайті: offset, cursor, SEO та prefetch

Зазначимо: коли каталог перевищує 10 000 товарів або таблиця з логами містить 500 000 рядків, без пагінації не обійтися. У нашій практиці був проєкт з 1,5 млн записів у PostgreSQL — COUNT виконувався 4 секунди навіть після індексації. Користувачі втрачали позицію при натисканні «Назад», а пошукові боти не індексували всі сторінки. Ми реалізували пагінацію для 50+ проєктів, від інтернет-магазинів до аналітичних дашбордів. Особливо критично це для проєктів на Laravel та Next.js, де неправильна пагінація призводить до деградації Core Web Vitals та зниження конверсії. У цій статті розберемо реалізацію пагінації: від вибору алгоритму до SEO-тегів та prefetch.

Вибір типу пагінації для інтернет-магазину

Вибір між offset та cursor залежить від завдання. Offset-пагінація проста в реалізації: LIMIT 20 OFFSET 40. Але на великих наборах даних COUNT — вузьке місце. Ми використовуємо приблизний підрахунок через pg_class.reltuples у PostgreSQL, що прискорює запит у 100 разів. Cursor-пагінація швидша, але не дає URL для кожної сторінки — це проблема для SEO.

Критерій Offset Cursor
Швидкість на 1 млн рядків 2-4 с (COUNT) <10 мс
Стабільність при вставках Зсув Ні
SEO-сумісність Так Ні
Складність реалізації Низька Середня

Чому prefetch важливий для мобільних пристроїв?

Prefetch дозволяє завантажити наступну сторінку до кліку. На мобільних пристроях з повільним з'єднанням це знижує INP на 40%. Ми використовуємо react-query з staleTime: 30_000 та попередньо завантажуємо дані в useEffect. Приклад для Next.js:

useEffect(() => { if (page < lastPage) { queryClient.prefetchQuery({ queryKey: ['products', page + 1], queryFn: () => fetchProducts(page + 1), staleTime: 30_000, }); } }, [page]); 

Порівняння продуктивності: prefetch vs без prefetch

Сценарій LCP INP Час переходу
Без prefetch 2.8 с 200 мс 600 мс
З prefetch 2.1 с 120 мс 100 мс

Коли використовувати cursor-пагінацію?

Cursor-пагінація підходить для стрічок у реальному часі (Twitter, стрічка коментарів) або API з великим обсягом даних, де важливий порядок без зсувів. Ми використовуємо її в проєктах з більш ніж 100 000 записів при частих вставках. Cursor-пагінація вимагає унікального сортувального ключа (наприклад, ID або created_at) і не підтримує довільний перехід на сторінку, але забезпечує стабільність при додаванні нових записів.

Покрокове керівництво з впровадження пагінації на Next.js

  1. Визначте API-контракт: виберіть offset або cursor. Для offset — повертайте current_page, last_page, total, per_page.
  2. Реалізуйте серверну логіку: використовуйте paginate() у Laravel або find().skip().limit() у MongoDB. Кешуйте COUNT через Redis на 5 хвилин.
  3. Розробіть UI-компонент: з еліпсисом, aria-label, адаптивністю.
  4. Синхронізуйте з URL: через useSearchParams у Next.js або history.pushState у ванільному JS.
  5. Додайте prefetch: за допомогою React Query або useEffect з fetch.
  6. Впровадьте SEO-теги: <link rel="prev"/> та <link rel="next"/> для Яндекса. Google не використовує rel prev/next для ранжування (Google Search Central), але для Яндекса вони важливі.
  7. Протестуйте: перевірте LCP < 2.5 с, INP < 200 мс.

Серверна частина: offset проти cursor-пагінації

Для прискорення COUNT ми використовуємо приблизний підрахунок через pg_class.reltuples у PostgreSQL або кешування в Redis на 5 хвилин. Це знижує час запиту з секунд до мілісекунд.

// Laravel — стандартний paginate() public function index(Request $request): JsonResponse { $perPage = min($request->integer('per_page', 20), 100); $products = Product::where('is_active', true) ->orderByDesc('created_at') ->paginate($perPage); return response()->json([ 'data' => ProductResource::collection($products->items()), 'current_page' => $products->currentPage(), 'last_page' => $products->lastPage(), 'per_page' => $products->perPage(), 'total' => $products->total(), 'from' => $products->firstItem(), 'to' => $products->lastItem(), ]); } 

UI-компонент пагінації

Компонент виводить номери сторінок з еліпсисом при великій кількості. Кнопки з aria-label для доступності. Active-сторінка виділяється. Стилізація через Tailwind.

// components/Pagination.tsx interface PaginationProps { currentPage: number lastPage: number onPageChange: (page: number) => void } export function Pagination({ currentPage, lastPage, onPageChange }: PaginationProps) { const pages = buildPageRange(currentPage, lastPage) return ( <nav aria-label="Навігація по сторінках"> <ul className="flex items-center gap-1"> <li> <button onClick={() => onPageChange(currentPage - 1)} disabled={currentPage === 1} aria-label="Попередня сторінка" > ← </button> </li> {pages.map((page, i) => page === '...' ? ( <li key={`ellipsis-${i}`} aria-hidden="true">…</li> ) : ( <li key={page}> <button onClick={() => onPageChange(page as number)} aria-current={page === currentPage ? 'page' : undefined} className={page === currentPage ? 'font-bold' : ''} > {page} </button> </li> ) )} <li> <button onClick={() => onPageChange(currentPage + 1)} disabled={currentPage === lastPage} aria-label="Наступна сторінка" > → </button> </li> </ul> </nav> ) } function buildPageRange(current: number, last: number): (number | '...')[] { if (last <= 7) return Array.from({ length: last }, (_, i) => i + 1) const delta = 2 const range: (number | '...')[] = [] const left = current - delta const right = current + delta let prev: number | null = null for (let i = 1; i <= last; i++) { if (i === 1 || i === last || (i >= left && i <= right)) { if (prev !== null && i - prev > 1) range.push('...') range.push(i) prev = i } } return range } 

Синхронізація з URL

Номер сторінки повинен жити в URL — інакше користувач втрачає позицію при оновленні і не може поділитися посиланням. Використовуємо useSearchParams у Next.js App Router.

// Next.js App Router 'use client' import { useRouter, useSearchParams, usePathname } from 'next/navigation' function usePageParam() { const searchParams = useSearchParams() const router = useRouter() const pathname = usePathname() const page = Number(searchParams.get('page') ?? '1') const setPage = (newPage: number) => { const params = new URLSearchParams(searchParams.toString()) params.set('page', String(newPage)) router.push(`${pathname}?${params.toString()}`, { scroll: true }) } return [page, setPage] as const } 

Що входить у нашу роботу з пагінації

  • Аудит поточної схеми пагінації (SQL-запити, час відповіді)
  • Проєктування API-контракту (offset/cursor, формат відповіді)
  • Реалізація серверної логіки з кешуванням COUNT
  • Розробка UI-компонента з адаптивністю та доступністю
  • Синхронізація з URL (Next.js, React Router, Vanilla)
  • Налаштування prefetch для миттєвих переходів
  • Впровадження SEO-тегів (rel prev/next, canonical, sitemap для пагінації)
  • Документація та навчання команди замовника

Терміни та вартість

Базовий компонент з API-інтеграцією — від 1 дня. Повний пакет з URL-синхронізацією, prefetch, SEO-тегами, адаптивним дизайном та навчанням — від 2 до 4 днів. Вартість розраховується індивідуально після аналізу вашого проєкту. Економія часу розробки на готових компонентах становить до 30% порівняно з написанням з нуля.

Зв'яжіться з нами для безкоштовної оцінки вашого проєкту. Наші інженери з багаторічним досвідом допоможуть реалізувати пагінацію з урахуванням SEO та продуктивності. Гарантуємо LCP < 2.5 с та коректну індексацію в Яндексі. Замовте реалізацію пагінації з гарантією Core Web Vitals. Отримайте консультацію інженера та прототип за 1 день.