ホームページ > ウェブフロントエンド > CSSチュートリアル > タミングブレンドモード:「違い」と「除外」

タミングブレンドモード:「違い」と「除外」

尊渡假赌尊渡假赌尊渡假赌
リリース: 2025-03-26 10:53:14
オリジナル
768 人が閲覧しました

タミングブレンドモード:「違い」と「除外」

2020年まで、ブレンドモードは私があまり使用していなかった機能でした。なぜなら、最初に試してみることなく、どのような結果を生み出すことができるかはめったになかったからです。そして、「それを試して何が起こるかを見てください」というアプローチをとると、私が画面に作成した視覚的な嘔吐物にいつも恐ろしいことがありました。

問題は、それらが背中でどのように機能するかを本当に知らないことから生じました。このトピックで見たほぼすべての記事は、例、Photoshopとの比較、または冗長な芸術的説明に基づいています。例は素晴らしいものを見つけますが、あなたがあなたの頭にあなたが持っている別のアイデアを実装するものに見栄えの良いデモを適応させるために、あなたがあなたの頭の中にある別のアイデアを実装するものに適応させる手がかりがないとき、あなたは本当に時間のかかる、イライラし、最終的に無駄な冒険になります。その後、Photoshopの比較は、技術的なバックグラウンドから来る人にとってはほとんど役に立たない。芸術的な説明は、私にとってペンギン語のように感じます。

そのため、スペックに出くわしたときに電球の瞬間がありましたが、ブレンドモードが機能する方法に応じた数学的な式も含まれていることがわかりました。これは、このようなものが後ろでどのように機能するか、そしてそれが本当に便利な場所を最終的に理解できることを意味しました。そして今、私はよく知っているので、私は一連の記事でこの知識を共有します。

今日は、ブレンドが一般的にどのように機能するかに焦点を当て、その後、やや似た2つのブレンドモード(違いと除外)を詳しく見て、最後に、以下のようなクールなユースケースを分析するこの記事の肉に到達します。

ブレンドモードの「方法」について説明しましょう

ブレンドとは、2つのレイヤーを組み合わせて(1つを上に積み重ねて)、単一のレイヤーを取得することを意味します。これらの2つのレイヤーは2つの兄弟である可能性があります。この場合、使用するCSSプロパティはミックスブレンドモードです。また、2つの背景レイヤーにすることもできます。この場合、使用するCSSプロパティはバックグラウンドブレンドモードです。 「兄弟」のブレンドについて話すとき、これには、要素を擬似要素またはその親のテキストコンテンツまたは背景とブレンドすることが含まれることに注意してください。そして、背景層に関しては、それは私が話している背景イメージレイヤーだけではありません - 背景色もレイヤーです。

2つのレイヤーをブレンドするとき、上部のレイヤーはソースと呼ばれ、その下のレイヤーは宛先と呼ばれます。これは、これらの名前が少なくとも私にはあまり意味がないので、私がただ取るものです。宛先が出力になると思いますが、代わりにそれらは両方の入力であり、結果のレイヤーは出力です。

2つのレイヤーを正確に組み合わせることは、使用される特定のブレンドモードに依存しますが、常にピクセルごとです。たとえば、以下の図では、マルチリップブレンドモードを使用して、ピクセルのグリッドとして表される2つのレイヤーを組み合わせます。

大丈夫ですが、3つ以上のレイヤーがある場合はどうなりますか?さて、この場合、ブレンドプロセスは段階で発生し、下から始まります。

最初の段階では、下から2番目のレイヤーがソースであり、下からの最初のレイヤーは目的地です。これらの2つのレイヤーが溶け込み、結果が第2段階の宛先になり、下から3番目のレイヤーがソースです。 3番目のレイヤーをブレンドして最初の2つをブレンドした結果、3番目のステージの宛先が得られます。下から4番目のレイヤーがソースです。

もちろん、各段階で別のブレンドモードを使用できます。たとえば、違いを使用して最初の2つのレイヤーを下からブレンドし、次にマルチプリを使用して結果を下から3番目のレイヤーとブレンドします。しかし、これは私たちが将来の記事でもう少し入り込むものです。

ここで説明する2つのブレンドモードによって生成された結果は、2つのレイヤーのどれが上にあるかに依存しません。これはすべての可能なブレンドモードに当てはまるわけではありませんが、この記事で見ているモードの場合です。

また、分離可能なブレンドモードでもあります。つまり、ブレンド操作は各チャネルで個別に実行されます。繰り返しますが、これはすべての可能なブレンドモードの場合ではありませんが、違いと除外の場合です。

より正確には、結果の赤いチャネルは、ソースの赤いチャネルと宛先の赤いチャネルのみに依存します。結果のグリーンチャネルは、ソースの緑のチャネルと宛先の緑のチャネルのみに依存します。そして最後に、結果の青いチャネルは、ソースの青いチャネルと宛先の青いチャネルのみに依存します。

 r = f <sub>b</sub> (r <sub>s</sub> 、r <sub>d</sub> )
g = f <sub>b</sub> (g <sub>s</sub> 、g <sub>d</sub> )
b = f <sub>b</sub> (b <sub>s</sub> 、b <sub>d</sub> )
ログイン後にコピー

一般的なチャネルの場合、赤、緑、青のどちらかを指定せずに、ソース(上)レイヤーと目的地(下)レイヤーの2つの対応するチャネルの関数であることがあります。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、ch <sub>d</sub> )
ログイン後にコピー

心に留めておくべきことは、RGB値は[0、255]間隔で、または[0%、100%]間隔の割合として表現できることであり、式で実際に使用するものは小数値として表される割合です。たとえば、クリムゾンは、RGB(220、20、60)またはRGB(86.3%、7.8%、23.5%)として記述できます。どちらも有効です。ピクセルが深紅である場合に計算に使用するチャネル値は、10進数、つまり.863、.078、.235として表される割合です。

