Rounded scrollbar that hovers over content

Viewed 189

I have this scrollbar that has a width of 7px and hovers over the content of the container with opacity so that content can be seen under the scrollbar. The scrollbar should appear to be 7px from the right of the container, which is important. See https://codesandbox.io/s/gallant-kapitsa-igb6p?file=/style.css

I want the scrollbar to have rounded edges. Specifically I would put a border radius of 20px if it were a regular div. But the trouble is that I am using the border-right property to achieve the hover affect, which makes rounding the edges tricky. How can I accomplish this?

4 Answers

.list {
  position: relative;
  display: flex;
  max-height: 200px;
  max-width: 200px;
  flex-direction: column;
  overflow-y: overlay;
  border: 1px solid black;
}

.list::-webkit-scrollbar {
  width: 22px;
}

.list::-webkit-scrollbar-track {
  width: 20px;
}

.list::-webkit-scrollbar-thumb {
  height: 73px;
  width: 24px;
  background-clip: padding-box;
  background-color: rgba(0, 0, 0, 0.25);
  border-radius: 15px;
  border: 8px solid rgba(0, 0, 0, 0);
}

.list::-webkit-scrollbar-corner {
  background-color: transparent;
}


.list::-webkit-scrollbar-corner {
  background-color: transparent;
}
<ul class="list">
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    <li>item 4</li>
    <li>item 5</li>
    <li>item 6</li>
    <li>item 7 is pretty long so it goes under</li>
    <li>item 8</li>
    <li>item 9</li>
    <li>item 10</li>
    <li>item 11</li>
    <li>item 12</li>
    <li>item 13</li>
    <li>item 14</li>
    <li>item 15</li>
    <li>item 16</li>
    <li>item 17</li>
  </ul>

In your example you are already modifying the scrollbar, so any CSS will only apply to the scrollbar.

So in the .list::-webkit-scrollbar-thumb block, I'd replace

border-right: 7px solid transparent;

with

border-radius: 7px;

and if you want it slimmer, in the .list::-webkit-scrollbar block, just change the width to 7px;

EDIT:

So you want a gap between the border and the scrollbar. There's no real practical way to do this; browsers will always push the scrollbar to the edge of the screen. It's better for usability. But to achieve the effect you want, you can do this with a pseudo element of sorts. Wrap your list in a container, and give the container a padding. This will make it look like your scrollbar is "hovering" away from the edge.

See example below:

.list {
  position: relative;
  display: flex;
  max-height: 200px;
  max-width: 200px;
  flex-direction: column;
  overflow-y: overlay;
  /* border: 1px solid black; */
}

.pseudogap {
  padding-right: 10px;
  max-width: 210px;
  border: 1px solid black;
}

.list::-webkit-scrollbar {
  width: 7px;
  left: 20px;
}

.list::-webkit-scrollbar-thumb {
  height: 73px;
  /* border-right: 7px solid transparent; */
  border-radius: 7px;
  background-clip: padding-box;
  background-color: rgba(0, 0, 0, 0.25);
}

.list::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

.list::-webkit-scrollbar-corner {
  background-color: transparent;
}
<div class="pseudogap">
  <ul class="list">
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    <li>item 4</li>
    <li>item 5</li>
    <li>item 6</li>
    <li>item 7 is pretty long so it goes under</li>
    <li>item 8</li>
    <li>item 9</li>
    <li>item 10</li>
    <li>item 11</li>
    <li>item 12</li>
    <li>item 13</li>
    <li>item 14</li>
    <li>item 15</li>
    <li>item 16</li>
    <li>item 17</li>
  </ul>
</div>

Using svg as background:

.list {
  position: relative;
  display: flex;
  max-height: 200px;
  max-width: 200px;
  flex-direction: column;
  overflow-y: overlay;
  border: 1px solid black;
}

.list::-webkit-scrollbar {
  width: 14px;
}

