一些让人很哇塞的CSS实现 - filter属性

前言

最近阅读了张鑫旭老师的《CSS新世界》里面对一些css属性的运用很巧妙,属实打开了新世界的大门,这篇文章主要总结一下filter属性的运用,里面的例子主要来自书本或参考文章,经由自己一些改动实现;

完整代码可以关注公众号 前端一块砖, 公众号后台回复:filter,获取codepen地址

filter属性

filter,就是我们常说的滤镜,可以通过改变相关参数使元素出现模糊或颜色偏移等图形效果;

filter属性总共支持10个滤镜函数,我们来逐一介绍一下

blur

filter: blur(5px)

模糊,blur()函数支持任意长度值,但是不支持百分比值

blur()函数的参数值表示高斯函数的标准偏差值,可以理解为屏幕上互相融合的像素数量。因此,blur()函数的参数值越大,图像的模糊效果越明显

我们常见的毛玻璃效果就可以通过该函数实现,不过更合适的属性并不是filter 而是 backdrop-filter ; 它俩的语法几乎一模一样,区别在于 filter 是对当前元素运用滤镜效果,而 backdrop-filter 是让当前元素所在区域后面的内容应用滤镜效果,为了看到效果,必须使元素或其背景至少部分透明,见下例

背景图源: https://picsum.photos/
<div class="container">
 <div class="drop-box">
   <p>backdrop-filter: blur(10px)</p>
 </div>
 <div class="filter-box">
   <p>filter: blur(1px)</p>
 </div>
</div>
/* ...other css */
.drop-box {
    background-color: rgba(255, 255, 255, 0.3);
    border-radius: 5px;
    text-align: center;
    backdrop-filter: blur(10px);
    padding: 20px 40px;
}
.filter-box {
    background-color: rgba(255, 255, 255, .7);
    border-radius: 5px;
    text-align: center;
    filter: blur(1px);
    padding: 20px 40px;
}

可以看到filter使得文字内容也模糊了,而 backdrop-filter 符合我们的预期效果;但 backdrop-filter 目前在火狐上还有兼容性问题,下面这个例子🌰我们用filter来实现backdrop-filter的效果

背景图源: https://wallhaven.cc/

为了避免文字内容受到滤镜模糊影响,我们可以将滤镜设置在伪元素before上,动画效果和背景都通过伪元素实现

<ul class="cards">
 <li class="card">
   <h4 class="title">GenJi</h4>
   <p class="content">龍神の剣を喰え!</p>
 </li>
 <li class="card">
   <h4 class="title">Ana Amari</h4>
   <p class="content">该睡觉咯.</p>
 </li>
 <li class="card">
   <h4 class="title">Torbjörn</h4>
   <p class="content">他强任他强<br>我玩托比昂. </p>
 </li>
</ul>
/* ...other css */
.card {
    width: 220px;
    height: 300px;
    border-radius: 8px;
    padding: 0 24px;
    position: relative;
    cursor: pointer;
}
.card::before {
    z-index: -1;
    content: '';
    position: absolute;
    /* 逻辑属性,相当于 top: 0; right: 0; bottom: 0; left: 0; 的缩写 */
    inset: 0;
    background-color: pink;
    background-size: cover;
    background-position: center;
    border-radius: 12px;
    filter: blur(0px) opacity(1);
    transition: .2s linear;
}