ピクセルが黒の場合、計算に使用するチャネル値はすべて0です。これは、ブラックはRGB(0、0、0)またはRGB(0%、0%、0%)として記述できるためです。ピクセルが白の場合、計算に使用するチャネル値はすべて1です。これは、白はRGB(255、255、255)またはRGB(100%、100%、100%)として記述できるためです。

完全な透明度(0に等しいアルファ)がある場合は、結果は他の層と同一であることに注意してください。

違い

このブレンドモードの名前は、ブレンディング関数f b ()が行うことについての手がかりを提供する場合があります。結果は、2つのレイヤーの対応するチャネル値の差の絶対値です。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、ch <sub>d</sub> )= | ch s -ch d |
ログイン後にコピー

最初に、これは、2つの層の対応するピクセルが同一のRGB値(つまり、3つのチャネルの1つすべてに対してch s = ch d )を持っている場合、3つのチャネルすべての違いが0であるため、結果のレイヤーのピクセルは黒であることを意味します。

 <sub>ch s</sub> = ch <sub>d</sub>
ch = f <sub>b</sub> (ch <sub>s</sub> 、ch <sub>d</sub> )= | ch <sub>s</sub> -ch <sub>d</sub> | = 0
ログイン後にコピー

第二に、正の数と0の差の絶対値は変化しないままにするため、レイヤーのピクセルが黒い場合、対応する結果ピクセルが他のレイヤーのピクセルと同じRGB値を持つことになります(すべてのチャネルが0に等しい)。

黒いピクセルが上部(ソース)レイヤーにある場合、式でチャネル値を0に置き換えると、次のことがわかります。

 ch = f <sub>b</sub> (0、ch <sub>d</sub> )= | 0 -ch <sub>d</sub> | = | -ch <sub>d</sub> | = Ch <sub>d</sub>
ログイン後にコピー

黒いピクセルが底部(宛先)レイヤーにある場合、式でチャネル値を0に置き換えると、次のことがわかります。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、0)= | ch <sub>s</sub> -0 | = | ch <sub>s</sub> | = ch <sub>s</sub>
ログイン後にコピー

最後に、正のサブカニタリー数と1の差の絶対値はその数の補体を与えるため、レイヤーのピクセルが白の場合(すべてのチャネル1があります)、対応する結果ピクセルは他のレイヤーのピクセルが完全に反転します(フィルター:インバート(1)が行うもの)。

白いピクセルが上部(ソース)レイヤーにある場合、そのチャネル値をフォーミュラの1に置き換えると、次のことがわかります。

 ch = f <sub>b</sub> (1、ch <sub>d</sub> )= | 1 -ch <sub>d</sub> | = 1 -ch <sub>d</sub>
ログイン後にコピー

白いピクセルが底部(宛先)レイヤーにある場合、そのチャネル値をフォーミュラの1に置き換えると、次のことがわかります。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、1)= | ch <sub>s</sub> -1 | = 1 -ch <sub>s</sub>
ログイン後にコピー

これは、以下のインタラクティブペンで動作して見ることができます。ここでは、分離されたレイヤーの表示と、重複してブレンドされているレイヤーの表示を切り替えることができます。重複するケースで3つの列をホバリングすると、それぞれが何が起こっているかが明らかになります。

除外

今日見ている2番目と最後のブレンドモードの場合、結果は2つのチャネル値の2倍の積で、その合計から減算されます。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、ch <sub>d</sub> )= ch s ch d -2・ch s・ch d
ログイン後にコピー

両方の値は[0、1]間隔にあるため、その製品は常に最小のものと常に等しいため、製品の2倍は常に最大の合計に等しくなります。

上部(ソース)レイヤーの黒いピクセルを検討する場合は、上記の式でCH Sを0に置き換えると、対応する結果ピクセルのチャネルで次の結果が得られます。

 ch = f <sub>b</sub> (0、ch <sub>d</sub> )= 0 ch <sub>d</sub> -2・0・ch <sub>d</sub> = ch <sub>d</sub> -0 = ch <sub>d</sub>
ログイン後にコピー

底部(宛先)レイヤーの黒いピクセルを検討する場合は、上記の式でCh Dを0に置き換えると、対応する結果ピクセルのチャネルで次の結果が得られます。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、0)= ch <sub>s</sub> 0-2・ch <sub>s</sub>・0 = ch <sub>s</sub> -0 = ch <sub>s</sub>
ログイン後にコピー

したがって、レイヤーのピクセルが黒い場合、対応する結果ピクセルが他のレイヤーのピクセルと同一であることになります。

上部(ソース)レイヤーの白いピクセルを検討する場合は、上記の式でCH Sを1に置き換えると、対応する結果ピクセルのチャネルで次の結果が得られます。

 ch = f <sub>b</sub> (1、ch <sub>d</sub> )= 1 ch <sub>d</sub> -2・1・ch <sub>d</sub> = 1 ch <sub>d</sub> -2・ch <sub>d</sub> = 1 -ch <sub>d</sub>
ログイン後にコピー

下部(宛先)レイヤーの白いピクセルを検討する場合は、上記の式でCh Dを1に置き換えた場合、対応する結果ピクセルのチャネルで次の結果が得られます。

 ch = f <sub>b</sub> (ch <sub>s</sub> 、1)= ch <sub>s</sub> 1-2・ch <sub>s</sub>・1 = ch <sub>s</sub> 1-2・ch <sub>s</sub> = 1 -ch <sub>s</sub>
ログイン後にコピー

したがって、レイヤーのピクセルが白い場合、対応する結果ピクセルが他のレイヤーのピクセルが反転したものと同一であることになります。

これはすべて、次のインタラクティブデモに示されています。

