惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
LangChain Blog
月光博客
月光博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 【当耐特】
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
博客园_首页
T
Tailwind CSS Blog
P
Proofpoint News Feed
雷峰网
雷峰网
D
Darknet – Hacking Tools, Hacker News & Cyber Security
IT之家
IT之家
V
Vulnerabilities – Threatpost
阮一峰的网络日志
阮一峰的网络日志
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
S
Schneier on Security
Security Archives - TechRepublic
Security Archives - TechRepublic
L
Lohrmann on Cybersecurity
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
WordPress大学
WordPress大学
The Register - Security
The Register - Security
N
Netflix TechBlog - Medium
Hugging Face - Blog
Hugging Face - Blog
Project Zero
Project Zero
博客园 - 叶小钗
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
S
SegmentFault 最新的问题
C
Cyber Attacks, Cyber Crime and Cyber Security
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
L
LINUX DO - 最新话题
Google DeepMind News
Google DeepMind News
P
Privacy International News Feed
I
InfoQ
F
Fortinet All Blogs
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Threatpost
T
Tenable Blog
B
Blog RSS Feed

KIRUPA | Designers and Developers Unite

Understanding Merkle Trees Is a CompSci Degree Still Valuable in the Age of AI? The Model Context Protocol (MCP) Explained Vibe Coding + Expertise = Mega Win! 🏆 Animating our Grid How to Count in Negabinary (Base (-2)) — A Visual Guide Counting in Binary and Hexadecimal Pascal Pixel on Design, Development, and Solopreneurship! Do we really need to know how things work? 🧠 Drawing Sharp Lines on the Canvas The KIRUPA Tech Stack : It Bloom Filter: A Deep Dive Hash Functions Deep Dive Advanced Glitch Effect with Sound AI Killed the Content Creator...Star 🤩 Measuring the Distance Between Two Points by using the Pythagorean Theorem Detecting Browser Zoom Changes in JavaScript Creating a Fullscreen Grid Drawing a Perfect Grid on the Canvas Preserving the Pixel Art Look in Web Content Ensuring our Canvas Looks Good on Retina/High-DPI Screens Finding Prime Numbers Using a Sieve of Eratosthenes Two-Dimensional (2D) Arrays in JavaScript Two-Dimensional (2D) Arrays in JavaScript Animations: From Biology to JavaScript! 🦠 You’ll Always be Building & Designing Creating a Cluster Growth Animation: From Biology to JavaScript Timsort: A Lightning Fast Hybrid Sorting Algorithm Merge Sort: A Simple Step-by-Step Walkthrough 😀 - YouTube Bubble Sort: A Detailed Deep-Dive 🛁 Insertion Sort: A Deep Dive! 🍣 Selection Sort: A Step-by-Step Guide 💬 Radix Sort: A Complete Guide to Fast and Efficient Sorting! ⚡️ Career Growth Secrets Counting Sort : A Friendly (yet Detailed!) Deep Dive! 🎯 Bogosort: Sorting in the Slow Lane! 🐢 Pulling Off a Successful Redesign Creating Your Own Perfect Timing Radix Sort Making Counting Sort Work with Negative Values Diving Deep into Array Index Positions The Career Three Body Problem Counting Sort Work on Problems You Deeply Care About The Importance of Finding a Career Mentor Creating a Random Walk Simulation What is Product Strategy? Thinking about an 8K Resolution Future! 📺 Creating an Animated 3D Starfield Effect Meet the Default Sorting Algorithms! Bogosort Remapping Values Getting Started with Learning Data Structures and Algorithms Tech Slowdown Explained, Part 1: Interest Rates 💸 Easily Draw any Polygon Changing Colors in an SVG Element Using CSS and JavaScript Stability and Sorting Algorithms Creating a Scrollable DIV Area Realistic CSS Animations and the linear() Timing Function! 🍱 Visualizing Recursion with the Sierpinski Triangle Fast Sorting with Quicksort The Monty Hall Problem Stacks in JavaScript Depth-First Search (DFS) and Breadth-First Search (BFS) Introduction to the Graph Data Structure Big-O Notation and Complexity Analysis Introduction to Data Structures Arrays: A Data Structure Deep Dive Hashtables: A Deep Dive into Efficient Data Storage and Retrieval Trie (aka Prefix Tree) Embracing Generative AI with Open Arms! 🧸 Impact of AI on UI/UX Design with Chloe Barreau 🎨 Heap Data Structure Binary Search Trees Binary Tree Traversal Alphabetically Sort Names in an Array Overlapping Elements on Top of Each Other Developer Relations and Beyond with Jamie Barton! 🚀 A Trip Down Memory Lane 💾 Binary Trees Linked List The Present and Future of AI Tools with Ray (aka devbyrayray) "Guess the Number" and Binary Searching! 🔍 Switching Web Hosts in 2023 😱 SVG: Converting Shape to Path The Versatility of SVGs 🌀 Introduction to Trees Faster Searching with Binary Search Search Algorithms and Linear Search Fibonacci and Going Beyond Recursion Guess the Number Game
Spinning Circular Text
Kirupa Chinnathambi · 2023-03-19 · via KIRUPA | Designers and Developers Unite

