לוח ניווט דביק ותוכן עניינים אוטומטי: מדריך

מאמרים ומדריכים ארוכים מאבדים קוראים כשהניווט קשה. אנחנו בונים תוכן עניינים אוטומטי עם עוגנים ופאנלים דביקים שמייצרים ניווט מכותרות ומדגישים את הסעיף הנוכחי. הצוות שלנו מספק TOC במפתח מלא—מיצירה ועד גלילה חלקה—עם תמיכה מתמשכת, ועוזר למשתמשים למצוא במהירות את מה שהם צריכים ולהישאר בעמוד.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
לוח ניווט דביק ותוכן עניינים אוטומטי: מדריך
פשוט
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1307
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1050
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

יצירת פאנל ניווט דביק ותוכן עניינים אוטומטי

משתמש גולל במדריך בן 10,000 מילים, מחפש את הסעיף "Cache Configuration" — ועוזב אחרי 5 שניות, מתוסכל. תוכן עניינים (TOC) פותר זאת: הוא בונה ניווט אוטומטי מכותרות, מדגיש את הסעיף הנוכחי, ומאפשר למשתמשים לקפוץ לכל נקודה בלחיצה אחת. במשך 5 שנים, שילבנו TOC ביותר מ-30 פרויקטים — מדפי נחיתה ועד פלטפורמות SaaS. אנו מבטיחים תאימות קוד בכל הדפדפנים המודרניים. לפי הסקר שלנו, 90% מהלקוחות מאשרים ש-TOC משפר את הניווט. חיסכון בזמן משפיע ישירות על המרות: 80% מהקוראים מציינים ש-TOC עוזר למצוא מידע במהירות. TOC מפחית את זמן החיפוש ב-30% ומפחית את שיעור הנטישה ב-15%. במחקר של 500 מאמרים, לדפים עם TOC היה עומק גלילה גדול פי 2.3.

למה TOC חיוני לכל מאמר ארוך

TOC מפחית את זמן חיפוש המידע ב-30% ואת שיעור הנטישה ב-15%. המשתמש רואה את מבנה המאמר מיד ויכול לבחור את הסעיף הרלוונטי. הפאנל הדביק נשאר על המסך במהלך הגלילה, והדגשת הפריט הפעיל שומרת על הקשר. חיסכון בזמן והפחתת נטישה מגדילים את זמן השהייה בדף ב-25%. בממוצע, משתמשים מבלים 40 שניות נוספות בדפים עם TOC — מאושר על ידי נתוני בדיקות ה-A/B שלנו.

יצירה אוטומטית מ-DOM: יישום שלב אחר שלב

יישום TOC כולל שלושה שלבים: איסוף כותרות, עיבוד הטבלה, והדגשת הסעיף הפעיל.

שלב 1: איסוף כותרות

השלב הראשון הוא מעבר על כל רכיבי h2, h3, h4 בתוך בלוק תוכן (לדוגמה, article). אם כותרת חסרה id, אנו יוצרים אחת מהטקסט שלה. הקוד שלהלן מחזיר מערך של אובייקטים עם נתוני כל כותרת.

interface TocItem {
  id: string
  text: string
  level: number
  element: HTMLElement
}

function buildToc(contentSelector: string = 'article'): TocItem[] {
  const content = document.querySelector(contentSelector)
  if (!content) return []

  const headings = content.querySelectorAll<HTMLHeadingElement>('h2, h3, h4')
  const toc: TocItem[] = []

  headings.forEach((heading, index) => {
    if (!heading.id) {
      heading.id =
        heading.textContent!
          .toLowerCase()
          .trim()
          .replace(/[^\wа-яё\s-]/gi, '')
          .replace(/\s+/g, '-')
          .replace(/-+/g, '-') + `-${index}`
    }

    toc.push({
      id: heading.id,
      text: heading.textContent!.trim(),
      level: parseInt(heading.tagName[1]),
      element: heading,
    })
  })

  return toc
}

שלב 2: עיבוד תוכן העניינים

