在这个新教程中,我们将从一些灰度图像开始,并学习如何在滚动时平滑地显示它们的颜色变体。为了达到预期的效果,我们将利用不同的现代前端特性,如 css Grid、 clip-path
属性和 Intersection Observer api。
我们的灰度到颜色效果
无需进一步介绍,让我们看看我们将要构建的内容:
See the Pen How to Build a Grayscale to Color Effect on Scroll by Envato Tuts+ (@tutsplus) on CodePen.
浏览器支持
尽管此效果具有不错的浏览器支持,但请注意,它不适用于某些浏览器,例如早期版本的 Microsoft Edge。对于这个例子,我将专注于效果背后的技术,而不为其他浏览器提供回退。
注意:一旦你完成了本教程,就可以通过这个后续行动将你的技能提升到一个新的水平!
1. 从 html 标记开始
我们将从四个部分开始:
<section class="section">...</section>
<section class="section">...</section>
<section class="section">...</section>
<section class="section">...</section>
在每个部分中,我们将放置一个标题和一个全屏 div包装器。包装器将包含两个空div的 s。两个元素将共享相同的背景图像。第一个将显示它的灰度版本,而最后一个将显示其原始彩色版本:
<h2>...</h2>
<div class="vh-100 img-wrapper">
<div class="grayscale cover" style="background-image: url(IMG_SRC);"></div>
<div class="colored cover" style="background-image: url(IMG_SRC);"></div>
</div>
彩色图像将显示从左到右的幻灯片动画。data-animation令人高兴的是,我们可以通过属性自定义这个动画的方向。它所需要的只是将此属性添加到具有值、或的相应.colored元素。to-leftto-topto-bottom
2. 定义样式
准备好标记后,我们将继续使用主要样式。
实用程序类
对于这个演示,我们将首先定义两个实用程序类,我们将附加到目标元素:
.cover {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.vh-100 {
height: 100vh;
}
堆叠元素
默认情况下,div保存图像的 s 将堆叠在另一个之上。只有div灰度图像可见。
以下是所需的样式:
/*CUSTOM VARIABLES HERE*/
.img-wrapper {
display: grid;
}
.img-wrapper div {
grid-column: 1;
grid-row: 1;
}
灰度图像
要创建灰度图像,我们将使用grayscale() CSS 函数并将 1 or的值100%作为其参数传递。此外,我们将为所有灰度图像提供背景颜色作为后备,直到每个图像加载:
/*CUSTOM VARIABLES HERE*/
.grayscale {
filter: grayscale(1);
background-color: var(--gray);
}
彩色图像
如上所述,彩色图像最初将被隐藏。一旦它们的一部分在页面上可见,它们就会通过幻灯片动画变得可见。
在此处查看最终效果的 GIF 版本。
为了在视觉上隐藏它们,我们不会使用任何传统的 CSS 方式,例如display: none、opacity: 0和transform: translateX(-100%). 事实上,我们将尝试clip-path,一个现代的 CSS 属性,可以帮助我们构建有趣的效果。
快速clip-path 属性说明
该clip-path属性使我们能够切掉元素的一部分并仅显示它的特定部分。可见区域可以用不同的形状(圆形、椭圆形、多边形、矩形)表示。
在我们的示例中,我们将使用inset()函数来构建所需的矩形。
在最简单的形式中,它可以接收最多四个顺时针方向的值,这些值指定生成选定区域的侧偏移(上、右、下、左)。为简单起见,我们可以使用边距简写,它使我们能够将所有四个插图设置为一个、两个、三个或四个值。可选地,我们可以传递一些额外的值给这个函数来指定矩形的圆度。
因此,为了练习,我们假设我们有以下200 像素 x 300 像素的Pixabay图像。
如果我们给它clip-path: inset(10px 20px 30px 40px),生成的图像将是 140 像素 x 260 像素:
更进一步,一个元素clip-path: inset(0)意味着整个元素都会出现。
另一方面,将四个值之一设置为 100% 的元素意味着它将被挤压和隐藏。请记住,该值在函数中的顺序很重要,并且可以产生不同的动画。
回到我们的示例,这是我们最初隐藏彩色图像的方式:
.colored {
clip-path: inset(0 100% 0 0);
transition: all 1.5s ease-in-out;
}
.colored[data-animation="to-left"] {
clip-path: inset(0 0 0 100%);
}
.colored[data-animation="to-top"] {
clip-path: inset(0 0 100% 0);
}
.colored[data-animation="to-bottom"] {
clip-path: inset(100% 0 0 0);
}
3. 滚动动画
彩色图像将被动画化并在滚动时切换。
为了完成这项任务,我们将利用 Intersection Observer API。
当每个目标元素至少有 50% 进入视口时,它将接收到is-animated类。否则,它将失去这个类并被隐藏。
无需过多介绍,以下是实现此功能的 javascript 代码:
const targets = document.queryselectorAll(".colored");
const isAnimated = "is-animated";
const threshold = 0.5;
function callback(entries, observer) {
entries.forEach((entry) => {
const elem = entry.target;
if (entry.intersectionRatio >= threshold) {
elem.classList.add(isAnimated);
//observer.unobserve(elem);
} else {
elem.classList.remove(isAnimated);
}
});
}
const observer = new IntersectionObserver(callback, { threshold });
for (const target of targets) {
observer.observe(target);
}
注意 1:要查看此 API 的工作原理以及滚动时返回的内容,请在浏览器控制台中打印entry.
注意2:intersectionRatio最初,我尝试了一个而不是属性isIntersecting。但是,我注意到它在 Firefox 中存在问题。
提示:如果您希望动画只运行一次,则必须调用该 unobserve() 方法,如下所示:
...
if (entry.isIntersecting) {
elem.classList.add(isAnimated);
observer.unobserve(elem);
} else {
elem.classList.remove(isAnimated);
}
...
以及相关的 CSS 类:
.colored.is-animated {
clip-path: inset(0);
}
结论
就是这样,伙计们!今天,我们通过利用令人高兴的新 CSS 和 JavaScript 功能成功地构建了一个有趣的滚动效果。
显然,与任何现代工具一样,这种效果在浏览器支持方面有一些限制,特别是如果您针对的是较旧的浏览器。例如,作为后备,您可以默认显示彩色图像,以防浏览器不支持该clip-path属性。
- 浏览器支持
- 实用程序类
- 堆叠元素
- 灰度图像
- 彩色图像
- 快速clip-path 属性说明