这个滚动阴影 CSS 魔法是如何工作的?

How does this scrolling shadows CSS-magic work?

我发现 this infamous article 是 2012 年的。它详细介绍了如何创建滚动阴影并且仍然可以很好地工作,但我真的很想了解解决方案,但我似乎无法在网上找到必要的信息。

这是最初由@kizmarh 创建(blog-post)并由@leaverou 改进的缩小代码:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    /* Shadow covers */
    linear-gradient(white 30%, rgba(255, 255, 255, 0)), 
    linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%,

    /* Shadows */
    radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), 
    radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%;
  background-repeat: no-repeat;
  background-color: white;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  background-attachment: local, local, scroll, scroll;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

谁能解释一下这个效果是怎么实现的?我想我得到了一般要点(如果无法进一步滚动,则有白色阴影覆盖黑色阴影,这是通过背景附件实现的)但我真的对很多事情感到困惑:

How can the white shadows cover the black ones while the content behind them stays visible?

内容不在他们后面,内容在上面,这是合乎逻辑的,因为内容总是在背景之上。在阴影上使用与文本着色相同的黑色着色让你认为阴影在上面但实际上不是。

How are gradients placed by putting percentages after the declaration (linear-gradient(...) n% n%)?

0% 100% 表示 left 0% top 100%left bottom 相同,因为背景的宽度等于 100%(设置为 background-size)它也与 bottom 相同(有关详细信息:Using percentage values with background-position on a linear-gradient

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    /* Shadow covers */
    linear-gradient(white 30%, transparent), 
    linear-gradient(transparent, white 70%) bottom,

    /* Shadows */
    radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), 
    radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) bottom;
  background-repeat: no-repeat;
  background-color: white;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  background-attachment: local, local, scroll, scroll;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

Why isn't the code working when you use the background shorthand?

你只需要像下面这样正确地写它:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    /*Gradient                            position / size  repeat attachment*/
  
    /* Shadow covers */
    linear-gradient(white 30%, transparent) top   /100% 40px no-repeat local, 
    linear-gradient(transparent, white 70%) bottom/100% 40px no-repeat local,

    /* Shadows */
    radial-gradient(farthest-side at 50% 0   , rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) top   /100% 14px no-repeat, 
    radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) bottom/100% 14px no-repeat,
    #fff;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

请注意我是如何删除 scroll 的,因为它是默认值,您需要为所有渐变指定一个位置,因为它是 shorthand 中的 background-size 所必需的(相关 ).

What exactly is farthest-side at 50% 0 doing?

它正在创建一个 结束形状,其中中心位于 50% 0left 50% top 0center top)并且它应该触及边缘它的背景区域由background-size定义。 50% 100%center bottom

这里有一个基本的例子来说明:

.box {
  width:200px;
  height:100px;
  background:
    radial-gradient(farthest-side at center top,red 100%,transparent 100%) top/100% 50px no-repeat;
  border:1px solid;
}
<div class="box"></div>

我们的背景大小是 100% 50px,红色曲率触及边缘,因为色标是 100% 创建我们的半椭圆。

我们将形状的中心保持在中心的另一个简单示例:

.box {
  width:200px;
  height:100px;
  background:
    radial-gradient(farthest-side,red 100%,transparent 100%) top/100% 50px no-repeat;
  border:1px solid;
}
<div class="box"></div>

将我们的代码与不同的值一起使用可以更好地了解:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    /* Shadow covers */
    linear-gradient(white 30%, transparent) top   /100% 40px no-repeat local, 
    linear-gradient(transparent, white 70%) bottom/100% 40px no-repeat local,

    /* Shadows */
    radial-gradient(farthest-side at top    , red 100%, rgba(0, 0, 0, 0)) top   /100% 14px no-repeat, 
    radial-gradient(farthest-side at bottom , red 100%, rgba(0, 0, 0, 0)) bottom/100% 14px no-repeat,
    #fff;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

请注意我如何将 center top (50% 0) 简化为仅 top 并且 center bottom

也是如此

一些相关问题以获取有关 radial-gradient 的更多详细信息:

Why doesn't it work without background-color: white;?

没有以下情况也能正常工作:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    /* Shadow covers */
    linear-gradient(white 30%, transparent) top   /100% 40px no-repeat local, 
    linear-gradient(transparent, white 70%) bottom/100% 40px no-repeat local,

    /* Shadows */
    radial-gradient(farthest-side at top , rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) top/100% 14px no-repeat, 
    radial-gradient(farthest-side at bottom , rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) bottom/100% 14px no-repeat;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>


下面是使用不同颜色和值的代码,以更好地理解每个渐变和发生的情况。您还可以清楚地注意到上面是文字,不需要白色背景。

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  font-weight:bold;
  font-size:25px;
  background: 
    /* Shadow covers */
    linear-gradient(red 30%, white) top       /100% 40px no-repeat local, 
    linear-gradient(white, red 70%) bottom/100% 40px no-repeat local,

    /* Shadows */
    radial-gradient(farthest-side at top , yellow 100%, green 100%) top/100% 30px no-repeat, 
    radial-gradient(farthest-side at bottom , yellow 100%, green 100%) bottom/100% 30px no-repeat;
}

body {
 background:pink;
}
ul {
  margin:0;
  padding:0;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

这是您初始代码的优化版本:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  background: 
    linear-gradient(white 30%, transparent), 
    radial-gradient(farthest-side at top, rgba(0, 0, 0, .2), transparent),
    
    linear-gradient(transparent, white 70%) bottom,
    radial-gradient(farthest-side at bottom, rgba(0, 0, 0, .2), transparent) bottom;
  background-repeat: no-repeat;
  background-size: 100% 40px,100% 14px;
  background-attachment: local, scroll;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

另一个版本:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  
  --rad:radial-gradient(farthest-side, rgba(0, 0, 0, .2), transparent);  
  background: 
    linear-gradient(white 30%, transparent), 
    var(--rad) 0 -14px,
    
    linear-gradient(transparent, white 70%) bottom,
    rvar(--rad) 0 calc(100% + 14px);
  background-size: 100% 40px,100% 28px;
  background-attachment: local, scroll;
  background-repeat: no-repeat;
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

还有一个梯度较小的:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  
  --rad:radial-gradient(50% 50%, rgba(0, 0, 0, .2), transparent) no-repeat;  
  background: 
    linear-gradient(white 12px, transparent 40px calc(100% - 40px),white calc(100% - 12px)) local, 
    var(--rad) left 0 top    -14px / 100% 28px,    
    var(--rad) left 0 bottom -14px / 100% 28px;
  
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

最后一个(是的最后一个..)代码更少:

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 150px;
  
  --rad:radial-gradient(50% 14px, rgba(0, 0, 0, .2), transparent);  
  background: 
    linear-gradient(white 12px, transparent 40px calc(100% - 40px),white calc(100% - 12px)) local, 
    var(--rad) top   /100% 200%,    
    var(--rad) bottom/100% 200%;
  
}
<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>