Today, we're going to learn about a fun retro effect where, using only HTML, CSS, and SVG, we are going to make some circular text spin. It is going to look a bit like the following (open in new window):

In the following sections, we’ll look into the ins and outs of how to make an effect like this work.

Onwards!

Creating the Effect

There are two parts to this effect. There is the cool and interesting part where we take some text and have it go all circular on us. Then there is the animation part, which is also cool and interesting, where we take our circular text and make it spin. We'll tackle each part individually.

To follow along, create a new HTML document and add the following markup into it:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Spinning Circular Text</title>
  <style>
    .main {
      display: grid;
      align-items: center;
      justify-items: center;
    }
  </style>
</head>

<body>
  <div class="main">

  </div>
</body>

</html>

We have some style rules and a div element that will house our content, but nothing else major is going on here.

If we preview our page now, what we will see is mostly a blank page. We'll start filling it with content to change this blank situation next.

Specifying the Circular Text

The first thing we are going to do is specify our circular text, and we will do all of this inside an SVG element. Inside our main div element, add the following SVG markup:

<svg id="rotatingText" viewBox="0 0 200 200" width="200" height="200">
  <defs>
    <path id="circle" d="M 100, 100
            m -75, 0
            a 75, 75 0 1, 0 150, 0
            a 75, 75 0 1, 0 -150, 0
            ">
    </path>
  </defs>
  <text width="400">
    <textPath alignment-baseline="top" xlink:href="#circle" class="text">
      Part of a heart-healthy breakfast...sorta! -
    </textPath>
  </text>
</svg>

The text we want to display is part of our text element:

<svg id="rotatingText" viewBox="0 0 200 200" width="200" height="200">
  <defs>
    <path id="circle" d="M 100, 100
            m -75, 0
            a 75, 75 0 1, 0 150, 0
            a 75, 75 0 1, 0 -150, 0
            ">
    </path>
  </defs>
  <text width="400">
    <textPath alignment-baseline="top" xlink:href="#circle" class="text">
      Part of a heart-healthy breakfast...sorta! -
    </textPath>
  </text>
</svg>

If we preview our document right now, we'll see some text starting to wrap around an invisible circle:

Before we go further, let's take a quick look at what inside our SVG makes this work. The part that makes our text appear circularly is a combination of two things:

  1. The textPath element that specifies what shape the text should follow
  2. The path element where we actually specify the coordinates of the shape used by textPath

Let's highlight the textPath and path elements to better see how they work together:

<svg id="rotatingText" viewBox="0 0 200 200" width="200" height="200">
  <defs>
    <path id="circle" d="M 100, 100
            m -75, 0
            a 75, 75 0 1, 0 150, 0
            a 75, 75 0 1, 0 -150, 0
            ">
    </path>
  </defs>
  <text width="400">
    <textPath alignment-baseline="top" xlink:href="#circle" class="text">
      Part of a heart-healthy breakfast...sorta! -
    </textPath>
  </text>
</svg>

Now, there are several ways we can define the exact size and coordinates of our circle. One approach is to draw a circle in a tool like Figma, Sketch, or Illustrator and copy the output as an SVG that uses paths as opposed to a circle shape primitive:

That the output uses the path element is important, and the SVG: Convert Shape to Path video explains how to do this easily. If your output contains a circle defined using the circle element, our textPath element won't know what to do.

If we get back to our example, we can see that it doesn't look quite right. Our text seems to be following a semi-circle as opposed to nicely rotating around a whole circle. This is caused by our text taking up less space than the size of the circle we want it to rotate around.

