{"id":6053,"date":"2013-05-20T22:52:07","date_gmt":"2013-05-21T02:52:07","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=6053"},"modified":"2013-05-22T17:29:18","modified_gmt":"2013-05-22T21:29:18","slug":"cross-browser-svg-text-paths-without-javascript-even-in-older-ie","status":"publish","type":"post","link":"http:\/\/www.useragentman.com\/blog\/2013\/05\/20\/cross-browser-svg-text-paths-without-javascript-even-in-older-ie\/","title":{"rendered":"Cross-Browser SVG Text-Paths Without JavaScript \u2014 Even In Older IE."},"content":{"rendered":"\r\n<div class=\"example\">\r\n<div id=\"cookie-canvas\">\r\n<img decoding=\"async\" id=\"cookie\" src=\"\/tests\/textpath\/images\/cookie.jpg\" \/> \r\n<!--[if IE 9 | !IE]><!-->\r\n<svg id=\"myShape\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n     xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"\r\n    viewBox=\"0 0 407 407\" \r\n     >\r\n  <defs>\r\n    \r\n    <!-- \r\n        Note: the d attribute is the same as the VML shape's path attribute except:\r\n        \r\n        1) SVG can take float co-ordinates.  VML cannot.\r\n        2) all the numbers are separated by commas, not just the coordinate pairs.\r\n        3) the 'z' at the end in svg is an 'xe' in VML\r\n    -->\r\n    \r\n    <path id=\"path1\"\r\n          fill=\"none\" stroke=\"black\" stroke-width=\"1\"\r\n          d=\"M 212,65\r\n             C 276,81 292,91 305,103 361,155 \r\n         363,245 311,302 300,314 286,324 \r\n         271,332 248,343 227,347 202,347 \r\n         190,346 174,343 163,339 143,333\" >\r\n    <\/path>\r\n  <\/defs>\r\n  <text id=\"myText\">\r\n  <textPath  xlink:href=\"#path1\"><tspan dy=\"0.3em\">C is for Cookie, That's Good Enough For Me!<\/tspan><\/textPath>\r\n  <\/text>\r\n  \r\n  <\/svg>\r\n<!--<![endif]-->\r\n\r\n<!--[if lt IE 9 ]>\r\n  <?import namespace=\"v\" urn=\"urn:schemas-microsoft-com:vml\" \r\n    implementation=\"#default#VML\" declareNamespace \/>  \r\n    <v:group id=\"myShape\" >\r\n      \r\n      <v:shape id=\"path1\"\r\n          allowoverlap=\"true\" \r\n          coordsize=\"407,407\" \r\n          filled=\"t\" fillcolor=\"black\" stroked=\"f\"  \r\n          path=\"M212,65\r\n                C276,81,292,91,305,103,361,155,\r\n                 363,245,311,302,300,314,286,324,\r\n                 271,332,248,343,227,347,202,347,\r\n                 190,346,174,343,163,339,143,333\">\r\n        <v:path textpathok=\"t\"><\/v:path>\r\n        <v:textpath id=\"myText\" style=\"v-text-align: left\" on =\"t\" string=\"C is for Cookie, That's Good Enough For Me!\"><\/v:textpath>\r\n      \r\n        \r\n      <\/v:shape>\r\n    <\/v:group>\r\n  \r\n<![endif]-->\r\n<\/div>\r\n    <p>The text is not part of an image.  Hover over the image and see it animate. \r\n    <em>(Photo Credit: Renee Comet. Photo from <a href=\"http:\/\/commons.wikimedia.org\/wiki\/File:Chocolate_chip_cookie.jpg\">Wikimedia Commons<\/a>)<\/em><\/p>\r\n<\/div>\r\n<p>As <a href=\"http:\/\/instagram.com\/p\/QHl8qUBWih\/\">a<\/a> <a href=\"http:\/\/instagram.com\/p\/WFwvYlBWu5\/\">semi<\/a>&#8211;<a href=\"http:\/\/instagram.com\/p\/XqnvQjhWj3\/\">retired<\/a> <a href=\"http:\/\/instagram.com\/p\/U2ky_-BWhS\/\">calligrapher<\/a>, I have always been obessesed with typography on-line.  Typography on the web has improved immensely since I started doing web-development in the 1990&#8217;s, but passing by <a href=\"http:\/\/instagram.com\/p\/Zij_DYhWq4\/\">this poster at work<\/a> for the last two years has <strong>inspired me into researching textpaths in HTML5.<\/strong>  Designers have been using textpaths for years in print, but doing this on the web is a little tricky.  <strong><a href=\"http:\/\/en.wikipedia.org\/wiki\/Scalable_Vector_Graphics\">SVG<\/a>, which supports textpaths in modern browsers<\/strong>, is not supported by IE &lt;= 8.  <strong>Older IE does, however, support <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee384217%28v=vs.85%29.aspx\">VML<\/a><\/strong>, another vector markup format that can do textpaths as well.  After playing around, I found it is possible to <strong>put both on a web page and even code common CSS to style them<\/strong> &mdash; all without JavaScript.   JavaScript can, however, be added to add some interesting animation effects, as these demos illustrate:<\/p>\n<ul class=\"right-of-float\">\n<li><a href=\"\/tests\/textpath\/example1-svg-vml.html\">A clean room example of the cookie animation<\/a><\/li>\n<li><a href=\"\/tests\/textpath\/example2-svg-vml.html\">Animating text on a more complex path<\/a><\/li>\n<li><a href=\"\/tests\/textpath\/example3-svg-vml.html\">Using the outside of a martini glass as a set of textpaths.<\/a><\/li>\n<li><a href=\"\/tests\/textpath\/example3-svg-vml-animation.html\">Animating the martini glass textpath curves with tweening<\/a><\/li>\n<\/ul>\n<p>I&#8217;ll explain how we can <strong>layout and style textpaths in all browsers<\/strong>, including IE &lt;= 8.  I also explain <strong>what a Bezier Curve is<\/strong>, and introduce a tool, the <strong>Bezier Curve Construction Set<\/strong>, that will help you create your own scriptless textpaths.  The only script you&#8217;ll need is when we cover animated textpaths, where I will show how I <strong>push text on a path<\/strong> as well <strong>tween a textpath<\/strong>.   Note that all the demos and code in this article use <a href=\"http:\/\/jquery.org\">jQuery<\/a>, but there is no reason why you couldn&#8217;t use any other framework (or no framework at all) to do the same thing.<\/p>\n<h2>How to do this in modern browsers<\/h2>\n<p>Let&#8217;s walk through the SVG code that generates the curve that you see in the example above:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;svg id=\"myShape\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n     xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"&gt;\r\n  &lt;defs&gt;\r\n    &lt;path <span class=\"hilite\">id=\"path1\"<\/span>\r\n          fill=\"none\" stroke=\"black\" stroke-width=\"1\"\r\n          <span class=\"hilite3\">d=\"M 212,65\r\n             C 276,81 292,91 305,103 361,155 \r\n               363,245 311,302 300,314 286,324 \r\n               271,332 248,343 227,347 202,347 \r\n               190,346 174,343 163,339 143,333\"<\/span>&gt;\r\n    &lt;\/path&gt;\r\n  &lt;\/defs&gt;\r\n  &lt;text id=\"myText\"&gt;\r\n    &lt;textPath  <span class=\"hilite\">xlink:href=\"#path1\"<\/span> &gt;\r\n      &lt;tspan <span class=\"hilite2\">dy=\"0.3em\"<\/span>&gt;C is for Cookie, That's Good Enough For Me!&lt;\/tspan&gt;\r\n    &lt;\/textPath&gt;\r\n  &lt;\/text&gt;\r\n&lt;\/svg&gt;\r\n<\/pre>\n<\/blockquote>\n<p>SVG is XML-based markup that describes an image &mdash; an browser that supports it can read this description and draws it on the fly.  In the markup above &mdash; the <code>&lt;defs&gt;<\/code> section contains the <code>&lt;path&gt;<\/code> (called <span class=\"hilite\"><code>path1<\/code><\/span>) that we will use to draw the <code>textpath<\/code> with (you can see it referencing <code>#path1<\/code> in the <code>textpath<\/code>&#8216;s <code>xlink:href<\/code> attribute).  <span class=\"hilite3\">This path is described in the <code>d<\/code> attribute.<\/span>  If you are not familiar with SVG, you are probably feeling a little intimidated by this jumble of letters and numbers.  Let me walk you through what each part means:<\/p>\n<ol>\n<li>The <code>M<\/code> (the <strong>Move command<\/strong> tells the browser to move it&#8217;s virtual pen at the co-ordinate that follows it (in this case <code>212,65<\/code>.  This wil be the starting point of our curve<\/li>\n<li>The <code>C<\/code> (the <strong>Cubic Bezier Curve command<\/strong> tells the computer to draw a path described by each group of six numbers that follow it (I&#8217;ll explain what these numbers mean in the next section).<\/li>\n<\/ol>\n<p>Paths can also contain other commands like <code>L<\/code> (the Line-to command) which can draw a line from the last coordinate from the previous to it&#8217;s own co-ordinate.  There are more commands available, but we will concentrate on these three commands in this article (for more information about all the SVG path commands, check out <a href=\"http:\/\/www.w3.org\/TR\/SVG\/paths.html#PathElement\">Path Element<\/a> section of the <a href=\"http:\/\/www.w3.org\/TR\/SVG\/Overview.html\">SVG 1.1 Specification<\/a>).<\/p>\n<p>Also note the <span class=\"hilite2\"><code>dy=\"0.3em\"<\/code><\/span> in the <code>&lt;tspan&gt;<\/code> tag.  By default, text will sit on top of a SVG textpath curve.  Setting <code>dy=\"0.3em\"<\/code> will make the textpath <em>go through<\/em> the text instead.  Later in this article, you will see that <strong><em>this is an important point if you are creating textpaths that will look consistant in IE <= 8.<\/em><\/strong>.<\/p>\n<h2>So, what the heck is a Cubic Bezier Curve?<\/h2>\n<p>A Bezier Curve is a numeric representation of a curve and is commonly used in computer graphics.  Bezier Curves were famously used in 1962 by the French engineer Pierre Bezier to design automobile bodies at Renault (although he <a href=\"http:\/\/en.wikipedia.org\/wiki\/Pierre_B%C3%A9zier\">wasn&#8217;t the first to use them for automotive design<\/a> or come up with the math behind them &#8230; then again, <a href=\"http:\/\/www.cracked.com\/article_16072_5-famous-inventors-who-stole-their-big-idea.html\">a lot of people in history got credit for things they didn&#8217;t originally invent<\/a>).<\/p>\n<p>To describe what the numbers mean, let&#8217;s take a simple example of <code>M 200, 300 C 100, 100, 500, 100, 400, 300<\/code>:<\/p>\n<p><div id=\"attachment_6077\" style=\"width: 622px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-6077\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/diagram1.png\" alt=\"A diagram showing the SVG path  M 200, 300 C 100, 100  500, 100  400, 300\" width=\"612\" height=\"371\" class=\"size-full wp-image-6077\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/diagram1.png 612w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/diagram1-300x181.png 300w\" sizes=\"auto, (max-width: 612px) 100vw, 612px\" \/><p id=\"caption-attachment-6077\" class=\"wp-caption-text\">A diagram showing the SVG path  M 200, 300 C 100, 100, 500, 100, 400, 300<\/p><\/div><\/p>\n<p>The browser starts the curve at <code>(200, 300)<\/code> (which is the co-ordinate in the M, or &#8220;Move&#8221; command) and ends the curve at <code>(400, 300)<\/code> (the last co-ordinate in the C, or &#8220;Cubic Curve&#8221; command).  The first and second co-ordinates in the C command (<code>(100, 100)<\/code> and <code>(500, 100)<\/code>) are called <strong>control points<\/strong>.  The computer draws the beginning of the curve as if the line is being drawn towards the first control point and at the end of the curve looks like it is being drawn from the last control point.  This concept may be a little difficult to understand at first, so let&#8217;s take a look at an interactive version of the diagram to solidify your understanding of this concept.  Drag and drop any of the points in it, and see how the path syntax changes at the bottom of the frame:<\/p>\n<div style=\"width: 622px\" class=\"wp-caption aligncenter\">\n<iframe loading=\"lazy\" src=\"\/tests\/textpath\/bezier-curve-construction-set.html#path=M%20200%2C%20300%20C%20100%2C%20100%2C%20500%2C%20100%2C%20400%2C%20300&#038;imageURL=https:\/\/www.useragentman.com\/tests\/textpath\/images\/grid.png&#038;showFooter=1&#038;noInfo=1\" width=\"612\" height=\"371\" class=\"size-full wp-image-6077\"  scrolling=\"no\"><\/iframe><\/p>\n<p class=\"wp-caption-text\">Drag and drop any of the points in this interactive frame to see how the VML\/SVG path changes.  I hope this helps your understanding of how the C command works.<\/p>\n<\/div>\n<p>Now I understand this SVG path notation may be hard to grasp (it took me a while to), so I wrote a tool to help, the <a href=\"\/tests\/textpath\/bezier-curve-construction-set.html\">Bezier Curve Construction Set<\/a> (it is actually what powers the interactive diagram above).  You can use this tool to play around with Bezier Curves, and even include a background image that you may want use to guide you.  I made all the demos in this article with the help of this tool.<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/textpath\/bezier-curve-construction-set.html\">See the Bezier Curve Construction Set In Action.<\/a><\/p>\n<h2>So, What About IE?<\/h2>\n<p>While IE9+ can render the SVG above, there are, unfortunately, still users of IE8 and lower.  The good news is that these browsers can render VML, another Vector Markup Language (gee, maybe that&#8217;s what it stands for ;-) ).  VML was <a href=\"http:\/\/www.w3.org\/TR\/NOTE-VML\">submitted as a web standard in 1998<\/a>, but wasn&#8217;t accepted.  However, the W3C took bits of VML and competing vector format, <a href=\"http:\/\/www.w3.org\/TR\/1998\/NOTE-PGML-19980410\">PGML<\/a> and came up with SVG.  Because of this heritage, VML&#8217;s path syntax is very similar to SVG&#8217;s &mdash; although some of the commands differ, both use the <code>M<\/code>, <code>C<\/code> and <code>L<\/code> commands.  The rest of the markup, however, is quite different:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;?import namespace=\"v\" urn=\"urn:schemas-microsoft-com:vml\" \r\n     implementation=\"#default#VML\" declareNamespace \/&gt;   \r\n&lt;v:group id=\"myShape\" &gt;\r\n   \r\n   &lt;v:shape id=\"path1\"\r\n         allowoverlap=\"true\" \r\n         coordsize=\"407,407\" \r\n         filled=\"t\" fillcolor=\"black\" stroked=\"f\"  \r\n          <span class=\"hilite3\">path=\"M 212,65\r\n               C 276,81 292,91 305,103 \r\n                 361,155 363,245 311,302\r\n                 300,314 286,324 271,332\r\n                 248,343 227,347 202,347 \r\n                 190,346 174,343 163,339\"<\/span>&gt;\r\n      &lt;v:path textpathok=\"t\"&gt;&lt;\/v:path&gt;\r\n      &lt;v:textpath id=\"myText\" style=\"v-text-align: left\" on =\"t\" \r\n          string=\"C is for Cookie, That's Good Enough For Me!\"&gt;&lt;\/v:textpath&gt;\r\n   \r\n      \r\n   &lt;\/v:shape&gt;\r\n&lt;\/v:group&gt;\r\n<\/pre>\n<\/blockquote>\n<p>So, how do we make this markup work in all browsers?  Conditional Comments to the rescue!<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;!--\r\n    This first bit will be hidden from IE8 and below.\r\n    All other user agents will render it.\r\n--&gt;\r\n\r\n&lt;!--[if IE 9 | !IE]&gt;&lt;!--&gt;\r\n&lt;svg id=\"myShape\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n     xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"&gt;\r\n  &lt;defs&gt;\r\n     &lt;path id=\"path1\" \r\n           <span class=\"hilite3\">d=\"M 212,65\r\n              C 276,81 292,91 305,103 \r\n                361,155 363,245 311,302\r\n                300,314 286,324 271,332\r\n                248,343 227,347 202,347 \r\n                190,346 174,343 163,339<\/span>\" &gt;\r\n     &lt;\/path&gt;\r\n  &lt;\/defs&gt;\r\n  &lt;text id=\"myText\"&gt;\r\n   &lt;textPath  xlink:href=\"#path1\"&gt;\r\n      &lt;tspan dy=\"0.3em\"&gt;C is for Cookie, That's Good Enough For Me!&lt;\/tspan&gt;\r\n   &lt;\/textPath&gt;\r\n  &lt;\/text&gt;\r\n  \r\n&lt;\/svg&gt;\r\n&lt;!--&lt;![endif]--&gt;\r\n\r\n&lt;!--\r\n    Only IE8 and below will see and render the VML markup\r\n    below.\r\n--&gt;\r\n\r\n&lt;!--[if lt IE 9 ]&gt;\r\n   &lt;?import namespace=\"v\" urn=\"urn:schemas-microsoft-com:vml\" \r\n            implementation=\"#default#VML\" declareNamespace \/&gt;   \r\n      &lt;v:group id=\"myShape\" &gt;\r\n         \r\n         &lt;v:shape id=\"path1\"\r\n               allowoverlap=\"true\" \r\n               coordsize=\"407,407\" \r\n               filled=\"t\" fillcolor=\"black\" stroked=\"f\"  \r\n               <span class=\"hilite3\">path=\"M 212,65\r\n                       C 276,81 292,91 305,103 \r\n                         361,155 363,245 311,302\r\n                         300,314 286,324 271,332\r\n                         248,343 227,347 202,347 \r\n                         190,346 174,343 163,339\"<\/span>&gt;\r\n            &lt;v:path textpathok=\"t\"&gt;&lt;\/v:path&gt;\r\n            &lt;v:textpath id=\"myText\" style=\"v-text-align: left\" \r\n               on =\"t\" string=\"C is for Cookie, That's Good Enough For Me!\"&gt;&lt;\/v:textpath&gt;\r\n\r\n         &lt;\/v:shape&gt;\r\n      &lt;\/v:group&gt;\r\n   \r\n&lt;![endif]--&gt;\r\n<\/pre>\n<\/blockquote>\n<p>In the <code>&lt;head&gt;<\/code>, I also add the <a href=\"https:\/\/github.com\/zoltan-dulac\/svg-vml-textpaths\/blob\/master\/css\/vml.css\">vml.css<\/a> style-sheet, which also acts as a CSS reset for all the examples in this article.<\/p>\n<p>I mentioned earlier that the SVG version needed the <code>dy=\"0.3em\"<\/code> in the <code>&lt;tspan&gt;<\/code> tag to ensure parity with IE <= 8.  Let us show you some screenshots showing where the path is relative to the text in both browsers:\n\n\n\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>IE <= 8<\/th>\n<th>Chrome 26 (without dy=&#8221;0.3&#8243;)<\/th>\n<th>Chrome 26 (with dy=&#8221;0.3&#8243;)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-ie.jpg\" alt=\"cookie-with-path-screenshot-ie\" width=\"250\" height=\"350\" class=\"alignnone size-full wp-image-6137\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-ie.jpg 250w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-ie-214x300.jpg 214w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/>\n<\/td>\n<td>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-chrome.jpg\" alt=\"cookie-with-path-screenshot-chrome\" width=\"250\" height=\"350\" class=\"alignnone size-full wp-image-6136\" \/>\n<\/td>\n<td>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-chome-dy.jpg\" alt=\"cookie-with-path-screenshot-chome-dy\" width=\"250\" height=\"350\" class=\"alignnone size-full wp-image-6135\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-chome-dy.jpg 250w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/cookie-with-path-screenshot-chome-dy-214x300.jpg 214w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/>\n<\/td>\n<\/tr>\n<\/table>\n<p><a href=\"\/tests\/textpath\/example1-svg-vml-dy-test.html\" class=\"exampleLink\">See the demo where I got these screenshots from.<\/a><\/p>\n<p>I actually like the SVG default behaviour of placing the text on top of the path, but there I don&#8217;t believe there is any way for IE to do this.  :-\/<\/p>\n<h2>Can I Use CSS With SVG and VML?<\/h2>\n<p>Absolutely!  As a matter of fact, there are several CSS properties that are unique to both technologies.  Let&#8217;s walk through the CSS of the example at the top of the page:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n\/***********************************************\r\n * Note that I don't use the SVG or VML node\r\n * names in my CSS.  I try to style the common\r\n * elements by using IDs on the similar nodes.\r\n ***********************************************\/\r\n\r\n\/* \r\n * This rule is for the root of the SVG and VML \r\n * (i.e. the whole shape).\r\n *\/\r\n#myShape {\r\n  width: 407px;\r\n  height: 407px;\r\n  cursor: pointer;\r\n \r\n  \/* SVG *\/\r\n \r\n  \/*\r\n   * Webkit is the only browser that makes the transform \r\n   * origin 0 0 (WHY?!?!). We also can't use 50% 50%, \r\n   * because for SVG Webkit  doesn't understand that \r\n   * either (WHY!??!)\r\n   *\/\r\n  -webkit-transform-origin: 203.5px 203.5px;\r\n  \r\n  \r\n  \/*\r\n   * Even though it doesn't really do anything, \r\n   * we do -webkit-transform here. The translateZ(0)\r\n   * turns on GPU acceleration for animation on the\r\n   * node (if available).  I put the rotate(0deg)\r\n   * here as since we need to have the same tranform\r\n   * functions for all the animation states, otherwise\r\n   * the transition will fail.\r\n   *\/ \r\n  -webkit-transform: translateZ(0) rotate(0deg);\r\n          \r\n  \r\n  \/* \r\n   * We animate on hover for browsers that do CSS transitions.\r\n   * The \r\n   *\/\r\n       -o-transition: -o-transform 1s ease-out;\r\n  -webkit-transition: -webkit-transform 1s ease-out;\r\n          transition: transform 1s ease-out;\r\n  \r\n  \/* \r\n   * VML: a rotation in VML is surprisingly simple, and\r\n   * doesn't need the horrible Matrix filter notation (yay!) \r\n   *\/\r\n  <span class=\"hilite\">rotation: 0;<\/span>\r\n  \r\n  \/* \r\n   * This is needed by the VML in IE &lt; 8 in order to grab\r\n   * the mouseover events that do the animation in JavaScript\r\n   *\/\r\n  background: url('..\/images\/transparent.gif');\r\n}\r\n\r\n\/* IE9 will put the curve underneath the cookie unless we\r\n * set positioning to the &lt;SVG&gt; tag.  We don't do this in \r\n * VML since positioning a &lt;v:group&gt; will mess up layout.\r\n *\/\r\nsvg#myShape {\r\n  position: relative;\r\n}\r\n\r\n\/*\r\n * This rule is to style the text (i.e. the &lt;text&gt; node in SVG\r\n * and the &lt;v:shape&gt; node in VML).\r\n *\/\r\n#myText {\r\n\r\n  font-size: 50px;\r\n  \r\n  \/* SVG only.  For VML, the fill happens in the &lt;v:shape&gt; tag. *\/\r\n  <span class=\"hilite2\">fill: black;<\/span>\r\n  \r\n  \/* Note: VML will not accept @font-face fonts (!!!) *\/\r\n  font-family: \"Georgia\", \"Times New Roman\", sans-serif;\r\n  font-style: italic;\r\n}\r\n\r\n\r\n\r\n\r\n\/*\r\n * On hover, we want the shape animate in a full circle.\r\n * Note we don't bother with -ms-transform since this \r\n * is going to be handled by JavaScript, due to IE9's\r\n * support of CSS transitions (IE10, which does support\r\n * transitions, doesn't use the -ms vendor prefix with\r\n * either transforms or transitions).\r\n *\/\r\n#myShape:hover {\r\n       -o-transform: rotate(360deg);\r\n  -webkit-transform: translateZ(0) rotate(360deg);\r\n          transform: translateZ(0) rotate(360deg);\r\n  \r\n  \/* \r\n   * You would think this would work, but it doesn't,\r\n   * even without the transition. (I leave it here for \r\n   * to call this fact out).   Seems like we can't \r\n   * rotate in VML on hover, so we do this with \r\n   * JavaScript instead via the mouseover\r\n   * event.\r\n   *\/\r\n  rotation: 45;\r\n}\r\n\r\n#cookie {\r\n  left: -4px;\r\n  position: absolute;\r\n  top: 0;\r\n}\r\n\r\n<\/pre>\n<\/blockquote>\n<p>The interesting bits:<\/p>\n<ul>\n<li>The <span class=\"hilite2\"><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/SVG\/Tutorial\/Fills_and_Strokes\"><code>fill: black<\/code><\/a><\/span> is needed for the SVG <code>&lt;text&gt;<\/code> tag instead of using <code>color<\/code> to set the text&#8217;s color.  This is because SVG thinks of all objects, including text, as shapes, which can have independent <code>stroke<\/code> (i.e. outline) and <code>fill<\/code> styles.  You will note that for the VML, we must set <code>filled=\"t\"<\/code> and <code>fillcolor=\"black\"<\/code> inside the <code>&lt;v:shape&gt;<\/code> tag (It&#8217;s a shame this can&#8217;t be done in CSS).\n<\/li>\n<li>While modern browsers can use variations of the <code>transform<\/code> property, the really surprising thing here is the <span class=\"hilite\"><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb263877%28v=vs.85%29.aspx\"><code>rotation<\/code><\/a><\/span> property in VML.  This is so intuitive, you would think that older IE would use this kind of CSS syntax for HTML elements as well <a href=\"https:\/\/www.useragentman.com\/IETransformsTranslator\/index.html\">instead of using the really ugly numbers in the Matrix Filter<\/a>.  The problem here is that you cannot set a different value for this property using a <code>:hover<\/code> pseudo-class (Why IE?!?! WHY!?!?? It&#8217;s as if the people who built the IE back in the day hated web developers!).<\/li>\n<li>Note that I avoid using selectors with tag names, due to the huge difference between VML and SVG.  Instead I put the same id&#8217;s on the VML and SVG tags that render the same thing (e.g. <code>#myText<\/code> for styling the text in the vector markup, <code>#myShape<\/code> for styling the width and height of the vector markup&#8217;s canvas, etc).<\/li>\n<\/ul>\n<p>For those interested, Opera has <a href=\"http:\/\/www.opera.com\/docs\/specs\/presto25\/svg\/cssproperties\/\">a list of SVG-specific CSS properties<\/a> and which ones it currently supports, and the <a href=\"http:\/\/www.w3.org\/TR\/NOTE-VML\">VML submission to the W3C<\/a> has <a href=\"http:\/\/www.w3.org\/TR\/NOTE-VML#_Toc416858381\">a section on CSS for VML<\/a>.<\/p>\n<p>This CSS works well in IE <= 9 but the animations don't, so we include this script for these challenged browsers:\n\n\n\n<blockquote class=\"code\">\n<pre>\r\n\/*\r\n * This implements the rotation animation in \r\n * IE &lt;= 9, using jQuery.animate() on VML's \r\n * rotation CSS property (for IE &lt;= 8) and\r\n * IE9's -ms-transform CSS property.\r\n *\/\r\n\r\nvar IEAnimation = new function () {\r\n   var me = this,\r\n         $myShape;\r\n   \r\n   me.init = function () {\r\n     \r\n      $myShape = $('#myShape');\r\n      $myShape.hover(hoverIn, hoverOut);\r\n   \r\n   }\r\n   \r\n   function hoverIn(e) {\r\n     \r\n     \/\/ rotate from 0 to 360 in 1000 millseconds.\r\n     \r\n      $myShape.stop().animate({\r\n        \r\n        \/\/ This animated VML's rotation CSS property\r\n        \/\/ for IE &lt;= 8\r\n        \r\n         rotation: 360\r\n      }, {\r\n         duration: 1000,\r\n         step: function (now, tween) {\r\n           \r\n           \/\/ We need to animation IE9's -ms-transform property\r\n           \/\/ in the step method, since it is non-numeric.  now\r\n           \/\/ will be a number of degrees given in the rotation\r\n           \/\/ property.  Even though that property doesn't exist\r\n           \/\/ in IE9 and above, animate() still uses it to \r\n           \/\/ populate the step method's now parameter.\r\n           \r\n            $myShape.css('msTransform', 'rotate(' + now + 'deg)');\r\n         }\r\n      });\r\n   }\r\n   \r\n   function hoverOut(e) {\r\n     \r\n     \/\/ rotate from 360 to 0 in 1000 millseconds.  Same\r\n     \/\/ idea as the hoverIn() method.\r\n     \r\n      $myShape.stop().animate({\r\n         rotation: 0\r\n      }, {\r\n         duration: 1000,\r\n         step: function (now, tween) {\r\n            $myShape.css('msTransform', 'rotate(' + now + 'deg)');\r\n         }\r\n      });\r\n   }\r\n   \r\n}\r\n\r\n$(document).ready(IEAnimation.init)\r\n<\/pre>\n<\/blockquote>\n<h2>Other Types of Animations.<\/h2>\n<h3>Animating Text Along An Arbitrary Path.<\/h2>\n<p>Click on the screenshot below to see text animate along an image of a roller-coaster:<br \/>\n<div id=\"attachment_6106\" style=\"width: 355px\" class=\"wp-caption aligncenter\"><a href=\"\/tests\/textpath\/example2-svg-vml.html\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-6106\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/roller-coaster-screenshot.jpg\" alt=\"It&#039;s also possible to animate text along an arbitrary path.  Click the screenshot above to see text animate on the path of a roller-coaster.\" width=\"345\" height=\"195\" class=\"size-full wp-image-6106\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/roller-coaster-screenshot.jpg 345w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/roller-coaster-screenshot-300x169.jpg 300w\" sizes=\"auto, (max-width: 345px) 100vw, 345px\" \/><\/a><p id=\"caption-attachment-6106\" class=\"wp-caption-text\">It&#8217;s also possible to animate text along an arbitrary path.  Click the screenshot above to see text animate on the path of a roller-coaster.<\/p><\/div><\/p>\n<p>The SVG is rather similar to the &#8220;Cookie&#8221; example above, but let me highlight a few points:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;!--[if IE 9 | !IE]&gt;&lt;!--&gt;\r\n  &lt;svg id=\"myShape\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n       xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"\r\n      &gt;\r\n    &lt;defs&gt;\r\n      \r\n      &lt;!-- This is a path with two curves fused together --&gt;\r\n      &lt;path id=\"path1\"\r\n            fill=\"none\" stroke=\"black\" stroke-width=\"1\"\r\n            d=\"M 1, 281 \r\n               C 479, 74, 502, 65, 779, 200\r\n                 834, 236, 915, 343, 1023, 468\"&gt;\r\n      &lt;\/path&gt;\r\n    &lt;\/defs&gt;\r\n    &lt;text id=\"myText\"&gt;\r\n      &lt;textpath  <span class=\"hilite3\">class=\"textpath\"<\/span> xlink:href=\"#path1\" startOffset=\"0%\"&gt;\r\n        <span class=\"hilite2\">&lt;tspan dy=\"0.3em\"&gt;Type Doesn't Have To Be Flat!&lt;\/tspan&gt;<\/span>\r\n      &lt;\/textpath&gt;\r\n        &lt;\/text&gt;\r\n    \r\n  &lt;\/svg&gt;\r\n&lt;!--&lt;![endif]--&gt;\r\n\r\n&lt;!--[if lt IE 9 ]&gt;\r\n  &lt;?import namespace=\"v\" urn=\"urn:schemas-microsoft-com:vml\" \r\n           implementation=\"#default#VML\" declareNamespace \/&gt;  \r\n    &lt;v:group id=\"myShape\" &gt;\r\n      \r\n      &lt;!-- This is a path with two curves fused together --&gt;\r\n      &lt;v:shape id=\"path1\"\r\n          allowoverlap=\"true\" \r\n          coordsize=\"1024,481\" \r\n          filled=\"t\" fillcolor=\"black\" stroked=\"f\"  \r\n          path=\"M 1, 281 \r\n                C 479, 74, 502, 65, 779, 200\r\n                  834, 236, 915, 343, 1023, 468\r\n            \"&gt;\r\n \r\n          &lt;v:path textpathok=\"t\"  \/&gt;\r\n        &lt;v:textpath id=\"myText\" on=\"t\" <span class=\"hilite2\">string=\"Type Doesn't Have To Be Flat!\"<\/span> \/&gt;\r\n\r\n      &lt;\/v:shape&gt;\r\n    &lt;\/v:group&gt;\r\n  \r\n&lt;![endif]--&gt;\r\n<\/pre>\n<\/blockquote>\n<p>Note that take <span class=\"hilite3\">the <code>&lt;textpath&gt;<\/code> node and set its class to <code>\"textpath\"<\/code>.<\/span> This is because I cannot use jQuery to search for SVG nodeNames (e.g. <code>$('textpath')<\/code>), but I can search for classes of SVG nodes (e.g. <code>$('.textpath')<\/code>).<\/p>\n<p>Let&#8217;s also take a look at  <span class=\"hilite2\">where the text appears in each format<\/span>.  In SVG, it appears as text inside inside the <code>&lt;tspan&gt;<\/code> node, while in VML, it appears inside the <code>&lt;v:textpath&gt;<\/code>&#8216;s <code>string<\/code> attribute.  This is the same as the previous example, but this difference comes into play  when we are animate the text along it&#8217;s path using <code>jQuery.animate()<\/code>.  In SVG browsers, we manipulate the <code>&lt;textPath&gt;<\/code> node&#8217;s <code>startOffset<\/code> attribute, increasing it from <code>0%<\/code> to <code>100%<\/code>.  For VML browsers, we have to add spaces at the beginning of the <code>&lt;v:textpath&gt;<\/code> node&#8217;s <code>string<\/code> attribute.  Here is a simplified version of the actual  JavaScript code.<\/p>\n<blockquote class=\"code\">\n<pre>\r\nvar originalText = \"Text Doesn't Have To Be Flat!\";\r\n$textpath = $('textPath');   \/\/ note Chrome doesn't like 'textpath' with a lower case 'p'.\r\n        \r\n\/*\r\n * Since we want $textpath to be set to the SVG node, not the VML node,\r\n * we check the parentNode to make sure.\r\n *\/\r\nif ($textpath[0].parentNode.nodeName != 'text') {\r\n  $textpath = [];\r\n}\r\n\r\n$('#hoverControl\").hover(hoverIn, hoverOut);\r\n\r\nfunction hoverIn(e) {\r\n  \r\n  \/*\r\n   * We are animting using a dummy CSS property,\r\n   * appropriately called 'dummy'. :-)\r\n   *\/\r\n  $myShape.stop().animate({\r\n    dummy: 100\r\n  }, {\r\n    duration: duration,\r\n    \r\n    \/*\r\n     * now is going to be between 0 and 100.  \r\n     *\/\r\n    step: function (now, tween) {\r\n      \r\n      \/\/ For SVG browsers, we modify the startOffset attribute to push the text\r\n      if ($('svg textPath').length > 0) {\r\n        $textpath[0].setAttribute('startOffset', now + '%');\r\n        \r\n      \/\/ In IE <= 8, we have to add spaces to the beginning of the original\r\n      \/\/ test on the path. :-\/\r\n      } else {\r\n        ('#myText').string = getSpaces(now) + originalText;\r\n      }\r\n      \r\n    }\r\n  });\r\n}\r\n\r\n\r\n\/*\r\n * getSpaces(): returns a string with n space in it.\r\n *\/\r\nfunction getSpaces(n) {\r\n  var r = '';\r\n  for (var i=0; i<n; i++) {\r\n    r += ' ';\r\n  }\r\n  return r;\r\n}\r\n<\/pre>\n<\/blockquote>\n<p>The above is just a partial listing of the demo source.  <a href=\"https:\/\/github.com\/zoltan-dulac\/svg-vml-textpaths\/blob\/master\/js\/example2-animation.js\">The full source is available here at GitHub<\/a>.<\/p>\n<p><a href=\"\/tests\/textpath\/example2-svg-vml.html\" class=\"exampleLink\">See the roller-coaster demo in action.<\/a><\/p>\n<h3>Tweening the Text Path Itself<\/h3>\n<p>To illustrate how to tween on the path itself, let's use this example of text wrapping around a martini glass:<\/p>\n<p><div id=\"attachment_6111\" style=\"width: 241px\" class=\"wp-caption aligncenter\"><a href=\"\/tests\/textpath\/example3-svg-vml-animation.html\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-6111\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/martini-screenshot.jpg\" alt=\"Click the screenshot to see the martini example with tweened path animations.\" width=\"231\" height=\"399\" class=\"size-full wp-image-6111\" srcset=\"http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/martini-screenshot.jpg 231w, http:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/martini-screenshot-173x300.jpg 173w\" sizes=\"auto, (max-width: 231px) 100vw, 231px\" \/><\/a><p id=\"caption-attachment-6111\" class=\"wp-caption-text\">Click the screenshot to see the martini example with tweened path animations.<\/p><\/div><\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;!--[if IE 9 | !IE]&gt;&lt;!--&gt;\r\n&lt;svg id=\"myShape\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n     xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"&gt;\r\n  &lt;defs&gt;\r\n    \r\n   \r\n    <span class=\"hilite\">&lt;filter id=\"drop-shadow\"&gt;\r\n      &lt;feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"3\" result=\"blurred\"\/&gt;\r\n      &lt;feOffset in=\"blurred\" dx=\"0\" dy=\"0\" result=\"final_blur\"\/&gt;\r\n      &lt;feMerge&gt;\r\n        &lt;feMergeNode in=\"final_blur\"\/&gt;\r\n        &lt;feMergeNode in=\"SourceGraphic\"\/&gt;\r\n      &lt;\/feMerge&gt;\r\n    &lt;\/filter&gt;<\/span>\r\n    &lt;path id=\"headerPath\"\r\n          fill=\"none\" stroke=\"white\" stroke-width=\"1\"\r\n          d=\"M 27, 143 C 190, 111, 378, 122, 508, 148\" &gt;\r\n    &lt;\/path&gt;\r\n    \r\n    &lt;path id=\"leftGlassPath\"\r\n          fill=\"none\" stroke=\"white\" stroke-width=\"1\"\r\n          d=\"M 5, 182 \r\n              C 201, 479, 233, 478, 232, 529 \r\n              L 232, 732\" &gt;\r\n    &lt;\/path&gt;\r\n    \r\n    &lt;path id=\"rightGlassPath\"\r\n          fill=\"none\" stroke=\"white\" stroke-width=\"1\"\r\n          d=\"M 318, 735 \r\n              L 318, 530 \r\n              C 317, 478, 329, 478, 531, 183\" &gt;\r\n    &lt;\/path&gt;\r\n    \r\n    &lt;path id=\"bottomGlassPath\"\r\n          fill=\"none\" stroke=\"white\" stroke-width=\"1\"\r\n          d=\"M 153, 831 C 215, 894, 372, 878, 398, 821\" &gt;\r\n    &lt;\/path&gt;\r\n  &lt;\/defs&gt;\r\n  &lt;text id=\"headerText\"  &gt;\r\n    &lt;textPath class=\"textpath\"  xlink:href=\"#headerPath\" startOffset=\"50%\" &gt;\r\n      &lt;tspan dy=\"0.3em\"&gt;A Perfect Martini!&lt;\/tspan&gt;&lt;\/textPath&gt;\r\n  &lt;\/text&gt;\r\n  \r\n  &lt;text id=\"leftGlassText\" &gt;\r\n    &lt;textPath class=\"textpath\" xlink:href=\"#leftGlassPath\" \r\n              <span class=\"hilite\">style=\"filter:url(#drop-shadow)\"<\/span> startOffset=\"50%\" &gt;\r\n    &lt;tspan dy=\"0.3em\"&gt;\r\n      A hint of dry vermouth, two shots of gin and stirred &mdash; never, ever shaken.\r\n    &lt;\/tspan&gt;\r\n  &lt;\/textPath&gt;\r\n &lt;\/text&gt;\r\n      \r\n      \r\n  &lt;text id=\"rightGlassText\" &gt;\r\n    &lt;textPath class=\"textpath\" xlink:href=\"#rightGlassPath\" \r\n              <span class=\"hilite\">style=\"filter:url(#drop-shadow)\"<\/span> startOffset=\"50%\" &gt;\r\n    &lt;tspan dy=\"0.3em\"&gt;\r\n      Garnished with a blue cheese olive, a pickled onion, or a twist of lemon.\r\n    &lt;\/tspan&gt;\r\n  &lt;\/textPath&gt;\r\n &lt;\/text&gt;\r\n \r\n &lt;text id=\"bottomGlassText\"&gt;\r\n    &lt;textPath class=\"textpath\" xlink:href=\"#bottomGlassPath\" \r\n              <span class=\"hilite\">style=\"filter:url(#drop-shadow)\"<\/span> startOffset=\"50%\" &gt; \r\n      &lt;tspan dy=\"0.3em\"&gt;A drink of refinement and class.&lt;\/tspan&gt;\r\n    &lt;\/textPath&gt;\r\n &lt;\/text&gt;\r\n  \r\n&lt;\/svg&gt;\r\n&lt;!--&lt;![endif]--&gt;\r\n\r\n&lt;!--[if lt IE 9 ]&gt;\r\n  &lt;?import namespace=\"v\" urn=\"urn:schemas-microsoft-com:vml\" \r\n              implementation=\"#default#VML\" declareNamespace \/&gt;  \r\n    &lt;v:group id=\"myShape\" class=\"vml\" &gt;\r\n      \r\n      &lt;v:shape id=\"headerPath\"  \r\n          allowoverlap=\"true\" \r\n          coordsize=\"597,960\" \r\n          filled=\"t\" fillcolor=\"white\" stroked=\"f\"  \r\n          path=\"M 27, 143 C 190, 111, 378, 122, 508, 148\"&gt;\r\n             \r\n             \r\n             \r\n        &lt;v:path textpathok=\"t\" \/&gt;\r\n        &lt;v:textpath id=\"headerText\" on=\"t\" string=\"A Perfect Martini!\" \/&gt;\r\n      \r\n        \r\n      &lt;\/v:shape&gt;\r\n      \r\n      &lt;v:shape id=\"leftGlassPath\"  \r\n          allowoverlap=\"true\" \r\n          coordsize=\"597,960\" \r\n          filled=\"t\"  stroked=\"f\"  \r\n          path=\"M 5, 182 \r\n              C 201, 479, 233, 478, 232, 529 \r\n              L 232, 732\"&gt;\r\n        &lt;v:path textpathok=\"t\"  \/&gt;\r\n        \r\n        &lt;v:textpath id=\"leftGlassText\" on=\"t\" \r\n              string=\"A hint of dry vermouth, two shots of gin and stirred &mdash; never, ever shaken.\" \/&gt;\r\n        <span class=\"hilite2\">&lt;v:shadow id=\"shadow2\" on=\"True\" color=\"#000000\"\r\n              offset=\"2px,-2px\" obscured=\"True\" opacity=\"50%\"\/&gt;<\/span> \r\n      &lt;\/v:shape&gt;\r\n      \r\n      &lt;v:shape id=\"rightGlassPath\"  \r\n          allowoverlap=\"true\" \r\n          coordsize=\"597,960\" \r\n          filled=\"t\"  stroked=\"f\"  \r\n          path=\"M 318, 735 \r\n              L 318, 530 \r\n              C 317, 478, 329, 478, 531, 183\r\n            \"&gt;\r\n        &lt;v:path textpathok=\"t\"  \/&gt;\r\n        \r\n        &lt;v:textpath id=\"rightGlassText\" on=\"t\" \r\n              string=\"Garnished with a blue cheese olive, a pickled onion, or a twist of lemon.\"   \/&gt;\r\n        <span class=\"hilite2\">&lt;v:shadow id=\"shadow2\" on=\"True\" color=\"#000000\"   \r\n              offset=\"2px,-2px\" obscured=\"True\" opacity=\"50%\"\/&gt;<\/span> \r\n      &lt;\/v:shape&gt;\r\n      \r\n      &lt;v:shape id=\"bottomGlassPath\"  \r\n          allowoverlap=\"true\" \r\n          coordsize=\"597,960\" \r\n          filled=\"t\"  stroked=\"f\"  \r\n          path=\"M 153, 831 C 215, 894, 372, 878, 398, 821\"&gt;\r\n\r\n        &lt;v:path textpathok=\"t\"  \/&gt;\r\n        \r\n        &lt;v:textpath id=\"bottomGlassText\" on=\"t\" string=\"A drink of refinement and class.\"   \/&gt;\r\n       <span class=\"hilite2\">&lt;v:shadow id=\"shadow3\" on=\"True\" color=\"#000000\"\r\n              offset=\"2px,2px\" obscured=\"True\" opacity=\"50%\"\/&gt;<\/span> \r\n      &lt;\/v:shape&gt;\r\n      \r\n    &lt;\/v:group&gt;\r\n  \r\n&lt;![endif]--&gt;\r\n<\/pre>\n<\/blockquote>\n<p>Before we get into the animation code, let's look at the markup that produces the shadow behind the text.  Unfortunately, text-shadowing in most browsers is not as straight-forward as using the <code>text-shadow<\/code> CSS property.  While it works in Chrome and Safari, it doesn't in Firefox, Opera or IE.  The closest cross-browser solution for SVG is to <span class=\"hilite\">use an SVG Filter<\/span> (SVG filters are a whole topic itself &mdash; a great place to start to learn is thge <a rel=\"nofollow\" class=\"external text\" href=\"http:\/\/www.w3.org\/Graphics\/SVG\/IG\/resources\/svgprimer.html#filters\">W3C SVG primer on Filters<\/a>).  Firefox, Chrome, and Safari support SVG filters.  <span class=\"hilite2\">IE uses the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb229490%28v=vs.85%29.aspx\"><code>shadow<\/code> tag<\/a><\/span>.  <strong>Unforunately, there is no drop-shadowing supported in Opera.<\/strong>  You will also note that these text-shadows are not consistant (the SVG filter I included is a blurred one, while the IE one is not).  There are several challenges like this when dealing with some of the fancier styling you may want to do with SVG and VML text.<\/p>\n<p>As for the animation, each of the VML\/SVG nodes that have a path in it also has a <code>data-end-d<\/code> attribute to it.  The <code>data-end-d<\/code> does not do anything nativelty in VML or SVG &mdash; I use JavaScript to tween the animation of the curve to the value in this attribute.  I have posted this code (as well as all the code in this article) in GitHub, so invite you to <a href=\"https:\/\/github.com\/zoltan-dulac\/svg-vml-textpaths\/blob\/master\/js\/example3-animation.js\">walk through the code yourself<\/a> to see how this works (I hope the comments are self-explanatory).  One thing to note: when tweening SVG paths in JavaScript, you must set the textpath's xlink:href attribute in the <code>text-path<\/code> to the same path in order to force a repaint in older WebKit browsers (I was wondering why the iPad I was using wouldn't tween the martini example until I found <a href=\"https:\/\/gist.github.com\/mbostock\/3151228\">Mike Bostock's workaround for this issue<\/a>).<\/p>\n<p>If you view the martini example in IE &lt;= 8, you'll see that <strong>VML cannot embed fonts using <code>@font-face<\/code>.<\/strong>  If this is a show-stopper for you, then you are out of luck.  However, you can degrade gracefully to a system font if it's not, and I believe that neat animation effect may outweigh the lack of <code>@font-face<\/code> support in general coolness. :-)<\/p>\n<table class=\"dataTable\">\n<thead>\n<tr>\n<th>Internet Explorer <= 8<\/th>\n<th>Firefox 21 (other browsers, including IE 9+, look similar)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/martini-screenshot-ie.jpg\"  \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/martini-screenshot.jpg\"  \/><\/td>\n<\/tbody>\n<\/table>\n<\/ul>\n<p><a class=\"exampleLink\" href=\"\/tests\/textpath\/example3-svg-vml-animation.html\">See the above example in action.<\/a><\/p>\n<h2>In Conclusion.<\/h2>\n<p>As I mentioned throughout this article, there are a few gotchas that you have to keep in mind when doing cross-browser textpaths:<\/p>\n<ol>\n<li>You can use CSS to style a few things (e.g. font-families, -weights and -sizes). Other things you can style in CSS in SVG only and with VML node attributes (e.g. fill and stroke colors and widths).  Still other things require SVG filters and additional VML tags (e.g. text-shadows).<\/li>\n<li>Both SVG and VML have their own unique CSS properties (and some of the SVG ones are not supported by all browsers).<\/li>\n<li>VML doesn't support <code>@font-face<\/code> (<a href=\"http:\/\/www.khaaan.com\/\">KHHHHAAAAAANNNN!!!!<\/a>).<\/li>\n<li>jQuery cannot do cross-browser searches for SVG nodes by tag-name, but you can search for nodes via classes and ids.<\/li>\n<li>When tweening SVG paths in JavaScript, you must set the textpath's xlink:href attribute in the <code>text-path<\/code> to the same path in order to force a repaint in older WebKit browsers.<\/li>\n<li>Older-IE can rotate VML objects a lot more easily than HTML objects.<\/li>\n<\/ol>\n<p>Despite the challenges, I believe this opens up a lot of typographic possibilities on the web.  There is admittedly quite a little bit of work to set up right the first time you do it, but I've found it's easy to do once you have the basic template down and know the gotchas listed in this article.  Feel free to download all the code in this article and play.  It'll be another interesting trick in your web development toolkit to show-off with.<\/p>\n<p><a href=\"https:\/\/github.com\/zoltan-dulac\/svg-vml-textpaths\" class=\"exampleLink\">Download all the examples from GitHub.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2013\/05\/c-is-for-cookie.jpg\" alt=\"c-is-for-cookie\" width=\"250\" height=\"180\" class=\"alignnone size-full wp-image-6178\" \/> Designers have been using textpaths for years in print, but doing this on the web is a little tricky. SVG, which supports textpaths in modern browsers, is not supported by IE <= 8. Older IE does, however, support VML, another vector markup format that can do textpaths as well. After playing around, I found it is possible to put both on a web page and even code common CSS to style them \u2014 all without JavaScript. I\u2019ll explain how we can layout and style textpaths in all browsers (including IE <= 8) as well as what a B\u00e9zier Curve is, and a bit of a code that will show how to push text on a path as well tween a textpath.\n<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-6053","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/6053","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=6053"}],"version-history":[{"count":137,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/6053\/revisions"}],"predecessor-version":[{"id":6531,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/6053\/revisions\/6531"}],"wp:attachment":[{"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=6053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=6053"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=6053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}