2

macOS hides scrollbars for trackpad users, which results in my users not knowing they can scroll a result set horizontally. I'm trying to use CSS to target the horizontal scrollbars only, so that I can make them permanently visible.

I'm able to override both scrollbar visual behavior with CSS:

::-webkit-scrollbar{
    -webkit-appearance: none;
    width: 7px;
}
::-webkit-scrollbar-thumb{
    border-radius: 4px;
    background-color: rgba(0,0,0,.5);
    box-shadow: 0 0 1px rgba(255,255,255,.5);
}

https://jsfiddle.net/ypk62h8v/1/

But when I try to apply the :horizontal pseudo-element, it doesn't work (Mac/Chrome):

HTML:

<div class="frame" style="">
    <div style="width:500px;height:500px;">
    SCROLLABLE
    </div>
</div>

CSS:

.frame {
    overflow-y: auto;
    overflow-x: auto;
    border: 1px solid black;
    height: 3em;
    width: 10em;
    line-height: 1em;
}

::-webkit-scrollbar:horizontal {
    -webkit-appearance: none;
    width: 7px;
}
::-webkit-scrollbar-thumb:horizontal {
    border-radius: 4px;
    background-color: rgba(0,0,0,.5);
    box-shadow: 0 0 1px rgba(255,255,255,.5);
}

https://jsfiddle.net/ypk62h8v/

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yarin
  • 173,523
  • 149
  • 402
  • 512
  • You are required to post a [mcve] here, **within your question**, and [not a link](https://meta.stackoverflow.com/a/254430/162698) to any other site. – Rob Aug 12 '23 at 00:55
  • added reproducable example – Yarin Aug 14 '23 at 14:19
  • If your goal is to make the scrollbars permanently visible, setting `overflow: scroll` instead of `overflow: auto` should accomplish that for you. Emphasis on should. I can't seem to get it to work on my MacBook with touchpad in any browser despite the docs here: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow#scroll – Zaqx Aug 16 '23 at 20:34
  • this might help https://stackoverflow.com/questions/46734299/macs-not-reliably-displaying-horizontal-scroll-bars – ac_mmi Aug 18 '23 at 16:42
  • The bounty probably attracted at least one [ChatGPT](https://meta.stackoverflow.com/questions/421831/temporary-policy-chatgpt-is-banned) plagiariser. – Peter Mortensen Aug 21 '23 at 15:22

5 Answers5

1

You are very close to doing what you want. Unfortunately there's no native way that I'm aware of to achieve exactly what you want. In order to style either of the scrollbars, you need to override the DOM, and tell the browser that you want to use custom styles.

After doing that, you can target the :horizontal class directly.

If this was my project, and I had a lot of containers overflowing horizontally, I would create a special container class, something like .horizontal-container which would override the DOM, and apply the styles to make sure the horizontal scroll bar is visible. It's bad UX to be able to scroll on both the X and Y axis (Unless it's like a Figma canvas style interaction), so I wouldn't be too worried about the vertical scroll not being visible.

Additionally

You could add a subtle animation like my second snippet to single to users that there is additionally content to the right.

.frame {
  border: 1px solid black;
  height: 5em;
  width: 15em;
  line-height: 1em;
  
  overflow: auto;
}

p {
  margin: 0;
}

/* You first need to target all scrollbars to override the DOM */
::-webkit-scrollbar {
    -webkit-appearance: auto;
}

/* Then you can target the :horizontal class on it's own */
::-webkit-scrollbar-thumb:horizontal {
    border-radius: 20px;
    background-color: rgba(255,0,0,.5);
    box-shadow: 0 0 1px rgba(255,255,255,.5);
}
<div class="frame" style="">
  <div style="width:500px;height:500px;">
    <p>SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, 
    </p> 
  </div>
</div>

Animation

This is more dramatic than what I'd actually do, but it's an example.

.frame {
  overflow-y: auto;
  overflow-x: auto;
  border: 1px solid black;
  height: 7em;
  width: 15em;
  line-height: 1em;
  position: relative;
}

.frame::after {
  content: "";
  height: 100%;
  width: 4rem;
  position: absolute;
  /* Turn this on to see the animation more clearly 
    background: red;
  */
  background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%);
  top: 0;
  left: calc(100% - 2rem);
  animation: bounce 4s infinite ease-in-out;
}

@keyframes bounce {
  0% {
    transform: translateX(-2rem);
  }
  50% {
    transform: translateX(2rem);
  }
    100% {
    transform: translateX(-2rem);
  }
}

p {
  margin: 0;
}
<div class="frame" style="">
  <div style="width:500px;height:500px;">
    <p>SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, SCROLLABLE, 
    </p> 
  </div>
