在 ::-webkit-scrollbar 上使用过渡效果?

43

是否可能在 WebKit 滚动条上使用转换效果?我尝试过:

div#main::-webkit-scrollbar-thumb {
    background: rgba(255,204,102,0.25);
    -webkit-transition: background 1s;
    transition: background 1s;
}

div#main:hover::-webkit-scrollbar-thumb {
    background: rgba(255,204,102,1);
}

但它没起作用。还有没有可能创建一个类似的效果(没有使用JavaScript)?

这里是一个演示RGBA过渡问题的jsfiddle

7个回答

25

通过Mari M的技巧background-color: inherit;-webkit-background-clip: text;,很容易实现。

演示地址:https://jsfiddle.net/s10f04du/

@media screen and (-webkit-min-device-pixel-ratio:0) { 
  .container {
    overflow-y: scroll;
    overflow-x: hidden;
    background-color: rgba(0,0,0,0);
    -webkit-background-clip: text;
    transition: background-color .8s;
  }
  .container:hover {
    background-color: rgba(0,0,0,0.18);  
  }
  .container::-webkit-scrollbar-thumb {
    background-color: inherit;
  }
}

11
这种方法在滚动期间会留下某种文本痕迹。请查看- https://jsfiddle.net/s10f04du/62/ - monish001
1
我找到了一个解决方法来摆脱“文本轨迹”。请参见下面的我的答案 - Trevin Avery
-1 因为这个解决方案确实使用了一个“hack”(顺便说一下,这现在已经不再需要了,可以使用动画 CSS 变量来完成),而且这个“hack”目前确实会留下文本轨迹。 - David Mulder

18

这里是基于回复的另一个想法。您可以使用颜色而不是背景颜色,然后使用盒阴影来着色拇指。您可以使用-webkit-text-fill-color 来重新着色文本:

https://codepen.io/waterplea/pen/dVMopv

*::-webkit-scrollbar-thumb {        
  box-shadow: inset 0 0 0 10px;
}

div {
  overflow: auto;
  -webkit-text-fill-color: black;
  color: rgba(0, 0, 0, 0);
  transition: color .3s ease;
}

div:hover {
  color: rgba(0, 0, 0, 0.3);
}

3
对我而言,这个解决方案会改变可滚动容器内部文本的颜色。 - nikitahl
1
另一个版本是基于你的代码,但用于我的项目中。https://jsfiddle.net/Lgt7qz1n/3/ - FH0

13

简短回答: 不,无法在 ::-webkit-scrollbar 上使用 transition

详细解答: 但是可以使用 CSS 完全实现类似的效果。

解释:

  1. 我们需要创建一个滚动的外部容器。然后我们想要创建一个内部容器。
  2. 外部容器将具有 background-color 属性。此属性将匹配我们希望在滚动条上进行转换的颜色。
  3. 内部容器将与外部容器的高度相匹配,并具有掩盖外部容器的 background-color
  4. 滚动条的 background-color 将继承外部容器的颜色。
  5. transition 属性应用于外部容器的 background-color

这里的一个主要缺点是,您必须进行一些掩码处理。如果您的背景不是纯色,这可能有点麻烦,因为内部容器很可能需要匹配。如果这不是问题,那么这将适合您。以下是将所有内容放在一起的代码,用于具有水平滚动组件的页面。

HTML

<div id="container-outer">
    <div id="container-inner">
        <!-- Content goes here -->
    </div>
</div>

CSS

->

CSS(层叠样式表)

    /* Scrollbar */
    ::-webkit-scrollbar {
        border: 0;
        height: 10px;
    }
    ::-webkit-scrollbar-track {
        background: rgba(0,0,0,0);
    }
    ::-webkit-scrollbar-thumb {
        background-color: inherit; /* Inherits from outer container */
        border-radius: 20px;
    }

    /* Container */
    #container-outer {
        overflow-y: hidden;
        overflow-x: scroll; /* Horizontal-only scrolling */
        height: 400px;
        background-color: white; /* Initial color of the scrollbar */
        transition: background-color 200ms;
    }
    #container-outer:hover {
        background-color: red; /* Hover state color of the scrollbar */
    }
    #container-inner {
        background-color: white; /* Masks outer container */
        font-size: 0;
        height: inherit; /* Inherits from outer container */
        width: 10000px; /* Set to see the scrolling effect */
    }

