將專注于實現(xiàn)復雜布局,兼容設備差異,制作酷炫動畫,制作復雜交互,提升可訪問性及構建奇思妙想效果等方面的內(nèi)容。
在兼顧基礎概述的同時,注重對技巧的挖掘,結合實際進行運用,歡迎大家關注。
正文從這里開始。
在過往,我們想要實現(xiàn)一個圖片的漸隱消失。最常見的莫過于整體透明度的變化,像是這樣:
<div class="img"></div>
div { width: 300px; height: 300px; background: url(image.jpg); transition: .4s; } .img:hover { opacity: 0; }
但是,CSS 的功能如此強大的今天。我們可以利用 CSS 實現(xiàn)的漸隱效果已經(jīng)不再是如此的簡單?!就扑]學習:css視頻教程】
想想看,下面這樣一個效果,是 CSS 能夠?qū)崿F(xiàn)的么?
答案是肯定的!本文就將一步一步,從零開始,僅僅使用一個標簽,實現(xiàn)上述的圖片漸隱效果。
這里,有兩個核心的點:
-
如何將一張圖片切割的這么細,切割成這么多塊?
-
基于上述 (1)的基礎上,又該如何分別控制這些小塊的獨立隱藏和展示呢?
莫慌,讓我們一步一步來解決他們。
強大的 Mask
首先,我們需要用到 Mask。
在 CSS 中,mask 屬性允許使用者通過遮罩或者裁切特定區(qū)域的圖片的方式來隱藏一個元素的部分或者全部可見區(qū)域。
語法
最基本,使用 mask 的方式是借助圖片,類似這樣:
div { width: 300px; height: 300px; background: url(image.jpg); transition: .4s; } .img:hover { opacity: 0; }
當然,使用圖片的方式后文會再講。借助圖片的方式其實比較繁瑣,因為我們首先還得準備相應的圖片素材,除了圖片,mask 還可以接受一個類似 background 的參數(shù),也就是漸變。
類似如下使用方法:
{ mask: linear-gradient(#000, transparent) /* 使用漸變來做遮罩 */ }
那該具體怎么使用呢?一個非常簡單的例子,上述我們創(chuàng)造了一個從黑色到透明漸變色,我們將它運用到實際中,代碼類似這樣:
下面這樣一張圖片,疊加上一個從透明到黑色的漸變,
{ background: url(image.png) ; mask: linear-gradient(90deg, transparent, #fff); }
應用了 mask 之后,就會變成這樣:
這個 DEMO,可以先簡單了解到 mask 的基本用法。
這里得到了使用 mask 最重要結論:圖片與 mask 生成的漸變的 transparent 的重疊部分,將會變得透明。
值得注意的是,上面的漸變使用的是 linear-gradient(90deg, transparent, #fff)
,這里的 #fff
純色部分其實換成任意顏色都可以,不影響效果。
CodePen Demo — 使用 MASK 的基本使用
使用 mask 實現(xiàn) hover 隱藏圖片
了解了 mask 的簡單用法后,我們來看這樣一個非常簡單的例子,我們改造下上述的第一個 DEMO。
<div class="img"></div>
div { width: 300px; height: 300px; background: url(image.jpg); } .img:hover { mask: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0)); }
是的,利用 Mask,我們同樣也可以得到近似的消失效果:
如果對于 Mask 你還不了解,你需要首先看看這篇:奇妙的 CSS MASK
當然,對于現(xiàn)在這個效果,有個很大的缺陷,那就是缺少了動畫。圖片是瞬間消失的。所以,我們還需要給上述的借助 mask 實現(xiàn)的圖片消失效果添加上動畫。
而這,就需要用上 CSS @property 了。
強大的 CSS @property
CSS @property,大家應該不那么陌生了。
@property CSS at-rule 是 CSS Houdini API 的一部分, 它允許開發(fā)者顯式地定義他們的 CSS 自定義屬性,允許進行屬性類型檢查、設定默認值以及定義該自定義屬性是否可以被繼承。
如果你對 CSS @property 還有所疑惑,建議你先快速讀一讀這篇文章 — CSS @property,讓不可能變可能
回到我們的正題,如果我們想給上述使用 Mask 的代碼,添加上動畫,我們期望代碼大概是這樣:
div { width: 300px; height: 300px; background: url(image.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))
變化的。
但是實際上,這樣并不會產(chǎn)生任何的動畫效果。
原因在于,我們 Mask 屬性本身是不支持過渡動畫的!
但是,利用上 CSS @property,整個效果就不一樣了。借助,CSS @property,我們改造一下代碼:
@property --m-0 { syntax: "<number>"; initial-value: 1; inherits: false; } div { width: 300px; height: 300px; background: url(image.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。
利用這個小技巧,我們就可以成功的實現(xiàn)基于 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,也就是實現(xiàn)
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 塊 -
由于設置了不同的過渡時間和延遲時間,整體上看上去,整個動畫就分成了兩部分
看看效果:
繼續(xù)切割為 4 重 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 的圖片漸隱消失術
基于 SCSS 簡化代碼
那么,如果我們要分割為 100 塊呢?或者 400 塊呢?還要手寫這些代碼嗎?
當然不需要,由于上面的代碼的規(guī)律非常的明顯,我們可以借助預處理器很好的封裝整個效果。從而快速的實現(xiàn)切割成任意規(guī)則塊數(shù)的效果。
完整的代碼如下:
$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(image.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
是我們最終生成的塊數(shù)$sqrt
是每行以及每列會擁有的塊數(shù)$per
是每一塊占整體圖片元素的百分比值$width
是整個圖片的寬高值$perWid
是每一塊的寬高值
-
利用了最上面的一段循環(huán)函數(shù),批量的生成 CSS @property 變量,從
--m-0
到--m-400
-
@function bgSet($n) {}
是生成 400 塊 mask 片段 -
@function positionSet($n)
是生成 400 塊 mask 的 mask-position,也就是生成 400 段不同定位,讓 400 塊 mask 剛好覆蓋整個圖片 -
@function transitionSet($n) {}
是隨機設置每個塊的動畫時間和延遲時間 -
代碼最下面,還有一段循環(huán)函數(shù),生成 400 個 CSS @property 變量的 hover 值,當 hover 的時候,全部變成 0
這樣,我們就實現(xiàn)了 400 分塊的漸隱效果。效果如下:
CodePen Demo — 基于 @property 和 mask 的圖片漸隱消失術
調(diào)整過渡變量,控制方向
當然,上面我們的對每一個小塊的 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,實現(xiàn)了一些原本看上去需要非常多 div 才能實現(xiàn)或者是需要借助 Canvas 才能實現(xiàn)的效果。同時,我們借助了 SCSS 預處理器,在尋找到規(guī)律后,極大的簡化了 CSS 代碼的書寫量。
到今天,強大的 CSS 已經(jīng)允許我們?nèi)プ鲈絹碓蕉喔幸馑嫉膭有?,CSS @propery 和 mask 這兩個屬性在現(xiàn)代 CSS 發(fā)揮了非常重要的作用,非常建議大家認真掌握以下這兩個屬性。
原文鏈接:https://juejin.cn/post/7167160342101884935
作者:chokcoco
(學習視頻分享:web前端)