これがCSSだけで実装できるとはすごすぎる! 窓から差し込む柔らかな日差しを実装 -sunlit
Post on:2024年12月18日
CSSのスゴ技を見つけたので、紹介します。
画像は観葉植物のシルエットだけ、壁、サッシ、そして柔らかな日差しのアニメーションもCSSで実装されています。CSSで複数のぼかしを作り、CSSの回転・拡大縮小を利用してシルエットの動きが実装されています。
sunlit pure css implementation
sunlit -GitHub
CSSで実装された窓から差し込む日差しは、デモページでご覧ください。クリックまたはタップ、スペースキーを押すと、アニメーションが始まります。
実装を見てましょう。
HTMLは、背景付きのdiv
で構成されており、観葉植物は写真画像です。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="blinds"> <div class="shutters"> <div class="shutter"></div> ... <div class="shutter"></div> </div> <div class="vertical"> <div class="bar"></div> <div class="bar"></div> </div> </div> |
まずは、ブラインドと観葉植物と日差しの実装
続いて、ぼかしのエフェクトを実装します。差し込む日差しをよりリアルにするため、壁に近いものは壁から遠いものよりぼやけないように、複数のぼかしレイヤーを使用して実装します。
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 |
#progressive-blur { position: absolute; height: 100%; width: 100%; } #progressive-blur>div { position: absolute; height: 100%; width: 100%; inset: 0; backdrop-filter: blur(var(--blur-amount)); mask-image: linear-gradient(252deg, transparent, transparent var(--stop1), black var(--stop2), black); } #progressive-blur>div:nth-child(1) { --blur-amount: 6px; --stop1: 0%; --stop2: 0%; } #progressive-blur>div:nth-child(2) { --blur-amount: 12px; --stop1: 40%; --stop2: 80%; } #progressive-blur>div:nth-child(3) { --blur-amount: 48px; --stop1: 40%; --stop2: 70%; } #progressive-blur>div:nth-child(4) { --blur-amount: 96px; --stop1: 70%; --stop2: 80%; } |
ぼかしエフェクトを実装
次に、少しの回転と拡大縮小を利用して、葉のうねりを実装します。ダイナミズムを加えるために、SVGフィルタとfeTurbulence
タグとfeDisplacementMap
タグを使用して、個々の葉をうならせるためにノイズを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<div id="leaves"> <svg style="width: 0; height: 0; position: absolute;"> <defs> <filter id="wind" x="-20%" y="-20%" width="140%" height="140%"> <feTurbulence type="fractalNoise" numOctaves="2" seed="1"> <animate attributeName="baseFrequency" dur="16s" keyTimes="0;0.33;0.66;1" values="0.005 0.003;0.01 0.009;0.008 0.004;0.005 0.003" repeatCount="indefinite" /> </feTurbulence> <feDisplacementMap in="SourceGraphic"> <animate attributeName="scale" dur="20s" keyTimes="0;0.25;0.5;0.75;1" values="45;55;75;55;45" repeatCount="indefinite" /> </feDisplacementMap> </filter> </defs> </svg> </div> |
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 |
#leaves { position: absolute; background-size: cover; background-repeat: no-repeat; bottom: -20px; right: -700px; width: 1600px; height: 1400px; background-image: url("./leaves.png"); filter: url(#wind); animation: billow 8s ease-in-out infinite; } @keyframes billow { 0% { transform: perspective(400px) rotateX(0deg) rotateY(0deg) scale(1); } 25% { transform: perspective(400px) rotateX(1deg) rotateY(2deg) scale(1.02); } 50% { transform: perspective(400px) rotateX(-4deg) rotateY(-2deg) scale(0.97); } 75% { transform: perspective(400px) rotateX(1deg) rotateY(-1deg) scale(1.04); } 100% { transform: perspective(400px) rotateX(0deg) rotateY(0deg) scale(1); } } |
日の出・日の入りのトランジションには、明暗だと急すぎるので、2つのトランジションが使用されています。色は実際の夕陽を眺めて選んだ色で、特別なものではありません。床に反射する光には近似である繊細な輝きもあります。
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 |
@keyframes sunrise { 0% { background-color: var(--night); } 10% { background-color: var(--dawn); } 35% { background-color: var(--morning); } 100% { background-color: var(--day); } } @keyframes sunset { 0% { background-color: var(--day); } 30% { background-color: var(--evening); } 60% { background-color: var(--dusk); } 90% { background-color: var(--dawn); } 100% { background-color: var(--night); } } #dappled-light { pointer-events: none; position: fixed; height: 100vh; width: 100vw; } #glow { position: absolute; background: linear-gradient(309deg, var(--bounce-light), var(--bounce-light) 20%, transparent); transition: background 1.0s var(--timing-fn); height: 100%; width: 100%; opacity: 0.5; } #glow-bounce { content: ""; position: absolute; background: linear-gradient(355deg, var(--bounce-light) 0%, transparent 30%, transparent 100%); transition: background 1.0s var(--timing-fn); opacity: 0.5; height: 100%; width: 100%; bottom: 0; } |
sponsors