Smooth Scrolling and Find In Page, a not so Smooth Combination …

There was this interesting Twitter conversation last week between Chris Coyier and Schepp last week. Apparently if you have Smooth Scrolling enabled, it also affects the behavior of Find in Page in Chrome: Whenever you want to go to the next result it will smooth scroll, instead of jump to it.

Schepp chimed in and offered the solution: leverage the :focus-within pseudo-class selector so that it’s only applied when the html has focus.

Combine it with prefers-reduced-motion and you’ll end up with this:

@media(prefers-reduced-motion: no-preference) {
    html:focus-within {
        scroll-behavior: smooth;
    }
}

There’s on nasty side-effect though: in-page jump links that refer to the id of an element will no longer work. You’ll actually need to sprinkle some <a name="…">#</a> elements over your markup to make those work smoothly …

Fixing Smooth Scrolling & Page Search →
Chromium Bug #866694 →

Overflow In CSS

Ahmad Shadeed is at it again(*), this time with a guide on Overflow in CSS:

In CSS, we can have control over an element when its content is too big to fit in. The property for that is overflow, which is a shorthand for overflow-x and overflow-y properties.

For this article, I will give an introduction to those properties, and then we will dive together into some concepts and use-cases that are related to overflow. Are you ready? Let’s dive in!

Overflow In CSS →

💁‍♂️ Again? Check out his guide on Viewport Units which also was amazingly detailed and complete.

Indicating Scroll Position on a Page With CSS

Scroll-based features tend to involve some bespoke concoction of CSS and JavaScript. But what if we could accomplish something that only uses CSS?

Take this ingenious horizontal scrollbar with CSS, for instance. I want to do something similar, but to indicate scrolled sections rather than capture continuous scrolling. In other words, rather than increasing the length of the indicator during scroll, I only want to increase the length when a certain section of the page has been reached.

Here’s a demo showing the end result: the scroll indicator does not update continuously but is stepped.

See the Pen CSS Scrolled Sections Indicator by Preethi Sam (@rpsthecoder) on CodePen.

The technique involved uses position: sticky; and some positioning applied on each “passageStop” (one per step).

Indicating Scroll Position on a Page With CSS →

Full Page Scroll-Snapping HTML Sections

Just some goofing around with Full Page Sections and Scroll Snapping:

[CODEPEN DEMO]

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Prevent content from being hidden underneath a fixed header by using scroll-margin-top

If you’ve ever implemented a design with a fixed header, you’ve surely had this problem:

You click a jump link like <a href="#header-3">Jump</a> which links to something like <h3 id="header-3">Header</h3>. That's totally fine, until you have a position: fixed; header at the top of the page obscuring the h3 you're trying to link to!

Fixed headers have a nasty habit of hiding the element you’re trying to link to.

Thankfully Chris Coyier from CSS-Tricks found and shared the straightforward solution:

h3 {
  scroll-margin-top: 5rem; /* whatever is a nice number that gets you past the header */
}

🐛 As noted in the comments below this doesn’t work Safari. In that browser you’ll need to use scroll-snap-margin-top. All other modern browsers do have excellent support for scroll-margin-top and play nice.

~

To not have to apply the CSS rule to too many elements, I’d adjust the snippet to use the :target selector.

The :target CSS pseudo-class represents a unique element (the target element) with an id matching the URL’s fragment.

That way it will work with any internally linked thing (headers in all their sizes, anchors, etc):

:target {
  scroll-margin-top: 5rem;
}

It was also nice to see that Mattias Geniar used this solution when implementing the Smooth Scrolling Sticky Navigation I wrote about earlier (Mattias is using scroll-padding-top though).

Fixed Headers and Jump Links? The solution is scroll-margin-top

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Pure CSS Scroll Shadows (Vertical + Horizontal)

A long time ago (2012!), Lea Verou shared a way on how to add scrolling shadows to containers that needs scrolling. Using those shadows in a scroll container is a great UX thing, as they visually tell the user that the content is scrollable.

Her code however, only worked with containers that scroll vertically. Based upon Lea’s code I created a version that also plays nice with horizontal scroll containers.

Whilst I was at it, I also introduced CSS Custom Properties, as they allow easy theming. Using the “CSS Variables” --background-color, --shadow-color, and --shadow-size you can configure the result.

Hope you like it 🙂

