Enhanced Footnote Navigation with Visual Highlighting

Summary

Implemented comprehensive footnote navigation improvements including visual highlighting animations, proper scroll positioning, and enhanced user experience for both footnote references and definitions.

Why Care

These improvements significantly enhance the reading experience by providing clear visual feedback when navigating between footnotes and their references. The smooth animations and proper scroll positioning make it easier to track footnote relationships in long-form content, reducing cognitive load and improving content discoverability.

Implementation

Changes Made

Core Files Modified:

  • site/src/components/markdown/AstroMarkdown.astro - Main footnote rendering and highlighting logic
  • site/src/utils/slugify.ts - Fixed text extraction for inline code in headings
  • site/src/components/articles/OneArticleOnPage.astro - Added scroll-margin-top for headings
  • site/src/layouts/OneArticle.astro - Added scroll-margin-top for headings
  • site/src/components/markdown/TableOfContents.astro - Improved progress bar visibility
  • site/src/components/markdown/CopyLinkButton.astro - Fixed TypeScript linter error

Test File Created:

  • content/lost-in-public/market-maps/Footnote-Highlight-Test.md - Comprehensive test document for footnote functionality

Key Improvements:

  1. Visual Highlighting System
    • Added CSS animations for footnote references and definitions
    • Implemented separate animation styles for references (with scaling) and definitions (without layout changes)
    • Created smooth 1-second animations with proper easing
  2. Enhanced Navigation
    • Fixed scroll positioning for footnote references with proper header clearance
    • Improved element ID handling for both numeric and alphanumeric footnote IDs
    • Added scroll-margin-top to prevent elements from being hidden behind fixed header
  3. Robust JavaScript Implementation
    • Replaced setTimeout-based animation removal with animationend event listeners
    • Eliminated flickering issues by properly timing class removal
    • Added comprehensive debugging and error handling
  4. Layout Improvements
    • Moved Table of Contents progress bar outside scroll area for better visibility
    • Fixed heading ID generation to include inline code content
    • Improved scroll behavior consistency across different content types

Technical Details

CSS Animation System

css
/* Footnote reference highlighting with scaling */
.footnote-ref.highlighted {
  background: rgba(4, 229, 229, 0.6);
  border-radius: 6px;
  padding: 8px;
  box-shadow: 0 0 20px rgba(4, 229, 229, 0.8), 0 0 40px rgba(4, 229, 229, 0.4);
  animation: footnote-highlight 1s ease-out;
  transform: scale(1.1);
}

/* Footnote definition highlighting without layout changes */
.footnote-definition.highlighted {
  background: rgba(4, 229, 229, 0.3);
  box-shadow: 0 0 20px rgba(4, 229, 229, 0.6);
  animation: footnote-highlight-definition 1s ease-out;
}

JavaScript Event Handling

javascript
// Listen for animation end to remove the class
const handleAnimationEnd = () => {
  targetElement.classList.remove('highlighted');
  targetElement.removeEventListener('animationend', handleAnimationEnd);
  console.log('[Footnote Highlight] Animation ended, removed highlight class');
};

targetElement.addEventListener('animationend', handleAnimationEnd);

Enhanced Element Detection

javascript
// Check for footnote references (#ref-*) or footnote definitions (any alphanumeric ID)
if (hash.startsWith('#ref-') || /^#[a-zA-Z0-9]+$/.test(hash)) {
  if (hash.startsWith('#ref-')) {
    // For footnote references, use querySelector (safe for #ref-*)
    targetElement = document.querySelector(hash);
  } else {
    // For footnote definitions (#1, #2, etc.), use getElementById to avoid CSS selector issues
    const id = hash.substring(1);
    targetElement = document.getElementById(id);
  }
}

Scroll Positioning Fixes

css
/* Added to both OneArticleOnPage.astro and OneArticle.astro */
.prose :global(h1),
.prose :global(h2),
.prose :global(h3),
.prose :global(h4),
.prose :global(h5),
.prose :global(h6) {
  scroll-margin-top: 150px; /* Account for fixed header */
}

.footnote-ref {
  scroll-margin-top: 150px; /* Account for fixed header when scrolling back to reference */
  display: inline-block; /* Ensure proper scroll positioning */
  position: relative; /* Ensure proper scroll positioning */
}

Integration Points

Markdown Processing Pipeline

  • Enhanced extractAllText function in slugify.ts to properly handle inline code in headings
  • Updated footnote rendering to use correct element IDs and structure
  • Integrated with existing scroll behavior and navigation systems

Table of Contents Integration

  • Modified progress bar positioning to ensure visibility
  • Maintained compatibility with existing TOC scroll tracking
  • Preserved all existing TOC functionality while improving layout

Content Management

  • Created test document following project's markdown structure
  • Ensured compatibility with existing content processing pipeline
  • Maintained backward compatibility with existing footnote formats

Documentation

Test File Structure

The created test file (Footnote-Highlight-Test.md) includes:
  • Multiple footnote references and definitions
  • Direct navigation links for testing
  • Expected behavior documentation
  • Comprehensive test scenarios

Usage Examples

Here is some text with a footnote reference [a1b2c3] that highlights when clicked.

Browser Compatibility

  • Tested with modern browsers supporting CSS animations and ES6 features
  • Graceful degradation for older browsers (animations disabled, navigation still works)
  • Mobile-friendly touch interactions

Performance Considerations

  • Lightweight CSS animations using transform and opacity
  • Efficient event listener management with automatic cleanup
  • Minimal DOM manipulation for optimal performance

Citations

[a1b2c3] This footnote definition will highlight when navigated to directly.