どうも上かるびです。
案件でmix-blend-modeを使ったのですが、わりと時間を溶かした&参考記事があまりなかったので共有しておきます。
デモ:固定ヘッダーのmix-blend-mode
ヘッダーは透過。ロゴとハンバーガーメニューをmix-blend-mode(プロパティは反転のdifference)かけたい、という想定です。
とりあえずデモをご覧ください。(デザインや画像などは簡単に済ませました)
デモで使用したコード
続いて解説、といきたいところですが、
「こちとら急いでるんや!いいからコードだけコピペさせてくれ!」という方もいると思いますので、まずはデモのコードを載せておきます。

必要最低限部分に書き直しています。
HTML
※jQuery ver.3.6 .0をheadで読み込んでいます。適宜削除お願いします。
※パスやアセットなども適宜変更してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>mix-blend-mode on header</title> <link rel="stylesheet" href="パス/mix-blend-mode.css" /> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> </head> <body> <header class="header"> <a class="header-title" href=""><img src="" alt="MIX BLEND MODE Inc." width="" height=""/></a> <span class="hamburger"></span> </header> <main id="container" class="main"> <section class="content"> <h1>mix-blend-modeは、<br>いいぞ。</h1> </section> <section class="content"> <h1>重なる、<br>文字と画像。</h1> </section> </main> <script src="パス/pureSmoothScroll.min.js"></script> </body> </html> |
CSS
※レスポンシブ処理はほとんどしていません。
※reset,normalizeなどは最低限しかかけておりません。
※ブラウザ対応は下記で出力されております。
last 2 version/IE 11/Firefox ESR/> 1% in JP/not dead
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
* { box-sizing: border-box; } body, h1, p { margin: 0; } img { max-width: 100%; height: auto; vertical-align: bottom; } .header { background-color: transparent; mix-blend-mode: difference; position: fixed; top: 0; display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 40px; z-index: 10; } .header-title { display: inline-block; width: 50%; color: #fff;//表示させたい色を反転した色 } .hamburger { display: inline-block; width: 80px; height: 3px; background-color: #fff;//表示させたい色を反転した色 position: relative; } .hamburger::before { content: ""; position: absolute; width: 100%; height: 100%; top: -16px; background-color: inherit; } .hamburger::after { content: ""; position: absolute; width: 100%; height: 100%; top: 16px; background-color: inherit; } .main { background-color: #fff; width: 100%; } .content { width: calc(100% - 80px); margin-left: auto; margin-right: auto; min-height: 100vh; } .title { color:crimson; font-size:8vw; margin-top:50vh; margin-bottom:50vh; } |
JavaScript
※Babelをかけて圧縮済みです。(コピペの際はコードをホバーすると出てくる< >のマークを押すとCtrl + Aで全選択できるようになります。
※挙動として、スマホとタブレットではスムーススクロールを適用しないようにしています。
1 |
"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _defineProperties(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function _createClass(e,t,i){return t&&_defineProperties(e.prototype,t),i&&_defineProperties(e,i),e}var momentumScroll,Util={isSmartPhone:function(){var e=navigator.userAgent;return 0<e.indexOf("iPhone")||0<e.indexOf("iPod")||0<e.indexOf("Android")&&0<e.indexOf("Mobile")||(0<e.indexOf("iPad")||0<e.indexOf("Android"))}},MomentumScroll=function(){function t(e){_classCallCheck(this,t),this.container=document.querySelector(e),this.scrollY=0,this.translateY=0,this.speed=.2,this.rafId=null,this.isActive=!1,this.scrollHandler=this.scroll.bind(this),this.resizeHandler=this.resize.bind(this),this.run()}return _createClass(t,[{key:"run",value:function(){this.isActive||(this.isActive=!0,this.on(),this.setStyles())}},{key:"destroy",value:function(){this.isActive&&(this.isActive=!1,this.off(),this.clearStyles(),this.rafId&&cancelAnimationFrame(this.rafId),this.rafId=null)}},{key:"resize",value:function(){document.body.style.height="".concat(this.container.clientHeight,"px")}},{key:"scroll",value:function(){var e=this;this.scrollY=window.scrollY||window.pageYOffset,this.rafId||(this.container.style.willChange="transform",this.rafId=requestAnimationFrame(function(){return e.render()}))}},{key:"on",value:function(){this.resize(),this.scroll(),window.addEventListener("scroll",this.scrollHandler,{passive:!0}),window.addEventListener("resize",this.resizeHandler),window.addEventListener("load",this.resizeHandler)}},{key:"off",value:function(){window.removeEventListener("scroll",this.scrollHandler),window.removeEventListener("resize",this.resizeHandler),window.removeEventListener("load",this.resizeHandler)}},{key:"setStyles",value:function(){this.container.style.position="fixed",this.container.style.width="100%",this.container.style.top=0,this.container.style.left=0}},{key:"clearStyles",value:function(){document.body.style.height="",this.container.style.position="",this.container.style.width="",this.container.style.top="",this.container.style.left="",this.container.style.transform="",this.container.style.willChange=""}},{key:"render",value:function(){var e=this,t=this.translateY+(this.scrollY-this.translateY)*this.speed;$("section").css({transform:"skewY("+(this.scrollY-this.translateY)/480+"deg)"});var i=Math.abs(this.scrollY-t)<=.1;this.translateY=i?this.scrollY:t;var n=Math.round(100*this.translateY)/100;this.container.style.transform="translate3d(0, -".concat(n,"px, 0)"),i?(this.rafId=null,this.container.style.willChange=""):this.rafId=requestAnimationFrame(function(){return e.render()})}}]),t}();Util.isSmartPhone()||document.addEventListener("DOMContentLoaded",function(){momentumScroll=new MomentumScroll("#container"),setInterval(momentumScroll.resize,1e3)}); |
mix-blend-modeとは?
簡単にいうと要素と要素が重なったときの色を混ざり方をCSS で指定できるというものです。
今回はdifferenceのプロパティを使用しましたが、イラレやフォトショでお馴染みのスクリーンや乗算なども指定できます。

基本的には動かない要素同士を組み合わせることがほとんどだと思います。
その他、詳しい解説はICSさんのサイトの記事を参考にするとよいかと思います。
固定ヘッダーにmix-blend-modeを使うときの3つの注意点
デザイナーさんから提示された参考サイトを見たときは「こんなん余裕っしょ」と高を括っていましたが、いざ実装しようとしたら半日くらいかかってしまいました…。
具体的な注意点は以下3つです。
①ヘッダーをposition:fixedする場合、コンテンツ部分もfixedする。(スタックコンテキストを揃える
②ヘッダーに入っている要素は表示させたい色を反転した色を指定する。
③ヘッダーの子要素に画像を使用する際はSVG形式、fillで色を指定してあるものを使用する。
詳しく解説します。
①ヘッダーをposition:fixedする場合、コンテンツ部分もfixedする(スタックコンテキストを揃える
今回は固定ヘッダーをposition:fixedを使って実装する場合を想定します。
まず注意したいのが、「mix-blend-modeは同じスタックコンテキストにある要素(子要素)に対して適用される」ということです。
今までスタックコンテキストを曖昧にしたままやってきた私はここで大きく躓きました。
「スタックコンテキストって何?」という方はこちらの記事を参照ください。
とりあえず行き着いた答えは、「headerにposition:fixedをかけてあるからその兄弟要素となるコンテンツ要素にもposition:fixedをかければいいんじゃね?」ということ。
ただコンテンツにもfixedをかけてしまうと、当然スクロールできなくなります。
なので、JavaScriptの慣性スクロールを使ってメインコンテンツ部分にfixedをかけちゃおうと思いつきました。
今回は自分のストックの中から慣性スクロールの部分のみ使用していけました。
実装したことがない方はライブラリを使用するのをおすすめします!
有名どころだとluxy.jsですね。
②ヘッダーに入っている要素は表示させたい色を反転した色を指定する
ヘッダーにbackground-color:transparentを指定して透過させているのですが、同様にmix-blend-modeもかかっているので、ヘッダー子要素には反転した色を指定する必要があります。
イラレやフォトショでも反転色を割り出す事ができるそうですが、Webツールを使うのもおすすめです。
③ヘッダーの子要素に画像を使用する際はSVG形式、fillで色を指定してあるものを使用する。
ここも結構つまずいたポイントです。
アウトライン化されたSVGをそのまま使ったらmix-blend-modeが効きませんでした。
そのSVGファイルをHTML上で見ると、fillのプロパティがなかったので、試しにつけてみたらうまく動作しました。
つまりSVG要素には色が指定されている必要があります。同時にヘッダーの子要素になるので、ここも反転色を使う必要があります。

複雑な色を使った画像だと実装は難しいかも…。
Web制作ではイラレのデザインカンプは少数派だと思いますが、今の会社はすべてイラレ…。
SVG出力の際、こちらの記事を参考にさせていただきました。
参考サイト



コメント