├── .gitignore ├── README.md ├── assets ├── base.svg ├── button.svg ├── cover.svg └── recolor-overlay.svg ├── index.html └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS system files 2 | .DS_Store 3 | **/.DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3D Pressable Button 2 | 3 | 4 | A realistic 3D button component built with HTML, CSS, and SVG that simulates the feel of pressing a physical button. The button features smooth animations, customizable colors, and responsive interactions. 5 | 6 | 7 | Created by [@BalintFerenczy](https://x.com/BalintFerenczy) 8 | 9 | Inspired by the amazing work at [Resend](https://resend.com/) 10 | 11 | 12 | ## Features 13 | 14 | - **Realistic 3D appearance** using layered SVG graphics 15 | - **Smooth animations** with custom easing functions 16 | - **Interactive states** - hover and press effects 17 | - **Customizable colors** through CSS variables 18 | - **Responsive design** that scales with container size 19 | 20 | ## Demo 21 | 22 | The button responds to user interactions with three distinct states: 23 | - **Normal**: The button in its resting position 24 | - **Hover**: Subtle downward movement when mouse hovers over 25 | - **Active**: Significant downward movement when pressed/clicked 26 | 27 | ## Usage 28 | 29 | ### Customization 30 | 31 | The button can be easily customized using CSS custom properties: 32 | 33 | ```css 34 | .frame { 35 | /* Button dimensions */ 36 | width: 400px; 37 | height: 400px; 38 | 39 | /* Movement distances */ 40 | --hover-travel: 3px; 41 | --press-travel: 40px; 42 | 43 | /* Color customization */ 44 | --color: black; 45 | --brightness: 1; 46 | --blend-mode: color; 47 | 48 | /* Transition settings */ 49 | --transition-duration: 0.4s; 50 | --transition-easing: ease-in-out; 51 | } 52 | ``` 53 | 54 | #### Changing Button Text 55 | 56 | Simply modify the text content: 57 | 58 | ```html 59 |

Click Me!

60 | ``` 61 | 62 | #### Changing Button Size 63 | 64 | Adjust the frame dimensions: 65 | 66 | ```css 67 | .frame { 68 | width: 200px; 69 | height: 200px; 70 | } 71 | ``` 72 | 73 | ## License 74 | 75 | This project is open source and available under the MIT License. 76 | 77 | ## Contributing 78 | 79 | Feel free to fork this project and submit pull requests for improvements or new features! 80 | 81 | ## Author 82 | 83 | Created by [@BalintFerenczy](https://x.com/BalintFerenczy) -------------------------------------------------------------------------------- /assets/base.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /assets/button.svg: -------------------------------------------------------------------------------- 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 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 |
137 | -------------------------------------------------------------------------------- /assets/cover.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /assets/recolor-overlay.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3D Pressable Button 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 | 15 | image 16 | image 17 | 18 | 19 | 20 | 21 | 22 | image 23 | 24 |

Button

25 | 26 |
27 | 28 |
29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .frame { 2 | position: relative; 3 | 4 | /* Button dimensions */ 5 | width: 400px; 6 | height: 400px; 7 | 8 | /* Movement distances */ 9 | --hover-travel: 3px; 10 | --press-travel: 40px; 11 | 12 | /* Color customization */ 13 | --color: black; 14 | --brightness: 1; 15 | --blend-mode: color; 16 | 17 | /* Transition settings */ 18 | --transition-duration: 0.4s; 19 | --transition-easing: linear(0, 0.008 1.1%, 0.031 2.2%, 0.129 4.8%, 0.257 7.2%, 0.671 14.2%, 0.789 16.5%, 0.881 18.6%, 0.957 20.7%, 1.019 22.9%, 1.063 25.1%, 1.094 27.4%, 1.114 30.7%, 1.112 34.5%, 1.018 49.9%, 0.99 59.1%, 1); 20 | } 21 | 22 | .frame, .recolor-overlay, .button, .text { 23 | user-select: none; 24 | } 25 | 26 | .base { 27 | width: 100%; height: 100%; 28 | } 29 | 30 | .recolor-overlay { 31 | position: absolute; 32 | width: 100%; height: 100%; 33 | color: var(--color); 34 | top: 0; 35 | left: 0; 36 | mix-blend-mode: var(--blend-mode); 37 | 38 | transition-property: all; 39 | transition-duration: var(--transition-duration); 40 | transition-timing-function: var(--transition-easing); 41 | } 42 | 43 | .button { 44 | position: absolute; 45 | width: 100%; height: 100%; 46 | top: 0; 47 | left: 0; 48 | filter: brightness(var(--brightness)); 49 | 50 | transition-property: all; 51 | transition-duration: var(--transition-duration); 52 | transition-timing-function: var(--transition-easing); 53 | } 54 | 55 | .cover { 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | width: 100%; height: 100%; 60 | } 61 | 62 | .frame:hover .button, .frame:hover .text, .frame:hover .recolor-overlay { 63 | margin-top: var(--hover-travel); 64 | } 65 | 66 | .frame:active .button, .frame:active .text, .frame:active .recolor-overlay { 67 | margin-top: var(--press-travel); 68 | } 69 | 70 | .text { 71 | font-family: sans-serif; 72 | font-size: 2rem; 73 | color: white; 74 | white-space: nowrap; 75 | 76 | position: absolute; 77 | width: 100%; 78 | height: 100%; 79 | top: 50%; 80 | left: 50%; 81 | text-align: center; 82 | align-content: center; 83 | translate: -50% -50%; 84 | transform: rotateY(0deg) rotateX(52.3deg) rotateZ(29deg) translateY(-28%) translateX(-16%); 85 | margin: 0px; 86 | padding: 0px; 87 | 88 | transition-property: all; 89 | transition-timing-function: var(--transition-easing); 90 | transition-duration: var(--transition-duration); 91 | } --------------------------------------------------------------------------------