Video wird geladen...

Video konnte nicht geladen werden

Zur Startseite

CSS Tip! 💫 You can create this responsive perspective warp animation with 3D CSS and container queries ✨ (Video reveals trick 👀) .warp { container-type: size; perspective: 100px; transform-style: preserve-3d; resize: both; overflow: hidden; } Couple of tricks in this one 🤓 The main idea is to create a...

187,474 Aufrufe • vor 2 Jahren •via X (Twitter)

10 Kommentare

Profilbild von jhey ▲🐻🎈
jhey ▲🐻🎈vor 2 Jahren

Here's that @CodePen link! 🚀 Works in Chrome, Firefox, and Safari 🤙 Recommend playing with different combinations of properties in this one 🤓 Tricky to do an exploding view for this one but showing the tunnel should help 🤞

Profilbild von YOUR TECH BRO 🧑‍💻
YOUR TECH BRO 🧑‍💻vor 1 Jahr

This is crazy 🤩

Profilbild von Parveen Tyagi
Parveen Tyagivor 1 Jahr

The use of mask-composite opens up so many possibilities. Could you share more examples or a tutorial on how to implement this in different scenarios?”

Profilbild von Nicolas Jesenberger
Nicolas Jesenbergervor 2 Jahren

Clever!

Profilbild von Cu & Código
Cu & Códigovor 2 Jahren

@umataldetatiana

Profilbild von FBP
FBPvor 2 Jahren

Savage, you should consider doing this for a living.

Profilbild von jhey ▲🐻🎈
jhey ▲🐻🎈vor 2 Jahren

We're building a site 🤙🤫 👀

Profilbild von Ajay
Ajayvor 2 Jahren

This would be pretty nice to see in magicui @dillionverma 👀

Profilbild von JohnPhamous
JohnPhamousvor 2 Jahren

wowow

Profilbild von Ajay
Ajayvor 2 Jahren

Where’s the link sir

Ähnliche Videos

CSS Tip! 🎠 You can create a responsive infinite marquee animation with container queries and no duplicate items 🤙 li{ animation: slide; } @​keyframes slide { to { translate: 0% calc(var(--i) * -100%);}} The trick is animating the items, not the list 😎 More tricks 👇 To get this one working, you need to animate the items and not the list (Watch the video first?). Each item needs to know its row index (--i) in the list and the parent needs to know how many rows are in the list: ul { --count: 12; } li:nth-of-type(1), li:nth-of-type(2) { --i: 0; } li:nth-of-type(3), li:nth-of-type(4) { --i: 1; } Once you have that, translate each item based on its row index in the list li { translate: 0% calc((var(--count) - var(--i)) * 100%); } Now for the animation. The key here is that each row has an animation-delay calculated from its index (--i). That number is offset to make it negative so the animation start is offset ✨ ul { --duration: 10s; } li { --delay: calc((var(--duration) / var(--count)) * (var(--i) - 8)); animation: slide var(--duration) var(--delay) infinite linear; } Make sure to wrap that animation in: @​media (prefers-reduced-motion: no-preference) { ... } Lastly, the fun parts! 🤓 To create the "vignette" mask. Use a layered mask on the container 😷 .scene { --buff: 3rem; height: 100%; width: 100%; mask: linear-gradient(transparent, white var(--buff) calc(100% - var(--buff)), transparent), linear-gradient(90deg, transparent, white var(--buff) calc(100% - var(--buff)), transparent); mask-composite: intersect; } To create the 3D skewed effect, use a chained transform (Try toggling it in the demo ⚡️): .grid { transform: rotateX(20deg) rotateZ(-20deg) skewX(20deg); } As for the responsive part, use container queries! 🔥 article { container-type: inline-size; } When the article (card) is narrower than 400px update the grid and animation settings 🤙 Double the rows means double the duration! @​container (width < 400px) { .grid { --count: 12; grid-template-columns: 1fr; } li:nth-of-type(1) { --i: 0; } li:nth-of-type(2) { --i: 1; } li:nth-of-type(3) { --i: 2; } li:nth-of-type(4) { --i: 3; } li { --duration: 20s; } } CSS has the magic to be able to update those animations at runtime based on your custom property values 😎 An added bonus in this demo is that it doesn't require any JavaScript at all, for any of it 🤯 We can use CSS :has() for those toggles that update the styles, even the theme toggle! 🫶 Any questions, let me know! Make sure to check out the video. Will do a walkthrough one to follow-up 🤙 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

541,845 Aufrufe • vor 2 Jahren