少なくとも1つのレイヤーが黒と白のピクセルしかない限り、違いと除外はまったく同じ結果を生成することに注意してください。

それでは、ブレンドモードの「何」に目を向けましょう

ここに興味深い部分があります - 例!

テキスト状態の変更効果

リンクがある段落があるとしましょう。

 <p>こんにちは、<a href="'%EF%BC%83'"> world </a>!</p>
ログイン後にコピー

まず、いくつかの基本的なスタイルを設定して、テキストを画面の中央に配置し、フォントサイズを押し上げ、ボディの背景と段落とリンクの両方に色を設定します。

体 {
  ディスプレイ:グリッド;
  場所間:センター;
  高さ:100VH;
  背景:#222;
  色:#ddd;
  font-size:クランプ(1.25em、15vw、7em);
}

{色:金; }
ログイン後にコピー

これまでのところはあまり見えませんが、すぐにそれを変更します!

次のステップは、リンク全体をカバーし、その背景をCurrentColorに設定する絶対に配置された擬似要素を作成することです。

 {
  位置:相対;
  色:金;
  
  &::後 {
    位置:絶対;
    上:0;
    下:0;
    右:0;
    左:0;
    背景:CurrentColor;
    コンテンツ: '';
  }
}
ログイン後にコピー

上記は私たちが物事を台無しにしたように見えます...しかし、私たちは本当に持っていますか?ここにあるのは、金のテキストの上に金の長方形です。また、上記の作業について説明した2つのブレンドモードに注意を払った場合、おそらく次のことを推測しています。リンク内の2つの兄弟ノード(擬似エレメント長方形とテキストコンテンツ)をブレンドします。

 p {分離:分離株; }

{
  / *以前と同じ */
  
  &::後 {
    / *以前と同じ */
    ミックスブレンドモード:違い;
  }
}
ログイン後にコピー

身体の背景とブレンドを防ぐために、段落を分離する必要があることに注意してください。これはFirefoxの問題にすぎませんが(体に非常に暗い背景があることを考えると、それはあまり目立たない)、Chromeでは問題ありませんが、Specによれば、Firefoxが実際に正しいことが正しいことを覚えておいてください。ここでバギーな方法で動作しているのはクロムなので、バグが修正された場合に分離プロパティを設定する必要があります。

申し分なく、リンクがフォーカスまたはホバリングされている場合にのみ、これが起こることを望んでいます。そうでなければ、擬似要素は見えません - それが何も拡大されていないとしましょう。

 {
  / *以前と同じ */
  テキスト装置:なし;
  
  &::後 {
    / *以前と同じ */
    変換:スケール(0);
  }

  &:focus {outline:none}
  &:Focus、&:Hover {&:: after {transform:none; }}
}
ログイン後にコピー

また、リンクの下線とフォーカスアウトラインも削除しました。以下では、次の違いの効果を確認できます。ホバー(同じ効果が次のように発生します。フォーカスは、ライブデモでテストできるものです)。

今では状態が変わりましたが、それは荒いように見えますので、移行を追加しましょう!

 {
  / *以前と同じ */
  
  &::後 {
    / *以前と同じ */
    遷移:.25sの変換;
  }
}
ログイン後にコピー

もっと良い!

私たちの擬似が真ん中の存在からではなく、底の細い線から成長した場合、それはさらに良く見えます。これは、変換オリジンを下端に(100%垂直方向に、そして水平方向の価値)に設定し、最初はY軸に沿って何もないよりもわずかなものに擬似をスケーリングする必要があることを意味します。

 {
  / *以前と同じ */
  
  &::後 {
    / *以前と同じ */
    変換オリジン:0 100%;
    変換:scaley(.05);
  }
}
ログイン後にコピー

ここでやりたいことは、段落のフォントをより審美的に魅力的なものに置き換えることです。しかし、今では別の種類の問題があります。「d」の終わりは、focus/:hoverの長方形から出ています。

これは、リンクに水平パディングで修正できます。

 {
  / *以前と同じ */
  パディング:0 .25em;
}
ログイン後にコピー

パディングの右を設定するだけでなく、なぜこのパディングを右側と左側の両方に設定しているのか疑問に思っている場合は、その理由を以下に示します。リンクテキストが「エイリアンの世界」になると、パディングの左がないと、「A」の巻き毛の始まりが長方形の外側になります。

上記のマルチワードリンクを備えたこのデモは、ビューポート幅を減らすときに別の問題を強調しています。

ここでの簡単な修正の1つは、表示を設定することです。リンクのインラインブロック。これは完璧な解決策ではありません。また、リンクテキストがビューポート幅よりも長いときに壊れますが、この特定のケースでは機能するため、今すぐここに残してみましょう。しばらくの間、この問題に戻ります。

次に、軽いテーマの状況を考えてみましょう。リンクのテキストのために黒の代わりに白を得る方法はないので:ホバーまたは:どちらも白ではない2つの同一のハイライトレイヤーをブレンドしてフォーカスするため、ここでは少し異なるアプローチが必要です。

この場合に私たちが行うことは、最初に背景、通常の段落のテキストの色、リンクのテキストの色が必要な値に設定されますが、反転しました。私は当初、この反転を手動で行っていましたが、その後、SASS Invert()関数を使用するという提案を得ました。次に、基本的に逆にしたい明るいテーマであるこの暗いテーマができた後、CSS Invert()フィルター関数の助けを借りてすべてを再び反転させることで、望ましい結果を得ることができます。

ここでの小さな警告:フィルターを設定することはできません:ボディまたはHTML要素にフィルターを設定できません。ただし、段落の周りに背景とフィルターの両方をラッパーに設定できます。

 <section>
  <p>こんにちは、<a href="'%EF%BC%83'">エイリアンワールド</a>!</p>
