Return
Updated

用 linear-gradient 实现图片渐变消失效果

用 linear-gradient 实现图片渐变消失效果

在给文章放置 HeroImage 时,发现我的图片不够高清,拉伸填充容器后糊的像屎一样。

于是想用渐变消失的方式将图片塑造成类似 “嵌” / “糊” 在背景墙上的效果。

说着简单,结果发现这个小视效几个 AI 都生成不好,最后还是回归传统手艺,古法研制。

初步尝试

选择 linear-gradient 作为渐变工具,其原理是在图片上层覆盖一个渐变蒙版, 通过调整透明度来实现图片的渐变消失效果。

重点在于确定希望展示的视觉中心,因为是文章头图,需要兼顾图片信息和标题之上的时间戳, 所以选择图片的中间偏上位置作中心(40%)。

因为 HeroImage 的父容器是 main 元素,其宽(800px)远大于图片宽度(高度 1:1 填充), 所以水平方向的蒙版起始点和结束点需要更靠近中间位置(35% / 65%),避免两侧出现明显白边。

效果 1 效果1

代码实现

.hero-image::after {
    content: "";
    /* 让元素充满父容器 */
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: 
    /* 背景是默认白色 */
        linear-gradient(
            to bottom, /* 从上到下 */
            white 0%,
            rgba(255,255,255,0.6) 10%,
            rgba(255,255,255,0.05) 20%,
            transparent 40%,
            rgba(255,255,255,0.05) 60%, 
            rgba(255,255,255,0.65) 80%, 
            white 100%
        ),
        linear-gradient(
            to right, /* 从左到右 */
            white 35%, 
            rgba(255,255,255,0.6) 40%, 
            rgba(255,255,255,0.05) 45%, 
            rgba(255,255,255,0.05) 55%, 
            rgba(255,255,255,0.6) 60%, 
            white 65%
        );
    pointer-events: none;
}

问题发现

在浏览器窗口宽度较小时,图片会被压缩,导致渐变位置不准确, 极限情况还会出现白边。

效果2

解决方案

clamp() 解决效果并不理想,等寒假再研究吧。

暗色主题补充

为了适配暗色主题,需要调整渐变蒙版的颜色。

  • 使用 root 变量来定义蒙版颜色:
:root {
    --mask-color-rgb: 255, 255, 255;
    --mask-color-hex: #ffffff;
}
.dark {
    --mask-color-rgb: 24, 24, 27;
    --mask-color-hex: #18181b;
}
  • 然后在渐变中使用这些变量:
.hero-image::after {
    content: "";
    /* 让元素充满父容器 */
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
    background: 
        linear-gradient(
            to bottom, /* 从上到下 */
            var(--mask-color-hex) 0%,
            rgba(var(--mask-color-rgb), 0.6) 10%,
            rgba(var(--mask-color-rgb), 0.05) 20%,
            transparent 40%,
            rgba(var(--mask-color-rgb), 0.05) 60%, 
            rgba(var(--mask-color-rgb), 0.65) 80%, 
            var(--mask-color-hex) 100%
        ),
        linear-gradient(
            to right, /* 从左到右 */
            var(--mask-color-hex) 35%, 
            rgba(var(--mask-color-rgb), 0.6) 40%, 
            rgba(var(--mask-color-rgb), 0.05) 45%, 
            rgba(var(--mask-color-rgb), 0.05) 55%, 
            rgba(var(--mask-color-rgb), 0.6) 60%, 
            var(--mask-color-hex) 65%
        );
}