קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
HTML
<ul class="threeD-button-set">
<li><button>New Game</button></li>
<li><button>Continue</button></li>
<li><button>Online</button></li>
<li><button>Settings</button></li>
<li><button>Quit</button></li>
</ul>
CSS
body {
perspective: 40vw;
}
.threeD-button-set {
--y:;
--x:;
--distance: 1px;
--theme: hsl(180 100% 50%);
--theme-bg: hsl(180 100% 50% / 25%);
--theme-bg-hover: hsl(180 100% 50% / 40%);
--theme-text: white;
--theme-shadow: hsl(180 100% 10% / 25%);
--_max-rotateY: 10deg;
--_max-rotateX: 15deg;
--_btn-bg: var(--theme-bg);
--_btn-bg-hover: var(--theme-bg-hover);
--_btn-text: var(--theme-text);
--_btn-text-shadow: var(--theme-shadow);
--_bounce-ease: cubic-bezier(.5, 1.75, .75, 1.25);
/* remove margins */
margin: 0;
/* vertical rag-right layout */
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2.5vh;
/* create 3D space context */
transform-style: preserve-3d;
/* clamped menu rotation to not be too extreme */
transform:
rotateY(
clamp(
calc(var(--_max-rotateY) * -1),
var(--y),
var(--_max-rotateY)
)
)
rotateX(
clamp(
calc(var(--_max-rotateX) * -1),
var(--x),
var(--_max-rotateX)
)
)
;
/* removes Safari focus ring on after button interaction */
&:focus {
outline: none;
}
@media (--motionOK) {
will-change: transform;
transition: transform .1s ease;
animation: rotate-y 5s ease-in-out infinite;
}
@media (--dark) {
--theme: hsl(255 53% 50%);
--theme-bg: hsl(255 53% 71% / 25%);
--theme-bg-hover: hsl(255 53% 50% / 40%);
--theme-shadow: hsl(255 53% 10% / 25%);
}
@media (--HDcolor) {
@supports (color: color(display-p3 0 0 0)) {
--theme: color(display-p3 .4 0 .9);
}
}
}
.threeD-button-set > li {
/* change display type from list-item */
display: inline-flex;
/* create context for button pseudos */
position: relative;
/* create 3D space context */
transform-style: preserve-3d;
}
.threeD-button-set button {
/* strip out default button styles */
appearance: none;
outline: none;
border: none;
-webkit-tap-highlight-color: transparent;
/* bring in brand styles via props */
background-color: var(--_btn-bg);
color: var(--_btn-text);
text-shadow: 0 1px 1px var(--_btn-text-shadow);
font-size: min(5vmin, 3rem);
font-family: Audiowide;
padding-block: .75ch;
padding-inline: 2ch;
border-radius: 5px 20px;
/* prepare for 3D perspective transforms */
transform: translateZ(var(--distance));
transform-style: preserve-3d;
&:is(:hover, :focus-visible):not(:active) {
/* subtle distance plus bg color change on hover/focus */
--distance: 15px;
background-color: var(--_btn-bg-hover);
/* if motion is OK, setup transitions and increase distance */
@media (--motionOK) {
--distance: 3vmax;
transition-timing-function: var(--_bounce-ease);
transition-duration: .4s;
&::after { transition-duration: .5s }
&::before { transition-duration: .3s }
}
}
&::after,
&::before {
/* create empty element */
content: '';
opacity: .8;
/* cover the parent (button) */
position: absolute;
inset: 0;
/* style the element for border accents */
border: 1px solid var(--theme);
border-radius: 5px 20px;
/* move in Z space with a multiplier */
transform: translateZ(calc(var(--distance) / 3));
/* if motion is OK, transition the Z space move */
@media (--motionOK) {
transition: transform .1s ease-out;
}
}
/* exceptions for one of the pseudo elements */
/* this will be pushed back and have a thicker border */
&::before {
border-width: 3px;
transform: translateZ(calc(var(--distance) / 3 * -1));
/* in dark mode, it glows! */
@media (--dark) {
box-shadow:
0 0 25px var(--theme),
inset 0 0 25px var(--theme);
}
}
@media (--motionOK) {
will-change: transform;
transition:
transform .2s ease,
background-color .5s ease;
}
}
@keyframes rotate-y {
50% {
transform: rotateY(15deg) rotateX(-6deg);
}
}
JS
import {rovingIndex} from 'https://cdn.skypack.dev/roving-ux'
const menu = document.querySelector('.threeD-button-set')
const menuRect = menu.getBoundingClientRect()
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
rovingIndex({
element: document.querySelector('.threeD-button-set'),
target: 'button',
})
if (motionOK) {
window.addEventListener('mousemove', ({target, clientX, clientY}) => {
const {dx,dy} = getAngles(clientX, clientY)
menu.style.setProperty('--x', `${dy / 20}deg`)
menu.style.setProperty('--y', `${dx / 20}deg`)
})
}
const getAngles = (clientX, clientY) => {
const { x, y, width, height } = menuRect
const dx = clientX - (x + 0.5 * width)
const dy = clientY - (y + 0.5 * height)
return {dx,dy}
}
אלא אם צוין אחרת, התוכן של דף זה הוא ברישיון Creative Commons Attribution 4.0 ודוגמאות הקוד הן ברישיון Apache 2.0. לפרטים, ניתן לעיין במדיניות האתר Google Developers. Java הוא סימן מסחרי רשום של חברת Oracle ו/או של השותפים העצמאיים שלה.
עדכון אחרון: 2023-10-25 (שעון UTC).
[{
"type": "thumb-down",
"id": "missingTheInformationINeed",
"label":"חסרים לי מידע או פרטים"
},{
"type": "thumb-down",
"id": "tooComplicatedTooManySteps",
"label":"התוכן מורכב מדי או עם יותר מדי שלבים"
},{
"type": "thumb-down",
"id": "outOfDate",
"label":"התוכן לא עדכני"
},{
"type": "thumb-down",
"id": "translationIssue",
"label":"בעיה בתרגום"
},{
"type": "thumb-down",
"id": "samplesCodeIssue",
"label":"בעיה בדוגמאות/בקוד"
},{
"type": "thumb-down",
"id": "otherDown",
"label":"סיבה אחרת"
}]
[{
"type": "thumb-up",
"id": "easyToUnderstand",
"label":"התוכן קל להבנה"
},{
"type": "thumb-up",
"id": "solvedMyProblem",
"label":"התוכן עזר לי לפתור בעיה"
},{
"type": "thumb-up",
"id": "otherUp",
"label":"סיבה אחרת"
}]