Configuring Emacs Scrolling for Better Usability

By default, scrolling in Emacs recenters the window when point moves off-screen, and rapid scrolling through large, heavily fontified files can introduce noticeable input lag. This article outlines configurations that make scrolling more predictable and responsive.

Customizing scroll recentering

Adjusting the automatic scrolling behavior can prevent Emacs from making large jumps when point moves beyond the visible portion of the window:

;; Scroll by up to 20 lines to bring point back into view before falling back to
;; the normal automatic scrolling behavior.
(setq scroll-conservatively 20)

When point moves off-screen or into the scroll margin, setting scroll-conservatively to a moderate value like 20 allows Emacs to scroll the text by up to 20 lines in either direction to bring point back into view.

Note: Setting scroll-conservatively to a value above 100 prevents automatic scrolling from centering point, regardless of how far point moves. Emacs instead scrolls only far enough to bring point into view, placing it at the top or bottom of the window depending on the direction of scrolling.

Maintaining vertical context

While scroll-conservatively controls how Emacs reacts when point leaves the window, you can also define a boundary to force scrolling before point reaches the absolute edge:

;; Keep 3 lines of context visible above and below point.
(setq scroll-margin 3)

Setting scroll-margin to 3 establishes a boundary of three lines at both the top and bottom of the Emacs window, forcing the buffer to scroll automatically as soon as your cursor enters this area instead of waiting for it to reach the absolute edge of the screen.

This keeps point away from the top and bottom edges of the window whenever automatic scrolling can move it out of the margin.

Note: Leaving scroll-margin at the default of 0 ensures the cursor can sit directly on the top or bottom line before triggering a scroll. Many users prefer this default setting because it maximizes usable vertical screen space and mirrors the edge-scrolling behavior found in most other modern text editors.

Horizontal scrolling

When line truncation is enabled (truncate-lines is non-nil), Emacs automatically scrolls horizontally when point approaches the left or right edge of the window. hscroll-margin controls how close point can get to an edge, while hscroll-step controls how far the window moves when automatic horizontal scrolling occurs.

;; Horizontal scrolling
(setq hscroll-margin 2
      hscroll-step 1)

Setting hscroll-margin to 2 causes horizontal scrolling to trigger when point comes within two columns of the left or right edge, while setting hscroll-step to 1 forces the window to pan exactly one column at a time.

This transforms horizontal movement into a column-by-column scroll, replacing the default behavior where Emacs jumps the view by half a screen horizontally and forces you to visually search for your cursor.

Deferring fontification during input

Fontification (syntax highlighting) requires CPU time to parse and colorize text. In large or complex buffers, this process can block the main thread, leading to input latency. Setting redisplay-skip-fontification-on-input to t causes Emacs to prioritize user input over immediate syntax highlighting:

;; Skip some fontification when input is pending.
(setq redisplay-skip-fontification-on-input t)

The tradeoff is that syntax highlighting may temporarily lag behind the underlying text while your input is actively being processed. When scrolling rapidly into an unseen section of a file or pasting a large block of code, the text might appear uncolored or incorrectly colored for a fraction of a second. However, the delay is virtually unnoticeable, and the correct colors will render as soon as the input queue clears.

Preserving screen position

Setting scroll-preserve-screen-position to t fixes a common visual annoyance when paging up or down through a file (using C-v or M-v). If your cursor is in the middle of the screen and you hit Page Down, the cursor stays exactly in the middle of your monitor:

;; Preserve point's vertical screen position when scrolling.
(setq scroll-preserve-screen-position t)

Note: There is one exception involving next-screen-context-lines (default 2), which controls how many lines of text are repeated from your previous screen when you scroll by a full window. If your cursor is resting on one of these repeated lines at the edge of the window when you jump, Emacs does not preserve its vertical screen position. Instead, it moves the cursor into the newly revealed text. This prevents the cursor from getting stranded at the extreme edge of the window and ensures you have enough surrounding text to read comfortably.

Disabling automatic vertical scrolling

Setting auto-window-vscroll to nil prevents movement and scrolling functions from automatically modifying the window's vertical scroll position when they encounter display rows taller than the window:

;; Do not automatically adjust vertical scrolling through tall display rows.
(setq auto-window-vscroll nil)

This makes vertical movement through buffers containing large elements, such as inline images, much more predictable by avoiding sudden partial-screen shifts. The tradeoff is that tall display rows become more cumbersome to navigate because Emacs no longer automatically scrolls through their partially visible portions to reveal the rest of the element.

Top and bottom scroll errors

