我对滚动时堆叠某些结构化文本范围的纯 CSS 方式感兴趣,可能使用 CSS
position: sticky
。
作为参考,以下是 VS Code 中的功能:https://learn.microsoft.com/en-us/visualstudio/ide/editor-sticky-scroll?view=vs-2022
还有 IntelliJ:https://blog.jetbrains.com/idea/2024/02/intellij-idea-2024-1-eap-4/#sticky-lines-in-the-editor
当您在“连接窗格”部分中导航和滚动时,我还在 Azure 数据资源管理器中看到了此功能,但在幕后他们使用 JavaScript 手动更新内联 CSS 样式。
在撰写本文时我能找到的最佳实现是 Mozilla 开发文档:https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky_positioning
当您滚动时,后续条目会很好地将前一个条目推开。但是,这只是一层并且不是嵌套的。他们通过包裹这些部分并使第一个子元素粘在滚动元素的顶部来实现这一点。当包装纸的底部滚动得太高时,它会开始清除粘性元素,同时下一个包装纸出现,使其看起来像是前者被推开。
这是一种简单的方法,其中嵌套元素被硬编码以停止距顶部的特定距离:
body {
font-size: 4em;
}
.window {
border: 1px solid black;
max-height: 3em;
overflow: scroll;
}
.sticky-parent {
position: sticky;
top: 0;
}
.child {
padding-left: 2em;
}
.sticky-child {
position: sticky;
top: 1em;
}
<div class="window">
<div class="parent">
<span class="sticky-parent">Parent</span>
<div class="child">
<span class="sticky-child">Child</span>
<br>Lorem<br>Ipsum
</div>
</div>
<div class="parent">
<span class="sticky-parent">Parent</span>
<div class="child">
<span class="sticky-child">Child</span>
<br>Lorem<br>Ipsum
</div>
</div>
<div class="parent">
<span class="sticky-parent">Parent</span>
<div class="child">
<span class="sticky-child">Child</span>
<br>Lorem<br>Ipsum
</div>
</div>
</div>
到目前为止,我还没有想到一种方法使
top
值相对或导数,只是显式的。当水平空间不足并且您想要一些粘性元素来包裹时,这可能是必要的。
但是从我们天真的答案中,我们看到我们可以用一些具有
top
值 N 的元素替换前一个具有相同 N 值的元素。并且我们看到它不会影响其他具有值的粘贴元素不等于 N。
现在,我们只需要隐藏允许滚动的内容(容器内不具有粘性的元素)。但这是一个问题,因为默认情况下,在 HTML 中,DOM 树中的后续元素出现在先前元素的顶部。即使我们将粘性元素的背景设置为实心,它们也会位于滚动的 Lorem Ipsum 下方。
要解决此问题,让我们使用同级 CSS 选择器来匹配所有非粘性同级,并为它们指定 -1 的 z 索引:
body {
font-size: 4em;
}
.window {
border: 1px solid green;
max-height: 5em;
overflow: scroll;
}
.object > .sticky {
position: sticky;
top: 0;
background-color: white;
display: block;
}
.object > .object > .sticky {
top: 1em;
}
.object > .object > .object > .sticky {
top: 2em;
}
.object > .object > .object > .object > .sticky {
top: 3em;
}
.object .sticky ~ * {
z-index: -1;
position: relative;
}
.object .object, .object .array,
.array .array, .array .object{
padding-left: 1em;
}
.string, .number {
padding-left: 1em;
}
.key::after {
content: ": ";
}
.string .value {
color: blue;
}
.number .value {
color: purple;
}
<div class="window">
<div class="object array">
<div class="sticky"><span class="key">Students</span><span class="brace_square">[</span></div>
<div class="object">
<div class="sticky"><span class="brace_curly">{</span></div>
<div class="string"><span class="key">First Name</span><span class="value">Firsty</span></div>
<div class="string"><span class="key">Last Name</span><span class="value">Lasty</span></div>
<div class="number"><span class="key">Age</span><span class="value">42</span></div>
<div class="object array">
<div class="sticky"><span class="key">Favorite Numbers</span><span class="brace_square">[</span></div>
<div class="number"><span class="value">1</span></div>
<div class="number"><span class="value">2</span></div>
<div class="number"><span class="value">3</span></div>
<span class="brace_square">]</span>
</div>
<div class="object array">
<div class="sticky"><span class="key">Least Favorite Numbers</span><span class="brace_square">[</span></div>
<div class="number"><span class="value">4</span></div>
<div class="number"><span class="value">5</span></div>
<div class="number"><span class="value">6</span></div>
<span class="brace_square">]</span>
</div>
<span class="brace_curly">}</span>
</div>
</div>
<div class="object array">
<div class="sticky"><span class="key">Teacher</span><span class="brace_square">[</span></div>
<div class="object">
<div class="sticky"><span class="brace_curly">{</span></div>
<div class="string"><span class="key">First Name</span><span class="value">Firsty</span></div>
<div class="string"><span class="key">Last Name</span><span class="value">Lasty</span></div>
<div class="number"><span class="key">Age</span><span class="value">42</span></div>
<span class="brace_curly">}</span>
</div>
</div>
<div class="object array">
<div class="sticky"><span class="key">Principal</span><span class="brace_square">[</span></div>
<div class="object">
<div class="sticky"><span class="brace_curly">{</span></div>
<div class="string"><span class="key">First Name</span><span class="value">Firsty</span></div>
<div class="string"><span class="key">Last Name</span><span class="value">Lasty</span></div>
<div class="number"><span class="key">Age</span><span class="value">42</span></div>
<span class="brace_curly">}</span>
</div>
</div>
</div>
到目前为止,我还无法使用 Angular 和 Sass 的组合来使顶部动态化。使用 Angular,我可以进行变量绑定(这是 CSS 功能),但不能进行循环。使用 Sass,我可以进行循环,但在计算任何变量之前,Sass 会转换为 CSS,因此循环计数器不能是动态的。
我能得到的最好的办法就是动态地向每个粘性元素添加一个基于深度的类,从而产生
<div class="sticky sticky0">
和 <div class="sticky sticky1">
等等。然后,我可以将此循环放入我的 Sass 中,并使用一些任意高的数字来为所有嵌套的粘性元素生成 CSS:
.object > .sticky {
// position: sticky;
// top: 0;
background-color: white;
display: block;
}
@for $i from 0 through 20 {
.object > .sticky#{$i} {
position: sticky;
top: #{$i}em;
}
}