Normalize Scroll Left
This utility library addresses the inconsistent behavior of the `Element.scrollLeft` property when an element's direction is set to Right-to-Left (RTL) across different browsers. It provides methods to detect the browser's specific `scrollLeft` implementation type (e.g., WebKit's 'default', Firefox/Opera's 'negative', IE/Edge's 'reverse') and then normalize `scrollLeft` values to a consistent, WebKit-like `0` (most left) to `100` (most right) range for both getting and setting. The current stable version is 0.2.1. Releases appear to be driven by bug fixes and feature enhancements, such as ESM support in v0.2.0. Its key differentiator is robust feature detection to abstract away browser quirks, enabling developers to work with a predictable `scrollLeft` API for RTL content, based on established patterns from jQuery plugins and Stack Overflow solutions. It explicitly handles Server-Side Rendering (SSR) environments by returning `indeterminate` or `NaN` for relevant functions, indicating non-browser execution.
Common errors
-
ReferenceError: document is not defined
cause Attempting to call `detectScrollType`, `getNormalizedScrollLeft`, or `setNormalizedScrollLeft` in a Node.js (Server-Side Rendering) environment without a browser emulation layer.fixWrap DOM-dependent calls in a client-side check, e.g., `if (typeof document !== 'undefined') { /* call function */ }`, or ensure these functions are only executed on the client-side. -
detectScrollType() returns 'indeterminate' in browser
cause `detectScrollType()` was invoked before the `document.body` was fully loaded or available, preventing it from rendering the necessary dummy element for feature detection.fixEnsure that `detectScrollType()` is called only after the DOM is ready, for instance, within a `DOMContentLoaded` event listener or at the end of the `<body>` in traditional scripts. -
Scroll position not normalizing correctly for RTL elements.
cause The `direction` argument passed to `getNormalizedScrollLeft()` or `setNormalizedScrollLeft()` does not match the actual computed `direction` of the `HTMLElement`, or the element's `direction` itself is not correctly set to `rtl`.fixVerify that the `direction` argument (e.g., `'rtl'`) explicitly passed to the normalization functions accurately reflects the `getComputedStyle().direction` of the target `HTMLElement`.
Warnings
- breaking Version 0.2.0 introduced ESM support via the 'module' field. Projects using CommonJS `require()` might need to adjust their import statements or build configurations to properly consume the package, especially if relying on older Node.js versions or specific bundler setups.
- gotcha The `detectScrollType()` function requires a browser DOM environment to operate, as it renders a dummy element. It will return `'indeterminate'` in non-browser (e.g., Node.js/SSR) environments and also if called before `document.body` is fully loaded.
- gotcha Both `getNormalizedScrollLeft()` and `setNormalizedScrollLeft()` explicitly require the `direction` ('rtl' or 'ltr') as an argument. This is for performance reasons to avoid expensive `getComputedStyle` calls and potential reflows. Providing an incorrect `direction` might lead to unexpected scroll behavior.
- gotcha Functions like `getNormalizedScrollLeft()` return `NaN` and `setNormalizedScrollLeft()` does nothing when executed in a non-browser environment (e.g., Node.js for SSR). This is by design to avoid DOM access errors.
Install
-
npm install normalize-scroll-left -
yarn add normalize-scroll-left -
pnpm add normalize-scroll-left
Imports
- detectScrollType
const detectScrollType = require('normalize-scroll-left').detectScrollType;import { detectScrollType } from 'normalize-scroll-left'; - getNormalizedScrollLeft
const getNormalizedScrollLeft = require('normalize-scroll-left').getNormalizedScrollLeft;import { getNormalizedScrollLeft } from 'normalize-scroll-left'; - setNormalizedScrollLeft
const setNormalizedScrollLeft = require('normalize-scroll-left').setNormalizedScrollLeft;import { setNormalizedScrollLeft } from 'normalize-scroll-left';
Quickstart
import { detectScrollType, getNormalizedScrollLeft, setNormalizedScrollLeft } from 'normalize-scroll-left';
// This quickstart demonstrates how to use normalize-scroll-left to handle
// inconsistent Element.scrollLeft behavior in RTL layouts across browsers.
// 1. Detect the browser's scroll type (caches result)
// Must be called after the DOM body is loaded.
const scrollType = detectScrollType();
console.log(`Detected scroll type: ${scrollType}`); // e.g., 'default', 'negative', 'reverse', 'indeterminate' in SSR
// 2. Create a dummy scrollable element for demonstration
const container = document.createElement('div');
container.id = 'my-scrollable-container';
container.style.direction = 'rtl';
container.style.width = '100px';
container.style.overflowX = 'scroll';
container.style.whiteSpace = 'nowrap';
container.style.border = '1px solid black';
container.innerHTML = '<span style="display:inline-block; width:200px; height:20px;">Scrollable Content</span>';
document.body.appendChild(container);
// Simulate scrolling to the most right (normalized to 100)
setNormalizedScrollLeft(container, 100, 'rtl');
console.log(`After setting normalized scrollLeft to 100 (most right): ${getNormalizedScrollLeft(container, 'rtl')}`);
// Simulate scrolling to a specific position (normalized to 20)
setNormalizedScrollLeft(container, 20, 'rtl');
console.log(`After setting normalized scrollLeft to 20: ${getNormalizedScrollLeft(container, 'rtl')}`);
// Clean up
document.body.removeChild(container);