Hiding Vertical Scrollbars with Pure CSS in Chrome, IE (6+), Firefox, Opera, and Safari


I just spent the past day trying to figure out the best way to hide scrollbars using pure CSS in the latest versions of every browser.  I wanted to be able to still scroll within the element, however, so using:

.element { overflow: hidden; }

 was not an option.  I looked at how Facebook hides their scrollbars in the chat window, I looked at recommendations made on StackOverflow, and I invented a lot of solutions on my own.  Eventually, I arrived at a solution that I like.

 

So first, a little background... my preliminary research revealed the following:

  • There is a CSS rule that can hide scrollbars in Webkit-based browsers (Chrome and Safari).  That rule is: 
    .element::-webkit-scrollbar { width: 0 !important }
  • There is a CSS rule that can hide scrollbars in IE 10+.  That rule is: 
    .element { -ms-overflow-style: none; }
  • There used to be a CSS rule that could hide scrollbars in Firefox, but it has since been deprecated.  That rule was: 
    .element { overflow: -moz-scrollbars-none; }

 

The StackOverflow-recommended approach was to give my element scrollbars, wrap it in a

containing element, and make the containing element element smaller, and give it:

overflow: hidden;

 

This is the approach Facebook uses for their chat window. However, there are two problems with

this approach:

  1. We have to hard-code in the width of a scrollbar, but this width can vary from browser to browser
  2. In Webkit browsers like Chrome and Safari, if we highlight text and drag to the right, it scrolls the inner element to the left and the scrollbars are revealed
See this screenshot from Facebook, after I clicked and dragged to the right:

 

I searched StackOverflow to see if there were any fixes to the clicking and dragging issue.  I found a JavaScript solution that seemed to work, but it was kind of hacky.  Essentially, you bind to the scroll event for your element and set the scrollLeft to 0 every time the scroll event fires.  That seems to work, but if the browser lags at all, it can look glitchy.  I continued searching for a better solution.

One solution I found recommended setting:

.element:active { pointer-events: none; }

That prevented Webkit users from scrolling to the right when clicking and dragging to the right on text, but it also prevented them from scrolling down when clicking and dragging down on the text.  Clearly that wouldn't be a good solution.

 

Then I thought: what if instead of covering the scrollbars with a containing element, I used an ::after element to just put a white box overtop of the scrollbar?  That seemed to work, but it required that I knew how wide the scrollbar was.  After a little tweaking, I found a way to create an element that was just as wide as a scrollbar and covered the existing scrollbar.  Essentially, what I did was create an element that was nothing but a vertical scrollbar.  Then I put an ::after element on that that covered it with a solid color.  Finally, I moved the whole piece overtop of the existing scrollbar.  This method was pretty simple, but it still left a lot to be desired.  What if I didn't want the extra white space to the right of my scrollable element?  I continued searching for a better solution...

 

Next, I tried to see if there would be some hacky way to hide scrollbars in Firefox.  I could already hide them in Chrome, Safari, and IE, so Firefox was the last remaining puzzle piece.  I stumbled upon the -moz-appearance CSS property and tried a number of options.  One thing that almost worked was:

.element { -moz-appearance: menuimage; }

This removed the scrollbars from the element, but unfortunately, it also restricted the width and height of my element.  I couldn't find any way to change the size.  After many hours, I gave up on hiding scrollbars in Firefox.

 

Then another idea came to mind.  What if the used the transform property of CSS to mess with the scrollbars somehow?  The transform property affects everything in the element, including the scrollbars!  I decided that the scale option would be my best bet.  What I ended up doing was scaling the x axis of the scrollbar element by a factor of about 0.001.  This made the scrollbar so thin that it disappeared.  Then, I wrapped the text content in another element and scaled the x axis of that element by a factor of 1000.  That seemed to work!  However, text highlighting was glitchy in Firefox with this approach.

 