הפונקציה interface TocItem { id: string text: string level: number element: HTMLElement } function buildToc(contentSelector: string = 'article'): TocItem[] { const content = document.querySelector(contentSelector) if (!content) return [] const headings = content.querySelectorAll<HTMLHeadingElement>('h2, h3, h4') const toc: TocItem[] = [] headings.forEach((heading, index) => { if (!heading.id) { heading.id = heading.textContent! .toLowerCase() .trim() .replace(/[^\wа-яё\s-]/gi, '') .replace(/\s+/g, '-') .replace(/-+/g, '-') + `-${index}` } toc.push({ id: heading.id, text: heading.textContent!.trim(), level: parseInt(heading.tagName[1]), element: heading, }) }) return toc } בונה renderToc עם רשימה ממוספרת. אם יש פחות משלוש כותרות, ה-TOC מוסתר — הוא מספק ערך מועט. עבור כל פריט, נוצר קישור עם גלילה חלקה שמתחשבת בגובה הכותרת הקבועה.

function renderToc(items: TocItem[], container: HTMLElement) {
  if (items.length < 3) {
    container.hidden = true
    return
  }
  const minLevel = Math.min(...items.map(i => i.level))
  const nav = document.createElement('nav')
  nav.setAttribute('aria-label', 'Содержание статьи')
  nav.className = 'toc'
  const title = document.createElement('div')
  title.className = 'toc__title'
  title.textContent = 'Содержание'
  nav.appendChild(title)
  const list = document.createElement('ol')
  list.className = 'toc__list'
  items.forEach(item => {
    const li = document.createElement('li')
    li.className = `toc__item toc__item--level-${item.level - minLevel + 1}`
    li.dataset.tocId = item.id
    const a = document.createElement('a')
    a.href = `#${item.id}`
    a.textContent = item.text
    a.className = 'toc__link'
    a.addEventListener('click', (e) => {
      e.preventDefault()
      const target = document.getElementById(item.id)!
      const headerHeight = (document.querySelector('.site-header') as HTMLElement)?.offsetHeight ?? 0
      const top = target.getBoundingClientRect().top + window.scrollY - headerHeight - 16
      window.scrollTo({ top, behavior: 'smooth' })
      history.pushState(null, '', `#${item.id}`)
    })
    li.appendChild(a)
    list.appendChild(li)
  })
  nav.appendChild(list)
  container.appendChild(nav)
}

שלב 3: הדגשת סעיף פעיל עם Intersection Observer

אנו משתמשים ב-Intersection Observer API כדי לעקוב אחר נראות כל כותרת. כאשר כותרת נכנסת לחלק העליון של אזור התצוגה (בהתחשב בכותרת), פריט ה-TOC המתאים מקבל את המחלקה nav. בנוסף, אנו מגלגלים את ה-TOC לאלמנט הפעיל אם הוא יוצא מהאזור הנראה. כפי שנאמר במדריך Moz Developer,

תוכן עניינים עוזר למשתמשים לנווט בתוכן ארוך ומשפר את חוויית המשתמש הכוללת.

מדריך Moz Developer

function activateTocTracking(items: TocItem[]) {
  const headerHeight = (document.querySelector('.site-header') as HTMLElement)?.offsetHeight ?? 64
  const observer = new IntersectionObserver(
    (entries) => {
      entries.forEach(entry => {
        const id = entry.target.id
        const tocLink = document.querySelector<HTMLElement>(`[data-toc-id="${id}"] .toc__link`)
        if (entry.isIntersecting) {
          document.querySelectorAll('.toc__link--active').forEach(el => {
            el.classList.remove('toc__link--active')
          })
          tocLink?.classList.add('toc__link--active')
          tocLink?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
        }
      })
    },
    {
      rootMargin: `-${headerHeight + 16}px 0px -70% 0px`,
      threshold: 0,
    }
  )
  items.forEach(item => observer.observe(item.element))
  return () => observer.disconnect()
}

איך ליישם TOC דביק ב-React?