注:

  • 显然,这是一个Webkit解决方案。问题明确提到了Webkit而不是其他任何东西,因此本答案仅涉及Webkit。
  • 你的外部容器可能需要设置max-width,该值应与内部容器的width相匹配,否则在极大的显示器上可能会出现一些异常情况。这是一种边缘情况,当浏览器宽度大于水平滚动内容的宽度时。这是假设您正在使用水平滚动(如示例代码)的情况。
  • 在大多数情况下,在移动设备上悬停样式不能按预期工作。考虑到Webkit移动浏览器市场占有率很高,使用此解决方案之前请注意这一点。

10

如果我们过渡border-color而不是background-color,就可以避免使用background-clip: text,这会在存在嵌套文本时留下一些碎片。该内容的翻译来源于@brillout的答案

完整解释如下:

  1. 将您的内容放置在某个包装器div内,然后为包装器添加一个border-color转换,以在悬停时更改颜色。
  2. 向滚动条添加插入式边框,并设置宽度足够大以填充整个元素。
  3. 在滚动条上设置border-color:inherit

现在当我们悬停在包装器上时,边框颜色会过渡。由于包装器没有边框,因此我们看不到任何变化。但是,滚动条正在继承该颜色,因此滚动条颜色会发生变化。

以下是最重要的代码。 完整示例可在此处的 fiddle 和下面的代码段中找到。

#scroller {
  /* fill parent */
  display: block;
  width: 100%;
  height: 100%;

  /* set to some transparent color */
  border-color: rgba(0, 0, 0, 0.0);
  /* here we make the color transition */
  transition: border-color 0.75s linear;
  /* make this element do the scrolling */
  overflow: auto;
}

#scroller:hover {
  /* the color we want the scrollbar on hover */
  border-color: rgba(0, 0, 0, 0.1);
}

#scroller::-webkit-scrollbar,
#scroller::-webkit-scrollbar-thumb,
#scroller::-webkit-scrollbar-corner {
  /* add border to act as background-color */
  border-right-style: inset;
  /* sum viewport dimensions to guarantee border will fill scrollbar */
  border-right-width: calc(100vw + 100vh);
  /* inherit border-color to inherit transitions */
  border-color: inherit;
}

<div id="scroller">...</div>

body {
  background: whitesmoke;
}

#wrapper {
  width: 150px;
  height: 150px;
  margin: 2em auto;
  box-shadow: 0 0 15px 5px #ccc;
}

#scroller {
  /* fill parent */
  display: block;
  width: 100%;
  height: 100%;
}

#content {
  display: block;
  width: 300px;
  height: auto;
  padding: 5px;
}

#scroller {
  /* The background-color of the scrollbar cannot be transitioned.
     To work around this, we set and transition the property
     of the wrapper and just set the scrollbar to inherit its
     value. Now, when the the wrapper transitions that property,
     so does the scrollbar. However, if we set a background-color,
     this color shows up in the wrapper as well as the scrollbar.
     Solution: we transition the border-color and add a border-right
     to the scrollbar that is as large as the viewport. */
  border-color: rgba(0, 0, 0, 0.0);
  transition: border-color 0.75s linear;
  /* make this element do the scrolling */
  overflow: auto;
}

#scroller:hover {
  border-color: rgba(0, 0, 0, 0.1);
  transition: border-color 0.125s linear;
}

