Home >Web Front-end >CSS Tutorial >Creating Directionally Lit 3D Buttons with CSS
I’m not too sure how I stumbled into this one. But something led me to this tweet:
Has anyone done this directional lighting cursor interaction with CSS? pic.twitter.com/zLL7Sk6kW5
— Jed Bridges (@JedBridges) July 1, 2020
And, to me, that’s a challenge.
The button design is neat. But I didn’t want to do a direct copy. Instead, we decided to make a “Twitter” button. The idea is that we create an almost transparent button with a social icon on it. And then that social icon casts a shadow below. Moving our mouse across the button shines a light over it. Pressing the button pushes it onto the surface. Here’s the final result:
Directional Lighting 3D CSS Twitter Button ?
— Jhey ?? (@jh3yy) January 30, 2021
? https://t.co/qpfzEwUMey via @CodePen pic.twitter.com/zWfwtPaixo
In this article, we’re going to look at how you can make it too. The cool thing is, you can swap the icon out to whatever you want.
My first-take approach for creating something like this is to scaffold the markup. Upon first inspection, we’ll need to duplicate the social icon used. And a neat way to do this is to use Pug and leverage mixins:
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
Here, we’ve created a mixin for rendering an SVG of the Twitter icon. This would render the Twitter icon if we invoke it like so:
<span><span>+icon()</span> </span>
Doing that will give us a big Twitter icon.
See the Pen 1. Render An Icon by SitePoint (@SitePoint) on CodePen.
Because social icon sets tend to use the same “0 0 24 24” viewBox, we could make the title and path arguments:
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
Then our Twitter icon becomes
<span><span>+icon()</span> </span>
But, we could pass it a key — and then have the paths stored in an object if we have many icons we wanted to use or repeat:
<span><span>mixin icon(title, path)</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= title </span> <span>path<span><span>(d=path)</span></span> </span>
This can be a neat way to create an icon mixin to reuse. It’s a little overkill for our example, but worth noting.
Now, we need some markup for our button.
<span><span>+icon('Twitter Icon', 'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')</span> </span>
It’s always good to be mindful of accessibility. We can check what our button gives off by checking the Accessibility panel in your browser’s developer tools.
It might be a good idea to put a span in for our button text and hide the icons with aria-hidden. We can hide the span text too whilst making it available to screen readers:
<span><span>mixin icon(key)</span> </span> <span>- </span> <span>const PATH_MAP = { </span> <span>Twitter<span>:</span> "M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" </span> } <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= <span><span>`<span>${key}</span> Icon`</span></span> </span> <span>path<span><span>(d=<span>PATH_MAP[key]</span>)</span></span> </span> <span><span>+icon('Twitter')</span> </span>
We’ve got different options for applying those aria-hidden attributes. The one we’ll use is changing the mixin code to apply aria-hidden:
<span><span>.scene</span> </span> <span>button<span>.button</span> </span> <span>span<span>.button__shadow</span> </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__content</span> </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__shine</span> </span>
Another neat way with Pug is to pass through all attributes to a mixin. This is useful in scenarios where we only want to pass some attributes through:
<span><span>.scene</span> </span> <span>button<span>.button</span> </span> <span>span<span>.button__shadow</span> </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__content</span> </span> <span>span<span>.button__text</span> Twitter </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__shine</span> </span>
If we check the Accessibility panel again, our button only reads “Twitter”. And that’s what we want!
Here’s the part you came for — how we style the thing. To start, we’ve dropped this in:
<span><span>mixin icon(key)</span> </span> <span>- </span> <span>const PATH_MAP = { </span> <span>Twitter<span>:</span> "...path code" </span> } <span>svg<span>.button__icon<span>(role=<span>'img' aria-hidden="true" xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= <span><span>`<span>${key}</span> Icon`</span></span> </span> <span>path<span><span>(d=<span>PATH_MAP[key]</span>)</span></span> </span>
That allows us to create the 3D transforms we need for our button. Try switching that off in the final demo and you’ll see that everything breaks.
Let’s hide the span text from our eyes. We can do this in many ways. One recommended way to hide an element from our eyes, but not those of the screenreader, is to use these styles:
<span><span>mixin icon(key)</span> </span> <span>- </span> <span>const PATH_MAP = { </span> <span>Twitter<span>:</span> "...path code" </span> } <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span><span>&attributes(attributes)</span></span> </span> <span>title= <span><span>`<span>${key}</span> Icon`</span></span> </span> <span>path<span><span>(d=<span>PATH_MAP[key]</span>)</span></span> </span>
Before we start working on our button, we’re going to tilt the scene. We can do this using a transform. Here we chain the transform to get it into the position we want. I spent a bit of time tinkering with values here on live stream to get it close to the original:
<span>* { </span> <span>transform-style: preserve-3d; </span><span>} </span>
You’ll notice a size variable there too. We’re going to drive certain things for our button with CSS variables. This will make it handy for tinkering with values and the effect. Usually, we’d put these under the scope they’re required in. But, for demos like this, putting them under the :root at the top of our file makes it easier for us to play with.
<span><span>.button__text</span> { </span> <span>position: absolute; </span> <span>width: 1px; </span> <span>height: 1px; </span> <span>padding: 0; </span> <span>margin: -1px; </span> <span>overflow: hidden; </span> <span>clip: rect(0, 0, 0, 0); </span> <span>white-space: nowrap; </span> <span>border-width: 0; </span><span>} </span>
These are the variables we’re working with, and they’ll make sense as we build up our button.
Let’s move on to the button! The button element is going to fill the scene element. We could have applied the sizing and transforms directly on the button. But if we were to introduce other buttons and elements, we’d have to transform and size them all. This is something to be mindful of with CSS in general. Try to make your container elements dictate the layout:
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
Here we strip the button styles. And that gives us this.
See the Pen 9. Strip Button Styles by SitePoint (@SitePoint) on CodePen.
Next, we need to create a common starting point for the button content and the shadow. We can do this by giving each element absolute positioning. The content will have a 3D translate based on the depth variable we defined before:
<span><span>+icon()</span> </span>
Note how we’re also making use of the --radius variable too.
See the Pen 10. Give The Button Depth by SitePoint (@SitePoint) on CodePen.
It’s hard to distinguish between the two icons at this stage. And now’s a good time to style them. We can apply some basic icon styling and use a scoped fill for each SVG icon:
<span><span>mixin icon(title, path)</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= title </span> <span>path<span><span>(d=path)</span></span> </span>
It’s getting there! The icons aren’t the same size at the moment, though. We’ll get to that.
See the Pen 11. Apply Scoped Fill by SitePoint (@SitePoint) on CodePen.
Let’s get the button press in place. This part is really quick to integrate:
<span><span>+icon('Twitter Icon', 'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')</span> </span>
That’s it! Using scoped CSS variables, we’re saying remove the z-axis translation on :active. Adding the transition to the transform stops it from being so instant.
See the Pen 12. Press on :active by SitePoint (@SitePoint) on CodePen.
All that’s left to do is style the button layers and the shine. Let’s start with the shadow:
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
Another scoped style here. We’re saying that when we press the button, the shadow is no longer blurred. And to blur the shadow, we use the CSS filter property with a blur filter — the value of which we defined in our CSS variables. Have a play with the --blur variable and see what happens.
See the Pen 13. Reduce Blur on Hover by SitePoint (@SitePoint) on CodePen.
For the content layer, we’re going to use a background color and then apply a backdrop filter. Much like filter, backdrop-filter is a way for us to apply visual effects to elements. A common use case currently is to use blur for “Glassmorphism”:
<span><span>+icon()</span> </span>
We use the value of --blur and apply a transition for backdrop-filter. Because of the way we scoped our --blur variable on :active, we get the transition almost for free. Why the overflow: hidden? We’re anticipating that shine element that will move around the button. We don’t want it wandering off outside, though.
See the Pen 14. Styling Content Layer by SitePoint (@SitePoint) on CodePen.
And now, the last piece of the puzzle— that light shine. This is what’s been causing the icons to be a different size. Because it has no styles, it’s affecting the layout. Let’s give it some styles:
<span><span>mixin icon(title, path)</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= title </span> <span>path<span><span>(d=path)</span></span> </span>
That absolute positioning will sort out the icon sizing. Applying a border radius will make the spotlight round. And we use filter again to give the blurry spot light effect. You’ll notice we’ve chained a brightness filter on the end there to brighten things up a bit after they’re blurred.
See the Pen 15. Styling Shine by SitePoint (@SitePoint) on CodePen.
Using the 3D translation ensures that the shine sits above the button, which it would do. This way, there’s no chance of it getting cut by z-fighting with other elements.
That’s all we need for the styles for now. Now it’s time for some scripts.
We’re going to use GreenSock here for convenience. They have some neat utilities for what we want. But, we could achieve the same result with vanilla JavaScript. Because we’re using scripts with type “module”, we can take advantage of SkyPack.
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
And now we’re ready to start tinkering. We want our button to respond to pointer movement. The first thing we want is to translate the shine as if it follows our pointer. The second is to shift the button depending on where our pointer is.
Let’s grab the elements we need and set up some basic event listeners on the document:
<span><span>+icon()</span> </span>
Try moving your pointer around in this demo to see the valuables we get returned for x and y:
See the Pen 16. Grabbing Elements and Creating Event Listeners by SitePoint (@SitePoint) on CodePen.
This is the trickiest bit. We need some math to work out the shine position. We’re going to translate the shine after its initial reset. We need to first update the shine styles to accommodate this. We’re using the scoped CSS variables --x and --y. We give them a fallback of -150 so they’ll be out of shot when the demo loads:
<span><span>mixin icon(title, path)</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= title </span> <span>path<span><span>(d=path)</span></span> </span>
Then, in our update function we calculate the new position for the shine. We’re basing this on a percentage of the button size. We can calculate this by subtracting the button position from our pointer position. Then we divide that by the position. To finish, multiply by 200 to get a percentage:
<span><span>+icon('Twitter Icon', 'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')</span> </span>
For example, POS_X:
We multiply by 200 because the shine is half the size of the button. This particular part is tricky because we’re trying to track the pointer and map it into 3D space.
To apply that to the button, we can set those CSS variables using gsap.set. That’s a GSAP method that works as a zero second tween. It’s particularly useful for setting values on elements:
<span><span>mixin icon(key)</span> </span> <span>- </span> <span>const PATH_MAP = { </span> <span>Twitter<span>:</span> "M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" </span> } <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= <span><span>`<span>${key}</span> Icon`</span></span> </span> <span>path<span><span>(d=<span>PATH_MAP[key]</span>)</span></span> </span> <span><span>+icon('Twitter')</span> </span>
But, if we want to take it one step further, we can use a quickSetter from GSAP, which would be better for performance in real-world scenarios where we’re making lots of updates:
<span><span>.scene</span> </span> <span>button<span>.button</span> </span> <span>span<span>.button__shadow</span> </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__content</span> </span> <span><span>+icon('Twitter')</span> </span> <span>span<span>.button__shine</span> </span>
That makes our update function look something like this:
<span><span>mixin icon()</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title Twitter icon </span> <span>path<span><span>(d=<span>'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z'</span>)</span></span> </span>
The accuracy of following the pointer would need more calculations to be precise. Have a play with this demo where the overflow on the button is visible and the shine is more prominent. You can see how the shine element loses its tracking.
See the Pen 17. Translating the Shine Playground by SitePoint (@SitePoint) on CodePen.
This demo puts everything where it should be.
See the Pen 18. Translating the Shine by SitePoint (@SitePoint) on CodePen.
Last feature. Let’s shift the button for an added touch. Here, we’re going to base the shift of the button on pointer position. But, we’re going to limit its movement. To do this, we can use another GSAP utility. We’re going to use mapRange. This allows us to map one set of values to another. We can then pass a value in and get a mapped value back out.
First, we’ll define a limit for movement. This will be a percentage of the button size:
<span><span>+icon()</span> </span>
Now, in our update function we can calculate the percentage of shift. We do this by mapping the window width against the limit. And we input our pointer position to get the mapped percentage back:
<span><span>mixin icon(title, path)</span> </span> <span>svg<span>.button__icon<span>(role=<span>'img' xmlns='http://www.w3.org/2000/svg' viewbox='0 0 24 24'</span>)</span></span> </span> <span>title= title </span> <span>path<span><span>(d=path)</span></span> </span>
In this block we’re mapping the range of 0 to window.innerWidth against -10 to 10. Passing pointer position x will give us a value between -10 and 10. And then we can apply that percentage shift to our button. We do the same for vertical shift and this gives us an update function like the following:
<span><span>+icon('Twitter Icon', 'M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z')</span> </span>
That’s how you create a directional lit 3D button with CSS and a little scripting. The cool thing is that we can make changes with relative ease.
For the final demo, I’ve added some extra details and changed the icon. You might recognize it.
See the Pen 20. SitePoint Button by SitePoint (@SitePoint) on CodePen.
As always, thanks for reading. Wanna see more? Come find me on Twitter or check out the the live stream!
Creating a 3D button that changes when clicked involves using the :active pseudo-class in CSS. This pseudo-class is used to style an element when it’s being activated by the user. For instance, you can change the color, size, or position of the button when it’s clicked. Here’s a simple example:
.button:active {
background-color: #3e8e41;
box-shadow: 0 5px #666;
transform: translateY(4px);
}
In this example, the button’s background color changes to a different shade of green when clicked. The box-shadow property adds a shadow effect, and the transform property moves the button down slightly.
Adding a hover effect to your 3D button can be achieved using the :hover pseudo-class in CSS. This pseudo-class is used to style an element when the mouse pointer is over it. You can change the color, size, or add a shadow to the button when it’s hovered over. Here’s a simple example:
.button:hover {
background-color: #3e8e41;
box-shadow: 0 5px #666;
}
In this example, the button’s background color changes to a different shade of green when hovered over, and a shadow effect is added.
Making your 3D button responsive involves using media queries in CSS. Media queries allow you to apply different styles for different devices or screen sizes. For instance, you can change the size or position of the button depending on the screen size. Here’s a simple example:
@media screen and (max-width: 600px) {
.button {
width: 100%;
padding: 20px;
}
}
In this example, the button’s width is set to 100% and the padding is increased when the screen size is 600px or less.
Adding a transition effect to your 3D button can be achieved using the transition property in CSS. This property allows you to specify the speed of the effect. For instance, you can make the color change or the shadow appear gradually. Here’s a simple example:
.button {
transition: background-color 0.5s ease, box-shadow 0.5s ease;
}
In this example, the background color and the shadow change gradually over a period of 0.5 seconds.
Creating a 3D button with rounded corners involves using the border-radius property in CSS. This property allows you to add rounded borders to an element. For instance, you can make the button’s corners round. Here’s a simple example:
.button {
border-radius: 12px;
}
In this example, the button’s corners are rounded with a radius of 12px.
Creating a 3D button with a gradient background involves using the linear-gradient function in CSS. This function allows you to create a gradient that transitions between two or more colors. Here’s a simple example:
.button {
background: linear-gradient(to right, #ff7f00, #ff5500);
}
In this example, the button’s background transitions from a light orange color to a darker orange color.
Creating a 3D button with a shadow effect involves using the box-shadow property in CSS. This property allows you to add a shadow to an element. For instance, you can add a shadow to the button to make it look 3D. Here’s a simple example:
.button {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
In this example, the button has a shadow that’s 5px below the button and has a blur radius of 15px. The color of the shadow is a semi-transparent black.
Creating a 3D button with a border involves using the border property in CSS. This property allows you to add a border to an element. For instance, you can add a border to the button to make it stand out. Here’s a simple example:
.button {
border: 2px solid #ff5500;
}
In this example, the button has a 2px solid border with a color of orange.
Creating a 3D button with text inside involves using the text properties in CSS. These properties allow you to style the text inside an element. For instance, you can change the color, size, or font of the text inside the button. Here’s a simple example:
.button {
color: #fff;
font-size: 20px;
font-family: Arial, sans-serif;
}
In this example, the text inside the button is white, has a size of 20px, and uses the Arial font.
Creating a 3D button that’s compatible with all browsers involves using vendor prefixes in CSS. These prefixes allow you to use new CSS features before they’re fully supported in all browsers. For instance, you can use the -webkit- prefix for Chrome and Safari, the -moz- prefix for Firefox, and the -ms- prefix for Internet Explorer. Here’s a simple example:
.button {
-webkit-transition: background-color 0.5s ease, box-shadow 0.5s ease;
-moz-transition: background-color 0.5s ease, box-shadow 0.5s ease;
-ms-transition: background-color 0.5s ease, box-shadow 0.5s ease;
transition: background-color 0.5s ease, box-shadow 0.5s ease;
}
In this example, the transition effect is compatible with Chrome, Safari, Firefox, and Internet Explorer.
The above is the detailed content of Creating Directionally Lit 3D Buttons with CSS. For more information, please follow other related articles on the PHP Chinese website!