</section>
ログイン後にコピー
体 {
  /*以前と同じ、 
     場所コンテンツ、背景、色の宣言なしでは、 
     セクションに移動します */
}

セクション {
  ディスプレイ:グリッド;
  場所間:センター;
  背景:Invert(#DDD) / * SASS INVERT(<color>)function * /;
  色:Invert(#222); / * sass invert <color>)function */;
  フィルター:Invert(1); / * CSSフィルターInvert()関数 */
}

{
  / *以前と同じ */
  色:Invert(紫); / * sass invert(<color>)function */
}</color></color></color>
ログイン後にコピー

この効果を採用しているナビゲーションバー(および他の巧妙なトリックの束の例は次のとおりですが、これらはこの記事の範囲外です)。別のオプションを選択して、アクションを確認してください。

注意する必要がある他の何かは次のとおりです。この手法を使用すると、セクションのすべての子孫が反転します。そして、これはおそらくIMG要素の場合に私たちが望むものではありません。私は、暗闇から明るいテーマに切り替えると、ブログ投稿の画像を逆にすることを期待していません。その結果、セクションのすべてのIMGの子孫のフィルター反転を逆転させる必要があります。

セクション {
  / *以前と同じ */
  
  &、&img {filter:invert(1); }
}
ログイン後にコピー

すべてをまとめると、以下のデモは、画像を使用した暗いテーマと明るいテーマの両方のケースを示しています。

次に、ラッピングリンクのテキストの問題に戻り、A Elementsインラインブロックのオプションを作成するよりも良いオプションがないかどうかを確認しましょう。

まあ、私たちはします!テキストコンテンツと擬似をブレンドする代わりに、2つの背景レイヤーをブレンドできます。 1つのレイヤーがテキストにクリップされ、もう1つのレイヤーはボーダーボックスにクリップされ、その垂直サイズはホバリングされたケースで最初に5%から100%の間でアニメーション化されます。

 {
  / *以前と同じ */
  -webkit-text-fill-color:透過;
     -moz-text-fill-color:透明;
  -full:線形勾配(currentColor、currentColor);
  背景: 
    var( - フル)、 
    var( -  full)0 100%/1%var( -  sy、5%)Repeat-x;
  -webkit-background-clip:テキスト、ボーダーボックス。
          バックグラウンドクリップ:テキスト、ボーダーボックス。
  Background-Blend-Mode:違い;
  遷移:バックグラウンドサイズ.25S;
	
  &:Focus、&:Hover { -  sy:100%; }
}
ログイン後にコピー

私たちはもう擬似要素さえ持っていないので、CSSのいくつかを取り、リンク自体に移動し、この新しいテクニックに合わせて微調整しました。 Mix-Blend-Modeの使用から、バックグラウンドブレンドモードの使用に切り替えました。私たちは現在、変換の背景サイズを移行しています。そして、私たちは現在、変換ではなく、バックグラウンドサイズの垂直コンポーネントを表すカスタムプロパティを変えています。

これは完璧な解決策でもありませんが、はるかに優れています。

最初の問題は、Firefoxでキャプションのライブデモリンクをチェックした場合に確実に気づいた問題です。まったく機能しません。これは、2018年に明らかに報告したFirefoxのバグによるもので、Blendモードでおもちゃを始めて再びヒットするまで忘れてしまいました。

2番目の問題は、録音で顕著な問題です。リンクはやや色あせたようです。これは、何らかの理由で、Chromeがリンクのようなインライン要素をブレンドするため(これはDivのようなブロック要素では発生しないことに注意してください)、これらのインライン要素が通常以外のものに設定されている場合、最寄りの祖先(この場合のセクション)の背景(この場合はセクション)をブレンドします。

さらに奇妙なことに、分離を設定します。リンクまたはその親の段落に分離しても、これが起こるのを止めません。私はまだそれがコンテキストと何か関係があるに違いないと感じるしつこい感じがあったので、私はそれに可能なハックを投げ続けることにしました、そして、おそらく何かがうまくいくことを願っています。まあ、私はそれにあまり時間を費やす必要はありませんでした。不透明度をサブナティアに設定する(ただし、まだ1に十分に近いため、完全に不透明ではないことは目立たない)値が修正されます。

 {
  / *以前と同じ */
  不透明:.999; / *ブレンド問題を修正するためのハック¯_(ツ)_/¯ */
}
ログイン後にコピー

最終的な問題は、録音で顕著な別の問題です。 「Amur」の終わりに「R」を見ると、背景の長方形の外に落ちると、右端が切り取られていることに気付くことができます。これは、「Leopard」の「R」と比較する場合、特に顕著です。

私はこれを修正することを期待していませんでしたが、とにかくTwitterに質問を投げました。そして、あなたは何を知っていますか、それは修正できます!既に設定しているパディングと組み合わせてボックスデカールブレークを使用すると、望ましい効果を達成するのに役立ちます!

 {
  / *以前と同じ */
  ボックスデカールブレイク:クローン;
}
ログイン後にコピー

Box-Decoration-Breakには、すべてのWebKitブラウザーの-WebKit-Prefixが必要ですが、少なくとも1つの値がテキストであるバックグラウンドクリップのようなプロパティの場合とは異なり、Auto-Prefixingツールは問題をうまく処理できます。そのため、上記のコードにプレフィックスバージョンを含めていません。

私が得た別の提案は、パディングを補うために負のマージンを追加することでした。私はこれについて行き来します - 私はそれの有無にかかわらず、私が結果をよりよく好きかどうかを決めることができません。いずれにせよ、それは言及する価値のあるオプションです。

 $ p:.25em;

{
  / *以前と同じ */
  マージン:0( -  $ p); / * SASSが減算を実行しようとしないように、括弧内に配置します */
  パディング:0 $ p;
}
ログイン後にコピー

それでも、勾配の背景ポジションまたは背景サイズだけをアニメーション化することは少し退屈であることを認めなければなりません。しかし、Houdiniのおかげで、これは現時点ではChromiumでのみサポートされているにもかかわらず、私たちが望む勾配のあらゆるコンポーネントを創造的でアニメーション化できるようになりました。たとえば、下のような放射状勾配()の半径またはconic-勾配()の進行状態。

要素の領域(または背景)のみを反転させる

これは、要素の複製を使用して達成されることがよくあるような効果です。2つのコピーは他のコピーの上にレイヤー化されています。そのうちの1つは、両方のレイヤーを表示するために反転フィルターとクリップパスが上部に使用されます。別のルートは、アルファが低い2番目の要素を十分に階層化することです。

これらのアプローチは両方とも、すべてのコンテンツと子孫を使用して要素全体の一部を反転させたい場合にジョブを完了しますが、背景の一部だけを反転させたい場合は、私たちを助けることができません。また、新しいフィルター()関数(既にSafariによってサポートされています)は、背景レイヤーのみに影響を及ぼしますが、その一部だけでなく、背景の領域全体に影響します。

これがブレンドが始まる場所です。テクニックは非常に簡単です。背景層があります。その一部は、他の層と透明性(または黒)の反転が必要な白い領域を提供する1つ以上の勾配層を逆転させたいです。次に、今日説明した2つのブレンドモードのいずれかを使用してブレンドします。反転の目的のために、私は除外を好みます(違いよりも短いキャラクターです)。

これが最初の例です。 2層の背景を持つ正方形の要素があります。 2つの層は、猫の絵と、白と透明の間の鋭い遷移を持つ勾配です。

 div {
  背景: 
    線形勾配(45deg、白い50%、透明0)、 
    URL(cat.jpg)50%/ cover;
}
ログイン後にコピー

これにより、次の結果が得られます。また、寸法、ボーダーラジウス、影を設定し、その過程でテキストを見せかけましたが、この文脈ではすべてのものはそれほど重要ではありません。

次に、左下の半分を反転させるために、もう1つのCSS宣言が必要です。

 div {
  / *以前と同じ */
  Background-Blend-Mode:除外; / *または違いですが、それは1文字長い */
}
ログイン後にコピー

テキストが反転の影響を受けないことに注意してください。背景にのみ適用されます。

おそらく、インタラクティブな前後の画像スライダーを知っているでしょう。ここでCSS-Tricksでこの種の何かを見たことがあるかもしれません。 compressor.ioで見たことがあります。これは、これらの記事で使用されているものを含む画像を圧縮するためによく使用します。

私たちの目標は、100バイト未満のJavaScriptを使用して、単一のHTML要素を使用して種類のものを作成することです。

私たちの要素は範囲入力になります。最小属性または最大属性を設定していないため、それぞれデフォルトで0と100になります。値も設定していないため、デフォルトは50になります。これは、カスタムプロパティを提供する値でもあります。

 <input type="'range'" style="'-k:50'/">
ログイン後にコピー

CSSでは、基本的なリセットから始めて、ViewPortの高さ全体を占めるブロック要素に入力を作成します。また、そのトラックと親指に寸法とダミーの背景を指定して、すぐに画面上で何かを見ることができるようにします。

 $ Thumb-W:5em;

@mixin track(){
  国境:なし;
  幅:100%;
  高さ:100%;
  背景:url(flowers.jpg)50%/ cover;
}

@mixin thumb(){
  国境:なし;
  幅:$ thumb-w;
  高さ:100%;
  背景:紫。
}

* {
  マージン:0;
  パディング:0;
}

[type = 'range'] {
  &、&:: -webkit-slider-thumb、 
  &:: -webkit-slider-runnable-track {-webkit-appearance:none; }
  
  表示:ブロック;
  幅:100VW;高さ:100VH;
  
  &:: -webkit-slider-runnable-track {@includeトラック; }
  &:: -Moz-Range-Track {@includeトラック; }
  
  &:: -webkit-slider-thumb {@include thumb; }
  &:: -MOZ-RANGE-THUMB {@include thumb; }
}
ログイン後にコピー

次のステップは、トラックに別のバックグラウンドレイヤーを追加することです。これは、透明性と白の分離線が現在の範囲の入力値(k)に依存し、2つをブレンドする線形勾配のものです。

 @mixin track(){
  / *以前と同じ */
  背景:
    url(flowers.jpg)50%/ cover、 
    線形勾配(90deg、透明なvar( -  p)、白0);
  Background-Blend-Mode:除外;
}

[type = 'range'] {
  / *以前と同じ */
  -P:calc(var( -  k) * 1%);
}
ログイン後にコピー

トラックの2つの背景層の順序は、除外と違いの両方が通勤しているため、重要ではないことに注意してください。

それは何かのように見え始めていますが、親指をドラッグすると、分離線を動かすことは何もありません。これは、現在の値(勾配の分離線の位置)が自動的に更新されないため、現在の値(勾配の分離線の位置)が発生しています。スライダー値が変更されるたびに、この値を設定するたびにスライダー値を取得するJavaScriptのほんの少しで修正しましょう。

 addeventListener( 'input'、e => {
  _t = e.targetとします。
  _t.style.setProperty( ' -  k'、_t.Value)
})
ログイン後にコピー

今ではすべて正常に機能しているようです!

しかし、それは本当にですか?私たちは親指の背景のために少しよりファンシーなことをしているとしましょう:

 $ sumb-r:.5*$ thumb-w;
$ sumb-l:2px;

@mixin thumb(){
  / *以前と同じ */
   - リスト:#fff 0%60deg、透明0%;
  背景: 
    conic-gradient(60deg、var( -  list)から)0/37.5%/ *左矢印 */、 
    conic-gradient(240deg、var( -  list))100%/37.5%/ *右矢印 */、 
    放射状勾配(円、 
      透明なcalc(#{$ thumb -r}  - #{$ thumb -l}  -  1px) / *内部円 * /、 
      #fff calc(#{$ thumb-r}  - #{$ thumb-l})calc(#{$ thumb-r} -1px) / * circle line * /、 
      透明な$ thumb-r / *外側の円 * /)、 
    線形勾配(
      #fff calc(50% - #{$ thumb-r} .5*#{$ thumb-l}) /*トップライン* /、 
      透明性0 Calc(50%#{$ Thumb-r}  -  .5*#{$ thumb-l}) /*circle* /、、 
      #fff 0/ *ボトムライン */)50%0/#{$ thumb-l};
  バックグラウンドリピート:ノーリピート。
}
ログイン後にコピー

線形勾配()は、薄い垂直分離線を作成し、radial-勾配()が円を作成し、2つの円錐勾配()層が矢印を作成します。

この問題は、親指を一方の端からもう一方の端にドラッグするときに明らかになりました。分離線は親指の垂直の正中線に固定されたままではありません。

-Pを計算すると-Pを設定すると、分離線は0%から100%に移動します。 100%前の半分の親指の幅まで、親指の半分の幅、$サム-Rの出発点から移動する必要があります。つまり、親指の幅を100%引いた範囲内で、$ Thumb-W。両端から半分を差し引くと、親指の幅全体が差し引かれます。それを修正しましょう!

 -P:calc(#{$ thumb-r} var( -  k) *(100% - #{$ thumb-w}) / 100);
ログイン後にコピー

もっと良い!

しかし、範囲の入力の動作、トラックのコンテンツボックス(Chrome)の制限内または実際の入力のコンテンツボックス(Firefox)の制限内で境界ボックスが移動する方法は、まだ正しく感じられません。親指の正中線(そしてその結果、分離線)がビューポートの端までずっと進んだ場合、それははるかに良く見えます。

範囲の入力がどのように機能するかを変更することはできませんが、入力を左の半分の親指の幅と右側の親指の幅の半分で拡張することができます。これにより、幅はビューポート、100VWの幅に加えて、親指の幅、$ Thumb-Wに等しくなります。

ボディ{オーバーフロー:隠された; }

[type = 'range'] {
  / *以前と同じ */
  マージン左側: -  $ Thumb-r;
  幅:calc(100VW#{$ thumb-w});
}
ログイン後にコピー

カーソルに関連するいくつかの見事な微調整、それだけです!

これのより豪華なバージョン(Compressor.io Webサイトに触発された)は、マウスが移動すると3D回転も変化するカード内に入力を配置することです。

垂直スライダーも使用できます。これは、カスタムスタイルの垂直スライダーを作成する唯一の信頼性の高いクロスブラウザーの方法であるため、それらに回転を適用することがわずかに複雑ですが、これは背景も回転します。私たちが行うことは、-P値と(回転していない)スライダーコンテナのこれらの背景を設定し、入力とそのトラックを完全に透明に保つことです。

これは、以下のデモで動作することができます。そこでは、私の愛するクリターのパーカーを見せびらかす私の写真を反転させています。

もちろん、radial-gradient()を使用してクールな効果も使用できます。

背景: 
  放射状勾配(varの円( -  x、50%)var( -  y、50%)、 
    #000 calc(var( -  card-r)-1px)、#fff var( -  card-r))border-box、 
  $ IMG 50%/カバー。
ログイン後にコピー

この場合、-xおよび-yのカスタムプロパティによって与えられる位置は、カード上のマウスの動きから計算されます。

背景の逆の領域は、必ずしも勾配によって作成する必要はありません。また、背景画像に対するテキストの対照についてこの古い記事に示されているように、見出しのテキストの背後にある領域にすることもできます。

漸進的な反転

反転のためのブレンド技術は、複数の方法でフィルターを使用するよりも強力です。また、勾配に沿って徐々に効果を適用することができます。たとえば、左側はまったく反転していませんが、その後、完全な反転までずっと右に進みます。

この効果を取得する方法を理解するには、最初に反転効果(P)効果を取得する方法を理解する必要があります。ここで、Pは[0%、100%]間隔(または小数表現を使用する場合は[0、1]間隔)に任意の値になります。

違いと除外の両方に役立つ最初の方法は、白のアルファチャネルをpに設定することです。これは、スライダーをドラッグすることでInvrsionの進行状況を制御する以下のデモで動作して見ることができます。

HSL(0、0%、100% / 100%)の表記について疑問に思っている場合、これは、スペックによれば、1のアルファを持つ白を表す有効な方法です。

さらに、フィルター:インバート(P)が一般的なケースで動作する方法(つまり、すべてのチャネル値をつぶした間隔[min(p、q)、max(p、q)]にスケーリングする)により、qはp(またはq = 1 -p)の補体であり、それを反転する前(1から減算する)(1から減算する)、一般的なチャネルchのための一般的なチャネルChのためにフォローを持っているときに、順に繰り返します。

 1-(q ch・(p -q))= 
= 1-(1 -p ch・(p-(1 -p)))= 
= 1-(1 -p ch・(2・p -1))= 
= 1-(1 -p 2・ch・p -ch)= 
= 1 -1 p -2・Ch・p ch = 
= CH P -2・Ch・p
ログイン後にコピー

私たちが得たのは、他のチャネルがPである除外の式です!したがって、他のレイヤーがRGB(P、P、P)である場合、除外ブレンドモードを使用することにより、[0%、100%]間隔の任意のPのフィルターと同じ効果を取得できます。

これは、左端に沿って完全に反転しないから、右端に沿って完全に反転する線形勾配()に沿って徐々に反転することができることを意味します。

背景: 
  url(butterfly_blues.jpg)50%/ cover、 
  線形勾配(90deg、 
    #000 / * RGB(0%、0%、0%)およびHSL(0、0%、0%)に相当します * /、 
    #fff / * RGB(100%、100%、100%)およびHSL(0、0%、100%) * /)に相当します。
Background-Blend-Mode:除外;
ログイン後にコピー

ブラックから白への勾配を使用するには、段階的な反転に勾配を使用すると、除外ブレンドモードでのみ機能し、違いでは機能しないことに注意してください。この場合、その式の差によって生成される結果は、中央の50%グレーを通過しない擬似段階的反転ですが、3つのチャネルのそれぞれが勾配に沿ってさまざまなポイントでゼロになっているRGB値を介してです。それがコントラストがスターカーに見える理由です。また、おそらくもう少し芸術的ですが、それは本当に私が意見を持っている資格があるものではありません。

バックグラウンド全体に異なるレベルの反転を持つことは、必ずしも黒から白への勾配から来る必要はありません。また、画像の黒い領域が背景色を維持し、白い領域が完全に反転し、除外ブレンドモードを使用するときにすべての部分に部分的な反転があるため、白黒の画像からもたらされる可能性があります。違いは再びスターカーのデュートンの結果をもたらします。

これは、次のインタラクティブデモで見ることができます。ここでは、背景色を変更し、2つのブレンドモードによって生成された結果の間に分離線をドラッグできます。

Hollow intersection effect

The basic idea here is we have two layers with only black and white pixels.

Ripples and rays

Let's consider an element with two pseudos, each having a background that's a repeating CSS gradient with sharp stops:

 $d: 15em;
$u0: 10%;
$u1: 20%;

div {
  &::before, &::after {
    ディスプレイ:インラインブロック。
    width: $d;
    height: $d;
    background: repeating-radial-gradient(#000 0 $u0, #fff 0 2*$u0);
    コンテンツ: '';
  }
  
  &::後 {
    background: repeating-conic-gradient(#000 0% $u1, #fff 0% 2*$u1);
  }
}
ログイン後にコピー

Depending on the browser and the display, the edges between black and white may look jagged… or not.

Just to be on the safe side, we can tweak our gradients to get rid of this issue by leaving a tiny distance, $e, between the black and the white:

 $u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  &::前に {
    背景: 
      repeating-radial-gradient(
        #000 0 calc(#{$u0} - #{$e0}), 
        #fff $u0 calc(#{2*$u0} - #{$e0}), 
        #000 2*$u0);
  }
  
  &::後 {
    背景: 
      repeating-conic-gradient(
        #000 0% $u1 - $e1, 
        #fff $u1 2*$u1 - $e1, 
        #000 2*$u1);
  }
}
ログイン後にコピー

Then we can place them one on top of the other and set mix-blend-mode to exclusion or difference, as they both produce the same result here.

 div {
  &::before, &::after {
    /* same other styles minus the now redundant display */
    位置:絶対;
    mix-blend-mode: exclusion;
  }
}
ログイン後にコピー

Wherever the top layer is black, the result of the blending operation is identical to the other layer, whether that's black or white. So, black over black produces black, while black over white produces white.

Wherever the top layer is white, the result of the blending operation is identical to the other layer inverted. So, white over black produces white (black inverted), while white over white produces black (white inverted).

However, depending on the browser, the actual result we see may look as desired (Chromium) or like the ::before got blended with the greyish background we've set on the body and then the result blended with the ::after (Firefox, Safari).

The way Chromium behaves is a bug, but that's the result we want. And we can get it in Firefox and Safari, too, by either setting the isolation property to isolate on the parent div (demo) or by removing the mix-blend-mode declaration from the ::before (as this would ensure the blending operation between it and the body remains the default normal, which means no blending) and only setting it on the ::after (demo).

Of course, we can also simplify things and make the two blended layers be background layers on the element instead of its pseudos. This also means switching from mix-blend-mode to background-blend-mode.

 $d: 15em;
$u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  width: $d;
  height: $d;
  背景: 
    repeating-radial-gradient(
      #000 0 calc(#{$u0} - #{$e0}), 
      #fff $u0 calc(#{2*$u0} - #{$e0}), 
      #000 2*$u0), 
    repeating-conic-gradient(
      #000 0% $u1 - $e1, 
      #fff $u1 2*$u1 - $e1, 
      #000 2*$u1);;
  background-blend-mode: exclusion;
}
ログイン後にコピー

This gives us the exact same visual result, but eliminates the need for pseudo-elements, eliminates the potential unwanted mix-blend-mode side effect in Firefox and Safari, and reduces the amount of CSS we need to write.

Split screen

The basic idea is we have a scene that's half black and half white, and a white item moving from one side to the other. The item layer and the scene layer get then blended using either difference or exclusion (they both produce the same result).

When the item is, for example, a ball, the simplest way to achieve this result is to use a radial-gradient for it and a linear-gradient for the scene and then animate the background-position to make the ball oscillate.

 $d: 15em;

div {
  width: $d;
  height: $d;
  背景: 
    radial-gradient(closest-side, #fff calc(100% - 1px), transparent) 
      0/ 25% 25% no-repeat,
    linear-gradient(90deg, #000 50%, #fff 0);
  background-blend-mode: exclusion;
  animation: mov 2s ease-in-out infinite alternate;
}

@keyframes mov { to { background-position: 100%; } }
ログイン後にコピー

We can also make the ::before pseudo the scene and the ::after the moving item:

 $d: 15em;

div {
  display: grid;
  width: $d;
  height: $d;
  
  &::before, &::after {
    grid-area: 1/ 1;
    background: linear-gradient(90deg, #000 50%, #fff 0);
    コンテンツ: '';
  }
  
  &::後 {
    place-self: center start;
    padding: 12.5%;
    ボーダーラジウス:50%;
    背景:#fff;
    mix-blend-mode: exclusion;
    animation: mov 2s ease-in-out infinite alternate;
  }
}

@keyframes mov { to { transform: translate(300%); } }
ログイン後にコピー

This may look like we're over-complicating things considering that we're getting the same visual result, but it's actually what we need to do if the moving item isn't just a disc, but a more complex shape, and the motion isn't just limited to oscillation, but it also has a rotation and a scaling component.

 $d: 15em;
$t: 1s;

div {
  /* same as before */
  
  &::後 {
    /* same as before */
    /* creating the shape, not detailed here as
       it's outside the scope of this article */
    @include poly;
    /* the animations */
    アニメーション: 
      t $t ease-in-out infinite alternate, 
      r 2*$t ease-in-out infinite, 
      s .5*$t ease-in-out infinite alternate;
  }
}

@keyframes t { to { translate: 300% } }
@keyframes r {
  50% { rotate: .5turn; }
  100% { rotate: 1turn;; }
}
@keyframes s { to { scale: .75 1.25 } }
ログイン後にコピー

Note that, while Safari has now joined Firefox in supporting the individual transform properties we're animating here, these are still behind the Experimental Web Platform features flag in Chrome (which can be enabled from chrome://flags as shown below).

More examples

We won't be going into details about the “how” behind these demos as the basic idea of the blending effect using exclusion or difference is the same as before and the geometry/animation parts are outside the scope of this article. However, for each of the examples below, there is a link to a CodePen demo in the caption and a lot of these Pens also come with a recording of me coding them from scratch.

Here's a crossing bars animation I recently made after a Bees & Bombs GIF:

And here's a looping moons animation from a few years back, also coded after a Bees & Bombs GIF:

We're not necessarily limited to just black and white. Using a contrast filter with a subunitary value (filter: contrast(.65) in the example below) on a wrapper, we can turn the black into a dark grey and the white into a light grey:

Here's another example of the same technique:

If we want to make it look like we have a XOR effect between black shapes on a white background, we can use filter: invert(1) on the wrappers of the shapes, like in the example below:

And if we want something milder like dark grey shapes on a light grey background, we don't go for full inversion, but only for partial one. This means using a subunitary value for the invert filter like in the example below where we use filter: invert(.85):

It doesn't necessarily have to be something like a looping or loading animation. We can also have a XOR effect between an element's background and its offset frame. Just like in the previous examples, we use CSS filter inversion if we want the background and the frame to be black and their intersection to be white.

Another example would be having a XOR effect on hovering/ focusing and clicking a close button. The example below shows both night and light theme cases:

ブリング・ミー・トゥ・ライフ

Things can look a bit sad only in black and white, so there are few things we can do to put some life into such demos.

The first tactic would be to use filters. We can break free from the black and white constraint by using sepia() after lowering the contrast (as this function has no effect over pure black or white). Pick the hue using hue-rotate() and then fine tune the result using brightness() and saturate() or contrast().

For example, taking one of the previous black and white demos, we could have the following filter chain on the wrapper:

フィルター: 
  contrast(.65) /* turn black and white to greys */
  sepia(1) /* retro yellow-brownish tint */
  hue-rotate(215deg) /* change hue from yellow-brownish to purple */
  blur(.5px) /* keep edges from getting rough/ jagged */
  contrast(1.5) /* increase saturation */
  brightness(5) /* really brighten background */
  contrast(.75); /* make triangles less bright (turn bright white dirty) */
ログイン後にコピー

For even more control over the result, there's always the option of using SVG filters.

The second tactic would be to add another layer, one that's not black and white. For example, in this radioactive pie demo I made for the first CodePen challenge of March, I used a purple ::before pseudo-element on the body that I blended with the pie wrapper.

 body, div { display: grid; }

/* stack up everything in one grid cell */
div, ::before { grid-area: 1/ 1; }

body::before { background: #7a32ce; } /* purple layer */

/* applies to both pie slices and the wrapper */
div { mix-blend-mode: exclusion; }

.a2d { background: #000; } /* black wrapper */

.pie {
  background: /* variable size white pie slices */
    conic-gradient(from calc(var(--p)*(90deg - .5*var(--sa)) - 1deg), 
      透明、 
      #fff 1deg calc(var(--sa) var(--q)*(1turn - var(--sa))), 
      transparent calc(var(--sa) var(--q)*(1turn - var(--sa)) 1deg));
}
ログイン後にコピー

This turns the black wrapper purple and the white parts green (which is purple inverted).

Another option would be blending the entire wrapper again with another layer, this time using a blend mode different from difference or exclusion. Doing so would allow us more control over the result so we're not limited to just complementaries (like black and white, or purple and green). That, however, is something we'll have to cover in a future article.

Finally, there's the option of using difference (and not exclusion) so that we get black where two identical (not necessarily white) layers overlap. For example, the difference between coral and coral is always going to be 0 on all three channels, which means black. This means we can adapt a demo like the offset and XOR frame one to get the following result:

With some properly set transparent borders and background clipping, we can also make this work for gradient backgrounds:

Similarly, we can even have an image instead of a gradient!

Note that this means we also have to invert the image background when we invert the element in the second theme scenario. But that should be no problem, because in this article we've also learned how to do that: by setting background-color to white and blending the image layer with it using background-blend-mode: exclusion!

閉じる考え

Just these two blend modes can help us get some really cool results without resorting to canvas, SVG or duplicated layers. But we've barely scratched the surface here. In future articles, we'll dive into how other blend modes work and what we can achieve with them alone or in combination with previous ones or with other CSS visual effects such as filters. And trust me, the more tricks you have up your sleeve, the cooler the results you're able to achieve get!

以上がタミングブレンドモード:「違い」と「除外」の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
関連するチュートリアル
人気のおすすめ
最新のコース
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート