ホームページ >ウェブフロントエンド >CSSチュートリアル >高度な CSS スキル: 画像のフェードを実現する複数の方法

高度な CSS スキル: 画像のフェードを実現する複数の方法

青灯夜游
青灯夜游転載
2023-01-14 05:30:013596ブラウズ

高度な CSS スキル: 画像のフェードを実現する複数の方法

は、複雑なレイアウトの実装、デバイスの違いとの互換性、クールなアニメーションの作成、複雑なインタラクションの作成、アクセシビリティの向上、奇抜なエフェクトの構築に焦点を当てます。

基本的な概要を踏まえながら、スキルの探究と現実と組み合わせた応用にも重点を置いていますので、ぜひご注目ください。

本文はここから始まります。

以前は、画像のフェードアウトを実現したいと考えていました。最も一般的なのは、次のような全体的な透明度の変更です:

<div class="img"></div>
div {
    width: 300px;
    height: 300px;
    background: url(高度な CSS スキル: 画像のフェードを実現する複数の方法.jpg);
    transition: .4s;
}
.img:hover {
    opacity: 0;
}

ただし、今日の CSS は非常に強力です。 CSS で実現できるフェード効果は、もはやそれほど単純ではありません。 [推奨学習: css ビデオ チュートリアル ]

考えてみてください。CSS を使用すると、次のような効果を実現できますか?

#答えは「はい」です。この記事では、ラベルを 1 つだけ使用して、上記の画像フェード効果を実現する方法を最初から段階的に説明します。

ここには 2 つの重要な点があります:

  • 画像をこれほど細かく、非常に多くの部分に切り分けるにはどうすればよいでしょうか?

  • 上記 (1) に基づいて、これらの小さなブロックの独立した非表示と表示を制御するにはどうすればよいでしょうか?

パニックにならないで、段階的に解決していきましょう。

強力なマスク

まず第一に、マスクを使用する必要があります。

CSS では、マスク属性を使用すると、ユーザーは画像の特定の領域をマスクまたはトリミングすることで、要素の表示領域の一部またはすべてを非表示にすることができます。

構文

マスクを使用する最も基本的な方法は、次のような画像を使用することです:

div {
    width: 300px;
    height: 300px;
    background: url(高度な CSS スキル: 画像のフェードを実現する複数の方法.jpg);
    transition: .4s;
}
.img:hover {
    opacity: 0;
}

もちろん、画像を使用する方法については後で説明します。画像を使用する方法は、対応する画像素材を最初に準備する必要があるため、実際にはさらに面倒ですが、マスクは画像に加えて、背景のようなパラメーター (グラデーション) も受け入れることができます。

次の使用法と同様です:

{
    mask: linear-gradient(#000, transparent)                      /* 使用渐变来做遮罩 */
}

具体的にはどのように使用しますか?非常に単純な例です。上では黒から透明へのグラデーション カラーを作成しました。実際に適用しました。コードは次のようになります:

次の図は、透明から黒へのグラデーション カラーが重ねられています。 ,

{
    background: url(高度な CSS スキル: 画像のフェードを実現する複数の方法.png) ;
    mask: linear-gradient(90deg, transparent, #fff);
}

高度な CSS スキル: 画像のフェードを実現する複数の方法

マスクを適用すると、次のようになります:

高度な CSS スキル: 画像のフェードを実現する複数の方法

このデモは、最初は簡単です。理解してください。マスクの基本的な使い方。

ここで、マスクを使用することの最も重要な結論が得られます。

画像とマスクによって生成されたものとの間の透明なグラデーションの重なった部分が透明になります。

上記のグラデーションでは

linear-gradient(90deg, traditional, #fff) が使用されており、ここでは #fff 単色の部分が使用されていることは注目に値します。実際、効果に影響を与えることなく、任意の色に変更できます。

CodePen デモ -- MASK の基本的な使用法

マスクを使用してホバーと画像の非表示を実装する

マスクの簡単な使用法を理解した後、次のことを試してみましょう。このような非常に単純な例では、上記の最初のデモを変換します。

<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

もちろん、現在の効果には大きな欠陥があります。つまり、アニメーションが欠如しています。画像が一瞬で消えてしまいます。したがって、マスクを使用して実現される上記の画像消失効果にアニメーションを追加する必要もあります。

そして、これには CSS @property を使用する必要があります。

強力な 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 分割图片

到了这一步,后面的步骤其实就很明朗了。

由于 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 块

  • 由于设置了不同的过渡时间和延迟时间,整体上看上去,整个动画就分成了两部分

看看效果:

继续切割为 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 块呢?还要手写这些代码吗?

当然不需要,由于上面的代码的规律非常的明显,我们可以借助预处理器很好的封装整个效果。从而快速的实现切割成任意规则块数的效果。

完整的代码如下:

$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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。