Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@
All notable changes to this project are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [2.1.0] - 2026-07-13

### Added

- The `JayButton Classic` and `JayButton Studio` names for the two maintained designs.
- Descriptive `.jay-button-classic`, `.jay-button-studio`, and `.jay-button-studio__cap` class names.

### Changed

- The live demo and documentation now present Classic and Studio together.
- The project preview now shows both distinct button designs.

### Fixed

- Restored the original glossy brown face, copper highlight, deep edge, ground shadow, and press depth for `.JayBrown`.
- Removed unrelated page-wide rules from the original stylesheet while preserving the button itself.

### Compatibility

- `.JayBrown`, `.jay-button`, and `.jay-button__cap` remain supported without markup changes.

## [2.0.0] - 2026-07-12

### Added
Expand Down Expand Up @@ -30,3 +51,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- The original `.JayBrown` single-element class remains available for existing markup.

[2.0.0]: https://github.com/JaydenART/JaydenART_Realistic_3D_CSS_Button/releases/tag/v2.0.0
[2.1.0]: https://github.com/JaydenART/JaydenART_Realistic_3D_CSS_Button/compare/v2.0.0...v2.1.0
115 changes: 74 additions & 41 deletions JayButton.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* JaydenART Realistic 3D CSS Button v2.0.0 */
/* JaydenART Realistic 3D CSS Button v2.1.0 */

