CSS制作类似 Photoshop 模糊蒙版效果

  • 引言
  • 不兼容IE的纯css实现代码
  • 实现代码
  • 实现原理
  • 兼容IE10,IE11的模糊蒙版效果,使用canvas
  • 实现代码
  • 实现原理


引言

为了使一个在图片上悬浮的方框呈现磨砂玻璃的效果,就是透过这个方框看到下方的图片是模糊的这样一个效果,以下用css来做一个简单的效果。

不兼容IE的纯css实现代码

实现代码

首先创建好背景与模糊方框的html代码

<div class='bg'>
    <div class='blur'></div>
</div>

以下是css代码,这里是在网上随便找的图片,如果图片失效,替换为其他图片链接即可

html,body {
    height: 100%;
    margin: 0;
}
.bg {
    height: 100%;
    overflow: auto;
}
.blur {
    width: 500px;
    height: 500px;
    position: relative;
    margin: 200px auto 400px;
    border: 1px solid #ffffff99;
}
.blur::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    filter: blur(4px);
}
.bg, .blur::before {
    background-image: url(http://file.youlai.cn/cnkfile1/M00/10/46/oYYBAFlU1WWAGvkPAAQlbBVHA7Y81.jpeg);
    background-attachment: fixed;
    background-size: cover;
}

实际效果图(点击效果图可查看demo演示):

python磨砂效果 ps做磨砂效果的方法_css

实现原理

就实现原理来讲,并非蒙版效果,而是两层图片叠加,一层图片在最下方未模糊处理,一层在方框内,做了模糊处理(filter: blur(4px)

其实如果考虑兼容所有,可以不用模糊处理,直接用Photoshop把图片模糊了,方框内就用模糊处理过的图片,只要图片尺寸相同,效果呈现是一样的。

设置两张图片的background-attachment: fixed; background-size: cover;样式,使背景图像扩展至足够大,以使背景图像完全覆盖背景区域,以及当页面的其余部分滚动时,背景图像不会移动。

以上两种效果相加便做成上方代码演示的效果。因为是使用filter使图片模糊,所以在使用filter: progid:DXImageTransform.Microsoft.Blur(Pixel Radius=5,MakeShadow=false);样式时是能兼容IE6-IE9的,但是IE10,IE11,没有任何能模糊图片的样式,所以想要在IE10以及IE11下使用,可以使用SVG的filter。
代码如下

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="blue">
    <filter id="blur">
        <feGaussianBlur in="SourceGraphic" stdDeviation="1" />
    </filter>
    <image filter="url(#blur)" x="0" y="0" width="200px" height="100px" xlink:href="http://file.youlai.cn/cnkfile1/M00/10/46/oYYBAFlU1WWAGvkPAAQlbBVHA7Y81.jpeg" alt="">
</svg>

效果如下

python磨砂效果 ps做磨砂效果的方法_javascript_02


这里只展示了用svg的filter模糊图片的效果,如果具体实现可以参照上方纯css实现方法,不过这种方法不能使用background-attachment: fixed; background-size: cover;样式带来的效果(方框在图片上位置变化呈现磨砂玻璃透视效果),而要手动通过JS获取位置,定位位置。

兼容IE10,IE11的模糊蒙版效果,使用canvas

实现代码

html代码

<div class='bg'>
  <div class='blur-box'>
    <div class="blur" id="blurID"></div>
  </div>
</div>

css代码

html,body {
  margin: 0;
  height: 100%;
}
.bg {
  height: 100%;
  overflow: auto;
}
.blur-box {
  width: 500px;
  height: 500px;
  position: relative;
  margin: 200px auto 500px;
  border: 1px solid #ffffff;
}
.blur {
  width: 100%;
  height: 100%;
}
.bg, .blur {
  background-image: url(./oYYBAFlU1WWAGvkPAAQlbBVHA7Y81.jpeg);
  background-attachment: fixed;
  background-size: cover;
}

js代码

function gaussBlur(imgData) {
    var pixes = imgData.data;
    var width = imgData.width;
    var height = imgData.height;
    var gaussMatrix = [],
        gaussSum = 0,
        x, y,
        r, g, b, a,
        i, j, k, len;

    var radius = 10;
    var sigma = 5;

    a = 1 / (Math.sqrt(2 * Math.PI) * sigma);
    b = -1 / (2 * sigma * sigma);
    //生成高斯矩阵
    for (i = 0, x = -radius; x <= radius; x++, i++) {
        g = a * Math.exp(b * x * x);
        gaussMatrix[i] = g;
        gaussSum += g;

    }

    //归一化, 保证高斯矩阵的值在[0,1]之间
    for (i = 0, len = gaussMatrix.length; i < len; i++) {
        gaussMatrix[i] /= gaussSum;
    }
    //x 方向一维高斯运算
    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for (j = -radius; j <= radius; j++) {
                k = x + j;
                if (k >= 0 && k < width) {//确保 k 没超出 x 的范围
                    //r,g,b,a 四个一组
                    i = (y * width + k) * 4;
                    r += pixes[i] * gaussMatrix[j + radius];
                    g += pixes[i + 1] * gaussMatrix[j + radius];
                    b += pixes[i + 2] * gaussMatrix[j + radius];
                    // a += pixes[i + 3] * gaussMatrix[j];
                    gaussSum += gaussMatrix[j + radius];
                }
            }
            i = (y * width + x) * 4;
            // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题
            // console.log(gaussSum)
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
            // pixes[i + 3] = a ;
        }
    }
    //y 方向一维高斯运算
    for (x = 0; x < width; x++) {
        for (y = 0; y < height; y++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for (j = -radius; j <= radius; j++) {
                k = y + j;
                if (k >= 0 && k < height) {//确保 k 没超出 y 的范围
                    i = (k * width + x) * 4;
                    r += pixes[i] * gaussMatrix[j + radius];
                    g += pixes[i + 1] * gaussMatrix[j + radius];
                    b += pixes[i + 2] * gaussMatrix[j + radius];
                    // a += pixes[i + 3] * gaussMatrix[j];
                    gaussSum += gaussMatrix[j + radius];
                }
            }
            i = (y * width + x) * 4;
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
        }
    }
    return imgData;
}

  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');
  var img = new Image();
  //这里直接修改图片的路径
  img.src = "./oYYBAFlU1WWAGvkPAAQlbBVHA7Y81.jpeg";
  img.onload = function () {
      //设置canvas的宽高
      canvas.height = img.height;
      canvas.width = img.width;
      //将图像绘制到canvas上面
      ctx.drawImage(img, 0, 0, img.width, img.height);
      //从画布图像获取
      var data = ctx.getImageData(0, 0, img.width, img.height);
      //将图像数据进行高斯模糊
      var emptyData = gaussBlur(data);
      //将模糊的图像数据再渲染到画布上面
      ctx.putImageData(emptyData, 0, 0);
      // canvas图像转base64格式,div背景设置为此数据
      document.getElementById('blurID').style.backgroundImage = 'url('+ canvas.toDataURL( 'image/png', 1 ) +')'
  };