By default, Emacs immediately signals an error if you attempt to scroll past the top or bottom of a buffer. Setting scroll-error-top-bottom to t changes this behavior so that your first attempt to scroll past the boundary safely moves the cursor to the exact beginning or end of the document:

;; Move point to the buffer boundary before signaling a scrolling error.
(setq scroll-error-top-bottom t)

Instead of throwing an error immediately, it moves your cursor directly to the first or last character of the buffer. If you attempt to scroll again while your cursor is already resting on that final position, Emacs will then signal the standard scrolling error.

Enabling faster scrolling

Rapid scrolling can become sluggish when Emacs encounters previously unfontified text. Setting fast-but-imprecise-scrolling to t prevents Emacs from becoming unresponsive when you move rapidly through large buffers:

;; Avoid fontifying unfontified text while scrolling rapidly.
(setq fast-but-imprecise-scrolling t)

The primary tradeoff is that scrolling can become visually imprecise. However, this behavior is generally nothing to worry about. For typical programming tasks using a standard monospaced font, line heights remain consistent, meaning you will likely never experience this imprecision at all. Even in modes that do use variable font sizes, the visual jump is minor and temporary. Once you stop scrolling and the input queue clears, Emacs finishes fontifying the visible text and corrects the layout, ensuring your final view is accurate.

Scroll aggressiveness

By default, when point moves beyond the top or bottom of the window, Emacs scrolls the buffer and places point around the middle of the screen. Setting scroll-up-aggressively and scroll-down-aggressively to 0.01 keeps point near the edge of the screen instead:

;; Provide a "stick-to-edge" scrolling experience.
(setq-default scroll-up-aggressively 0.01
              scroll-down-aggressively 0.01)

This results in minimal, predictable scrolling increments.

Permitting scrolling during search

By default, attempting to scroll the window while in an active isearch session (using C-s or C-r) cancels the search. You can allow scrolling without losing your search context.

;; Allow scrolling actions while remaining inside a search block.
(setq isearch-allow-scroll 'unlimited)

This allows you to scroll away from your current match to check another part of the file for reference, and then resume your search by pressing C-s to jump to the next match.

Shell and compilation buffers

When executing long-running processes in interactive shells or REPLs (comint-mode), new output arriving at the bottom of the buffer will frequently scroll your view downward. Setting comint-scroll-to-bottom-on-input to t and comint-scroll-to-bottom-on-output to nil causes Emacs to snap point to the bottom of the buffer only when you supply keyboard input:

;; Auto-scroll to bottom only when you type, not when background output arrives.
(setq-default comint-scroll-to-bottom-on-input t
              comint-scroll-to-bottom-on-output nil)

This allows you to scroll up through compilation logs or terminal history to read errors without the screen aggressively jumping to the bottom every time a new line is printed.

The mouse wheel scrolling

The default mouse wheel behavior in Emacs can feel jumpy, as it scrolls multiple lines per click and accelerates based on scroll speed. You can easily modify this and assign modifier keys to perform horizontal scrolling or text scaling:

;; Scroll one line at a time and map modifier keys to specific actions.
(setq mouse-wheel-scroll-amount
      '(1
        ((shift) . hscroll) ((meta))
        ((control meta) . global-text-scale)
        ((control) . text-scale)))

;; Disable acceleration of scrolling.
(setq mouse-wheel-progressive-speed nil)

Setting mouse-wheel-scroll-amount to 1 configures the mouse wheel to scroll exactly one line vertically, while mapping modifier keys like Shift for horizontal scrolling and Control for text scaling turns your mouse into a navigation multi-tool. Paired with setting mouse-wheel-progressive-speed to nil, this prevents rapid wheel movements from dynamically accelerating the scroll distance.

The result is a predictable, line-by-line scrolling experience that stops you from losing your place, with the tradeoff being that navigating very long files with a physical scroll wheel requires more physical effort since the view will not jump in large increments.

Note: If you prefer a keyboard-driven workflow and want to disable mouse input entirely, check out the inhibit-mouse package.

Modern pixel-precise scrolling

Emacs 29 introduced pixel-precise scrolling for pointing devices that support suitable high-resolution scrolling events.

;; Enable pixel-precise scrolling for supported pointing devices.
(pixel-scroll-precision-mode 1)

;; (setq pixel-scroll-precision-use-momentum nil) ; Optional: disable momentum

Enabling pixel-scroll-precision-mode activates pixel-resolution scrolling for supported mouse and touchpad input, removing the traditional limitation of scrolling by whole text lines.