April 28, 2025
I always love those CSS articles of various styles and cool effects. So for today, I'd like to contribute my own group of "The Glitched Goblet" styles. These are all made to work in modern browsers, and are all subtle enough to not be annoying.
This blog post is best experienced on a dark background, so if you’re reading this in light mode, switch to dark mode for the full effect. I may make another part 2 to this post for lighter backgrounds if there's enough interest.
It gives headings that arcade‑cabinet glow. Just be sure to use it sparingly. Too much and it’s like a glowing sun.
.cool-heading {
color: #00e9ff;
text-shadow: 0 0 2px #00e9ff, 0 0 20px #0088ff;
}
A skinny ::after
bar that blips every 750 ms like a terminal cursor. Great for giving that “typing” feel.
.typey::after {
content: '';
display: inline-block;
width: 0.6ch;
height: 1em;
margin-left: 0.1ch;
background: currentColor;
animation: blink 750ms steps(1) infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
}
Prefers‑reduced‑motion? Wrap the animation in:
@media (prefers-reduced-motion: reduce) {
.typey::after {
animation: none;
}
}
Cards levitate and crank the glow just a smidge.
Hover over the card below to see it in action!
.card {
background: #111;
border-radius: 1rem;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 20px #00ffff55;
}
A button that's literally tilted. Everyone loves a good button interaction! And I get so bored of the darken on hover
that we've grown used to. So why not make them a little more fun?
.button {
position: relative;
overflow: hidden;
background: #4f46e5;
color: #000;
transition: transform 0.1s ease;
}
.button:hover {
background: #3c36b2;
transform: translate(1px, -1px) skewX(1deg) skewY(-1deg);
}
.button:active {
transform: translate(-1px, 1px) skewX(-1deg) skewY(1deg);
}
Subtle-ish concentric ring that expands then fades. It's a great way for grabbing the users attention. Obviously this example is sped up for demo purposes, but could be made to remind the user that there is something to look at.
@keyframes pulseRing {
0% {
transform: scale(1);
opacity: 0.6;
}
100% {
transform: scale(1.8);
opacity: 0;
}
}
.pulsing-button-wrapper {
position: relative;
display: inline-block;
}
.pulsing-ring {
position: absolute;
inset: 0;
border: 2px solid currentColor;
border-radius: 9999px;
animation: pulseRing 1.2s ease-out infinite;
pointer-events: none;
}
.pulsing-button {
position: relative;
z-index: 10;
padding: 0.5rem 1.5rem;
background-color: #4f46e5;
color: white;
border-radius: 9999px;
font-weight: bold;
border: none;
}
<div class="pulsing-button-wrapper">
<span class="pulsing-ring"></span>
<button class="pulsing-button">Click Me</button>
</div>
Only shows in browsers that support it. That being Chrome and Edge. Firefox and Safari don’t support it yet. :'(
Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating... Repeating...
.dark::-webkit-scrollbar {
width: 8px;
}
.dark::-webkit-scrollbar-thumb {
background: linear-gradient(#00eaff, #ff00ff);
border-radius: 4px;
}
A card whose glow inhales and exhales every few seconds. I'm sorry, but also not. It does really create that "lived in" feeling. It’s a great way to add some life to your site.
Hover to pause the breath; keyboard focus shows the same effect.
🫁 You are now aware of your breathing. 🫁
/* container you want to glow */
.breathing-card {
background: #111;
color: #fafafa;
padding: 1.5rem;
border-radius: 1rem;
box-shadow: 0 0 8px 2px #00ffc855; /* starting glow */
animation: breathe 6s ease-in-out infinite;
transition: box-shadow 0.2s;
}
/* pause motion on user intent */
.breathing-card:hover,
.breathing-card:focus-visible {
animation-play-state: paused;
}
@keyframes breathe {
0%,
100% {
box-shadow: 0 0 8px 2px #00ffc855;
}
50% {
box-shadow: 0 0 20px 8px #00ffc8aa;
}
}
/* motion-sensitive users */
@media (prefers-reduced-motion: reduce) {
.breathing-card {
animation: none;
}
}
A micro-glitch that fires only when the user clicks (or presses Enter/Space). The element pops a few offset shadows for ~120 ms, then settles back.
<button class="glitch-jitter-btn">Click Me</button>
.glitch-jitter-btn {
position: relative;
padding: 0.75rem 2rem;
background: #0f0;
color: #000;
border: none;
border-radius: 9999px;
font-weight: 700;
cursor: pointer;
box-shadow: 0 0 6px 2px #00ff00aa;
transition: transform 0.1s;
}
/* keyframes = sideways jerk + triple glow */
@keyframes jitter {
0% {
transform: translate(0, 0);
box-shadow: 0 0 6px 2px #00ff00aa;
}
25% {
transform: translate(-1px, 1px);
box-shadow: 2px -2px 4px #00ff00aa, -2px 2px 4px #00ff00aa;
}
50% {
transform: translate(1px, -1px);
box-shadow: -2px 2px 4px #00ff00aa, 2px -2px 4px #00ff00aa;
}
75% {
transform: translate(-1px, 1px);
box-shadow: 2px 2px 4px #00ff00aa, -2px -2px 4px #00ff00aa;
}
100% {
transform: translate(0, 0);
box-shadow: 0 0 6px 2px #00ff00aa;
}
}
/* JS toggles the helper class */
.glitch-fire {
animation: jitter 0.12s steps(1) forwards;
}
/* accessibility: give keyboard users parity */
.glitch-jitter-btn:focus-visible {
outline: 3px solid #00ff00aa;
}
document.addEventListener('click', (e) => {
const btn = e.target.closest('.glitch-jitter-btn')
if (!btn) return
btn.classList.remove('glitch-fire')
void btn.offsetWidth // force reflow
btn.classList.add('glitch-fire')
})
Links start bare, then on focus/hover a thin neon underline zooms in from center.
a.glow-link {
position: relative;
color: #0ff;
text-decoration: none;
}
a.glow-link::after {
content: '';
position: absolute;
left: 50%;
bottom: -2px;
width: 0;
height: 2px;
background: currentColor;
transition: width 0.25s ease, left 0.25s ease;
}
a.glow-link:hover::after,
a.glow-link:focus-visible::after {
width: 100%;
left: 0;
}
Call it once every N
minutes. Again, this is repeated for demo purposes, but you can set it to a longer interval. It’s a one‑shot animation that makes the text flicker. It’s a bit of a gimmick, but it’s fun.
The Glitched Goblet
@keyframes flicker {
0%,
100% {
clip-path: inset(0 0 0 0);
}
10% {
clip-path: inset(20% 0 60% 0);
}
20% {
clip-path: inset(40% 0 20% 0);
}
30% {
clip-path: inset(10% 0 70% 0);
}
}
.logo-glitch {
animation: flicker 0.6s steps(1) forwards;
}
I hope you enjoyed this little list of CSS flourishes. I had a lot of fun making them and I hope you have fun trying them out. If you have any questions or suggestions for future posts, feel free to reach out to me on LinkedIn, BlueSky or in the comments on dev.to.