I had a 3D codeblock in a YouTube thumbnail and decided to try and make it with HTML & CSS - you can watch the video where I make it here: https://youtu.be/Z-3tPXf9a7M
A Pen by DynamicDev on CodePen.
I had a 3D codeblock in a YouTube thumbnail and decided to try and make it with HTML & CSS - you can watch the video where I make it here: https://youtu.be/Z-3tPXf9a7M
A Pen by DynamicDev on CodePen.
| <!-- inspired by a thumbnail of one of my recent videos --> | |
| <!-- https://assets.codepen.io/308367/3-grid-layouts.jpg --> | |
| <!-- with JS --> | |
| <pre contenteditable class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.awesome-layouts</span> <span class="token punctuation">{</span> | |
| <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> | |
| <span class="token punctuation">}</span></code></pre> | |
| </div> | |
| <!-- css only version --> | |
| <!-- <div class="pre-container css-only"> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <div></div> | |
| <pre contenteditable class="language-css" tabindex="0"><code class="language-css"><span class="token selector">.awesome-layouts</span> <span class="token punctuation">{</span> | |
| <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> | |
| <span class="token punctuation">}</span></code></pre> | |
| </div> | |
| </div> --> | |
| <a href="https://youtu.be/Z-3tPXf9a7M" target="_blank" class="yt">YouTube tutorial on making this here</a> |
| const pre = document.querySelector("pre"); | |
| document.addEventListener("mousemove", (e) => { | |
| rotateElement(e, pre); | |
| }); | |
| function rotateElement(event, element) { | |
| // get mouse position | |
| const x = event.clientX; | |
| const y = event.clientY; | |
| // console.log(x, y) | |
| // find the middle | |
| const middleX = window.innerWidth / 2; | |
| const middleY = window.innerHeight / 2; | |
| // console.log(middleX, middleY) | |
| // get offset from middle as a percentage | |
| // and tone it down a little | |
| const offsetX = ((x - middleX) / middleX) * 45; | |
| const offsetY = ((y - middleY) / middleY) * 45; | |
| // console.log(offsetX, offsetY); | |
| // set rotation | |
| element.style.setProperty("--rotateX", offsetX + "deg"); | |
| element.style.setProperty("--rotateY", -1 * offsetY + "deg"); | |
| } |
| :root { | |
| --pink: hsl(338, 70%, 55%); | |
| --teal: hsl(183, 70%, 62%); | |
| --white: hsl(334, 7%, 95%); | |
| } | |
| body { | |
| background: hsl(224, 32%, 12%); | |
| background-image: conic-gradient( | |
| from 0deg at 50% 50%, | |
| blue, | |
| purple, | |
| purple, | |
| blue | |
| ); | |
| background-blend-mode: multiply; | |
| min-block-size: 100dvh; | |
| display: grid; | |
| place-items: center; | |
| } | |
| pre { | |
| --selector: var(--pink); | |
| --property: var(--teal); | |
| --punctuation: var(--white); | |
| --undefined: var(--white); | |
| font-size: 3rem; | |
| font-weight: bold; | |
| color: var(--undefined); | |
| background: hsl(222, 45%, 7%); | |
| padding: 2rem; | |
| border-radius: 1rem; | |
| position: relative; | |
| transform-style: preserve-3d; | |
| transform: perspective(5000px) rotateY(var(--rotateX)) rotateX(var(--rotateY)); | |
| } | |
| pre > * { | |
| text-shadow: 0 0 0.3em currentColor; | |
| } | |
| pre::before, | |
| pre::after { | |
| content: ""; | |
| position: absolute; | |
| border-radius: inherit; | |
| } | |
| /* shadow */ | |
| pre::before { | |
| inset: 0.75rem; | |
| border-radius: inherit; | |
| background: black; | |
| z-index: -1; | |
| transform: translateZ(-50px); | |
| filter: blur(15px); | |
| opacity: 0.5; | |
| } | |
| /* gradient thingy */ | |
| pre::after { | |
| z-index: -2; | |
| inset: -1rem; | |
| background: linear-gradient(-45deg, red, blue); | |
| transform: translateZ(-50px); | |
| } | |
| .selector { | |
| color: var(--selector); | |
| } | |
| .property { | |
| color: var(--property); | |
| } | |
| .punctuation { | |
| color: var(--punctuation); | |
| } | |
| .property + .punctuation { | |
| color: var(--property); | |
| } | |
| .pre-container { | |
| position: relative; | |
| display: grid; | |
| grid-template: repeat(3, 1fr) / repeat(3, 1fr); | |
| } | |
| /* extras for CSS only */ | |
| .css-only pre { | |
| grid-row: 1 / -1; | |
| grid-column: 1 / -1; | |
| transition: transform 200ms ease-in-out; | |
| } | |
| .pre-container.css-only > div { | |
| z-index: 10; | |
| position: absolute; | |
| outline: 1px solid lime; | |
| } | |
| .pre-container.css-only > div:nth-child(1) { | |
| grid-column: 1 / 2; | |
| grid-row: 1 / 2; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(2) { | |
| grid-column: 2 / 3; | |
| grid-row: 1 / 2; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(3) { | |
| grid-column: 3 / 4; | |
| grid-row: 1 / 2; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(4) { | |
| grid-column: 1 / 2; | |
| grid-row: 2 / 3; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(5) { | |
| grid-column: 2 / 3; | |
| grid-row: 2 / 3; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(6) { | |
| grid-column: 3 / 4; | |
| grid-row: 2 / 3; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(7) { | |
| grid-column: 1 / 2; | |
| grid-row: 3 / 4; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(8) { | |
| grid-column: 2 / 3; | |
| grid-row: 3 / 4; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(9) { | |
| grid-column: 3 / 4; | |
| grid-row: 3 / 4; | |
| inset: 0; | |
| } | |
| .pre-container.css-only > div:nth-child(1):hover ~ pre { | |
| --rotateX: -25deg; | |
| --rotateY: 25deg; | |
| } | |
| .pre-container.css-only > div:nth-child(2):hover ~ pre { | |
| --rotateX: 0deg; | |
| --rotateY: 25deg; | |
| } | |
| .pre-container.css-only > div:nth-child(3):hover ~ pre { | |
| --rotateX: 25deg; | |
| --rotateY: 25deg; | |
| } | |
| .pre-container.css-only > div:nth-child(4):hover ~ pre { | |
| --rotateX: -25deg; | |
| --rotateY: 0deg; | |
| } | |
| .pre-container.css-only > div:nth-child(5):hover ~ pre { | |
| --rotateX: 0deg; | |
| --rotateY: 0deg; | |
| } | |
| .pre-container.css-only > div:nth-child(6):hover ~ pre { | |
| --rotateX: 25deg; | |
| --rotateY: 0deg; | |
| } | |
| .pre-container.css-only > div:nth-child(7):hover ~ pre { | |
| --rotateX: -25deg; | |
| --rotateY: -25deg; | |
| } | |
| .pre-container.css-only > div:nth-child(8):hover ~ pre { | |
| --rotateX: 0deg; | |
| --rotateY: -25deg; | |
| } | |
| .pre-container.css-only > div:nth-child(9):hover ~ pre { | |
| --rotateX: 25deg; | |
| --rotateY: -25deg; | |
| } | |
| .yt { | |
| position: fixed; | |
| bottom: 1.5rem; | |
| color: #bcbcbc; | |
| } |