I then thought of another idea that involved using transform.  What if I mirrored the element with the scrollbar, and then mirrored the text inside?  That would put the scrollbar on the left instead of the right.  I did that, and then I gave the element with the scrollbar a negative margin of 17px (the width of my scrollbar).  The scrollbar disappeared since it went outside the region of the containing element (which had overflow: hidden;).  As an added bonus, when I highlighted text in Webkit and dragged to the left, the scrollbar didn't scroll into view!  Unfortunately, this solution required me to know exactly how wide the scrollbar was.  I was looking for a solution that didn't require me to hardcode the width of the scrollbar.

 

Then, I found that I could set position: absolute; and right: 0; and it would move the scrollbar out of view without having to know the width.  That solution worked well in all browsers but IE.  For some reason, when the scrollbar gets reversed, IE removes the margin between the text and the scrollbar.  What ended up happening was that the left side of the text was getting chopped off.  So then I added a Webkit-specific rule to reverse the scrollbars only when the user was using a Webkit browser.  This solution worked in all browsers and can be seen here.

 

But then I got to thinking... wait a minute, why not just hide the scrollbar for Webkit browsers and use the overflow: hidden; solution for all other browsers?  But of course!  How simple!   I did make some changes to the original overflow: hidden; solution, however.  I set the desired width on both the element that contains the text and the outermost container.  Then I set position: absolute; and left: 0; on the text element so that the scrollbar would be out of view.  This approach doesn't need to know the width of the scrollbar ahead of time in order to work.  That solution works for all browsers too, and can be seen here.

 

And here is the full code:

HTML

<div class="outer-container">
<div class="inner-container">
<div class="element">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Integer vehicula quam nibh, eu tristique tellus dignissim
quis. Integer condimentum ultrices elit ut mattis.
Praesent rhoncus tortor metus, nec pellentesque enim
mattis nec. Nulla vitae turpis ut dui consectetur
pellentesque quis vel est. Curabitur rutrum, mauris ut
mollis lobortis, sem est congue lectus, ut sodales nunc
leo a libero. Cras quis sapien in mi fringilla tempus
condimentum quis velit. Aliquam id aliquam arcu. Morbi
tristique aliquam rutrum. Duis tincidunt, orci suscipit
cursus molestie, purus nisi pharetra dui, tempor
dignissim felis turpis in mi. Vivamus ullamcorper arcu
sit amet mauris egestas egestas. Vestibulum turpis neque,
condimentum a tincidunt quis, molestie vel justo. Sed
molestie nunc dapibus arcu feugiat, ut sollicitudin metus
sagittis. Aliquam a volutpat sem. Quisque id magna
ultrices, lobortis dui eget, pretium libero. Curabitur
aliquam in ante eu ultricies.

Quisque vitae tincidunt purus. Vivamus feugiat bibendum
erat, nec interdum urna porta sed. Nunc lobortis neque
orci, ut suscipit nisl congue feugiat. Vivamus feugiat
tellus quis cursus sollicitudin. Curabitur dolor massa,
dictum ut ipsum in, porttitor pellentesque ante. Aenean
egestas cursus tempor. Maecenas semper tortor sit amet
egestas cursus. Mauris porttitor quis nisi ut tincidunt.
Curabitur adipiscing eleifend nibh. Praesent mauris leo,
consequat vitae orci eget, vestibulum bibendum nisi.
Aliquam tempus diam ut tortor cursus, eget sodales augue
adipiscing. Nulla at dignissim libero.
</div>
</div>
</div>

 

CSS

.element, .outer-container {
width: 200px;
height: 200px;
}

.outer-container {
border: 5px solid purple;
position: relative;
overflow: hidden;
}

.inner-container {
position: absolute;
left: 0;
overflow-x: hidden;
overflow-y: scroll;
}

.inner-container::-webkit-scrollbar {
display: none;
}

 

I hope this helps someone!  Enjoy 🙂


