网站设置背景模糊特效感受朦胧之美

网站设置背景模糊特效感受朦胧之美

七月 13, 2019

前言


一直都喜欢iOS,Mac 和现在window10上的透明模糊效果,很多人都喜欢朦胧之美,我也不例外。

Mac

window10

iOS

如果是50%的白色背景,HTML如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    <div class="nav">
<ul id="menu-menu" class="menu">

<li class="pview menu-item menu-item-type-post_type menu-item-object-page">
<a href="/about/" title="关于" target="_blank" rel="noopener">关于</a>
</li>

<li class="pview menu-item menu-item-type-post_type menu-item-object-page">
<a href="/categories/" title="分类" target="_blank" rel="noopener">分类</a>
</li>

<li class="pview menu-item menu-item-type-post_type menu-item-object-page">
<a href="/archives/" title="归档" target="_blank" rel="noopener">归档</a>
</li>

<li class="pview menu-item menu-item-type-post_type menu-item-object-page">
<a href="/tags/" title="标签云" target="_blank" rel="noopener">标签云</a>
</li>

</ul>
<p id="copyright">
&copy; 2019 王猛.
Powered by <a href="http://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>
Theme <a href="https://github.com/Fechin/hexo-theme-diaspora" title="Diaspora" target="_blank" rel="noopener">Diaspora</a>
by Fechin
</p>
</div>

CSS代码如下(不相关的内容就不再赘述):

1
2
3
4
5
6
7
8
9
.nav {
position: fixed;
height: 100%;
width: 100%;
background: rgba(255,255,255,0.5 );
z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

效果如图所示:

50%的白色背景效果

文本内容确实很难阅读,因为文本背后的图像和文本都显示出来了,使整个界面都变得混乱,而且背景颜色也只是50%的不透明值。当然,我们可以通过增加背景颜色的alpha参数的值来提高可读性,但是效果不是我们想要的。

1
2
3
4
5
6
7
8
9
.nav {
position: fixed;
height: 100%;
width: 100%;
background: rgba(255,255,255,0.8 );
z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

80%的白色背景效果

增加背景颜色的alpha值确实解决了可读性的问题,但是这个效果不是那么的令人满意

很多朋友就想到不是在CSS中我们可以通过blur()滤镜做出模糊元素的效果吗,那我们也来试一试

1
2
3
4
5
6
7
8
9
10
.nav {
position: fixed;
height: 100%;
width: 100%;
background: rgba(255,255,255,0.8 );
filter:blur(10px);
z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

filter:blur(10px);

怎么连连文本都模糊了,这本质上是SVG模糊滤镜原语的一个对应的硬件加速版本。但是,如果我们直接给我们的示例应用一个blur()滤镜,整个元素都会被模糊,这样可读性就更差了。为元素应用blur()滤镜,结果更糟了*

提出问题:有没有什么办法,能让它只应用在元素的backdrop上(也就是我们元素后面的背景的一部分)?

解决方案


如果是我们的元素有一个background-attachment属性,值为fixed,可能就ok了,只是技术含量低。通过上面的实践可以知道我们不能直接模糊我们的元素,我们可以将它应用到一个定位于元素背后的伪元素上,并让伪元素的背景和div容器上的背景无缝匹配。

首先,我们添加一个伪元素(::before or ::after),并设置绝对定位,所有的偏移量都为0,这样它就完美覆盖整个<div>元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.nav {
position: fixed;
height: 100%;
width: 100%;

z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav::after{

content:'';
position: absolute;
top: 0;
bottom:0;
left: 0;
right: 0;
background: rgba(255, 0, 0, 0.8); /* 做调试用*/

}

我们还应用了一个半透明的red背景,这样我们可以看明白我们正在弄哪块内容,否则在处理透明(也就是,invisible)元素的时候调试会比较困难。如图所示:

伪元素::after

伪元素模糊覆盖在文本的上方

我们的伪元素就在我们的内容的上方,然后将其模糊。我们可以通过添加z-index: -1;来把它置于元素下方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.nav {
position: fixed;
height: 100%;
width: 100%;

z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav::after{

content:'';
position: absolute;
top: 0;
bottom:0;
left: 0;
right: 0;
background: rgba(255, 0, 0,0.8); /* 做调试用*/
z-index: -1;
}

在用负的z-index值来将子元素移动到它的父元素下面时要小心:如果父元素是作为背景嵌套在其它元素中,子元素也会移到其它元素下方。

z-index:-1

现在是时候把半透明的红色背景去掉了,用一个和我们背景相符的图片,可以复制<body>的背景,或者直接拆分伪元素的规则。现在我们可以模糊了吗?试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.nav {
position: fixed;
height: 100%;
width: 100%;

z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav::after{

content:'';
position: absolute;
top: 0;
bottom:0;
left: 0;
right: 0;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: -1;
background: url(../img/welcome-cover.jpg) 0 / cover fixed;;
filter: blur(10px);
}

为什么不直接在main::before中使用background: inherit?因为这样的话它会继承main的背景,而不是body的背景,这样伪元素得到的就只是一个半透明的白色背景。

blur

如上图所示,我们差不多完成了。中间的模糊效果看起来很完美,但是在接近边缘的地方模糊比较少。这是因为模糊半径(blur radius)会减少覆盖有纯色模糊的面积。

为了规避这个问题,我们让伪元素至少比它的容器的尺寸大30px(和模糊半径的值相等),通过应用一个-30px 或更小的margin值来让它保持在一个安全的区域内,因为不同的浏览器可能会使用不同的模糊算法。如图所示:

margin-30px

这修复了边缘处褪色模糊的问题,但是现在在我们的容器外边也有一些模糊,这使得它看起来像污迹而不像磨砂。幸好,这个问题也容易解决:我们只要应用为div应用overflow: hidden;,把多余的模糊剪掉即可。最后的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

.nav {
position: fixed;
height: 100%;
width: 100%;

z-index: 3;
top: -100%;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
}
.nav::after{

content:'';
position: absolute;
top: 0;
bottom:0;
left: 0;
right: 0;
transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: -1;
background: url(../img/welcome-cover.jpg) 0 / cover fixed;;
filter: blur(10px);
margin: -30px;
}

效果如下所示:

最终效果

如上图的所示,模糊就比较自然了。

End