From b422984fa23acb2e1758dd044c64dff69dbad5e6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 1 Jun 2025 12:53:29 -0400 Subject: [PATCH] Add custom scrollbar and scroll behavior to sidebar The changes add a custom scrollbar and enhanced scroll functionality to the sidebar, with cross-browser support, accessibility features, and device-specific optimizations. --- kjvstudy_org/static/style.css | 235 +++++++++++++++++++++++++++++++ kjvstudy_org/templates/base.html | 71 ++++++++++ 2 files changed, 306 insertions(+) diff --git a/kjvstudy_org/static/style.css b/kjvstudy_org/static/style.css index eebdd42..88462e9 100644 --- a/kjvstudy_org/static/style.css +++ b/kjvstudy_org/static/style.css @@ -120,6 +120,241 @@ div { visibility: visible !important; } +/* Custom scrollbar for sidebar */ +.sidebar::-webkit-scrollbar { + width: 8px; +} + +.sidebar::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.1); + border-radius: 4px; + margin: 0.5rem 0; +} + +.sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + border-radius: 4px; + transition: background-color 0.2s ease; +} + +.sidebar::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.5); +} + +.sidebar::-webkit-scrollbar-thumb:active { + background: rgba(255, 255, 255, 0.6); +} + +/* Firefox scrollbar styling */ +.sidebar { + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(255, 255, 255, 0.1); + scroll-behavior: smooth; +} + +/* Enhanced scrollbar for better UX */ +.sidebar::-webkit-scrollbar-corner { + background: transparent; +} + +/* Scrollbar styles for different states */ +.sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.4); +} + +.sidebar:focus-within::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.45); +} + +/* Theme-aware scrollbar styling */ +@media (prefers-color-scheme: dark) { + .sidebar::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.2); + } + + .sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.4); + } + + .sidebar::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.6); + } +} + +/* High contrast mode support */ +@media (prefers-contrast: high) { + .sidebar::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.3); + border: 1px solid rgba(255, 255, 255, 0.5); + } + + .sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.8); + border: 1px solid rgba(255, 255, 255, 0.9); + } +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + .sidebar { + scroll-behavior: auto; + } + + .sidebar::-webkit-scrollbar-thumb { + transition: none; + } +} + +/* Mobile and touch device enhancements */ +@media (max-width: 768px) { + .sidebar::-webkit-scrollbar { + width: 6px; + } + + .sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.4); + border-radius: 3px; + } +} + +/* Touch scrolling improvements */ +.sidebar { + -webkit-overflow-scrolling: touch; + overscroll-behavior: contain; +} + +/* iPad-specific scrollbar styling */ +@media (min-width: 768px) and (max-width: 1366px) { + .sidebar::-webkit-scrollbar { + width: 10px; + } + + .sidebar::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.08); + border-radius: 5px; + margin: 0.75rem 0; + } + + .sidebar::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0.25) 100%); + border-radius: 5px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + } + + .sidebar::-webkit-scrollbar-thumb:hover { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0.45) 100%); + } +} + +/* Auto-hide scrollbar when not scrolling */ +.sidebar { + overflow-y: auto; + overflow-x: hidden; +} + +.sidebar:not(:hover):not(:focus-within) { + scrollbar-width: none; +} + +.sidebar:not(:hover):not(:focus-within)::-webkit-scrollbar { + width: 0px; + background: transparent; +} + +/* Show scrollbar on hover/focus */ +.sidebar:hover::-webkit-scrollbar, +.sidebar:focus-within::-webkit-scrollbar { + width: 8px; + transition: width 0.2s ease; +} + +@media (min-width: 768px) and (max-width: 1366px) { + .sidebar:hover::-webkit-scrollbar, + .sidebar:focus-within::-webkit-scrollbar { + width: 10px; + } +} + +/* Active scrolling visual feedback */ +.sidebar::-webkit-scrollbar-thumb:active { + background: rgba(255, 255, 255, 0.7); + transform: scale(1.1); + transition: all 0.1s ease; +} + +/* Smooth scroll enhancements */ +.sidebar { + scroll-padding-top: 1rem; + scroll-padding-bottom: 1rem; +} + +/* Focus-visible scrollbar enhancement */ +.sidebar:focus-visible::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.6); + box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3); +} + +/* Scrollbar animation on keyboard navigation */ +.keyboard-navigation .sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.5); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* Better scrollbar visibility during navigation */ +.sidebar-nav a:focus { + scroll-margin-top: 2rem; + scroll-margin-bottom: 2rem; +} + +/* Initial scrollbar reveal animation */ +@keyframes scrollbarReveal { + 0% { + opacity: 0; + transform: translateX(10px); + } + 50% { + opacity: 1; + transform: translateX(0); + } + 100% { + opacity: 0.6; + transform: translateX(0); + } +} + +.sidebar::-webkit-scrollbar-thumb { + animation: scrollbarReveal 3s ease-out; +} + +/* Scrollbar accessibility improvements */ +.sidebar[aria-label] { + scrollbar-gutter: stable; +} + +/* Better contrast for users with vision difficulties */ +@media (prefers-contrast: more) { + .sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(255, 255, 255, 1); + } + + .sidebar::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.7); + } +} + +/* Scrollbar size adjustment for different zoom levels */ +@media (min-resolution: 192dpi) { + .sidebar::-webkit-scrollbar { + width: 12px; + } + + .sidebar::-webkit-scrollbar-thumb { + border-radius: 6px; + } +} + .sidebar-header { padding: 0 1rem 1.5rem; border-bottom: 1px solid rgba(255, 255, 255, 0.15); diff --git a/kjvstudy_org/templates/base.html b/kjvstudy_org/templates/base.html index e9a0e00..c1e70cb 100644 --- a/kjvstudy_org/templates/base.html +++ b/kjvstudy_org/templates/base.html @@ -1116,9 +1116,80 @@ setupKeyboardNavigation(); } + // Enhanced scrollbar functionality + function enhanceScrollbarExperience() { + const sidebar = document.getElementById("sidebar"); + if (!sidebar) return; + + // Add smooth scrolling to sidebar navigation links + const navLinks = sidebar.querySelectorAll('.sidebar-nav a'); + navLinks.forEach(link => { + link.addEventListener('click', (e) => { + // Smooth scroll the link into view within sidebar + setTimeout(() => { + link.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + inline: 'nearest' + }); + }, 100); + }); + }); + + // Enhanced keyboard navigation with scrollbar awareness + sidebar.addEventListener('keydown', (e) => { + if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { + setTimeout(() => { + const focusedElement = document.activeElement; + if (focusedElement && sidebar.contains(focusedElement)) { + focusedElement.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + inline: 'nearest' + }); + } + }, 50); + } + }); + + // Add scroll position memory + let scrollPosition = 0; + sidebar.addEventListener('scroll', () => { + scrollPosition = sidebar.scrollTop; + }); + + // Restore scroll position on page reload + const savedScrollPosition = sessionStorage.getItem('sidebar-scroll-position'); + if (savedScrollPosition) { + sidebar.scrollTop = parseInt(savedScrollPosition); + sessionStorage.removeItem('sidebar-scroll-position'); + } + + // Save scroll position before page unload + window.addEventListener('beforeunload', () => { + sessionStorage.setItem('sidebar-scroll-position', sidebar.scrollTop.toString()); + }); + + // Add accessibility enhancements + sidebar.setAttribute('aria-label', 'Main navigation sidebar'); + sidebar.setAttribute('role', 'navigation'); + + // Show scrollbar briefly on focus to indicate scrollability + sidebar.addEventListener('focus', () => { + sidebar.style.scrollbarWidth = 'thin'; + setTimeout(() => { + if (!sidebar.matches(':hover')) { + sidebar.style.scrollbarWidth = 'none'; + } + }, 2000); + }); + } + // Initialize on page load and handle layout changes document.addEventListener('DOMContentLoaded', () => { initializeIPadSupport(); + enhanceScrollbarExperience(); + // Force sidebar to be visible immediately const sidebar = document.getElementById("sidebar"); if (sidebar && window.innerWidth > 767) {