Comments (35)

  1. mani says:

    excellent!

    still I don't understand why other browsers don't support hiding scrollbars in times of touch screens!

  2. Max says:

    really really good

  3. Martin says:

    This does not seem to work with ie 8. Is this a fact or a problem with my code

  4. Alessandro Vendruscolo says:

    Firefox 28 on Mac OS still shows the vertical scrollbar.

  5. Rans says:

    Obrigado!

  6. Juan says:

    It worked by the book!!! Thank you so much John.

  7. Will says:

    This works perfectly with everything but Firefox (29.0.1)! I've been looking for this solution for hours. Thanks John! Checkout http://www.wegopheryou.com using FireFox and you'll see it's not working with that. Maybe another workaround for FireFox?

  8. arcei says:

    @martin you shouldn't use hidden scrollbars it if they don't work on ie8.

  9. bob says:

    Excellent write up. I like how you outlined the process, including attempts that didn't work out.

  10. Rodney Espinoza says:

    Muchas gracias saludos desde Costa Rica, viva la sele!!

  11. Sarah R says:

    Thank you! You saved me several hours of work. In my case the "outer-container"  in in a container fixed to the page and its width is a percentage. In this case I found that I did not need to set the width of these containers except on the element container where I added 101% to hide the scrollbar. I also had issues with the inner container collapsing and had to add a height to it (same as outer-container and element)

  12. Seth W. Klein says:

    I can't find a reason to include left: 0.

  13. Morteza says:

    Excellent

    Thank you 🙂

  14. Dess says:

    Hi! I just wonder, what if my div height is responsive. I mean it depends on the screen and I assigned it like: height: calc(100% – 120px); The scroll bar won't function. How do I solve this?

  15. Markus says:

    Thanks John !!! works great here 🙂

  16. -moz-scrollbars-none says:

    This still seems to work even in the newest firefox. I am a developer of css styles and I've never seen this really changed. I've always been able to use:

    * { overflow: -moz-scrollbars-none !important; }

    To hide the scollbars, but still allow scrolling

    As far as I know, the only problem with it, is in linux, you cannot use your scroll wheel when there is no scroll bar, which is ok for me because I use the middle button to go into scroll mode — however — this may annoy others which makes it a broken "feature". at least for the linux versions I've used.  I have used this in windows however with no problems.

  17. John Kurlak says:

    @Martin I just tested it in IE8 and it worked.

  18. John Kurlak says:

    @-moz-scrollbars-none If you go to developer.mozilla.org/…/overflow and look at the Mozilla Extensions section, it says that "-moz-scrollbars-none" is "an obsolete API and is no longer guaranteed to work."  Better to go with an approach that is more stable.

  19. Firefox says:

    As someone already said, still showing scrollbars in Firefox on Mac

  20. 3rfan says:

    You are a genius sir. Your great article helped me so much!

  21. Seth W. Klein says:

    I've done more research into browser support in a post on Stack Overflow at stackoverflow.com/…/26087052 .

  22. mary says:

    how to make the horizontal scroll bar visible to scroll to the right

  23. Kanaga says:

    Thank u..very nice.

  24. Alex says:

    Thanks for the hot tip! Worked like a charm.

  25. Tom says:

    Doesn't work for with:100%, does it?

  26. Syed umair shah says:

    please provide a solution for scroll design on all browsers

  27. mygzi says:

    As @Tom said, doesn't appear to work when width is set to 100% vs. fixed pixel dimension. Scroll bar still shows.

  28. trinione says:

    For IE 10+ I added the '-ms-overflow-style' property as in:

    .inner-container {

    position: absolute;

    left: 0;

    overflow-x: hidden;

    overflow-y: scroll;

    -ms-overflow-style: none;

    }

  29. Anonymous says:

    Amazing! I really appreciate it!

  30. Anonymous says:

    What If I want to scroll the content using mouse scroll? Is there any way to do this?

  31. Anonymous says:

    not work with Opera ,what the css for it?

  32. Anonymous says:

    Works so well! I can finally go to sleep now. MUCH GRATITUDE!!!

  33. Dan says:

    awesome job

Skip to main content