.card:nth-child(1)::before {
    background-image: url(https://th.wallhaven.cc/small/mp/mplmy1.jpg);
}
.card:nth-child(2)::before {
    background-image: url(https://th.wallhaven.cc/small/6q/6q228x.jpg);
}
.card:nth-child(3)::before {
    background-image: url(https://th.wallhaven.cc/small/gj/gj99ye.jpg);
}
/* 通过css选择器选出非hover的.card元素 */
.cards:hover>.card:not(:hover)::before {
    /* 给其伪类同时添加模糊、透明度和明暗度的滤镜 */
    filter: blur(5px) opacity(0.8) brightness(0.8);
}
/* 对于hover的元素,其伪类增强饱和度,尺寸放大 */
.card:hover::before {
    filter: saturate(1.2);
    transform: scale(1.05);
}

brightness

filter: brightness(2.4)

亮度,上面👆的例子我们已经用到过了,参数值支持数值和百分比值,不传参默认取1,参数为0表示没有亮度,元素呈纯黑色

brightness可以用来模拟电影谢幕效果,这里我们用hover触发动画

背景图源: https://wallhaven.cc/
<div class="container">
 <div class="text">
   <p>该睡觉咯.</p>
 </div>
</div>
.container::before {
    z-index: -1;
    content: '';
    inset: 0;
    position: absolute;
    background-image: url(https://w.wallhaven.cc/full/6q/wallhaven-6q228x.png), linear-gradient(rgb(219, 166, 166), rgb(0, 0, 172));
    background-size: cover;
}

/* 我们等背景图加载完再手动通过hover触发动画 */
.container:hover::before {
    /* forwards表示当动画完成后,保持最后一帧的状态 */
    animation: fade-away 2.5s linear forwards;
}

.container:hover>.text {
    animation: show 2s cubic-bezier(.74, -0.1, .86, .83) forwards;
}

.text {
    line-height: 55px;
    color: #fff;
    font-size: 36px;
    text-align: center;
    opacity: 0;
}

/* 背景变暗动画 */
@keyframes fade-away {
    30% {
        filter: brightness(1);
    }
    100% {
        filter: brightness(0);
    }
}

/* 文字出现动画 */
@keyframes show {
    20% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

drop-shadow

filter: drop-shadow(4px 4px 8px blue);
filter: drop-shadow(x偏移, y偏移, 模糊大小, 色值);

投影,drop-shadow用来给元素设置符合真实世界阴影规则的投影效果;相比于box-shadow,它不支持阴影扩展,不支持内阴影,不支持累加投影;但不同于box-shadow只会在盒子的四周留下阴影,它能使盒子中镂空或透明的部分也出现阴影轮廓

<div class="container">
 <div class="item" style="border-bottom-color: pink; transform: rotateZ(0);"></div>
 <div class="item" style="border-bottom-color: lightblue; transform: rotateZ(60deg);"></div>
 <div class="item" style="border-bottom-color: slateblue; transform: rotateZ(120deg);"></div>
 <div class="item" style="border-bottom-color: slategrey; transform: rotateZ(180deg);"></div>
 <div class="item" style="border-bottom-color: olive; transform: rotateZ(240deg);"></div>
 <div class="item" style="border-bottom-color: salmon; transform: rotateZ(300deg);"></div>
</div>
/* ...other css */
.item {
    display: block;
    height: 0;
    width: 4px;
    border-width: 0 4px 80px 4px;
    border-style: none solid solid;
    border-color: transparent;
    position: absolute;
    transform-origin: bottom;
}
.container {
    display: inline-flex;
    justify-content: center;
    width: 160px;
    height: 160px;
    transform-origin: center;
    animation: rotateAnimate 10s linear infinite forwards;
    filter: drop-shadow(1px 1px 5px black)
}
@keyframes rotateAnimate {
    from {
        transform: rotate(0);
    }
    to {
        transform: rotate(360deg);
    }
}

上面这个例子中,我们通过css边框实现了一个类似风车的东西?我们可以看到,使用drop-shadow后的阴影轮廓是围绕元素中的非透明区域的;而如果我们使用的是box-shadow,阴影轮廓就会是矩形的

[图片上传失败...(image-8661ce-1654243934506)]

grayscale

filter: grayscale(50%)

灰度,灰度表示以黑色为基准色,根据图像原来的颜色,以不同饱和度的黑色来显示图像;灰度有两个非常实用的应用场景:

图标点亮

filter: grayscale(1);

一般情况下我们需要准备彩色和灰色两份图标来表示点亮和未点亮状态,而使用grayscale滤镜可以实现置灰效果,少准备一份图标;

网页置灰

某些特殊节日我们可能需要将网站首页置灰,通过灰度滤镜,一行代码就能快速实现

body {
 filter: grayscale(1);
}

hue-rotate

filter: hue-rotate(90deg)

色调旋转,参数值为角度,hue-rotate()函数可以调整元素的色调,但饱和度和亮度保持不变;运用该滤镜可以快速实现相同风格的颜色效果,比我们自己调试出来的亮红配亮绿靠谱

button {
background-color: lightblue;
border-color: white;
}
button:nth-child(2) {
filter: hue-rotate(60deg)
}
button:nth-child(3) {
filter: hue-rotate(120deg)
}
button:nth-child(4) {
filter: hue-rotate(180deg)
}
button:nth-child(5) {
filter: hue-rotate(240deg)
}
button:nth-child(6) {
filter: hue-rotate(300deg)
}

invert

filter: invert(1);

反相,invert可以让元素的亮度和色调同时反转,参数值支持数值和百分比值,invert配合hue-rotate可以在不太重要的页面快速实现深色模式

<div class="card">
 <h4>Some Words</h4>
 <img src="https://picsum.photos/id/1080/6858/4574" alt="">
</div>
/* 通过媒体查询判断当前用户代理是设置是否处在黑暗模式 */
@media (prefers-color-scheme: dark) {
    body {
        background-color: #000;
        /* 将页面所有内容反相,调整色调以符合深色模式效果 */
        filter: invert(1) hue-rotate(180deg);
    }
    /* 图片内容反相后就不是原图了,因此我们对图片再次反相以恢复原来的样子 */
    img {
        filter: invert(1) hue-rotate(180deg);
    }
}

这里我们可以在谷歌浏览器地址栏输入 chrome://flags/,搜索 dark ,找到 Auto Dark Mode for Web Contents 打开实验中的黑暗模式,重启浏览器,就可以验证效果啦

saturate

filter: saturate(230%)

饱和度,参数值支持数值和百分比值,不传值则默认为1;饱和度用来控制图片中含色成分和消色成分(灰色)的比例,饱和度越高,含色成分越高,饱和度越低,消色成分越高,饱和度为0时表现为灰度效果,等同于 grayscale(1)

sepia

filter:sepia(60%)

褐色,参数支持数值和百分比值,默认值是0;当参数值为1时表现为深褐色,可以用来实现老照片的效果;

contrast

filter: contrast(200%)

对比度,参数值支持数值和百分比值 , 默认值为1;值为0的时候表示无对比度,图片会变成一个灰色色块,色值#808080;

opacity

filter: opacity(25%)

透明度,与opacity属性基本一致,不推荐使用

完整代码可以关注公众号 前端一块砖, 公众号后台回复:filter,获取codepen地址

参考

[1]《css新世界》

[2] 巧用CSS filter,让你的网站更加酷炫!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容