🐛🍏 A note on MobileSafari (iOS)

Out of the box this technique unfortunately does not play that nice on iOS: MobileSafari does not seem to re-render the backgrounds during scroll. I did notice however that it will correctly re-render after manually zooming in and out on the page. This is detailed in Webkit Bug 181048.

In said bug report a solution to the problem is mentioned:

I’ve discovered that updating a CSS variable on a -webkit-overflow-scrolling: touch; element when it’s scrolled causes it to repaint correctly.

With a little bit of JavaScript we can trigger exactly this:

// Fix for Mobile Safari that doesn't correctly re-render backgrounds during scroll
// @ref https://bugs.webkit.org/show_bug.cgi?id=181048
if (CSS.supports("-webkit-overflow-scrolling: touch")) {
  document.querySelectorAll(".scrollcontainer").forEach((scroller) => {
    scroller.addEventListener("scroll", () => {
      scroller.style.setProperty("--force-paint", Date.now());
    });
  });
}
Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

React Native Parallax Scroll Header with Tabs

Nice writeup on how to create a typical screen where there’s a header image that fades out and disappears as you start scrolling.

Essentially, everything but the header is put into a scrollview. In order to keep elements ‘fixed’ (i.e. the tab bar), I use the transform property with a translateY that is set to the scrollview’s current scroll position. Since animating transform properties is supported natively, all animations run at 60fps.

React Native Parallax Scroll with Tabs →

Scroll to the future – CSS and JavaScript features that make navigating around a single page smooth, beautiful and less resource-hungry.

Very in-depth article on Evil Martians’ team blog on scrolling:

We have scrolled to the bottom of modern web specifications to take you on a whirlwind tour of latest CSS and JavaScript features that make navigating around a single page smooth, beautiful and less resource-hungry.

Subjects tackled are styling of scrollbars, position: sticky, IntersectionObserver, Smooth Scrolling, the overscroll-behavior property, etc.

I especially like this part of the closing notes (next to the plea for Progressive Enhancement):

Maybe even now, while you were scrolling through this article, another browser has shipped support for a property that will make your life easier, and your bundle size smaller.

Scroll to the future →

Customizing Pull-to-Refresh and Overflow Effects with CSS’ overscroll-behavior

Next to dynamic imports, another feature that landed in Chrome 63 is CSS overscroll-behavior:

Scrolling is one of the most fundamental ways to interact with a page, but certain patterns can be tricky to deal with. For example, the browsers pull to refresh feature, where swiping down at the top of the page, does a hard reload.

In some cases, you might want to override that behavior and provide your own experience.

The CSS overscroll-behavior property allows you to do just that: override the default scroll behavior. With it you can prevent a full reload when a pull-to-refresh gesture is performed (and inject your own logic), disable rubber banding (no more for need this nasty hack), etc.

Another typical use case is one where you have a scrollable piece of content that is layed out above another scrollable piece of content – yes: a modal. The default behavior is that when reaching the scroll boundary of the modal, the content underneath it starts to scroll:

Setting overscroll-behavior: contain; on the modal will prevent this default behavior, resulting in a better experience :

overscroll-behavior is available in the new Chrome 63 and in Firefox (ever since version 36!). Other browsers currently don’t support this.

Here’s a pen:

See the Pen
overscroll-behavior: contain
by Aaron Iker (@aaroniker)
on CodePen.

Take control of your scroll: customizing pull-to-refresh and overflow effects →

Sticky Sidebar

Sticky Sidebar ⬆⬇ is a pure JavaScript plugin for making smart and high performance sticky sidebar, works with sidebar if it’s taller or shorter than the viewport, integrated with resize sensor to re-calculate the dimensions automatically when the size of sidebar or its container is changed, supports jQuery/Zepto and compatible with Firefox, Chrome, Safari, and IE9+.

<div id="main-content" class="main">
    <div id="sidebar" class="sidebar">
        <div class="sidebar__inner">
            <!-- Content goes here -->
        </div>
    </div>
    <div id="content" class="content">
        <!-- Content goes here -->
    </div>
</div>

<script type="text/javascript">
    var sidebar = new StickySidebar('#sidebar', {
        containerSelector: '#main-content',
        innerWrapperSelector: '.sidebar__inner',
        topSpacing: 20,
        bottomSpacing: 20
    });
</script>

Sticky Sidebar →