.jay-button {
.jay-button,
.jay-button-studio {
--jay-cap: #abcf37;
--jay-cap-hover: #b9dc49;
--jay-edge: #718a23;
Expand All @@ -25,7 +26,8 @@
appearance: none;
}

.jay-button::before {
.jay-button::before,
.jay-button-studio::before {
content: "";
position: absolute;
z-index: -1;
Expand All @@ -35,7 +37,8 @@
box-shadow: inset 0 -1px 0 rgb(0 0 0 / 0.32);
}

.jay-button::after {
.jay-button::after,
.jay-button-studio::after {
content: "";
position: absolute;
z-index: -2;
Expand All @@ -46,7 +49,8 @@
filter: blur(7px);
}

.jay-button__cap {
.jay-button__cap,
.jay-button-studio__cap {
position: relative;
display: block;
padding: 1rem 1.55rem;
Expand All @@ -62,7 +66,8 @@
}

@media (hover: hover) and (pointer: fine) {
.jay-button:hover .jay-button__cap {
.jay-button:hover .jay-button__cap,
.jay-button-studio:hover .jay-button-studio__cap {
background: var(--jay-cap-hover);
transform: translateY(-1px);
box-shadow:
Expand All @@ -72,105 +77,133 @@
}
}

.jay-button:active .jay-button__cap {
.jay-button:active .jay-button__cap,
.jay-button-studio:active .jay-button-studio__cap {
transform: translateY(var(--jay-travel));
box-shadow:
inset 0 2px 3px rgb(0 0 0 / 0.16),
inset 0 -1px 0 rgb(255 255 255 / 0.28);
}

.jay-button:focus-visible {
.jay-button:focus-visible,
.jay-button-studio:focus-visible {
outline: 3px solid var(--jay-focus);
outline-offset: 5px;
}

.jay-button:disabled {
.jay-button:disabled,
.jay-button-studio:disabled {
cursor: not-allowed;
opacity: 0.48;
}

.jay-button:disabled .jay-button__cap {
.jay-button:disabled .jay-button__cap,
.jay-button-studio:disabled .jay-button-studio__cap {
transform: none;
}

.jay-button[data-tone="brown"] {
.jay-button[data-tone="brown"],
.jay-button-studio[data-tone="brown"] {
--jay-cap: #6c5b54;
--jay-cap-hover: #7b6961;
--jay-edge: #382f2b;
--jay-ink: #ffffff;
}

/* Backward-compatible single-element class from the original release. */
.JayBrown {
/* JayButton Classic preserves the original JaydenART signature button. */
.JayBrown,
.jay-button-classic {
display: inline-block;
min-inline-size: 10rem;
padding: 1rem 1.55rem;
border: 1px solid #3b312d;
border-radius: 14px;
color: #ffffff;
background: #6c5b54;
box-sizing: content-box;
margin: 0 0 15px;
padding: 8px 20px 10px;
border: 1px solid rgb(127 70 34);
border-radius: 10px;
color: rgb(255 255 255);
background:
linear-gradient(0deg, rgb(255 255 255 / 0) 0, rgb(255 255 255 / 0) 1%, rgb(206 133 88 / 0.99) 100%),
rgb(114 71 42);
box-shadow:
inset 0 1px 0 rgb(255 255 255 / 0.22),
inset 0 -2px 0 rgb(0 0 0 / 0.2),
0 6px 0 #382f2b,
0 11px 14px rgb(0 0 0 / 0.28);
font: 700 1rem/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
inset 0 0 5px 1px rgb(239 159 105 / 0.6),
inset 0 1.5px 0 rgb(229 151 98),
0 6px 0 rgb(89 50 24),
0 8px 3px 1px rgb(0 0 0 / 0.99);
font: 700 14px/1 "Coda", Helvetica, sans-serif;
text-align: center;
text-shadow: 0 -1px 1px rgb(45 22 7);
cursor: pointer;
transform: translateY(0);
transition: transform 130ms ease, background-color 130ms ease, box-shadow 130ms ease;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
appearance: none;
}

@media (hover: hover) and (pointer: fine) {
.JayBrown:hover {
background: #7b6961;
transform: translateY(-1px);
.JayBrown:hover,
.jay-button-classic:hover {
background:
linear-gradient(180deg, rgb(255 255 255 / 0) 0, rgb(211 140 99 / 0.7) 100%),
rgb(137 89 57);
box-shadow:
inset 0 0 5px 1px rgb(239 159 105 / 0.6),
inset 0 1.5px 0 rgb(234 161 112 / 0.96),
0 6px 0 rgb(89 50 24),
0 8px 3px 1px rgb(0 0 0 / 0.99);
text-shadow: 0 -1px 1px rgb(30 45 77);
}
}

.JayBrown:active {
transform: translateY(4px);
.JayBrown:active,
.jay-button-classic:active {
margin: 5px 0 10px;
background:
linear-gradient(0deg, rgb(255 255 255 / 0) 0, rgb(255 255 255 / 0) 1%, rgb(206 133 88 / 0.99) 100%),
rgb(114 71 42);
box-shadow:
inset 0 2px 3px rgb(0 0 0 / 0.18),
0 2px 0 #382f2b,
0 6px 9px rgb(0 0 0 / 0.26);
inset 0 1px 10px 1px rgb(239 159 105 / 0.6),
inset 0 1.5px 0 rgb(234 171 129),
0 2px 0 rgb(89 50 24),
0 3px 3px 1px rgb(0 0 0 / 0.99);
}

.JayBrown:focus-visible {
.JayBrown:focus-visible,
.jay-button-classic:focus-visible {
outline: 3px solid #abcf37;
outline-offset: 5px;
}

@media (prefers-reduced-motion: reduce) {
.jay-button__cap,
.JayBrown {
.jay-button-studio__cap {
transition-duration: 0.01ms;
}

.jay-button:hover .jay-button__cap,
.jay-button:active .jay-button__cap,
.JayBrown:hover,
.JayBrown:active {
.jay-button-studio:hover .jay-button-studio__cap,
.jay-button-studio:active .jay-button-studio__cap {
transform: none;
}
}

@media (forced-colors: active) {
.jay-button,
.JayBrown {
.jay-button-studio,
.JayBrown,
.jay-button-classic {
forced-color-adjust: none;
}

.jay-button__cap,
.JayBrown {
.jay-button-studio__cap,
.JayBrown,
.jay-button-classic {
border-color: ButtonText;
color: ButtonText;
background: ButtonFace;
}

.jay-button::before {
.jay-button::before,
.jay-button-studio::before {
background: ButtonText;
}
}
61 changes: 32 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# JaydenART<sup>®</sup> Realistic 3D CSS Button

<p><strong>A button that actually presses.</strong> Pure CSS, no JavaScript, no images, and no dependencies.</p>
<p><strong>Two button styles, one small stylesheet.</strong> Pure CSS, no JavaScript, no images, and no dependencies.</p>

<a href="https://jaydenart.github.io/JaydenART_Realistic_3D_CSS_Button/">
<img src="assets/button-preview.svg" alt="JaydenART realistic CSS button shown at rest and pressed, with the cap moving down while the base stays anchored" width="100%">
<img src="assets/button-preview.svg" alt="JayButton Classic in glossy brown beside JayButton Studio in JaydenART green, each shown with dimensional press styling" width="100%">
</a>

<p>
Expand All @@ -12,36 +12,49 @@
<a href="LICENSE"><img src="https://img.shields.io/github/license/JaydenART/JaydenART_Realistic_3D_CSS_Button?style=for-the-badge" alt="MIT License"></a>
</p>

## Why It Feels Real
## Choose a style

Many CSS buttons move the whole element, including the shadow that is supposed to anchor it to the page. This component separates the moving cap from the fixed edge and ground shadow:
### JayButton Classic

- The outer button owns the edge and shadow.
- The inner cap lifts on hover and travels down on press.
- The component keeps stable dimensions through every state.
- Touch, keyboard, reduced-motion, disabled, and forced-color states are included.
Classic is the original JaydenART signature button. Its warm copper highlight, glossy brown face, deep edge, and compact press motion are preserved from the first release. Use it when you want the distinctive original look in a single HTML element.

## Use It
```html
<link rel="stylesheet" href="JayButton.css">

<button class="jay-button-classic" type="button">Jayden Yoon ZK</button>
```

Add [`JayButton.css`](JayButton.css) to your project:
The original `.JayBrown` class is still supported:

```html
<link rel="stylesheet" href="JayButton.css">
<button class="JayBrown" type="button">Jayden Yoon ZK</button>
```

<button class="jay-button" type="button">
<span class="jay-button__cap">Start building</span>
### JayButton Studio

Studio is the newer layered component. Its cap moves independently while the edge and ground shadow stay planted, keeping the button dimensions stable through every state.

```html
<button class="jay-button-studio" type="button">
<span class="jay-button-studio__cap">Start building</span>
</button>
```

For the brown JaydenART variant:
The original Studio class names from version 2.0 remain supported:

```html
<button class="jay-button" type="button" data-tone="brown">
<span class="jay-button__cap">Continue</span>
<button class="jay-button" type="button">
<span class="jay-button__cap">Start building</span>
</button>
```

## Customize It
For the brown Studio tone, add `data-tone="brown"` to the outer button.

## Why the names

Classic and Studio are two maintained styles, not old and new releases of the same design. The names make that distinction clear while repository versions continue to describe changes to the complete package.

## Customize Studio

Override the component variables on the button or in your own class:

Expand Down Expand Up @@ -69,17 +82,7 @@ Override the component variables on the button or in your own class:

## Accessibility

The demo uses native `<button>` elements, visible `:focus-visible` rings, a disabled state, touch-safe interactions, reduced-motion handling, and a forced-colors fallback. Keep the visible label inside `.jay-button__cap`; add an `aria-label` only when the visible text does not describe the action.

## Legacy Class

The original single-element class remains available, so existing markup does not break:

```html
<button class="JayBrown" type="button">Press me</button>
```

New work should use `.jay-button` with `.jay-button__cap` because that structure keeps the cap and base physically independent.
Both examples use native `<button>` elements and visible `:focus-visible` rings. Studio also includes disabled, reduced-motion, and forced-colors states. Keep the visible Studio label inside its cap element. Add an `aria-label` only when the visible text does not describe the action.

## Development

Expand All @@ -89,7 +92,7 @@ npm run check
npm run serve
```

The test suite checks the public HTML and CSS contracts, accessibility states, local assets, security policy, and documentation hygiene.
The test suite checks the public HTML and CSS contracts, both component aliases, accessibility states, local assets, security policy, and documentation hygiene.

## Contributing

Expand Down
Loading