#scroller::-webkit-scrollbar,
#scroller::-webkit-scrollbar-thumb,
#scroller::-webkit-scrollbar-corner {
  /* add border to act as background-color */
  border-right-style: inset;
  /* sum viewport dimensions to guarantee border will fill scrollbar */
  border-right-width: calc(100vw + 100vh);
  /* inherit border-color to inherit transitions */
  border-color: inherit;
}

#scroller::-webkit-scrollbar {
  width: 0.5rem;
  height: 0.5rem;
}

#scroller::-webkit-scrollbar-thumb {
  border-color: rgba(0, 0, 0, 0.1);
  /* uncomment this to hide the thumb when not hovered */
  /* border-color: inherit; */
}

#scroller::-webkit-scrollbar-thumb:hover {
  border-color: rgba(0, 0, 0, 0.15);
}

#scroller::-webkit-scrollbar-thumb:active {
  border-color: rgba(0, 0, 0, 0.2);
}
<div id="wrapper">
  <div id="scroller">
    <div id="content">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pretium mi felis, pharetra ornare lorem pellentesque pulvinar. Donec varius condimentum nunc at mollis. Pellentesque posuere et quam eu tristique. Integer interdum enim non interdum mattis. Suspendisse gravida nibh enim, non efficitur lacus suscipit quis. Etiam pharetra libero auctor ultricies ornare. Duis dapibus semper semper. Nam sit amet lobortis arcu.

  Maecenas fermentum risus quis justo convallis, non ornare erat fringilla. Cras eleifend leo sapien, ac iaculis orci ultricies sed. Praesent ultrices accumsan risus, pharetra pharetra lorem dignissim id. Aenean laoreet fringilla eros, vel luctus eros luctus sed. Nullam fermentum massa sit amet arcu dictum, nec bibendum lectus porta. Duis pellentesque dui sed nisi ultricies, vitae feugiat dui accumsan. Nam sollicitudin, ex et viverra ultricies, justo metus porttitor quam, quis vestibulum nibh nisl eget leo.

  Integer luctus arcu et sapien accumsan fringilla. Integer mollis tellus vel imperdiet elementum. Ut consequat ac nibh ac sagittis. Duis neque purus, pellentesque nec erat id, pharetra ornare sapien. Etiam volutpat tincidunt nunc ac facilisis. Aenean sed purus pellentesque, vehicula mauris porta, fringilla nibh. Ut placerat, risus et congue rutrum, lorem arcu aliquet urna, sollicitudin venenatis lorem eros et diam. Aliquam sodales ex risus, ac vulputate ipsum porttitor vel. Pellentesque mattis nibh orci. Morbi turpis nulla, tincidunt vitae tincidunt in, sodales et arcu. Nam tincidunt orci id sapien venenatis porttitor ut eu ipsum. Curabitur turpis sapien, accumsan eget risus et, congue suscipit ligula.

  Maecenas felis quam, ultrices ac ornare nec, blandit at leo. Integer dapibus bibendum lectus. Donec pretium vehicula velit. Etiam eu cursus ligula. Nam rhoncus diam lacus, id tincidunt dui consequat id. Ut eget auctor massa, quis laoreet risus. Nunc blandit sapien non massa bibendum, ac auctor quam pellentesque. Quisque ultricies, est vitae pharetra hendrerit, elit enim interdum odio, eu malesuada nibh nulla a nisi. Ut quam tortor, feugiat sit amet malesuada eu, viverra in neque. Nullam lacinia justo sit amet porta interdum. Etiam enim orci, rutrum sit amet neque non, finibus elementum magna. Sed ac felis quis nunc fermentum suscipit.

  Ut aliquam placerat nulla eget aliquam. Phasellus sed purus mi. Morbi tincidunt est dictum, faucibus orci in, lobortis eros. Etiam sed viverra metus, non vehicula ex. Sed consectetur sodales felis, vel ultrices risus laoreet eget. Morbi ut eleifend lacus, ac accumsan risus. Donec iaculis ex nec ante efficitur vestibulum.
    </div>
  </div>
</div>


