57

I'm trying to make a curved text effect using CSS3, HTML Canvas, or even SVG (see image below for example)? Is this possible? If so, how can I achieve this effect?

Update: To clarify: The text that will be styled this way will be dynamic.

Arched or Curved Text Example

web-tiki
  • 99,765
  • 32
  • 217
  • 249
gabriel
  • 1,787
  • 2
  • 19
  • 24
  • http://tavmjong.free.fr/INKSCAPE/MANUAL/web/svg_tests.php shows what you can achieve with SVG. A good look at source may help you figure out the solution – Vishal Seth May 15 '10 at 17:15
  • @Gabriel, weird question: what is that font? It's delicious. – Winfield Trail Jul 04 '11 at 16:41
  • @sudowned: It's been a while, but I believe it's Futura. – gabriel Jul 15 '11 at 17:37
  • Hope this will help you : http://stackoverflow.com/questions/7251177/curving-an-image-that-starts-as-a-rectangle-uploaded-by-user-preferably-using/29118400#29118400 – Sajith Mar 18 '15 at 09:38

10 Answers10

37

SVG supports text-on-a-path directly, though it does not 'bend' the individual glyphs along the path. Here's an example of how you create it:

...
<defs>
  <path id="textPath" d="M10 50 C10 0 90 0 90 50"/>
</defs>
<text fill="red">
  <textPath xlink:href="#textPath">Text on a Path</textPath>
</text>
...
Phrogz
  • 296,393
  • 112
  • 651
  • 745
22

You can certainly do it with canvas, try out this code as an example:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Testing min-width and max-width</title>
    <style type="text/css">

    </style>

  </head>
  <body>
      <canvas id="cnv"></canvas>
      <script type="text/javascript" charset="utf-8">
          cnv = document.getElementById("cnv");
          cnv.width = 500;
          cnv.height = 300;
          ctx = cnv.getContext("2d");
          ctx.font = "bold 12px sans-serif";
          text = "abcdefghijklm"
          for (i = 0; i < text.length; i++) {
              ctx.fillText(text[i], 300, 100);
              ctx.rotate(0.1);
          }
      </script>
  </body>
</html>

It doesn't do it exactly right, but I'm certain you'll manage to tweak it to your likening ;)

Jakub Hampl
  • 39,863
  • 10
  • 77
  • 106
13

You can do it using some CSS, however I'm sure you won't get it running on IE any time soon. On the other hand, the cool thing is that the text is selectable :D

.num1 {
  -webkit-transform: translate(0px, 30px) rotate(-35deg);
}
.num2 {
  -webkit-transform: translate(0px, 25px) rotate(-25deg);
}
.num3 {
  -webkit-transform: translate(0px, 23px) rotate(0deg);
}
.num4 {
  -webkit-transform: translate(0px, 25px) rotate(25deg);
}
.num5 {
  -webkit-transform: translate(0px, 30px) rotate(35deg);
}

span {display: inline-block; margin: 1px;}
<div style="width: 300px; height: 300px; margin: 50px auto">
    <span class="num1">a</span><span class="num2">b</span><span class="num3">c</span><span class="num4">d</span><span class="num5">e</span>
</div>
mfluehr
  • 2,832
  • 2
  • 23
  • 31
Jakub Hampl
  • 39,863
  • 10
  • 77
  • 106
  • Frankly, I don't care about IE. This is intended for an iPhone-optimized website so I'm only worried about it displaying properly in Webkit. I might be able to pull off what you're suggesting for dynamic text using a bit of JavaScript trickery. Thanks. – gabriel May 15 '10 at 18:27
  • IE9+ supports CSS3 2d transforms , and IE8 and below support microsoft's matrix transforms, but they're a little different in handling. – JayC Nov 15 '12 at 21:36
  • 1
    @JayC Yes and this post is 2 years old. I believe that using the `-ms-` prefix should mostly work, although I have no means to test. – Jakub Hampl Nov 15 '12 at 23:01
11

It's not a pure CSS solution but CircleType.js works great for arced text.

http://circletype.labwire.ca/

peterhry
  • 1,120
  • 12
  • 16
4

There is a jQuery Plugin to curve text using CSS3 called arctext.js. It's pretty good and has a range of configuration options. I guess it won't work on IE8 but I guess most CSS3 thing don't!

There's also a demo page with some example of it in action here.

Mark Rhodes
  • 10,049
  • 4
  • 48
  • 51
3

This tutorial shows you exactly how to do it using HTML5 and canvas. One of the other answers presented a similar idea, which is to use the canvas.rotate method. This one also uses canvas.translate.

The full code from the tutorial is:

function drawTextAlongArc(context, str, centerX, centerY, radius, angle) {
  var len = str.length,
    s;
  context.save();
  context.translate(centerX, centerY);
  context.rotate(-1 * angle / 2);
  context.rotate(-1 * (angle / len) / 2);
  for (var n = 0; n < len; n++) {
    context.rotate(angle / len);
    context.save();
    context.translate(0, -1 * radius);
    s = str[n];
    context.fillText(s, 0, 0);
    context.restore();
  }
  context.restore();
}
var canvas = document.getElementById('myCanvas'),
  context = canvas.getContext('2d'),
  centerX = canvas.width / 2,
  centerY = canvas.height - 30,
  angle = Math.PI * 0.8,
  radius = 150;

context.font = '30pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'blue';
context.strokeStyle = 'blue';
context.lineWidth = 4;
drawTextAlongArc(context, 'Text along arc path', centerX, centerY, radius, angle);

// draw circle underneath text
context.arc(centerX, centerY, radius - 10, 0, 2 * Math.PI, false);
context.stroke();
<!DOCTYPE HTML>
<html>

<head>
  <style>
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>

<body>
  <canvas id="myCanvas" width="578" height="250"></canvas>
</body>

</html>
Amith
  • 730
  • 6
  • 22
Simon Elms
  • 17,832
  • 21
  • 87
  • 103
3

You can use SVG with <textPath> like this:

function updateMessage(str) {
  document.getElementById("MyMessage").textContent = str;
}
<button onClick="updateMessage('The text has changed');">Change the text</button>
<svg viewBox="0 0 1000 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <path id="CurvedPath"
          d="M 0 150 Q 325 50 650 150 " />
  </defs>
  <text font-size="54" x='325' y='50'  text-anchor="middle"  fill="darkgreen" font-family=Arial,Helvetica  style="text-shadow: 2px 2px 3px gray;">
    <textPath id='MyMessage' xlink:href="#CurvedPath">THIS TEXT IS CURVED</textPath>
  </text>
</svg>
mfluehr
  • 2,832
  • 2
  • 23
  • 31
Vereb
  • 14,388
  • 2
  • 28
  • 30
2
<embed width="100" height="100" type="image/svg+xml" src="path.svg">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="textPath" d="M10 50 C10 0 90 0 90 50"/>
    </defs>
  </svg>
</embed>
Arsen7
  • 12,522
  • 2
  • 43
  • 60
1

I used the tutorial mentioned above (by Simon Tewsi) to write a better solution, regarding the kerning issue. Uses no library, pure JS.

See it at http://jsfiddle.net/fidnut/cjccg74f/

function drawTextAlongArcInside(ctx, str, font, color, radius, angle, centerX, centerY, wspace)

Note: SO is demanding that I put all the code from JSFiddle in here too. I don't think this is wise, too much code, so I am adding only the name of the function.

Rookie Vee
  • 113
  • 1
  • 2
  • 10
-1

There is also transform: skew(x, y), which does not use canvas.