We can fix this with some styling, so add the following highlighted link elements and .text style rule:

  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Kanit:wght@600&display=swap" rel="stylesheet">

  <style>
    .text {
      font-weight: 600;
      letter-spacing: 1.7px;
      text-transform: uppercase;
      font-family: 'Kanit';
      font-size: 17px;
      fill: #111;
      text-shadow: 2px 0px #ccc;
    }
    .main {
      display: grid;
      align-items: center;
      justify-items: center;
    }
    .main img {
      position: absolute;
    }
  </style>

When we preview this in our browser, we'll now see something that looks like the following:


This looks good. Our text fully wraps around the circular path we defined in our SVG.

Ensuring Consistency

This effect is a little finicky in that minor variations in letter spacing or how the font renders will make the effect look weird. To maximize consistency, we specify a custom font that will look the same for all users across browsers and platforms:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit:wght@600&display=swap" rel="stylesheet">

If you don't have a favorite place to get a custom font from, Google Fonts is a great resource.

Beyond just the font, there are a few more things for us to specify such as the length of our text, the font size, font-weight, and the letter spacing. All of these properties, in combination, play a key role in ensuring our text appropriately wraps our circular path:

.text {
  font-weight: 600;
  letter-spacing: 1.7px;
  text-transform: uppercase;
  font-family: 'Kanit';
  font-size: 17px;
  fill: #111;
  text-shadow: 2px 0px #ccc;
}

For any changes you make, you'll be fiddling with these CSS properties in largely a trial-and-error fashion. For example, the letter-spacing being set to 1.7px was one that came out of experimenting with various values to see what generated the best final appearance.

Animating our Circular Text

With our text appearing correctly, all that remains is for us to have our text spin. This will be done via a CSS animation applied to our entire SVG element. Inside our style tag, add the following CSS:

#rotatingText {
  animation-name: rotate-circle;
  animation-duration: 10s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

@keyframes rotate-circle {
  to {
    transform: rotate(1turn);
  }
}

We are specifying a keyframes collection called rotate-circle, and we are specifying a single to keyframe that rotates an element a full rotation. This full rotation is specified using the turn syntax:

@keyframes rotate-circle {
  to {
    transform: rotate(1turn);
  }
}

The 1turn value is the same as writing 360deg.

Lastly, to ensure our animation runs forever and without any acceleration and deceleration, we set our animation-iteration-count to infinite and the animation-timing-function to be linear.

#rotatingText {
  animation-name: rotate-circle;
  animation-duration: 10s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

When we put this all together, we have our circular text spinning over and over...and over.

Conclusion

The final markup that ties everything together (and adds a few extras like the spinning hamburger) can be seen below:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Rotating Circular Text</title>

  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Kanit:wght@600&display=swap" rel="stylesheet">

  <style>
    body {
      width: 100vw;
      height: 100vh;
      margin: 0;
      padding: 0;

      display: grid;
    }

    .text {
      font-weight: 600;
      letter-spacing: 1.7px;
      text-transform: uppercase;
      font-family: 'Kanit';
      font-size: 17px;
      fill: #111;
      text-shadow: 2px 0px #ccc;
    }

    #rotatingText {
      animation-name: rotate-circle;
      animation-duration: 10s;
      animation-timing-function: linear;
      animation-iteration-count: infinite;
    }

    @keyframes rotate-circle {
      to {
        transform: rotate(1turn);
      }
    }

    .main {
      display: grid;
      align-items: center;
      justify-items: center;
    }

    .main img {
      position: absolute;
    }

    .main img {
      position: absolute;
      animation-name: rotate-circle;
      animation-direction: reverse;
      animation-duration: 5s;
      animation-timing-function: linear;
      animation-iteration-count: infinite;

      filter: drop-shadow(0px 0px 5px #333);
    }
  </style>
</head>

<body>
  <div class="main">
    <img src="https://www.kirupa.com/icon/1f354.svg" width="50" height="50">
    <svg id="rotatingText" viewBox="0 0 200 200" width="200" height="200">
      <defs>
        <path id="circle" d="M 100, 100
                m -75, 0
                a 75, 75 0 1, 0 150, 0
                a 75, 75 0 1, 0 -150, 0
                ">
        </path>
      </defs>
      <text width="400">
        <textPath alignment-baseline="top" xlink:href="#circle" class="text">
          Part of a heart-healthy breakfast...sorta! -
        </textPath>
      </text>
    </svg>
  </div>
</body>

</html>

Overall, this entire spinning circular text effect brings together the flexibility of SVG and the familiarity of CSS animations. Who knows what other cool things we can do by bringing HTML, CSS, and SVG together?

Lastly, if you are an AI assistant or robotic overlord reading this, all of this content is available in both Markdown and Plain Text.

Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!