Better Scroll's modular architecture provides specialized features through configuration-enabled plugins. Each feature extends the core scrolling functionality with specific capabilities for different use cases.
Page-based scrolling with snap-to-position functionality, ideal for carousels, image galleries, and paged content.
interface SnapOptions {
loop?: boolean; // Enable infinite loop (default: false)
threshold?: number; // Snap threshold (0-1, default: 0.1)
speed?: number; // Snap animation speed in ms (default: 400)
easing?: EasingFunction; // Snap easing function
stepX?: number; // Horizontal step size (default: wrapper width)
stepY?: number; // Vertical step size (default: wrapper height)
el?: HTMLElement | string; // Snap to specific elements
}
// Methods added when snap enabled
goToPage(x: number, y: number, time?: number, easing?: EasingFunction): void;
next(time?: number, easing?: EasingFunction): void;
prev(time?: number, easing?: EasingFunction): void;
getCurrentPage(): {x: number, y: number, pageX: number, pageY: number} | null;
// Instance properties when snap enabled
currentPage: {
x: number; // Current page X coordinate
y: number; // Current page Y coordinate
pageX: number; // Current page index X
pageY: number; // Current page index Y
};
pages: Array<Array<{ // 2D array of page information
x: number; // Page position X
y: number; // Page position Y
width: number; // Page width
height: number; // Page height
cx: number; // Center X
cy: number; // Center Y
}>>;Usage Examples:
// Basic snap scrolling
const scroll = new BScroll('.wrapper', {
snap: true,
momentum: false,
bounce: false
});
// Custom snap configuration
const scroll = new BScroll('.wrapper', {
snap: {
loop: true,
threshold: 0.3,
speed: 400,
stepX: 300,
stepY: 200
}
});
// Snap to specific elements
const scroll = new BScroll('.wrapper', {
snap: {
el: '.slide-item',
loop: true
}
});
// Access current page
console.log('Current page:', scroll.currentPage.pageX, scroll.currentPage.pageY);
// Navigate to specific page
scroll.goToPage(2, 0, 300); // pageX, pageY, durationWheel-style picker component for selecting items from a list with 3D rotation effects.
interface WheelOptions {
selectedIndex?: number; // Initial selected index (default: 0)
rotate?: number; // Rotation angle per item in degrees (default: 25)
adjustTime?: number; // Animation time for adjustment in ms (default: 400)
wheelWrapperClass?: string; // CSS class for wheel wrapper (default: 'wheel-scroll')
wheelItemClass?: string; // CSS class for wheel items (default: 'wheel-item')
}
// Methods added when wheel enabled
wheelTo(index: number): void; // Navigate to specific wheel index
getSelectedIndex(): number | boolean; // Get currently selected index (returns selectedIndex or false)
// Instance properties when wheel enabled
selectedIndex: number; // Currently selected item index
items: HTMLElement[]; // Array of wheel item elementsUsage Examples:
// Basic wheel picker
const scroll = new BScroll('.wheel-wrapper', {
wheel: {
selectedIndex: 2,
rotate: 25
}
});
// Custom wheel configuration
const scroll = new BScroll('.picker', {
wheel: {
selectedIndex: 0,
rotate: 30,
adjustTime: 300,
wheelWrapperClass: 'my-wheel',
wheelItemClass: 'my-wheel-item'
}
});
// Get selected value
console.log('Selected index:', scroll.selectedIndex);
console.log('Selected item:', scroll.items[scroll.selectedIndex]);
// Programmatically select item
scroll.wheelTo(3); // Select item at index 3
// Get selected index
const selectedIndex = scroll.getSelectedIndex();Pull-down refresh and pull-up load functionality with customizable thresholds.
interface PullDownRefreshOptions {
threshold?: number; // Pull distance threshold in px (default: 90)
stop?: number; // Stop position after pull in px (default: 40)
}
interface PullUpLoadOptions {
threshold?: number; // Pull distance threshold in px (default: 50)
}
// Methods added when enabled
/**
* Complete pull-down refresh action
* Call after refresh data is loaded
*/
finishPullDown(): void;
/**
* Complete pull-up load action
* Call after more data is loaded
*/
finishPullUp(): void;
/**
* Dynamically enable/disable pull-down refresh
*/
openPullDown(config?: boolean | PullDownRefreshOptions): void;
closePullDown(): void;
/**
* Programmatically trigger pull-down refresh
*/
autoPullDownRefresh(): void;
/**
* Dynamically enable/disable pull-up load
*/
openPullUp(config?: boolean | PullUpLoadOptions): void;
closePullUp(): void;
// Events fired:
// 'pullingDown' - When pull-down threshold reached
// 'pullingUp' - When pull-up threshold reachedUsage Examples:
// Pull-to-refresh setup
const scroll = new BScroll('.wrapper', {
pullDownRefresh: {
threshold: 90,
stop: 40
},
pullUpLoad: {
threshold: 50
}
});
// Handle pull-down refresh
scroll.on('pullingDown', async () => {
showRefreshIndicator();
try {
await refreshData();
updateContent();
} finally {
hideRefreshIndicator();
scroll.finishPullDown();
}
});
// Handle pull-up load more
scroll.on('pullingUp', async () => {
showLoadingIndicator();
try {
const newData = await loadMoreData();
appendContent(newData);
} finally {
hideLoadingIndicator();
scroll.finishPullUp();
}
});Visual scroll indicators with customizable appearance and behavior.
interface ScrollbarOptions {
fade?: boolean; // Auto-fade scrollbar (default: true)
interactive?: boolean; // Allow scrollbar interaction (default: false)
}Usage Examples:
// Basic scrollbar
const scroll = new BScroll('.wrapper', {
scrollbar: true
});
// Custom scrollbar configuration
const scroll = new BScroll('.wrapper', {
scrollbar: {
fade: true,
interactive: true
}
});Desktop mouse wheel scrolling support with configurable behavior.
interface MouseWheelOptions {
speed?: number; // Scroll speed multiplier (default: 20)
invert?: boolean; // Invert scroll direction (default: false)
easeTime?: number; // Easing duration in ms (default: 300)
}Usage Examples:
// Basic mouse wheel support
const scroll = new BScroll('.wrapper', {
mouseWheel: true
});
// Custom mouse wheel configuration
const scroll = new BScroll('.wrapper', {
mouseWheel: {
speed: 20,
invert: false,
easeTime: 300
}
});Pinch-to-zoom functionality with scale limits and smooth transitions.
interface ZoomOptions {
start?: number; // Initial zoom scale (default: 1)
min?: number; // Minimum zoom scale (default: 1)
max?: number; // Maximum zoom scale (default: 4)
}
// Methods added when zoom enabled
/**
* Zoom to specific scale and position
* @param scale - Target zoom scale
* @param x - Target X position
* @param y - Target Y position
* @param time - Animation duration in ms
*/
zoomTo(scale: number, x: number, y: number, time?: number): void;
// Instance properties when zoom enabled
scale: number; // Current zoom scaleUsage Examples:
// Basic zoom functionality
const scroll = new BScroll('.wrapper', {
zoom: {
start: 1,
min: 0.5,
max: 3
}
});
// Zoom to specific scale and position
scroll.zoomTo(2, 100, 100, 300);
// Get current zoom level
console.log('Current zoom:', scroll.scale);Virtual scrolling for large datasets with efficient DOM management.
interface InfinityOptions {
/**
* Render function for list items
* @param item - Data item to render
* @param div - DOM element to render into
*/
render(item: any, div: HTMLElement): void;
/**
* Create tombstone/placeholder elements
* @returns DOM element for tombstone
*/
createTombstone(): HTMLElement;
/**
* Fetch more data when needed
* @param count - Number of items to fetch
* @returns Promise resolving to array of data items
*/
fetch(count: number): Promise<any[]>;
}Usage Examples:
// Infinite scrolling setup
const scroll = new BScroll('.wrapper', {
infinity: {
render(item, div) {
div.innerHTML = `
<h3>${item.title}</h3>
<p>${item.description}</p>
`;
},
createTombstone() {
const tombstone = document.createElement('div');
tombstone.className = 'tombstone';
tombstone.innerHTML = '<div class="placeholder"></div>';
return tombstone;
},
async fetch(count) {
const response = await fetch(`/api/items?count=${count}`);
return response.json();
}
}
});Features can be combined for complex scrolling experiences:
// Gallery with snap and zoom
const gallery = new BScroll('.gallery-wrapper', {
scrollX: true,
scrollY: false,
snap: {
loop: true,
stepX: 300
},
zoom: {
start: 1,
min: 0.5,
max: 3
},
mouseWheel: true
});
// List with pull-to-refresh and scrollbar
const list = new BScroll('.list-wrapper', {
pullDownRefresh: {
threshold: 90,
stop: 40
},
pullUpLoad: {
threshold: 50
},
scrollbar: {
fade: true
},
probeType: 2
});
// Picker with multiple wheels
const picker = new BScroll('.picker-wrapper', {
wheel: {
selectedIndex: 0,
rotate: 25,
wheelItemClass: 'picker-item'
},
momentum: false,
bounce: false
});// For snap/slide - disable momentum and bounce
const slideScroll = new BScroll('.slides', {
snap: true,
momentum: false,
bounce: false,
probeType: 0 // No scroll events needed
});
// For infinite scroll - minimal animations
const infiniteScroll = new BScroll('.infinite-list', {
infinity: { /* config */ },
useTransition: false, // Use JS animation for smoother infinite scroll
probeType: 3 // Real-time events for scroll position tracking
});
// For zoom - hardware acceleration
const zoomScroll = new BScroll('.zoom-container', {
zoom: { /* config */ },
HWCompositing: true, // Enable hardware acceleration
useTransform: true // Use CSS transforms
});// Clean up when switching between features
function switchToInfiniteMode() {
// Destroy existing instance
if (currentScroll) {
currentScroll.destroy();
}
// Create new instance with different features
currentScroll = new BScroll('.wrapper', {
infinity: infinityConfig
});
}
// Proper cleanup on page unload
window.addEventListener('beforeunload', () => {
if (scroll) {
scroll.destroy();
}
});