
📜 Scroll block in CSS and jQuery: fixed height with scrolling
Wall-of-text SEO blocks, half-screen comments, admin logs, and 30-column tables all break the layout and force readers to scroll endlessly. Sound familiar? There's a solution, and it's embarrassingly simple: a block with fixed height and internal scroll.
When I first started building layouts, I'd shove content into overflow: hidden and pray nobody would notice the cut-off text. Then I discovered scroll blocks, and it changed everything: clients' SEO texts became neat, pages stopped bloating on mobile, and neighboring scripts no longer conflicted.
Below are two working approaches: pure CSS (for most tasks) and a jQuery wrapper (for custom scenarios). Both are battle-tested on dozens of projects, work correctly on mobile devices, and don't interfere with neighboring scripts.
💡 Quick overview:
- Wrap content in a
<div>with classesscroll-blockandscroll-content - Set
max-height+overflow-y: autoin CSS, scroll block is ready - Connect the jQuery plugin from the article for auto-scroll, animation, and events
- Style the scrollbar via
::-webkit-scrollbarto match your site's design
What is a scroll block and where you actually need it
A scroll block is a container with fixed height whose content scrolls internally, independent of the page's main scroll. The browser adds a scrollbar automatically when content exceeds the set height.
Where I constantly apply this solution:
- SEO texts. The client wants a 3,000-word wall in the middle of a landing page, I wrap it in a scroll block, the page doesn't turn into an endless canvas.
- Comments and logs. Long discussion threads or debug logs in the admin panel, fixed height saves the interface from sprawling.
- Data tables. Horizontal scroll for tables is classic, but vertical scroll on a table with 50+ rows solves the problem just as well.
- Chat widgets and notifications. A chat window with message history, same scroll block, just with auto-scroll to the last message.
Technically everything relies on two CSS properties: max-height (or height) and overflow-y. But the devil is in the details: mobile browsers, nested containers, conflicts with position: fixed, and iOS Safari peculiarities require a careful approach.
Check out this short tutorial on the overflow property, it clearly shows all scroll modes and their behavior:
CSS solution: fast and without JavaScript
For the vast majority of cases, JavaScript isn't needed. Three lines of CSS are enough:
1 .scroll-block { 2 max-height: 320px; 3 overflow-y: auto; 4 border: 1px solid #e0e0e0; 5 padding: 16px; 6 }
Breaking it down. max-height sets the ceiling, the block won't grow taller than 320px but can be shorter if there's less content. overflow-y: auto tells the browser: "show the scrollbar only when content overflows the container." Border and padding are optional, but without padding text sticks to the scrollbar and looks cheap.
HTML stays semantically clean:
1 <div class="scroll-block"> 2 <p>Your long SEO text, logs, table, or whatever.</p> 3 </div>
This solution works identically in Chrome, Firefox, Safari, and Edge, the overflow specification has been stable since CSS2 and is supported by all modern browsers. On mobile devices, scroll inside the block doesn't conflict with the page's main scroll (unlike clever JavaScript solutions from the 2010s that caught touchmove and often broke scrolling).
But there's a nuance with iOS Safari: by default, scroll inside the block is "inelastic," there's no native rubber-band effect. If you need smooth inertial scroll like the main content, add:
1 .scroll-block { 2 -webkit-overflow-scrolling: touch; 3 }
The property -webkit-overflow-scrolling: touch enables native momentum scroll on iOS. Note: with iOS 13, Apple made this the default behavior for overflow: auto, so for recent versions the prefix is optional. But if the project supports old iPads, keep it.
jQuery solution: when you need full control
The CSS method solves most tasks. The remaining cases are when you need programmatic scroll to bottom (chat), custom events when reaching block boundaries, or scroll animation via button. This is where jQuery comes in.
Here's a ready plugin, minimal, no dependencies except jQuery itself, tested on projects with modern WordPress versions and doesn't conflict with other theme scripts:
1 (function($) { 2 $.fn.scrollBlock = function(options) { 3 var settings = $.extend({ 4 maxHeight: 320, 5 autoScroll: false, 6 scrollSpeed: 400, 7 onTopReached: null, 8 onBottomReached: null 9 }, options); 10 11 return this.each(function() { 12 var $block = $(this); 13 14 $block.css({ 15 'max-height': settings.maxHeight + 'px', 16 'overflow-y': 'auto' 17 }); 18 19 if (settings.autoScroll) { 20 $block.animate({ 21 scrollTop: $block[0].scrollHeight 22 }, settings.scrollSpeed); 23 } 24 25 $block.on('scroll', function() { 26 var scrollTop = $block.scrollTop(); 27 var maxScroll = $block[0].scrollHeight - $block.outerHeight(); 28 29 if (scrollTop <= 0 && settings.onTopReached) { 30 settings.onTopReached.call(this); 31 } 32 if (scrollTop >= maxScroll && settings.onBottomReached) { 33 settings.onBottomReached.call(this); 34 } 35 }); 36 }); 37 }; 38 })(jQuery);
Where to launch it: your script (separate theme JS file or <script> section in the footer). Include after jQuery:
1 $(document).ready(function() { 2 $('.scroll-content').scrollBlock({ 3 maxHeight: 400, 4 autoScroll: true, 5 scrollSpeed: 600, 6 onBottomReached: function() { 7 console.log('Reached bottom of block'); 8 } 9 }); 10 });
What's happening here: the plugin takes a selector, applies a CSS height limit, optionally scrolls the block to bottom, and tracks reaching top/bottom boundaries via callbacks. No magic, just a wrapper over standard jQuery methods .css(), .animate(), and the scroll event.
Use this solution when: a) you need to auto-scroll chat to the last message, b) smooth scroll animation via external "Down"/"Up" button is required, c) you need to attach analytics to the "user read to the end" event.
Multiple blocks on one page
Scenario: three scroll blocks with different content on the page. If you set one class .scroll-block without unique identifiers, everything works, CSS applies to all at once. But as soon as each block needs its own height, welcome to the world of IDs.
CSS for multiple blocks with different heights:
1 #seo-text-block { 2 max-height: 320px; 3 overflow-y: auto; 4 } 5 6 #changelog-block { 7 max-height: 480px; 8 overflow-y: auto; 9 } 10 11 #comments-block { 12 max-height: 600px; 13 overflow-y: auto; 14 }
HTML:
1 <div id="seo-text-block" class="scroll-block"> 2 <!-- Long SEO text --> 3 </div> 4 5 <div id="changelog-block" class="scroll-block"> 6 <!-- Changelog list --> 7 </div>
With the jQuery plugin, same logic: initialize each block separately with its own settings:
1 $('#seo-text-block').scrollBlock({ maxHeight: 320 }); 2 $('#changelog-block').scrollBlock({ maxHeight: 480, autoScroll: true }); 3 $('#comments-block').scrollBlock({ maxHeight: 600, autoScroll: true, scrollSpeed: 300 });
If there are many blocks (10+) and all identical, a common class is enough. If different, IDs plus individual settings. No magic with nth-child or manual iteration, CSS selectors handle this out of the box.
Styling the scrollbar: so it doesn't look like 2007
The default browser scrollbar is a gray rectangle from the Windows XP era. Two minutes of CSS, and it fits your design:
1 .scroll-block::-webkit-scrollbar { 2 width: 6px; 3 } 4 5 .scroll-block::-webkit-scrollbar-track { 6 background: #f1f1f1; 7 border-radius: 3px; 8 } 9 10 .scroll-block::-webkit-scrollbar-thumb { 11 background: #c1c1c1; 12 border-radius: 3px; 13 } 14 15 .scroll-block::-webkit-scrollbar-thumb:hover { 16 background: #a1a1a1; 17 }
Important: ::-webkit-scrollbar pseudo-elements work in Chrome, Edge, Safari, and Opera, covering the vast majority of users. Firefox uses separate properties scrollbar-width: thin and scrollbar-color, but you can't globally style the scrollbar in Firefox at the element level (only page-wide). For Firefox, this is enough:
1 html { 2 scrollbar-width: thin; 3 scrollbar-color: #c1c1c1 #f1f1f1; 4 }
Don't overdo scrollbar width: 4-8px is the optimal range. Thinner than 4px, users won't hit it with their finger on mobile. Thicker than 8px, the scrollbar starts drawing too much attention.
⁉️🤔 Frequently asked questions
Does the scroll block work on mobile devices?
Yes, and without hacks. The CSS property
overflow-y: autois natively supported by iOS Safari and Chrome for Android. The block's internal scroll doesn't conflict with the page's main scroll, the browser determines which container to scroll based on finger position. Only nuance: on old iOS (before 13), add-webkit-overflow-scrolling: touchfor inertial scroll.
Can you use a scroll block inside a Flexbox or Grid container?
You can. The scroll block needs fixed height, set it via
max-heightin pixels or viaflex-basis/grid-rowwith an absolute value. Don't use percentage height inside a flex child without explicit height on the parent, the browser can't calculate the base for overflow computation, and scroll won't appear.
How to make smooth scroll of the block to bottom without jQuery?
In pure JavaScript:
element.scrollTo({ top: element.scrollHeight, behavior: 'smooth' }). ThescrollTomethod withbehavior: 'smooth'option is supported by all modern browsers. For chat auto-scroll, call this line after adding each new message.
Does the scroll block conflict with other scripts on the page?
CSS solution, no. These are native browser properties, they work in isolation. The jQuery plugin from the article uses its own namespace
$.fn.scrollBlockand doesn't touch global variables, so conflicts are ruled out. Tested on sites with 20+ active plugins, no problems arose.
Can you animate the appearance of a scroll block?
Yes. Add
max-height: 0andoverflow: hiddenin the initial state, then animate to target height. When animation completes, switchoverflowtoauto. In jQuery this is done via.animate({ 'max-height': '320px' }, 500, function() { $(this).css('overflow-y', 'auto') }). In pure CSS, viatransition: max-height 0.5s ease.
jQuery or CSS: what to use in 2026
The CSS solution covers the vast majority of scenarios and weighs zero kilobytes. If you just need a neat block with internal scroll, take it and don't overcomplicate.
The jQuery plugin is justified when: you're building a chat with auto-scroll, attaching analytics to scroll events, or animating scroll via an external button. In other cases, the jQuery wrapper is an excessive solution that adds a library dependency for three lines of CSS.
Try the CSS variant right now: copy three lines of styles, wrap test content in <div class="scroll-block">, and open the page on your phone. You'll see results in a minute, without npm install, without bundlers, without pain.



