Skip to content

Instantly share code, notes, and snippets.

@veged
Created May 15, 2026 09:13
Show Gist options
  • Select an option

  • Save veged/390269872be8ed914562df9750a04cfa to your computer and use it in GitHub Desktop.

Select an option

Save veged/390269872be8ed914562df9750a04cfa to your computer and use it in GitHub Desktop.
Pebble buttons (light + dark themes, 4 sizes each) — pure CSS skeuomorphic stone buttons with noise texture and engraved text
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Pebble buttons</title>
<style>
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap");
*{box-sizing:border-box}
html,body{margin:0;height:100%;font-family:'Inter',system-ui,sans-serif}
/* === ТЕМЫ === */
.pane-light {
--bg: #e6e3dc;
--face-c1: rgba(238,236,230,1);
--face-c2: rgba(180,176,168,1);
--rim: rgba(15,12,8,0.78);
--text-c1: rgba(70,62,50,1);
--text-c2: rgba(35,30,22,1);
--text-engrave-hi: rgba(255,254,250,0.85);
--text-engrave-sh: rgba(15,12,8,0.40);
--shadow-strong: rgba(15,12,8,1);
--shadow-mid: rgba(15,12,8,0.5);
--shadow-light: rgba(15,12,8,0.28);
--shadow-faint: rgba(15,12,8,0.12);
--hi-strong: rgba(255,254,250,1);
--hi-light: rgba(255,254,250,0.32);
--hi-faint: rgba(255,254,250,0.18);
--face-grain-opacity: .35;
}
.pane-dark {
--bg: #1f1f23;
--face-c1: rgba(98,98,108,1);
--face-c2: rgba(38,38,46,1);
--rim: rgba(0,0,0,0.92);
--text-c1: rgba(30,30,36,1);
--text-c2: rgba(8,8,12,1);
--text-engrave-hi: rgba(255,255,255,0.32);
--text-engrave-sh: rgba(0,0,0,0.85);
--shadow-strong: rgba(0,0,0,1);
--shadow-mid: rgba(0,0,0,0.78);
--shadow-light: rgba(0,0,0,0.55);
--shadow-faint: rgba(0,0,0,0.30);
--hi-strong: rgba(255,255,255,0.20);
--hi-light: rgba(255,255,255,0.15);
--hi-faint: rgba(255,255,255,0.20);
--face-grain-opacity: .42;
}
/* === LAYOUT === */
.panes{display:grid;grid-template-columns:1fr 1fr;min-height:100vh}
.pane{
background:var(--bg);
padding:60px 40px;
display:flex;flex-direction:column;align-items:center;justify-content:center;
gap:36px;
position:relative;overflow:hidden;
}
.pane::before{
content:""; position:absolute; inset:0;
background:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch' seed='2'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.4' numOctaves='2' stitchTiles='stitch' seed='13'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.05' numOctaves='2' stitchTiles='stitch' seed='37'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.5 -0.65'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
background-size: 280px 280px, 560px 560px, 220px 220px;
background-blend-mode: multiply, multiply;
mix-blend-mode: overlay;
opacity: 0.5;
pointer-events:none;
}
.pane > *{position:relative;z-index:1}
/* === КНОПКА-КАМУШЕК ===
Все размеры в px через --u = --pebble-h / 60px (безразмерный коэффициент).
При --pebble-h:60 → --u:1, всё × 1. При 120 → × 2. И т.д. */
button.pebble{
all:unset;cursor:pointer;
-webkit-tap-highlight-color:rgba(0,0,0,0);
--u: calc(var(--pebble-h, 60px) / 60px);
position:relative;isolation:isolate;
background-color:var(--rim);
filter:url(#pebble-noisy-shadow);
font-family:'Inter',system-ui,sans-serif;
line-height:1; border-radius:9999px;
display:inline-block; box-sizing:border-box;
font-size:calc(20px * var(--u));
}
/* outer — drop-shadow стек */
.pebble-outer{
position:relative;z-index:1;display:block;
border-radius:inherit;
transition:box-shadow 300ms ease;
box-shadow:
0 calc(1px * var(--u)) calc(1px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-strong),
0 calc(0.2px * var(--u)) calc(0.2px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-mid),
0 calc(6px * var(--u)) calc(3.6px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-light);
}
button.pebble:hover .pebble-outer{
box-shadow:
0 calc(0.5px * var(--u)) calc(0.6px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-mid),
0 calc(0.1px * var(--u)) calc(0.16px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-light),
0 calc(3.2px * var(--u)) calc(2.2px * var(--u)) calc(-0.2px * var(--u)) var(--shadow-light);
}
button.pebble:active .pebble-outer{
box-shadow: 0 0 0 0 var(--shadow-strong), 0 0 0 0 var(--shadow-mid), 0 0 0 0 var(--shadow-light);
}
/* inner — лицо камня (gradient + insets) */
.pebble-inner{
position:relative;z-index:1;display:block;
border-radius:inherit;
background-image:linear-gradient(180deg, var(--face-c1), var(--face-c2));
transition:box-shadow 300ms ease, clip-path 250ms ease, transform 250ms ease;
overflow:clip;box-sizing:border-box;
padding:calc(20px * var(--u)) calc(30px * var(--u));
clip-path:inset(0 0 0 0 round 9999px);
box-shadow:
0 0 0 0 inset var(--shadow-faint),
0 calc(-1px * var(--u)) calc(1.6px * var(--u)) 0 inset var(--shadow-light),
0 0 0 0 inset var(--shadow-faint),
0 0 calc(4.4px * var(--u)) calc(4px * var(--u)) inset var(--hi-light),
0 0 calc(10px * var(--u)) calc(1.6px * var(--u)) inset var(--hi-faint),
0 calc(1px * var(--u)) calc(3.6px * var(--u)) 0 inset var(--hi-strong),
0 calc(2.4px * var(--u)) calc(3.6px * var(--u)) 0 inset var(--hi-light),
0 calc(-2px * var(--u)) calc(3.5px * var(--u)) 0 inset var(--shadow-light);
}
button.pebble:hover .pebble-inner{
box-shadow:
0 calc(1.8px * var(--u)) calc(0.8px * var(--u)) 0 inset var(--shadow-light),
0 calc(-0.8px * var(--u)) calc(1px * var(--u)) calc(0.36px * var(--u)) inset var(--shadow-light),
0 calc(3.2px * var(--u)) calc(3.2px * var(--u)) 0 inset var(--shadow-light),
0 0 calc(6.4px * var(--u)) calc(5.6px * var(--u)) inset var(--hi-faint),
0 0 calc(14px * var(--u)) calc(2.4px * var(--u)) inset var(--hi-faint),
0 calc(2px * var(--u)) calc(2.4px * var(--u)) 0 inset var(--hi-light),
0 calc(-3.6px * var(--u)) calc(4px * var(--u)) calc(1.6px * var(--u)) inset var(--shadow-light);
}
button.pebble:active .pebble-inner{
clip-path:inset(clamp(1px, calc(1.25px * var(--u)), 2px) clamp(1px, calc(1.25px * var(--u)), 2px) clamp(1px, calc(1.25px * var(--u)), 2px) clamp(1px, calc(1.25px * var(--u)), 2px) round 9999px);
transform:scale(0.975);
box-shadow:
0 calc(3px * var(--u)) calc(1px * var(--u)) 0 inset var(--shadow-mid),
0 calc(-0.6px * var(--u)) calc(1px * var(--u)) calc(0.5px * var(--u)) inset var(--shadow-light),
0 calc(5px * var(--u)) calc(4px * var(--u)) 0 inset var(--shadow-mid),
0 0 calc(9px * var(--u)) calc(8.4px * var(--u)) inset var(--hi-faint),
0 0 calc(18px * var(--u)) calc(3.6px * var(--u)) inset var(--hi-faint),
0 calc(2.4px * var(--u)) calc(2.4px * var(--u)) 0 inset var(--hi-light),
0 calc(-2.4px * var(--u)) calc(4px * var(--u)) calc(2px * var(--u)) inset var(--shadow-light);
}
/* ::before — каменное зерно (3 слоя: мелкое, среднее, пигментные пятна) */
.pebble-inner::before{
content:""; position:absolute; inset:0; border-radius:inherit;
background:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.95' numOctaves='2' stitchTiles='stitch' seed='9'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='320'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='2' stitchTiles='stitch' seed='17'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.06' numOctaves='2' stitchTiles='stitch' seed='29'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.6 -0.7'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
background-size: 240px 240px, 480px 480px, 100px 100px;
background-blend-mode: multiply, multiply;
mix-blend-mode: overlay;
opacity: var(--face-grain-opacity);
pointer-events:none; z-index:1;
transition: opacity 250ms ease;
}
/* ::after — мелкое зерно вокруг бликового ободка (radial mask) */
.pebble-inner::after{
content:""; position:absolute; inset:0; border-radius:inherit;
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='80' height='80'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' stitchTiles='stitch' seed='5'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
background-size: 80px 80px;
-webkit-mask-image: radial-gradient(ellipse 80% 78% at center, transparent 35%, black 92%);
mask-image: radial-gradient(ellipse 80% 78% at center, transparent 35%, black 92%);
mix-blend-mode: overlay; opacity: 0.55;
pointer-events:none; z-index:2;
transition: opacity 250ms ease;
}
button.pebble:hover .pebble-inner::before{ opacity: calc(var(--face-grain-opacity) + 0.12); }
button.pebble:hover .pebble-inner::after{ opacity: 0.7; }
button.pebble:active .pebble-inner::before{ opacity: calc(var(--face-grain-opacity) + 0.25); }
button.pebble:active .pebble-inner::after{ opacity: 0.85; }
/* Текст с гравировкой и зерном через SVG-фильтр */
.pebble-inner span{
position:relative; z-index:4;
letter-spacing:-0.05em; font-weight:500;
color:rgba(0,0,0,0);
background-image:linear-gradient(180deg,
color-mix(in srgb, var(--text-c1) 75%, transparent),
color-mix(in srgb, var(--text-c2) 80%, transparent));
-webkit-background-clip:text; background-clip:text;
filter:url(#text-grain);
transition:transform 250ms ease;
display:block;
text-shadow:
0 -1px 0 var(--text-engrave-sh),
0 1px 0 var(--text-engrave-hi),
0 1px 1px var(--text-engrave-sh);
user-select:none;
}
button.pebble:active .pebble-inner span{ transform:scale(0.975); }
</style>
</head>
<body>
<!-- SVG-фильтры:
1) text-grain — мелкое + среднее зерно для гравировки текста
2) pebble-noisy-shadow — нойзовая drop-тень с feTurbulence + feDisplacementMap -->
<svg xmlns="http://www.w3.org/2000/svg" style="position:absolute;width:0;height:0;overflow:hidden" aria-hidden="true">
<defs>
<filter id="text-grain" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" seed="9" stitchTiles="stitch" result="t1"/>
<feColorMatrix in="t1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" result="dark1"/>
<feTurbulence type="fractalNoise" baseFrequency="0.35" numOctaves="2" seed="29" stitchTiles="stitch" result="t2"/>
<feColorMatrix in="t2" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" result="dark2"/>
<feMerge result="combined">
<feMergeNode in="dark1"/>
<feMergeNode in="dark2"/>
</feMerge>
<feComposite in="combined" in2="SourceGraphic" operator="in" result="masked"/>
<feBlend in="SourceGraphic" in2="masked" mode="multiply"/>
</filter>
<filter id="pebble-noisy-shadow" x="-30%" y="-30%" width="160%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="1.8" result="blur"/>
<feTurbulence type="fractalNoise" baseFrequency="0.55" numOctaves="2" seed="7" stitchTiles="stitch" result="noise"/>
<feDisplacementMap in="blur" in2="noise" scale="2.4" result="texturedBlur"/>
<feFlood flood-color="black" flood-opacity="0.42" result="dark"/>
<feComposite in="dark" in2="texturedBlur" operator="in" result="shadow"/>
<feOffset in="shadow" dx="0" dy="2" result="positionedShadow"/>
<feMerge>
<feMergeNode in="positionedShadow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
</svg>
<div class="panes">
<div class="pane pane-light">
<button class="pebble" style="--pebble-h:54px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:72px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:108px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:168px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
</div>
<div class="pane pane-dark">
<button class="pebble" style="--pebble-h:54px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:72px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:108px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
<button class="pebble" style="--pebble-h:168px"><span class="pebble-outer"><span class="pebble-inner"><span>Старт</span></span></span></button>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment