Loading video...

Video Failed to Load

Go Home

CSS Tip! ๐Ÿค™ You could use CSS :has() to power a context-aware custom cursor experience ๐Ÿ‘† :root:has(.player:hover) {--active: 1;} .cursor {scale: var(--active);} :root:has(.player:hover > [aria-label="Pause"]) .cursor-pause-icon { display: block; } CodePen.IO link below! ๐Ÿ‘‡

261,705 views โ€ข 3 years ago โ€ขvia X (Twitter)

4 Comments

jhey ส•โ€ขแดฅโ€ขส”'s profile picture
jhey ส•โ€ขแดฅโ€ขส”3 years ago

Here's that @CodePen link! ๐Ÿš€ You'll need to be in a browser that supports CSS :has() โš ๏ธ Messing around with ideas for the play button challenge. The cursor is shared between the videos which is neat ๐Ÿ˜Ž

Heru Hermawan's profile picture
Heru Hermawan3 years ago

@CodePen Great tip. Thanks, jhey!

blank_'s profile picture
blank_3 years ago

@CodePen How u invent this kind of stuff man

ColdHolder's profile picture
ColdHolder3 years ago

@CodePen @SaveToNotion #thread

Related Videos

CSS Trick โšก๏ธ (ห—หห‹ rogie หŽหŠห— challenge edition ๐Ÿค™) You can create this secret code reveal with only CSS using :has() and trig functions ๐Ÿ”ฅ .digit::hover + .digit, .digit:has(+ .digit:hover) { --active: var(--lerp-1); } :root { --lerp-1: calc(sin(50deg)); } .digit { scale: calc(var(--active) + 0.5); } There are a couple of moving parts. The first thing we can do is set up a scale. :root { --lerp-0: 1; /* === sin(90deg) */ --lerp-1: calc(sin(50deg)); --lerp-2: calc(sin(45deg)); --lerp-3: calc(sin(35deg)); --lerp-4: calc(sin(25deg)); --lerp-5: calc(sin(15deg)); } The digit styles define scale and blur. They also dictate the transition duration .digit { transition: scale calc(((1 - var(--active, 0)) + 0.2) * 1s); } When a digit is hovered, then you can set the --active custom property based on the digit position ๐Ÿค™ The digit that is hovered. .digit:hover { --active: var(--lerp-0); } And the digit on either side of that hovered digit .digit:is(:hover, :focus-visible) + .digit, .digit:has(+ .digit:is(:hover, :focus-visible)) { --active: var(--lerp-1); } We can select the previous sibling using :has() and the next sibling with the sibling combinator (+) And that's it! โญ๏ธ That's how you create these hover scale interactions with CSS ๐Ÿ™Œ We're jus' waiting on Firefox for :has() support. When that lands, it'll likely break the internet ๐Ÿ˜… CodePen.IO link below! ๐Ÿ‘‡

jhey ส•โ€ขแดฅโ€ขส”

375,402 views โ€ข 2 years ago

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,714 views โ€ข 2 years ago

CSS Trick ๐Ÿค™ You can create these tab bar controls by using :has() to count the number of tabs โญ๏ธ .tabs:has(input:nth-of-type(3)){--count: 3;} .tabs:has(:checked:nth-of-type(3)){--active: 200%;} .tabs::after{ translate:var(--active) 0;} Let's break it down in this ! ๐Ÿ“ผ Couple of CSS :has() tricks here combined with custom properties ๐Ÿ˜Ž First things first, lay out the tabs using display: grid. This gives you a way to create equal-width tabs ๐Ÿ™ .tabs { display: grid; grid-auto-flow: column; } Then you use :has() to count the number of tabs and store that in a custom property ๐Ÿค“ .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 ๐Ÿซถ Using the tab count, you can size the tab indicator. For the tab indicator, use the tabs pseudoelement: .tabs::after { content: ""; position: absolute; height: 100%; width: calc(100% / var(--count)); } See how you can use --count to determine its size ๐Ÿ“ Next, use :has() to determine which tab is active or :checked with 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; } Or you could set active to the translation: .tabs:has(:checked:nth-of-type(2)) { --active: 100%; } Setting the custom property allows you to use the index elsewhere if you need it ๐Ÿค™ The final piece 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 ส•โ€ขแดฅโ€ขส”

70,730 views โ€ข 2 years ago

CSS Tip! โญ๏ธ You can use mix-blend-mode with scoped custom properties to create this inverted :hover effect ๐Ÿค™ button > span { left: calc(var(--x, 0) * 1px); top: calc(var(--y, 0) * 1px); mix-blend-mode: difference; ๐Ÿ‘ˆ } The cool trick is that using mix-blend-mode acts like a color inverter which works well with monochromatic controls ๐Ÿ˜ Saves defining the :hover colors, etc. It works it out for you! As for how to move that spot around? A teeny bit of JavaScript ๐Ÿค const UPDATE = ({target, x, y }) => { const bounds = target.getBoundingClientRect() targetโ€‹.style.setProperty('--x', x - bounds.left) targetโ€‹.style.setProperty('--y', y - boundsโ€‹.top) } const BTNS = document.querySelectorAll('button') BTNS.forEach(BTN => BTN.addEventListener('pointermove', UPDATE)) On :hover you can use a scoped custom property to change the size of the spot button:is(:hover, :focus-visible) { --active: 1; } button span { transform: translate(-50%, -50%) scale(calc(var(--active, 0) * 3); transition: transform 0.25s; } But, what about the bouncy easy? You can use linear() where supported to create a bouncy transition โœจ @โ€‹supports (transition-timing-function: linear(0, 1)) { button:is(:hover, :focus-visible) span { transition-duration: 0.5s; transition-timing-function: linear( 0, 0.5007 7.21%, 0.7803 12.29%, ... ); } } That's it! Thanks for the challenge Alohe ๐Ÿค™ CodePen.IO link below! ๐Ÿ‘‡

jhey ส•โ€ขแดฅโ€ขส”

152,923 views โ€ข 2 years ago