.list::-webkit-scrollbar-thumb {
  height: 73px;
  background-clip: padding-box;
  border-right: 7px solid transparent;
  background: 0 0 / 100% 100% no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='7' height='100%'><rect fill='rgb(0,0,0)' fill-opacity='0.2' x='0' y='0' rx='7px' ry='7px' width='100%' height='100%'/></svg>");
}

.list::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

.list::-webkit-scrollbar-corner {
  background-color: transparent;
}
<ul class="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6 is pretty long so it goes under</li>
  <li>item 7</li>
  <li>item 8</li>
  <li>item 9</li>
  <li>item 10</li>
  <li>item 11</li>
  <li>item 12</li>
  <li>item 13</li>
  <li>item 14</li>
  <li>item 15</li>
  <li>item 16</li>
  <li>item 17</li>
</ul>

<p>Svg used in the background: </p>
<svg xmlns='http://www.w3.org/2000/svg' width='7' height='100%'> 
      <rect fill='rgb(0,0,0)' fill-opacity='0.4' x='0' y='0' rx='7px' ry='7px' width='100%' height='100%'/> 
    </svg>


Other approach could be using gradients. With your current settings, scrollbar width 14px, you can use it to set background property:

.list {
  position: relative;
  display: flex;
  max-height: 200px;
  max-width: 200px;
  flex-direction: column;
  overflow-y: overlay;
  border: 1px solid black;
}

.list::-webkit-scrollbar {
  width: 14px;
  padding-right: 7px;
}

.list::-webkit-scrollbar-thumb {
  height: 73px;
  background-clip: padding-box;
   background: radial-gradient(circle 4.6px at bottom center, #0004 0 75%,transparent 0 75%) 0 0 / 7px 3.6px no-repeat,
         radial-gradient(circle 4.6px at top center, #0004 0 75%,transparent 0 75%) -3.5px 100% / 100% 3.5px no-repeat,
         linear-gradient(90deg, #0004 0 7px, transparent 7px 100%) 0px 3.5px / 50% calc(100% - 7px) no-repeat ;

}

.list::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

.list::-webkit-scrollbar-corner {
  background-color: transparent;
}
<ul class="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item 4</li>
  <li>item 5</li>
  <li>item 6 is pretty long so it goes under</li>
  <li>item 7</li>
  <li>item 8</li>
  <li>item 9</li>
  <li>item 10</li>
  <li>item 11</li>
  <li>item 12</li>
  <li>item 13</li>
  <li>item 14</li>
  <li>item 15</li>
  <li>item 16</li>
  <li>item 17</li>
</ul>

body {
   margin: 0;
   padding: 0;
} 
.list {
  position: relative;
  display: flex;
  max-height: 200px;
  max-width: 200px;
  flex-direction: column;
  overflow-y: overlay;
  border: 1px solid black;
}

.list::-webkit-scrollbar {
   width: 0;
   border-radius: 20px;
   background-color: rgba(255,255,255,.2);
}
.list::-webkit-scrollbar-track {
   border-radius: 20px;
   background-color: rgba(255,255,255,.2);
   border: 7px solid transparent;
   background-clip: content-box;
   margin: 7px 0;
}
.list::-webkit-scrollbar-thumb {
   border-radius: 20px;
   background-color: rgba(0, 0, 0, 0.25);
   border: 7px solid transparent;
   background-clip: content-box;
}

.list:hover::-webkit-scrollbar {
   width: 20px;
}
<body>
    <ul class="list">
      <li>item 1</li>
      <li>item 2</li>
      <li>item 3</li>
      <li>item 4</li>
      <li>item 5</li>
      <li>item 6</li>
      <li>item 7 is pretty long so it goes under</li>
      <li>item 8</li>
      <li>item 9</li>
      <li>item 10</li>
      <li>item 11</li>
      <li>item 12</li>
      <li>item 13</li>
      <li>item 14</li>
      <li>item 15</li>
      <li>item 16</li>
      <li>item 17</li>
    </ul>
  </body>

here scrollbar visible on hover if you want to default you can set :-webkit-scrollbar width 0 to 20px and remove hover css

and if you want content does not overlap on scroll bar you can apply padding-right: 20px in list class

It shows this type refer below image

with padding right

Related