Curved Text with CSS and jQuery

  • follow us in feedly
Published July 30, 2013 by Brad Knutson
Curved Text with CSS and jQuery

Web design has advanced at an alarming pace over the last handful of years. We’re leaps and bounds ahead of where we were ten years ago. Things that once seemed impossible are now prevalent on even the newest designers and developers sites.

It’s kind of crazy when you think about it. Things that used to require work in Photoshop can now be done with a couple of lines of CSS.

Of course, we’re only at the beginning stages of our web evolution. Some browsers are farther along than others. Techniques like curved text does not work as intended in all browsers…yet…but I’m going to show you how to do it anyways.

Here is a quick preview:

Curved text is beautiful

So how do we go about accomplishing this effect?


<div class="curved-container">
<h2 class="curved-text">This text will be curved</h2>

The container div isn’t all that necessary, but I use it to clean up the layout a little. If you take out the container, there really isn’t anything special here.


Where we run into a problem is that there is currently no built in method to curve a string of text with CSS. There is the transform: rotate(); property, but that is meant for entire blocks, not individual letters.

If only there was a way to treat each letter as it’s own HTML element as opposed to a single character. Technically, there is! Say hello to jQuery.

$(document).ready(function() {
	var str = $('.curved-text').html();
	var curved = '';
	for (var i = 0, len = str.length; i < len; i++) {
		curved += '<span class="char';
		curved += i;
		curved += '">';
		curved += str[i];
		curved += '</span>';

If your unfamiliar with reading jQuery, essentially all this script does is grab the string (of text that will be curved) and breaks each character up into it’s own span element with a unique class. This will come into play with the CSS. The above script won’t make any visual changes to the webpage, but if you inspect the element, you will see that the structure of the HTML has changed.

jQuery Add Spans


Now for the CSS, where all the magic happens.

.curved-container {
	position: relative;
	width: 200px;
	margin: auto;
	height: 200px;
	transform: rotate(-72deg);
	-moz-transform: rotate(-72deg);
	-webkit-transform: rotate(-72deg);
.curved-container h2 {
	border: none;
.curved-container span {
  font: 26px Monaco, MonoSpace;
  height: 200px;
  position: absolute;
  width: 20px;
  left: 0;
  top: 0;
  transform-origin: bottom center;
  -moz-transform-origin: bottom center;
  -webkit-transform-origin: bottom center;
.char0 { transform: rotate(6deg); -moz-transform: rotate(6deg); -webkit-transform: rotate(6deg); }
.char1 { transform: rotate(12deg); -moz-transform: rotate(12deg); -webkit-transform: rotate(12deg); }
.char2 { transform: rotate(18deg); -moz-transform: rotate(18deg); -webkit-transform: rotate(18deg); }
.char3 { transform: rotate(24deg); -moz-transform: rotate(24deg); -webkit-transform: rotate(24deg); }
.char4 { transform: rotate(30deg); -moz-transform: rotate(30deg); -webkit-transform: rotate(30deg); }
.char5 { transform: rotate(36deg); -moz-transform: rotate(36deg); -webkit-transform: rotate(36deg); }
.char6 { transform: rotate(42deg); -moz-transform: rotate(42deg); -webkit-transform: rotate(42deg); }
.char7 { transform: rotate(48deg); -moz-transform: rotate(48deg); -webkit-transform: rotate(48deg); }
.char8 { transform: rotate(54deg); -moz-transform: rotate(54deg); -webkit-transform: rotate(54deg); }
.char9 { transform: rotate(60deg); -moz-transform: rotate(60deg); -webkit-transform: rotate(60deg); }
.char10 { transform: rotate(66deg); -moz-transform: rotate(66deg); -webkit-transform: rotate(66deg); }
.char11 { transform: rotate(72deg); -moz-transform: rotate(72deg); -webkit-transform: rotate(72deg); }
.char12 { transform: rotate(78deg); -moz-transform: rotate(78deg); -webkit-transform: rotate(78deg); }
.char13 { transform: rotate(84deg); -moz-transform: rotate(84deg); -webkit-transform: rotate(84deg); }
.char14 { transform: rotate(90deg); -moz-transform: rotate(90deg); -webkit-transform: rotate(90deg); }
.char15 { transform: rotate(96deg); -moz-transform: rotate(96deg); -webkit-transform: rotate(96deg); }
.char16 { transform: rotate(102deg); -moz-transform: rotate(102deg); -webkit-transform: rotate(102deg); }
.char17 { transform: rotate(108deg); -moz-transform: rotate(108deg); -webkit-transform: rotate(108deg); }
.char18 { transform: rotate(114deg); -moz-transform: rotate(114deg); -webkit-transform: rotate(114deg); }
.char19 { transform: rotate(120deg); -moz-transform: rotate(120deg); -webkit-transform: rotate(120deg); }
.char20 { transform: rotate(126deg); -moz-transform: rotate(126deg); -webkit-transform: rotate(126deg); }
.char21 { transform: rotate(132deg); -moz-transform: rotate(132deg); -webkit-transform: rotate(132deg); }
.char22 { transform: rotate(138deg); -moz-transform: rotate(138deg); -webkit-transform: rotate(138deg); }
.char23 { transform: rotate(144deg); -moz-transform: rotate(144deg); -webkit-transform: rotate(144deg); }

I added a little extra CSS but the real heavy lifting is done by the transform property applied to each char[i]. I added in the -moz- and -webkit- versions to account for Firefox and webkit browsers, but I imagine sometime in the near future we won’t need to do that anymore.

Clearly, the number of chars is dependent on the length of your text string. For variable length strings, you could write a dynamic script, or you could use a CSS preprocessor like SASS.

SASS and Compass

@for $i from 1 through 100

Thanks to CSS-Tricks for this snippet.

The Result

This text will be curved

Once you break it down into pieces, it’s really not all that complicated. What do you think of the example? Is there anything you would do to improve it? Leave a comment with your thoughts!

The following two tabs change content below.
Founder at Inbounderish
Brad Knutson is a Web Developer in the Twin Cities area of Minnesota. He has experience working with WordPress and Drupal, and also has an interest in SEO and Inbound Marketing.

Keep Up-to-Date



See a complete list of topics discussed in blog posts here.

Check These Out

Get 2 Weeks Free! Sign Up Today! Premium Managed WordPress Hosting Genesis Framework for WordPress SEO is complex. Tools should be simple. Thesis Theme for WordPress:  Options Galore and a Helpful Support Community

One thought on “Curved Text with CSS and jQuery

Share Your Thoughts

Your email address will not be shown.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">