CSS Tip! 💪 You can create these tab controls with CSS :has() + radio buttons ✨ .tabs:has(input:nth-of-type(3)) { --count: 3; } .tabs:has(:checked:nth-of-type(3)) { --active: 2; } .tabs::after { translate: calc(var(--active, 0) * 100%) 0; width: calc(100% / var(--count)); } Two CSS :has() tricks here combined with a rendering trick 🤙 The tab control is a container using display: grid. You can use :has() to count the number of tabs in the container: .tabs:has(input:nth-of-type(3)) { --count: 3; } .tabs:has(input:nth-of-type(4)) { --count: 4; } Using the cascade, the last valid :has() gives you the number of tabs 🫶 Once you know the number of tabs, you know how to size the indicator: .tabs::after { content: ""; position: absolute; height: 100%; width: calc(100% / var(--count)); } It's a pseudoelement that uses --count to determine its size 📏 The next :has() trick is determining which tab is active or :checked as it's an input [type=radio] .tabs:has(:checked:nth-of-type(2)) { --active: 1; } .tabs:has(:checked:nth-of-type(3)) { --active: 2; } You can use a zero-indexed translation here. If the second input is :checked, set --active: 1, then translate the pseudoelement on the tabs to that position 👉 .tabs::after { translate: calc(var(--active, 0) * 100%) 0; } The last rendering trick is using mix-blend-mode 👀 The tabs have a black background-color, the pseudoelement is white, and the label text is white. When you use mix-blend-mode: difference on the pseudoelement it will give this effect that the text transitions from white to black sliding across 😎 .tabs::after { color: hsl(0 0% 100%); mix-blend-mode: difference; } You can totally mix up the colors here though and go with a different effect. The mechanics of how you can use CSS :has() is the main point here 🙏 As always, any questions, suggestions, etc. let me know CodePen.IO link below! 👇 (There's even a Tailwind CSS play for this one too 👀)

jhey ʕ•ᴥ•ʔ

437,300 Aufrufe • vor 2 Jahren

CSS Tip! ✨ It's 2024 and you have a new way to make animated borders 🚀 .glow::after { offset-path: rect(0 100% 100% 0 round var(--radius)); animation: loop; } @​keyframes loop { to { offset-distance: 100%; }} Using the offset-* properties you can animate elements along the perimeter of others 😍 The rect() value gained support in Safari 17.2 🙌 To start, you create an element and put it inside your main element. For example, you put a span inside the button 🤙 Click me! Make the element fill its parent with absolute positioning and inset [data-glow] { position: absolute; inset: 0; } Now the good part, you use a pseudoelement on that element and define an offset-path [data-glow]::after { content: ""; offset-path: rect(0 auto auto 0 round var(--radius)); animation: loop 2.6s infinite linear; } With the rect value, you are saying the path fills the parent container: top: 0 right: auto || 100% bottom: auto || 100% left: 0 Then you can use round to make sure the path uses the same radius as whatever the parent has The @​keyframes animation merely animates the offset-distance of that pseudoelement to 100% @​keyframes loop { to { offset-distance: 100%; }} You can see this more clearly in the video 🫶 The offset-* properties also include an offset-anchor property. This allows you to dictate which point of the element follows the path. For example: anchor-offset: 100% 50%; This means that the "right, center" of the element will follow the perimeter of the parent element 🤙 Lastly, the visuals 🎨 For color, you can use a gradient such as a linear gradient to fill the pseudo-element. [data-glow]::after { background: radial-gradient( circle at right, hsl(320 90% 100%), transparent 50% ); } Then clip away everything so you only have the border and can still have translucent backgrounds, etc. Use a mask with mask-composite ✨ A little transparent border trick: [data-glow] { border: 2px solid transparent; mask: linear-gradient(transparent, transparent), linear-gradient(white, white); mask-clip: padding-box, border-box; mask-composite: intersect; } Bit of a long one. Hope you find it useful 🙏 CodePen.IO link below 👇

jhey ʕ•ᴥ•ʔ

283,418 Aufrufe • vor 2 Jahren

CSS Trick! 🤙 You can create gradient borders on translucent elements using mask-clip and mask-composite with a pseudo-element 🔥 .gradient-border::after { mask-clip: padding-box, border-box; mask-composite: intersect; mask: linear-gradient(transparent, transparent), linear-gradient(white, white); } It's the same "Transparent border trick" from before. But, now you apply it to a pseudo-element 😎 The trick is to create a pseudo-element with a gradient background and then mask it so we only see the part we want, the border ✨ mask-clip defines the area affected by a mask. Similar to how you can define background-size. Using padding-box and border-box constrains the two masks. mask-composite is the magic part ✨ It defines a compositing operation for stacked mask layers. Using intersect means that the parts that overlap get replaced. And this seems to work in all browsers 🙌 As for the rest of the styles... – Make sure you set pointer-events: none on the pseudo-element – Make sure it fills the parent element. You can use position: absolute and inset: 0 – Make sure the background fills the space including the border-width. You can use calc to achieve that: --bg-size: calc(100% + (2px * var(--border))); background: var(--gradient) center center / var(--bg-size) var(--bg-size); That's it! 🚀 Gradient borders on translucent elements. You can set all the backdrop-filter: blur() you like! 😅 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

269,739 Aufrufe • vor 2 Jahren

CSS Tip! 🚥 You can create these trending expanding scroll indicators with scroll-driven animations and flex 🤙 .indicator { animation: grow; animation-range: contain calc(50% - var(--size)...; animation-timeline: var(--card); } @​keyframes grow { 50% { flex: 3; }} What's the trick? Put the indicators in a container using flex layout and set a width larger than the number of indicators 😉 .indicators { aspect-ratio: 7 / 1; display: flex; } Importantly, set no gap 🤏 To mimic the gap set a transparent border on each indicator and set the background using padding-box .indicator { background: linear-gradient(#​fff, #​fff) padding-box; border-radius: 50px; border: 4px solid transparent; } Now for the animation. You want to create a view-timeline for each card that moves across 🤙 li:nth-of-type(1) { view-timeline: --one inline; } li:nth-of-type(2) { view-timeline: --two inline; } Make sure they use the inline axis too! The trick is hoisting these view-timeline so the indicators can use them with timeline-scope 👀 .track { timeline-scope: --one, --two, ...; } All that's left is for you to create the animation piece using some calc with the card size ⚡️ .indicator { --size: calc(var(--card-width) * 0.9); animation: grow both linear; animation-range: contain calc(50% - var(--size)) contain calc(50% + var(--size)); } .indicator:nth-of-type(1) { animation-timeline: --one; } .indicator:nth-of-type(2) { animation-timeline: --two; } @​keyframes grow { 50% { flex: 3; }} And there you have it, responsive scroll indicators using CSS scroll-driven animations 😎 Sprinkle a little JavaScript to make them clickable and scroll the the right card ✨ const shift = (event) => { if (event​.target.tagName === "BUTTON") { const index = [...event.target.parentNode.children].indexOf(event​.target); const item = document.querySelector(`li:nth-of-type(${index + 1})`); item.scrollIntoView({ behavior: "smooth", inline: "center" }); } }; As always, any questions or suggestions, let me know. I've put a JavaScript fallback in to use GSAP in browsers that don't have scroll-driven animations 🫶 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

575,316 Aufrufe • vor 2 Jahren

CSS Tip! 🤙 You can use mask-composite and some JavaScript to create this pointer proximity following glow border ✨ .glow { mask-composite: intersect; mask-clip: padding-box, border-box; mask: linear-gradient(#0000, #0000), conic-gradient(#0000 0deg, #​fff, #0000 45deg); } The trick is to mask a background-image with a combination of mask layers. mask-composite: intersect; means the mask used will be the intersection of the layers 🔥 use source-in, xor; in browsers that don't support intersect; In this demo, you can use pseudoelements and rely on scoped custom properties to do a lot of the heavy lifting for you 🙌 Once you've masked the background, you need to update the starting angle of the conic-gradient on pointermove 👆 You can work that out by getting the center point of each card and then calculating the angle between that and the pointer with Math.atan2 🤓 let ANGLE = Math.atan2( event?.y - CARD_CENTER[1], event?.x - CARD_CENTER[0] ) * 180 / Math.PI ANGLE = ANGLE < 0 ? ANGLE + 360 : ANGLE; CARD.​style.setProperty('--start', ANGLE + 90) You plug that into your conic-gradient mask as a custom property accounting for --spread ⚡️ conic-gradient(from calc((var(--angle) - (var(--spread) * 0.5)) * 1deg), #000 0deg, #​fff, #0000 calc(var(--spread) * 1deg)); To get the blur, you apply a blur to the glow container on each card 🤙 .glows { filter: blur(calc(var(--blur) * 1px); } That's it! Layers of masks that are clipped and composited before being blurred 😎 The added trick is to fade each one in when the pointer is in the defined proximity of the card. For example, don't show unless within 100px of a card. You can see that in the video. Check out the JavaScript code for that 🫶 Couldn't resist making this one 😁 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

1,179,179 Aufrufe • vor 2 Jahren

CSS Tip! 🤯 You can create a CSS-only version of this balance slider using a scroll animation on the underlying input[type=range] 🚀 ::-webkit-slider-thumb { view-timeline: --thumb inline; } Scroll animation driven by the slider thumb animates a number between the "min" and "max" of the range 😅 @​property --value { inherits: true; initial-value: 0; syntax: ' '; } @​keyframes sync { to { --value: 100; }} Tie that up to the contain animation-range ⚡️ .control { animation: sync both linear reverse; animation-timeline: --thumb; animation-range: contain; } Hoist the view timeline so all the parts of the control can use it! .control { timeline-scope: --thumb; } Use that value in a counter which is used for the labels. Create a low and a high for each side 😇 .control__label { counter-reset: low var(--value) high calc(100 - var(--value)); } .control__label::before { content: "COFFEE " counter(low) "%"; } .control__label::after { content: counter(high) "% MILK"; } That's the magic of updating the label values ✨ For the big track, it's a fake track. You can make use of the same --value property and do some calc() to work out the width of each part. .control__track::before { width: calc(var(--value) * 1% - 0.5rem); background: var(--coffee); border-radius: 4px; transition: width 0.1s; } The width leaves a little gap for the indicator piece 🤙 The color calculation for --coffee isn't too wild but again you can use the same --value .control__track { --coffee: hsl(24 74% calc( 24% + (30% * ((100 - var(--value, 0)) / 100)) / 1 ) / 0.4); } Now for the last piece. Making the track change height. You could set up another custom property and animate its value using the --thumb timeline too 🔥 @​property --shift { initial-value: 0; inherits: true; syntax: ' '; } @​keyframes shift { 0%, 31%, 61%, 100% { --shift: 0; } 32%, 60% { --shift: 1; } } Then use that --shift to update the translation of the label and height of the track 🤓 .label { transform: translateY(calc(var(--shift) * 50%)); transition: transform var(--speed) var(--timing); } Cool part here is that you can use the control to work out the @​keyframes percentages 😅 Oh. And the timing for that little bounce? Use the linear() function 😎 :root { --timing: linear( 0, 0.5007 7.21%, 0.7803 12.29%, 0.8883 14.93%, 0.9724 17.63%, 1.0343 20.44%, 1.0754 23.44%, 1.0898 25.22%, 1.0984 27.11%, 1.1014 29.15%, 1.0989 31.4%, 1.0854 35.23%, 1.0196 48.86%, 1.0043 54.06%, 0.9956 59.6%, 0.9925 68.11%, 1 ); } Should probably do a video on this one. Lots of little custom property tricks for sure! 💯 It's not too far off the range slider with the tooltip that came up previously As always, any questions, let me know! Also, this one only works in Chrome currently ✅🥲 This one's a bit rocket science ha 🚀 CodePen.IO link below! 👇

jhey ʕ•ᴥ•ʔ

377,435 Aufrufe • vor 2 Jahren

CSS Tip! ✨ You can create these parallax effects and image cross-fades with scroll-driven animations 🤙 img { animation: fade; animation-timeline: view(); mix-blend-mode: plus-lighter } img:last-of-type { animation-direction: reverse; } @​keyframes fade { to { opacity: 0; }} This one's fun! 😁 The trick with the cross-fading image is to make use of one animation that runs at the same time on two images inside a container. You use the same animation, animation-timeline, and animation-range. But, you use animation-direction: reverse on one of the images so they go in the opposite direction 🫶 The use of mix-blend-mode: plus-lighter; produces a better cross-fade result 💯 A viewTimeline (view()) works because you know that both images are the same height. The range you can use is img { animation-timeline: view(); animation-range: cover 45% cover 55%; } That means when the image has covered 45% of the scrollport (In this case, the window), start the animation. And finish when it has covered 55% 🎬 How about the slight parallax? This is a trick with calc(). You know the top of the small image and the big image line up. And you can do this by absolutely placing the caption outside of the small image. The trick is to translate the small image by a distance so it lines up with the bottom of the big image. You can do that like this :root { --catch-up: calc( var(--big-height) - var(--small-height) ); } @​keyframes move { to { translate: 0 var(--catch-up); }} Then drive that animation with a scroll-driven animation using the container of both images as the driver 🤙 /* section contains both images */ section { view-timeline: --container; } .img-fader { animation: catch-up both linear; animation-timeline: --container; animation-range: 50vh calc(100vh + (var(--big-height) * 0.25)); } That's it! Scroll-driven image cross-fading and parallax effects without any JavaScript. This demo will work in all browsers as there is some JavaScript in place where the API isn't supported 🤙 To do that, it uses GSAP ScrollTrigger 🏆 As always, any questions, requests, etc. hit me up! 🤙 CodePen.IO link below 👇

jhey ʕ•ᴥ•ʔ

241,952 Aufrufe • vor 2 Jahren