我最近在 CSS 中做了一个有趣的观察,我花了一些时间才准确理解发生了什么。
例如,考虑以下代码片段,其中父元素和子元素在给定的滚动值处接收完全相同的
background-color
。这两个元素还具有为 background
属性定义的相同转换。
滚动时,请注意子元素的背景颜色在过渡期间与父元素的背景颜色明显不同。
function toggleClassOnScroll() {
const scrollPosition = window.scrollY;
const threshold = 40;
if (scrollPosition > threshold) {
document.body.classList.add("js-scrolled");
} else {
document.body.classList.remove("js-scrolled");
}
}
toggleClassOnScroll();
window.addEventListener("scroll", toggleClassOnScroll);
:root {
--scroll-transition: background 1s ease;
--scroll-background: darkgrey;
}
nav {
background-color: transparent;
transition: var(--scroll-transition);
}
.js-scrolled nav {
background-color: var(--scroll-background);
}
nav a {
background-color: transparent;
transition: var(--scroll-transition);
}
.js-scrolled nav a {
background-color: var(--scroll-background);
}
/* setup (visual) */
body {
min-height: 200vh;
}
nav {
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
border-bottom: 2px dashed var(--scroll-background);
width: 100%;
}
nav ul {
display: flex;
gap: 1rem;
margin: 0;
padding: 0;
list-style-type: none;
}
nav a {
position: relative;
display: block;
padding: 0.75em;
font-size: 1.5rem;
text-decoration: none;
color: black;
}
nav a:before {
content: "";
position: absolute;
inset: 0;
background-color: inherit;
mix-blend-mode: multiply;
opacity: 0;
}
nav a:hover::before,
nav a:focus::before {
opacity: 1;
}
<nav>
<ul>
<li><a href="#">Colors</a></li>
<li><a href="#">Transparency</a></li>
<li><a href="#">Transitions</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
请注意,在我的用例中,由于导航项链接上的调查结果
mix-blend-mode
悬停效果,子元素也必须接收背景颜色。
由于两种背景颜色的初始值都设置为
transparent
,因此引入了alpha 通道,然后从技术上讲,它从 0 到 1 进行动画处理,从而产生滚动上定义的完整颜色。 因此,它应该与在例如
background-color
表示法中定义
rgb()
相同,初始 alpha 值为 0,并在滚动时使用 alpha 值为 1 设置此颜色。
rgb(169 169 169 / 0) -> rgb(169 169 169 / 1)
由于背景颜色与透明度重叠,我们在过渡过程中会得到不同的颜色。
这可以用一个简单的
维恩图来说明:
归属:Amousey,CC0,来自维基共享资源
background-color
、
transition-duration
和
transition-timing-function
,我个人认为这种行为在视觉上相当令人不安。我想知道是否有一种方法(或工具)可以防止过渡过程中的视觉差异。
也许有一个数学函数可以用来根据目标颜色、动画和重叠层来计算?
还是我想得太复杂了?这种情况实际上很常见吗?有(“更简单”)的解决方案吗?
background-color
上设置链接元素的
:hover
:
function toggleClassOnScroll() {
const scrollPosition = window.scrollY;
const threshold = 40;
if (scrollPosition > threshold) {
document.body.classList.add("js-scrolled");
} else {
document.body.classList.remove("js-scrolled");
}
}
toggleClassOnScroll();
window.addEventListener("scroll", toggleClassOnScroll);
:root {
--scroll-transition: background 1s ease;
--scroll-background: darkgrey;
}
nav {
background-color: transparent;
transition: var(--scroll-transition);
}
.js-scrolled nav {
background-color: var(--scroll-background);
}
.js-scrolled nav a:hover {
background-color: var(--scroll-background);
}
/* setup (visual) */
body {
min-height: 200vh;
}
nav {
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
border-bottom: 2px dashed var(--scroll-background);
width: 100%;
}
nav ul {
display: flex;
gap: 1rem;
margin: 0;
padding: 0;
list-style-type: none;
}
nav a {
position: relative;
display: block;
padding: 0.75em;
font-size: 1.5rem;
text-decoration: none;
color: black;
}
nav a:before {
content: "";
position: absolute;
inset: 0;
background-color: inherit;
mix-blend-mode: multiply;
opacity: 0;
}
nav a:hover::before,
nav a:focus::before {
opacity: 1;
}
<nav>
<ul>
<li><a href="#">Colors</a></li>
<li><a href="#">Transparency</a></li>
<li><a href="#">Transitions</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
我还认为你的代码有点过多,但可能是有原因的。