需求

点这里 先说需求, 如上图所示, 要实现内容区域在浏览器顶部与底部羽化效果.

便捷通道!

  1. 如果背景非图片与视频, 仅是纯色的话, 直接使用 css3 中的linear-gradient, 在上面盖个渐变色即可, 非常简单.

    .feathering {
      background-image: linear-gradient(
        to bottom,
        rgba(255, 255, 255, 0) 84%,
        rgba(255, 255, 255, 1) 100%
      );
    }
    
  2. 如果背景色不固定, 比如是渐变, 随机或者是视频与图片 此时内容区域为文本, 可以直接使用-webkit-background-clip实现(注意兼容)

    .feathering {
      background-image: linear-gradient(
        to bottom,
        rgba(255, 255, 255, 0) 84%,
        rgba(255, 255, 255, 1) 100%
      );
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    

如果以上两种情况都不适合你的话, 那还是老老实实的跟着下面走吧!

思路

  1. 使用canvas渲染出背景图片(或者视频)
  2. 结合canvas中的globalCompositeOperationcreateLinearGradient处理背景图
  3. 将背景图悬浮到内容上层, 并且给个 css 样式pointer-events: none;

直接上 CodePen!

{% codepen GRRyWOg %}

可以在上面codepen中的文本区域滚动, 看到效果已经实现了!

代码分析

这里主要分析JS代码为主

//    step 2 设置后面会用到的合成渐变
let gradient = ctx.createLinearGradient(0, 0, 0, height);
gradient.addColorStop(0, "rgba(0,0,0,1)");
gradient.addColorStop(0.22, "rgba(0,0,0,0)");
gradient.addColorStop(0.78, "rgba(0,0,0,0)");
gradient.addColorStop(1, "rgba(0,0,0,1)");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);

这里设置渐变的主要目的是为了后续使用canvas中的, globalCompositeOperation 我们将其值设置为source-in, 该值的主要目的是只保留新、旧图形重叠的新图形区域,其余皆变为透明。, 也就意味着以内容高度为基准, 0~0.220.78~1 这个黑色渐变区域将会显示图片, 而0.22~0.78这个区域将会呈现透明效果.

//    step 3 将图片渲染到canvas里面
let oImg = new Image();
oImg.onload = () => {
  ctx.globalCompositeOperation = "source-in";
  ctx.drawImage(oImg, 0, 0, width, height);
};
oImg.src = `https://i.imgur.com/9EjhC6W.jpg`;

这里需要注意的地方是ctx.drawImage必须要确保调用时图片已加载不然啥效果都没有, 所以我们把它放到了oImg.onload里面执行. 我们在drawImage之间设置了globalCompositeOperation来告诉canvas我们要以那种合成效果绘制图片.

总结

如果你考虑兼容与可控性, 那么使用canvas将是最好的方式.