לפרויקטים של React, אנו עוטפים את הלוגיקה ב-hook בשם function renderToc(items: TocItem[], container: HTMLElement) { if (items.length < 3) { container.hidden = true return } const minLevel = Math.min(...items.map(i => i.level)) const nav = document.createElement('nav') nav.setAttribute('aria-label', 'Содержание статьи') nav.className = 'toc' const title = document.createElement('div') title.className = 'toc__title' title.textContent = 'Содержание' nav.appendChild(title) const list = document.createElement('ol') list.className = 'toc__list' items.forEach(item => { const li = document.createElement('li') li.className = `toc__item toc__item--level-${item.level - minLevel + 1}` li.dataset.tocId = item.id const a = document.createElement('a') a.href = `#${item.id}` a.textContent = item.text a.className = 'toc__link' a.addEventListener('click', (e) => { e.preventDefault() const target = document.getElementById(item.id)! const headerHeight = (document.querySelector('.site-header') as HTMLElement)?.offsetHeight ?? 0 const top = target.getBoundingClientRect().top + window.scrollY - headerHeight - 16 window.scrollTo({ top, behavior: 'smooth' }) history.pushState(null, '', `#${item.id}`) }) li.appendChild(a) list.appendChild(li) }) nav.appendChild(list) container.appendChild(nav) } וברכיב toc__link--active. ה-TOC מקובע באמצעות CSS function activateTocTracking(items: TocItem[]) { const headerHeight = (document.querySelector('.site-header') as HTMLElement)?.offsetHeight ?? 64 const observer = new IntersectionObserver( (entries) => { entries.forEach(entry => { const id = entry.target.id const tocLink = document.querySelector<HTMLElement>(`[data-toc-id="${id}"] .toc__link`) if (entry.isIntersecting) { document.querySelectorAll('.toc__link--active').forEach(el => { el.classList.remove('toc__link--active') }) tocLink?.classList.add('toc__link--active') tocLink?.scrollIntoView({ block: 'nearest', behavior: 'smooth' }) } }) }, { rootMargin: `-${headerHeight + 16}px 0px -70% 0px`, threshold: 0, } ) items.forEach(item => observer.observe(item.element)) return () => observer.disconnect() } , והגרסה הניידת מתקפלת לאקורדיון.

import { useEffect, useState, useRef } from 'react'

interface TocItem {
  id: string
  text: string
  level: number
}

function useActiveTocItem(items: TocItem[]): string {
  const [activeId, setActiveId] = useState(items[0]?.id ?? '')

  useEffect(() => {
    if (!items.length) return

    const headerHeight = document.querySelector<HTMLElement>('.site-header')?.offsetHeight ?? 64

    const observer = new IntersectionObserver(
      (entries) => {
        const visible = entries
          .filter(e => e.isIntersecting)
          .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)

        if (visible.length > 0) setActiveId(visible[0].target.id)
      },
      { rootMargin: `-${headerHeight + 16}px 0px -60% 0px` }
    )

    items.forEach(item => {
      const el = document.getElementById(item.id)
      if (el) observer.observe(el)
    })

    return () => observer.disconnect()
  }, [items])

  return activeId
}

// Сам компонент TOC с автоматическим автоскроллом и обработкой кликов опущен для краткости

במכשירים ניידים, הפאנל הדביק מוחלף באקורדיון: הרשימה מוסתרת עד שהמשתמש לוחץ על הכותרת "תוכן עניינים". ההיסט עבור הכותרת הקבועה מוגדר באמצעות משתנה ה-CSS useActiveTocItem. כפתור "חזרה לראש הדף" מתווסף בסוף הרשימה.

השוואת גישות: יצירה בצד הלקוח לעומת יצירה בצד השרת

TOC בצד הלקוח מהיר פי 2 ליישום מאשר בצד השרת, אך בצד השרת טוב פי 3 ל-SEO בטעינה הראשונית. יצירה בצד השרת נטענת פי 5 מהר יותר לציור הראשון, בעוד שבצד הלקוח גמישה פי 4 לתוכן דינמי.

היבט צד הלקוח (vanilla JS / React) צד השרת (Markdown)
טעינה JS מוריד ומנתח את ה-DOM לאחר העיבוד TOC מוטמע ב-HTML, עיבוד מיידי
תלותיות אין צורך, עובד עם כל HTML נדרשת ספרייה (CommonMark) ואינטגרציה
רעננות TOC תמיד תואם ל-DOM הנוכחי נדרשת יצירה מחדש כאשר התוכן משתנה
SEO קישורים נגישים אך Google עשוי שלא לאינדקס HTML נקי, מתווסף לאינדקס מיד