</div>
tubstrr
  • 947
  • 2
  • 9
0

There's no direct CSS selector like :horizontal that you can use to specifically target horizontal scrollbars for customization in the same way you can target scrollbars without specifying orientation.

So, if you want to achieve this you should use following CSS and JavaScript Code:

// Add a class to the frame when the content overflows horizontally
const frame = document.querySelector('.frame');
const content = document.querySelector('.content');

frame.addEventListener('scroll', () => {
    if (content.scrollWidth > frame.offsetWidth) {
        frame.classList.add('has-horizontal-scroll');
    } else {
        frame.classList.remove('has-horizontal-scroll');
    }
});
.frame {
    overflow-y: auto;
    overflow-x: auto;
    border: 1px solid black;
    height: 3em;
    width: 10em;
    line-height: 1em;
}

.frame::-webkit-scrollbar {
    width: 7px;
    height: 7px;
}

.frame::-webkit-scrollbar-thumb {
    border-radius: 4px;
    background-color: rgba(0, 0, 0, .5);
    box-shadow: 0 0 1px rgba(255, 255, 255, .5);
}

.frame::-webkit-scrollbar-thumb:vertical {
    background-color: rgba(0, 0, 0, .5); /* Adjust vertical scrollbar appearance */
}


.frame.has-horizontal-scroll::-webkit-scrollbar-thumb:horizontal {
    background-color: rgba(0, 0, 0, .5); /* Adjust horizontal scrollbar appearance */
}
<div class="frame" style="">
    <div class="content" style="width:500px;height:500px;">
        SCROLLABLE
    </div>
</div>
Rai Hassan
  • 599
  • 1
  • 12
  • You could reserve space by adding scrollbar-gutter: stable; to your frame's css along with scrollbar-width and scrollbar-color. This would indicate to the user that there's a scrollbar. – SoftwareDveloper Aug 17 '23 at 18:13
0

Use overflow: scroll instead of overflow: auto

0

Your code is well set up and working properly You just removed the ':horizontal' and .frame classes in the overflow-y: auto-hidden change; So that all those devices work.

.frame {
    overflow-y: hidden; // change auto to hidden
}

::-webkit-scrollbar{
    -webkit-appearance: none;
    width: 7px;
}
::-webkit-scrollbar-thumb{
    border-radius: 4px;
    background-color: rgba(0,0,0,.5);
    box-shadow: 0 0 1px rgba(255,255,255,.5);
}
Yash Borda
  • 88
  • 7
-5

I understand that you're trying to target the horizontal scrollbar specifically using the :horizontal pseudo-element. Unfortunately, as of my knowledge the :horizontal and :vertical pseudo-elements are not supported in webkit-based browsers like Chrome and Safari.

However, you can still achieve your goal of making the horizontal scrollbar permanently visible by targeting the entire scrollbar area and thumb without using the :horizontal pseudo-element. Here's how you can modify your CSS to achieve that:

/* Apply styles to the entire scrollbar area */
::-webkit-scrollbar {
    -webkit-appearance: none;
    width: 7px;
    background-color: rgba(0,0,0,.2); /* Set background color */
}

/* Apply styles to the scrollbar thumb */
::-webkit-scrollbar-thumb {
    border-radius: 4px;
    background-color: rgba(0,0,0,.5);
    box-shadow: 0 0 1px rgba(255,255,255,.5);
}

This will target both horizontal and vertical scrollbars, but it will still make the horizontal scrollbar visible. Unfortunately, there's no direct pseudo-element targeting for horizontal scrollbars alone in webkit-based browsers.

To make the horizontal scrollbar permanently visible for a specific element using JavaScript, you can follow these steps:

// Get the element with class "frame"
const frame = document.querySelector('.frame');

// Add a scroll event listener to the frame
frame.addEventListener('scroll', () => {
    // Check if the current scroll position is at the maximum horizontal scroll
    const isAtMaxScroll = frame.scrollLeft === frame.scrollWidth - frame.clientWidth;

    // If at maximum scroll, apply the custom style to the scrollbar
    if (isAtMaxScroll) {
        frame.style.overflowX = 'scroll';  // Display the horizontal scrollbar
        frame.style.overflowY = 'auto';    // Display the vertical scrollbar
    } else {
        frame.style.overflowX = 'auto';    // Hide the horizontal scrollbar
    }
});
.frame {
    overflow-y: auto;
    overflow-x: auto;
    border: 1px solid black;
    height: 3em;
    width: 10em;
    line-height: 1em;
}

.content {
    width: 500px;
    height: 500px;
}
<div class="frame">
    <div class="content">
        SCROLLABLE
    </div>
</div>
Mohamad
  • 602
  • 2
  • 5
  • 18