以下为代码demo文件,因为getImageData 方法受同源策略影响,外链引入的图片不能拿到图片数据,所以在本地测试,就一个文件一个图片,就不放到github上了,直接用网盘分享一下。

网盘分享文件密码 55wj

实现原理

与以上方法原理一样,只是在模糊图片这一步骤使用了canvas,利用img标签获取到图片,再把图片渲染到canvas画布上,通过getImageData方法获取画布上图片数据,使用上方代码中的gaussBlur方法模糊处理图片数据,把处理好的数据再渲染到画布上面,把画布转成base64格式的数据,赋值到方框的背景。

因为这里写的模糊算法是在网上随便找的canvas模糊图片,所以不能通过配置模糊半径,只能固定模糊半径,想了解高斯模糊算法的同学可以看阮老师的这一篇高斯模糊的算法写出自己想要的算法。也可以使用一个比较成熟的插件StackBlur.js,

上方demo的代码经测试直接打开getImageData会报操作不安全,IE不会报错,如果想在chrome和火狐查看需要把demo文件放入前端起的服务中,推荐在vscode中使用Go live,只需要安装live server 插件,点击右下角Go live 就可以以当前软件打开的文件夹起一个前端服务,通过地址栏可以看到127.0.0.1:5500,这就是一个本地服务。

放一张效果图

python磨砂效果 ps做磨砂效果的方法_数据_03

此方法是通过计算图片中每个像素点的rgb值,与相邻像素的rgb值取平均值的方法模糊处理的,所以图片较大时计算会变慢,请酌情使用。