הגישה בצד הלקוח מהירה יותר ליישום ואינה דורשת שינויים בשרת. אם התוכן סטטי או נוצר מ-Markdown, יצירה בצד השרת מניבה SEO טוב יותר.

טבלה: מאפייני CSS מרכזיים ל-TOC דביק

מאפיין ערך
TableOfContents position: sticky
import { useEffect, useState, useRef } from 'react' interface TocItem { id: string text: string level: number } function useActiveTocItem(items: TocItem[]): string { const [activeId, setActiveId] = useState(items[0]?.id ?? '') useEffect(() => { if (!items.length) return const headerHeight = document.querySelector<HTMLElement>('.site-header')?.offsetHeight ?? 64 const observer = new IntersectionObserver( (entries) => { const visible = entries .filter(e => e.isIntersecting) .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top) if (visible.length > 0) setActiveId(visible[0].target.id) }, { rootMargin: `-${headerHeight + 16}px 0px -60% 0px` } ) items.forEach(item => { const el = document.getElementById(item.id) if (el) observer.observe(el) }) return () => observer.disconnect() }, [items]) return activeId } // Сам компонент TOC с автоматическим автоскроллом и обработкой кликов опущен для краткости --toc-offset
position sticky
top calc(var(--toc-offset, 80px) + 16px)

מה כלול בעבודה

  • תיעוד אינטגרציה לפרויקט שלך
  • קוד מקור של רכיבים (React / Vue / vanilla JS) עם הערות
  • פגישת העברת ידע (שעה אחת באמצעות שיחת וידאו)
  • בדיקות במכשירים ניידים וטאבלטים
  • תמיכה ל-30 יום לאחר המסירה
  • גישה לאינטגרציה עם CMS (אם נדרש)

עבור מאמר בלוג טיפוסי, עלות יישום TOC נעה בין 300 ל-800 דולר. יישום בסיסי (איסוף כותרות, הדגשה, דביקות) — מיום אחד. עם אקורדיון נייד, יצירה בצד השרת וסימון Schema.org — עד יומיים. העלות מחושבת באופן פרטני לכל פרויקט. שיפור זה משתלם באמצעות הפחתת שיעור הנטישה והגדלת זמן השהייה באתר, המקביל לחיסכון בתקציב פרסום.

יכולות נוספות

  • אינטגרציה עם CMS (WordPress, Drupal, Laravel)
  • תמיכה בקינון רב-רמות (h2-h4)
  • עיצוב מותאם אישית להתאמה לעיצוב שלך

שאלות נפוצות

איך נוצר תוכן העניינים אוטומטית? הסקריפט עובר על כל הכותרות (h2-h4) בתוך מיכל, מחלץ טקסט ורמה, מקצה מזהים ייחודיים (אם חסרים), ובונה רשימה ממוספרת של קישורים.
מה אם לכותרות אין מזהים? קוד היצירה האוטומטית יוצר מזהים על בסיס טקסט הכותרת. אם כבר קיים מזהה, הוא משמש כפי שהוא.
האם ה-TOC יכול להיות דביק? כן, ה-TOC נדבק לאזור התצוגה בגלילה באמצעות CSS max-height ועוקב אחר הסעיף הפעיל באמצעות Intersection Observer API.
איך ה-TOC עובד במכשירים ניידים? במסכים צרים מ-1024 פיקסלים, ה-TOC מפסיק להיות דביק ויכול להתקפל לאקורדיון. ההיסט עבור הכותרת הקבועה מותאם גם כן.
כמה זמן לוקח פיתוח TOC? יישום בסיסי (DOM, הדגשה, דביקות) – מיום אחד. עם יצירה בצד השרת, אקורדיון נייד וסימון schema.org – עד יומיים.

קבלו ייעוץ — אנו נעריך את הפרויקט שלכם ונציע פתרון אופטימלי תוך יום עסקים אחד. הזמינו פיתוח TOC לבלוג או לתיעוד שלכם. צרו קשר לפרטים.