M4RKYU.SYSEdition 2027
Skip to content
LOCZH/安大略 · 加拿大/▸logs · create a heart shaped animation with html5 css3 and javascript 1pjh待机OK/--:--:--EST
M4M4RK_YUportfolio
  • 创作创作
    创作Overview
    • 作品精选案例与项目记录
    • 游戏可玩原型与游戏开发日志
  • 影像影像
    影像Overview
    • 照片影像合集与视觉实验
    • 商店印刷品、海报和限量物件
  • 写作写作
    写作Overview
    • 博客长篇开发日志与现场笔记
    • 笔记短观察、链接与代码片段
  • 资源资源
    资源Overview
    • 工具38 款浏览器内开发工具
    • 链接每日使用的开发与设计书签
  • 关于关于
  • 联系联系
EN

同步 · dev.to / @markyu

CSS Heart Animation: Small Demo, Real Animation Lessons

A cleaner CSS heart animation tutorial focused on transform, pseudo-elements, keyframes, and the small mistakes that break simple UI animations.

发布日期
May 22 '24
·
阅读时长
2 min read
·
点赞
9
cssjavascriptfrontendanimation
在 dev.to 查看

本页目录

  • The HTML
  • The CSS Shape
  • Add the Pulse
  • Add a Click State With JavaScript
  • Respect Reduced Motion
  • What This Demo Teaches
  • Final Thought

Small CSS animations are underrated.

They look like toy demos, but they teach the same things you need for real UI work: transforms, timing, layout, pseudo-elements, and not accidentally triggering expensive repaint work.

Let’s build a heart animation with mostly CSS.

The HTML

Keep the markup boring:

<main class="stage">
  <button class="heart-button" aria-label="Like">
    <span class="heart"></span>
  </button>
</main>

The button gives us keyboard accessibility. The span handles the shape.

The CSS Shape

A heart is basically a rotated square with two circles attached.

.stage {
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: #111827;
}

.heart-button {
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 48px;
}

.heart {
  position: relative;
  display: block;
  width: 80px;
  height: 80px;
  background: #ef4444;
  transform: rotate(45deg);
}

.heart::before,
.heart::after {
  content: "";
  position: absolute;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: #ef4444;
}

.heart::before {
  left: -40px;
}

.heart::after {
  top: -40px;
}

Visual model:

circle + circle
   \     /
 rotated square

That is the whole trick.

Add the Pulse

Use transform, not layout properties.

.heart-button:hover .heart,
.heart-button:focus-visible .heart {
  animation: pulse 700ms ease-in-out infinite;
}

@keyframes pulse {
  0% {
    transform: rotate(45deg) scale(1);
  }
  45% {
    transform: rotate(45deg) scale(1.18);
  }
  100% {
    transform: rotate(45deg) scale(1);
  }
}

The common mistake is forgetting the rotation inside the keyframes. If you animate only scale(), the heart can snap back because transform gets replaced.

Bad:

transform: scale(1.2);

Good:

transform: rotate(45deg) scale(1.2);

Add a Click State With JavaScript

CSS hover is nice, but click feedback feels better.

const button = document.querySelector(".heart-button");

button.addEventListener("click", () => {
  button.classList.toggle("is-liked");
});
.heart-button.is-liked .heart,
.heart-button.is-liked .heart::before,
.heart-button.is-liked .heart::after {
  background: #fb7185;
}

.heart-button.is-liked .heart {
  box-shadow: 0 0 48px rgba(251, 113, 133, 0.55);
}

Respect Reduced Motion

This is a small demo, but accessibility still counts.

@media (prefers-reduced-motion: reduce) {
  .heart-button:hover .heart,
  .heart-button:focus-visible .heart {
    animation: none;
  }
}

I would add this even for playful UI. Not every user wants pulsing motion.

What This Demo Teaches

TechniqueReal UI use
::before / ::aftericons, badges, decorative layers
transformcheap animation
@keyframesreusable motion
focus-visiblekeyboard-friendly interaction
reduced motionaccessibility polish

Final Thought

This is not just a heart animation. It is a tiny lab for learning how browser motion behaves.

What small CSS animation taught you more than you expected?

相关阅读

CSS 3D Transform Bugs Usually Come From Perspective

A practical CSS 3D transform guide explaining perspective, rotateX, rotateY, transform-style, backface visibility, and debugging layout.

css

React Loading Screens Are a State Machine Problem

A practical React loading screen guide using hooks, request states, error states, CSS animation, and why spinners alone are not enough.

react

Frontend Linear Data Structures Deep Dive: Arrays, Stacks, Queues, and Linked Lists

The Big Picture Before diving into stacks, queues, and linked lists, it helps to know...

computerscience

原文发布

本文首发于 dev.to,评论与点赞保留在原站。

在 dev.to 继续阅读
上一篇Debug a Slow MySQL Query Before You Guess at IndexesA practical MySQL workflow for finding slow queries, reading EXPLAIN output, and deciding whether an index actually helps.
返回全部文章
下一篇JavaScript Memory Leaks Usually Start With One ReferenceA practical JavaScript memory guide covering stack, heap, garbage collection, closures, event listeners, timers, and leak debugging.
返回档案
M4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYU
始于 2024
ZhenXiao Mark YuZhenXiao Mark Yu
联系

看到什么有意思的?和我聊聊。

这是一个作品集,不是服务 · 但每一条留言我都会看 — 如果哪里让你有所触动,或者只想打个招呼,欢迎写信过来。

开启对话
频道开放

随时打个招呼 · 2026

--:--:--EST加拿大 安大略
  • 邮件
  • GitHub
  • dev.to
  • 领英
  • 推特 / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat

订阅

偶尔收到一封简讯

来自 m4rkyu.com 的笔记与日志——简短、标注日期、没有杂音。随时可退订。

作品

线上发布、游戏作品与视觉档案。

  • 项目
  • 游戏
  • 档案
  • 日志

资源

每日好用的工具与个人收藏的链接库。

  • 搜索
  • 最新
  • 工具
  • 链接
  • 笔记
  • 主题
  • 商店
RSSJSON Feed

工作室

背景、联系方式以及合作渠道。

  • 关于
  • 联系
  • 更新日志
  • 技术说明
  • 简历筹备中

社交

在常去的平台上找到我。

  • GitHub
  • dev.to
  • 领英
  • 推特 / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
  • 邮件
© 2026 ZhenXiao Mark Yumarkyu0615@gmail.com
  • 邮件
  • GitHub
  • dev.to
  • 领英
  • 推特 / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
隐私条款由 Next.js 16 · React 19 · Tailwind 4 构建