1
很酷的解决方案。做了一些修改,真的很适合我。唯一的缺点是滚动条和拇指应用相同的颜色,不可能让滚动条透明度为0.2,而拇指透明度为1.0。除此之外,我很喜欢它。 - RA.

8
通过对背景中使用的CSS变量进行动画处理,可以实现一种简洁的解决方案。请注意,要能够对CSS变量进行动画处理,您需要使用@property来设置它们。

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

@property --var1 {
  syntax: "<color>";
  inherits: true;
  initial-value: white;
}

.container {
  height: 100%;
  width: 100%;
  overflow-y: scroll;
  transition: --var1 .5s;
}

.container:hover {
  --var1: #aaa;
}

.container::-webkit-scrollbar {
  background: white;
  width: 8px;
}

.container::-webkit-scrollbar-thumb {
  background: var(--var1);
  border-radius: 4px;
}
<div class="container">
  test
  <div style="height: 1000px; width:100%;"></div>
</div>


我相当确定将 fadeInfadeOut 结合成一个是可能的,但是我的 CSS 动画知识有些有限(可能是一些 reversebackwards 的组合,但我现在不想去尝试)。 - David Mulder
不必使用@keyframesanimation,你可以使用transition属性。这样也可以解决快速悬停时不透明度跳动的问题。https://codepen.io/jespertheend/pen/BavNeYQ - Jespertheend
@Jespertheend 我没意识到transition可以与CSS变量一起使用。有趣!请随意编辑这个答案,如果我有时间并且不要忘记的话,稍后我也会进行编辑。 - David Mulder
很遗憾,编辑队列已满 :( - Jespertheend

2

我受到了@waterplea回答的启发。

默认情况下,box-shadow会继承文本颜色。使用这个特性非常好,可以实现我想要的效果。

.a {
  width: 100px;
  height: 200px;
  overflow-y: scroll;
  border: 1px solid #a3a3a3;

  transition: color 800ms;
  /* Initial color of scroll bar */
  color: rgba(8, 114, 252, 0.452);
}
.a span {
  /* Prevent content text from inheriting colors. */
  color: #000;
}

.a:hover {
  color: rgb(8, 114, 252);
}

.a::-webkit-scrollbar {
  appearance: none;
  width: 10px;
}

.a::-webkit-scrollbar-thumb {
  /* The box-shadow inherits the text color by default. */
  box-shadow: inset 0 0 0 20px;
  border-radius: 50px;
}
<div class="a">
  <span>
    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Ratione, odio. Lorem ipsum dolor sit, amet consectetur
    adipisicing elit. Ratione, odio. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Ratione, odio. Lorem ipsum
    dolor sit, amet consectetur adipisicing elit. Ratione, odio.
  </span>
</div>


0

让滚动条继承容器的background-color并使用过渡改变容器的background-color是可行的。但这样做会带来一个缺点,即容器的背景颜色也会改变。这使得该方法相当难以使用。您可以使用内部容器和遮罩来避免此问题,但这太麻烦了。

相反,您可以通过将容器的background-image设置为实心线性渐变来避免这个缺点,这样即使更改了background-color,容器的背景也不会改变。


.transparent-scrollbar::-webkit-scrollbar {
  width: 16px;
}

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

.transparent-scrollbar {
  /* background-image is set to solid linear gradient to make sure that the background of the container stays the same regardless of the change in the background-color property. This makes transition for the background-color possible without affecting the container's background.*/
  background-image: linear-gradient(white, white);
  background-color: transparent;
  transition: background-color 0.3s ease;
}

.transparent-scrollbar:hover {
  background-color: #babac0;
  transition: background-color 0.3s ease;
}

.transparent-scrollbar::-webkit-scrollbar-thumb {
  background-color: inherit;
  border-radius: 8px;
  border: 4px solid transparent;
  background-clip: content-box;
  transition: background-color 0.3s ease;
}


Codepen 示例:https://codepen.io/sbijay777/pen/poxvGdB


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接