將專注於實現複雜佈局,兼容設備差異,製作酷炫動畫,製作複雜交互,提升可訪問性及構建奇思妙想效果等方面的內容。
在兼顧基礎概述的同時,著重對技巧的挖掘,結合實際進行運用,歡迎大家關注。
正文從這裡開始。
在過往,我們想要實現一個圖片的漸隱消失。最常見的莫過於整體透明度的變化,像是這樣:
<div class="img"></div>
div { width: 300px; height: 300px; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); transition: .4s; } .img:hover { opacity: 0; }
#但是,CSS 的功能如此強大的今天。我們可以利用 CSS 實現的漸隱效果已經不再如此的簡單。 【推薦學習:css影片教學】
想想看,下面這樣一個效果,是 CSS 能夠實現的麼?
答案是肯定的!本文就將一步一步,從零開始,僅使用一個標籤,實現上述的圖片漸隱效果。
這裡,有兩個核心的點:
如何切割一張圖片的這麼細,切成這麼多塊?
基於上述 (1)的基礎上,又該如何分別控制這些小塊的獨立隱藏和展示呢?
莫慌,讓我們一步一步解決他們。
首先,我們需要用到 Mask。
在 CSS 中,mask 屬性允許使用者透過遮罩或裁切特定區域的圖片的方式來隱藏一個元素的部分或全部可見區域。
最基本,使用 mask 的方式是藉助圖片,類似這樣:
div { width: 300px; height: 300px; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); transition: .4s; } .img:hover { opacity: 0; }
當然,使用圖片的方式後文會再講。使用圖片的方式其實比較繁瑣,因為我們必須先準備對應的圖片素材,除了圖片,mask 還可以接受一個類似 background 的參數,也就是漸層。
類似如下使用方法:
{ mask: linear-gradient(#000, transparent) /* 使用渐变来做遮罩 */ }
那該怎麼使用呢?一個非常簡單的例子,上述我們創造了一個從黑色到透明漸變色,我們將它運用到實際中,代碼類似這樣:
下面這樣一張圖片,疊加上一個從透明到黑色的漸變,
{ background: url(CSS高階技巧:實現圖片漸隱消的多種方法.png) ; mask: linear-gradient(90deg, transparent, #fff); }
應用了mask 之後,就會變成這樣:
這個DEMO,可以先簡單了解到mask 的基本用法。
這裡得到了使用 mask 最重要結論:圖片與 mask 產生的漸變的 transparent 的重疊部分,將會變得透明。
值得注意的是,上面的漸變使用的是linear-gradient(90deg, transparent, #fff)
,這裡的#fff
純色部分其實換成任意顏色都可以,不影響效果。
了解了mask 的簡單用法後,我們來看這樣一個非常簡單的例子,我們改造下上述的第一個DEMO。
<div class="img"></div>
div { width: 300px; height: 300px; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); } .img:hover { mask: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0)); }
是的,利用Mask,我們同樣也可以得到近似的消失效果:
如果對於Mask 你還不了解,你需要先看看這篇:奇妙的CSS MASK
當然,對於現在這個效果,有個很大的缺陷,那就是缺少了動畫。圖片是瞬間消失的。所以,我們還要為上述的借助 mask 實現的圖片消失效果添加上動畫。
而這,就需要用上 CSS @property 了。
CSS @property,大家應該不那麼陌生了。
@property CSS at-rule 是CSS Houdini API 的一部分, 它允許開發者明確地定義他們的CSS 自訂屬性,允許進行屬性類型檢查、設定預設值以及定義該自訂屬性是否可以被繼承。
如果你对 CSS @property 还有所疑惑,建议你先快速读一读这篇文章 -- CSS @property,让不可能变可能
回到我们的正题,如果我们想给上述使用 Mask 的代码,添加上动画,我们期望代码大概是这样:
div { width: 300px; height: 300px; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); mask: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 1)); } .img:hover { mask: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0)); }
这里,mask 的是从 mask: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 1))
向 mask: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0))
变化的。
但是实际上,这样并不会产生任何的动画效果。
原因在于,我们 Mask 属性本身是不支持过渡动画的!
但是,利用上 CSS @property,整个效果就不一样了。借助,CSS @property,我们改造一下代码:
@property --m-0 { syntax: "<number>"; initial-value: 1; inherits: false; } div { width: 300px; height: 300px; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); mask: linear-gradient(90deg, rgba(0, 0, 0, var(--m-0)), rgba(0, 0, 0, var(--m-0))); transition: --m-0 0.5s; } div:hover { --m-0: 0; }
我们利用 CSS @property 定义了一个名为 --m-0
的变量,然后,我们将整个动画过渡效果赋予了这个变量,而不是整个 mask。
利用这个小技巧,我们就可以成功的实现基于 mask 属性的动画效果:
到了这一步,后面的步骤其实就很明朗了。
由于 mask 拥有和 background 一样的特性。因此,mask 是可以有多重 mask 的。也就是说,我们可以设置多个不同的 mask 效果给同一个元素。
什么意思呢?上面的效果只有一重 mask,我们稍微添加一些 mask 代码,让它变成 2 重 mask:
@property --m-0 { syntax: "<number>"; initial-value: 1; inherits: false; } @property --m-1 { syntax: "<number>"; initial-value: 1; inherits: false; } div { mask: linear-gradient(90deg, rgba(0, 0, 0, var(--m-0)), rgba(0, 0, 0, var(--m-0))), linear-gradient(90deg, rgba(0, 0, 0, var(--m-1)), rgba(0, 0, 0, var(--m-1))); mask-size: 50% 100%; mask-position: left, right; mask-repeat: no-repeat; transition: --m-0 0.3s, --m-1 0.25s 0.15s; } div:hover { --m-0: 0; --m-1: 0; }
这样,我们的步骤大概是:
首先将 mask 一分为二,左右两边各一个
然后,设置了两个基于 CSS @property 的变量,--m-0
和 --m-0
然后,给它们设置了不同的过渡时间和过渡延迟时间
在 hover 的一瞬间,再将这两个变量的值,都置为 0,也就是实现 linear-gradient(90deg, rgba(0, 0, 0, 1), rgba(0, 0, 0, 1))
到 linear-gradient(90deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0))
的变化,用于隐藏对应 mask 块
由于设置了不同的过渡时间和延迟时间,整体上看上去,整个动画就分成了两部分
看看效果:
好,既然 2 重 mask 效果没问题,那么我们可以再进一步,将整个效果切割为 4 个 mask。代码还是如法炮制,这里我再贴上核心代码:
@property --m-0 { syntax: "<number>"; initial-value: 1; inherits: false; } @property --m-1 { syntax: "<number>"; initial-value: 1; inherits: false; } @property --m-2 { syntax: "<number>"; initial-value: 1; inherits: false; } @property --m-3 { syntax: "<number>"; initial-value: 1; inherits: false; } div { mask: linear-gradient(90deg, rgba(0, 0, 0, var(--m-0)), rgba(0, 0, 0, var(--m-0))), linear-gradient(90deg, rgba(0, 0, 0, var(--m-1)), rgba(0, 0, 0, var(--m-1))), linear-gradient(90deg, rgba(0, 0, 0, var(--m-2)), rgba(0, 0, 0, var(--m-2))), linear-gradient(90deg, rgba(0, 0, 0, var(--m-3)), rgba(0, 0, 0, var(--m-3))); mask-size: 50% 50%; mask-repeat: no-repeat; mask-position: left top, right top, left bottom, bottom right; transition: --m-0 0.3s, --m-1 0.15s 0.1s, --m-2 0.25s 0.21s, --m-3 0.19s 0.15s; } div:hover { --m-0: 0; --m-1: 0; --m-2: 0; --m-3: 0; }
这样,我们就可以得到 4 块分割图片的 mask 消失效果:
好,再依次类推,我们就可以得到分割为 9 块的,分割为 16 块的。由于代码太多,就简单看看效果:
CodePen Demo -- 基于 @property 和 mask 的图片渐隐消失术
那么,如果我们要分割为 100 块呢?或者 400 块呢?还要手写这些代码吗?
当然不需要,由于上面的代码的规律非常的明显,我们可以借助预处理器很好的封装整个效果。从而快速的实现切割成任意规则块数的效果。
完整的代码如下:
$count: 400; $sqrt: 20; $per: 100% / $sqrt; $width: 300px; $perWid: 15; @for $i from 1 to ($count + 1) { @property --m-#{$i} { syntax: "<number>"; initial-value: 1; inherits: false; } } @function bgSet($n) { $bg : radial-gradient(rgba(0, 0, 0, var(--m-1)), rgba(0, 0, 0, var(--m-1))); @for $i from 2 through $n { $bg: $bg, radial-gradient(rgba(0, 0, 0, var(--m-#{$i})), rgba(0, 0, 0, var(--m-#{$i}))); } @return $bg; } @function positionSet($n) { $bgPosition: (); @for $i from 0 through ($n) { @for $j from 0 through ($n - 1) { $bgPosition: $bgPosition, #{$i * $perWid}px #{$j * $perWid}px; } } @return $bgPosition; } @function transitionSet($n) { $transition: --m-1 0.1s 0.1s; @for $i from 1 through $n { $transition: $transition, --m-#{$i} #{random(500)}ms #{random(500)}ms; } @return $transition; } div { width: $width; height: $width; background: url(CSS高階技巧:實現圖片漸隱消的多種方法.jpg); mask: bgSet($count); mask-size: $per $per; mask-repeat: no-repeat; mask-position: positionSet($sqrt); transition: transitionSet($count); } div:hover { @for $i from 1 through $count { --m-#{$i}: 0; } }
这里,简单解释一下,以生成 400 块小块为例子:
最上面的 SCSS 变量定义中,
$count
是我们最终生成的块数$sqrt
是每行以及每列会拥有的块数$per
是每一块占整体图片元素的百分比值$width
是整个图片的宽高值$perWid
是每一块的宽高值利用了最上面的一段循环函数,批量的生成 CSS @property 变量,从 --m-0
到 --m-400
@function bgSet($n) {}
是生成 400 块 mask 片段
@function positionSet($n)
是生成 400 块 mask 的 mask-position,也就是生成 400 段不同定位,让 400 块 mask 刚好覆盖整个图片
@function transitionSet($n) {}
是随机设置每个块的动画时间和延迟时间
代码最下面,还有一段循环函数,生成 400 个 CSS @property 变量的 hover 值,当 hover 的时候,全部变成 0
这样,我们就实现了 400 分块的渐隐效果。效果如下:
CodePen Demo -- 基于 @property 和 mask 的图片渐隐消失术
当然,上面我们的对每一个小块的 transition 的过渡时间和过渡延迟时间的设置,都是随机的:
@function transitionSet($n) { $transition: --m-1 0.1s 0.1s; @for $i from 1 through $n { $transition: $transition, --m-#{$i} #{random(500)}ms #{random(500)}ms; } @return $transition; }
我们完全可以通过一定的控制,让过渡效果不那么随机,譬如有一定的方向感。
下面,我们通过让动画的延迟时间与 $i
,也就是 mask 小块的 index 挂钩:
@function transitionSet($n) { $transition: --m-1 0.1s 0.1s; @for $i from 1 through $n { $transition: $transition, --m-#{$i} #{100 + random(500)}ms #{($i / 50) * random(100)}ms; } @return $transition; }
那么,整个动画的方向就是从左往右逐渐消失:
CodePen Demo -- 基于 @property 和 mask 的图片渐隐消失术 2
当然,有意思的是,这个效果,不仅仅能够运用在图片上,它其实可以作用在任何元素之上!
譬如,我们有的只是一段纯文本,同样适用这个效果:
CodePen Demo -- 基于 @property 和 mask 的文本渐隐消失术
到这里,简单总结一下。本文,我们核心利用了 CSS @propery 和 mask,实现了一些原本看上去需要非常多 div 才能实现或者是需要借助 Canvas 才能实现的效果。同时,我们借助了 SCSS 预处理器,在寻找到规律后,极大的简化了 CSS 代码的书写量。
到今天,强大的 CSS 已经允许我们去做越来越多更有意思的动效,CSS @propery 和 mask 这两个属性在现代 CSS 发挥了非常重要的作用,非常建议大家认真掌握以下这两个属性。
原文链接:https://juejin.cn/post/7167160342101884935
作者:chokcoco
(学习视频分享:web前端)
以上是CSS高階技巧:實現圖片漸隱消的多種方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!