{"id":3893,"date":"2011-12-21T01:34:31","date_gmt":"2011-12-21T05:34:31","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=3893"},"modified":"2011-12-21T01:46:29","modified_gmt":"2011-12-21T05:46:29","slug":"cross-browser-css-cursor-images-in-depth","status":"publish","type":"post","link":"https:\/\/www.useragentman.com\/blog\/2011\/12\/21\/cross-browser-css-cursor-images-in-depth\/","title":{"rendered":"Cross Browser CSS <code>cursor<\/code> Images In Depth"},"content":{"rendered":"\r\n<!--\r\n        This notice is required for the CanvasPainer widget below.\r\n\r\n\tCopyright (c) 2005, 2006 Rafael Robayna\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining \r\n\ta copy of this software and associated documentation files (the \"Software\"), \r\n\tto deal in the Software without restriction, including without limitation \r\n\tthe rights to use, copy, modify, merge, publish, distribute, sublicense, \r\n\tand\/or sell copies of the Software, and to permit persons to whom the Software \r\n\tis furnished to do so, subject to the following conditions:\r\n\t\r\n\tThe above copyright notice and this permission notice shall be included\r\n\tin all copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \r\n\tEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \r\n\tOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \r\n\tIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r\n\tDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR \r\n\tOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE \r\n\tOR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n\r\n\tAdditional Contributions by: Morris Johns\r\n-->\r\n\r\n\r\n<div id=\"canvasPainter\">\r\n<div id=\"controls\">\r\n  <div class=\"ctr_btn\" id=\"btn_1\" >brush 2<\/div> \r\n  <div class=\"ctr_btn\" id=\"btn_2\" >line<\/div> \r\n  <div class=\"ctr_btn\" id=\"btn_3\" >rectangle<\/div> \r\n  <div class=\"ctr_btn\" id=\"btn_4\" >circle<\/div> \r\n  <div class=\"ctr_btn\" id=\"btn_5\" >clear<\/div> \r\n  <div class=\"ctr_btn\" id=\"btn_9\">new<\/div>\r\n  <input class=\"color\" id=\"color\" value=\"#ff3333\"><\/div>\r\n<canvas id=\"canvas\" width=\"200\" height=\"200\"><\/canvas>\r\n<canvas id=\"canvasInterface\" width=\"200\" height=\"200\"><\/canvas>\r\n<p class=\"description\"><small>Paint widget a remix of <a href=\"http:\/\/caimansys.com\/painter\/\">CanvasPainter<\/a> \u00a9 <a href=\"http:\/\/caimansys.com\/\">Rafael Robayna<\/a><\/small><\/p>\r\n<\/div>\r\n<p><strong>If you are using a desktop browser (except for Opera), play with the paint widget on the left.<\/strong>  When you select a tool and mouse over the white canvas, your mouse arrow will change to a custom cursor representing that tool (&agrave; la Photoshop or The GIMP).  This is not done by creating a DOM object and moving it to the mouse&#8217;s coordinates &mdash; we are using CSS to do it using the <code>cursor<\/code> property&#8217;s <code>url()<\/code> function. <strong> When used properly, custom CSS cursors can add a little bit of polish<\/strong> to your web sites and applications.  However, <strong>doing this in a cross browser way can be a little confusing<\/strong> unless you know all the gotchas, and this article will go into depth about them.   We will also explore issues such as <strong>when to use custom cursors, performance, what makes good cursor design, cursor file formats, and cursor size.<\/strong><\/p>\n<h2>When Should I Use Custom Cursors Instead of the Built-in Ones?<\/h2>\n<p>In general, CSS cursors (built-in or custom) should be used as a hint to the user as to what action the mouse can perform.  Let&#8217;s take a look at an example that doesn&#8217;t use custom cursors to illustrate a common use-case: drag and drop.  To give users a visual cue that an item is draggable, it is common practice to set an object&#8217;s CSS <code>cursor<\/code> property to <code>move<\/code>.  Mouse over the object draggable object below to see how this works. <\/p>\n<div id=\"container\">\n<a href=\"#\" id=\"toDrag\" draggable=\"true\">Drag me!<\/a>\n<\/div>\n<p>This is done with the following CSS:<\/p>\n<blockquote class=\"code\">\n<pre>\r\na[draggable=\"true\"] {\r\n    cursor: move;\r\n}\r\n<\/pre>\n<\/blockquote>\n<p>The code above ensure that when a user &#8220;mouses over&#8221; a link with the HTML5 Drag and Drop &#8220;draggable&#8221; attribute, the <code>move<\/code> cursor appears.  It is a great way to help the user &#8220;figure out&#8221; how to use the user interface with minimal instruction.  A list of the built-in cross-browser cursor property values can be seen at <a href=\"http:\/\/www.quirksmode.org\/css\/cursor.html\">CSS2 Cursor Style Page<\/a>.<\/p>\n<p>The built-in cursors are great, but there are a few things to keep in mind.<\/p>\n<ul>\n<li><strong>Built-in cursors may look different depending on what browser\/operating system is being used<\/strong>.  For example, some browsers (e.g. Firefox on Windows 7) will show the <code>move<\/code> cursor as a four-pointed arrow (<img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/12\/move_cursor.png\" alt=\"[Four-Pointed Arrow Cursor]\" class=\"inline\" \/>) while others (e.g. Firefox on Mac OS X) will show a hand (<img decoding=\"async\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2011\/12\/cursor-hand.png\" alt=\"[Hand Cursor]\" class=\"inline\" \/>).  Using custom cursors, you can ensure all applications are using the same cursor for a more consistent expeience.  The example below is the same as the one above, except in all browsers, you will see the a hand icon.\n<div id=\"container2\">\n<a href=\"#\" id=\"toDrag2\" draggable=\"true\">Drag me!<\/a>\n<\/div>\n<\/li>\n<li><strong>Not all browsers support all the same &#8220;built-in&#8221; cursors, and custom cursors allows you to add support for them.<\/strong> For example, <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=258960\">while Firefox on Windows doesn&#8217;t support <code>context-menu<\/code><\/a>, it seems to be the only browser that <a href=\"https:\/\/developer.mozilla.org\/en\/CSS\/-moz-zoom-in\">supports the zoom-in and -out cursors<\/a>.  Using custom cursors, you can implement all of these in all browsers.<\/li>\n<li><strong>There may not be a built-in cursor for the use-case you need to solve.<\/strong>  A good example is in the paint widget at the beginning of this article &mdash; none of those cursors exist natively in any browser.<\/li>\n<li><strong>It&#8217;s nice to design your own cursors<\/strong>, since sometimes the built-in ones may be a little basic looking (If you do this, please keep in mind that users are used to the built in ones, so your custom cursor shouldn&#8217;t look too much different than them if you want your application to be easy-to-use).\n<\/ul>\n<h2>The CSS of Custom Cursors<\/h2>\n<p>Here is some sameple CSS code that will show custom cursor when the user mouses over a <code>div<\/code> with an id of <code>dragMe<\/code>.  If the browser doesn&#8217;t do custom cursors (like Opera), the cursor fallback to the built-in <code>move<\/code> cursor.<\/p>\n<blockquote class=\"code\">\n<pre>\r\n#dragMe {\r\n    cursor: url('customMoveCursor.cur'), move;\r\n}\r\n<\/pre>\n<\/blockquote>\n<p><strong>As long as your cursor is in the same directory as your stylesheet, and as long as it is an uncompressed .CUR file, it&#8217;s as simple as that.<\/strong> Note that <a href=\"http:\/\/en.wikipedia.org\/wiki\/ICO_%28file_format%29\">a .CUR file is just an .ICO file with extra information<\/a> that allows the developer to define the &#8220;host spot&#8221; position of the cursor (i.e. the part of the image which points to the position of the mouse).  Note that <strong>.CUR files support 32-bit color<\/strong> (16.7 million colors plus alpha channel transparency), so designers can create cursors that have semitransparent areas like shadows and anti-aliasing.   <\/p>\n<p><strong>How does one create a .CUR file?<\/strong> Not too many graphic tools create .CUR files natively, but there are some easy solutions. If you are a Photoshop user, the <a href=\"http:\/\/www.telegraphics.com.au\/svn\/icoformat\/trunk\/dist\/README.html\">ICO (Windows Icon) file format plugin for Photoshop<\/a> is what you are looking for (I have not used it myself, but it apparently can save .CUR files directly.  Any comment on how well this works would be most welcome). If, like me, you use the GIMP, simply save the file as a .ICO file and convert it with <a href=\"http:\/\/www.janthor.com\/sketches\/index.php?\/archives\/10-A-Python-script-to-convert-ICO-to-CUR-files.html\">this command line tool written in Python<\/a> by <a href=\"http:\/\/www.janthor.com\">Jan Thor<\/a>. <\/p>\n<h2>The Gotchas of Custom CSS Cursors<\/h2>\n<p>There are a few things you need to remember when using CSS cursors<\/p>\n<ol>\n<li><strong>You must add a default &#8220;built-in&#8221; cursor after your custom cursor,<\/strong> or the custom cursor will not load in Firefox.  Think of it as Mozilla&#8217;s way of enforcing good web practices. :-)<\/li>\n<li><strong>Internet Explorer interprets relative URLs as <em>relative to the HTML document<\/em><\/strong>, and not the CSS file like God (and the W3C) intended (Sometimes it seems that IE goes out of its way to make lives difficult for us developers).  This is true for all versions of IE, even IE9. To ensure cross-browser compatibility, you must either use an absolute URL:<br \/>\n<blockquote class=\"code\">\n<pre>\r\n#dragMe {\r\n    cursor: url('\/cursors\/customMoveCursor.cur'), move;\r\n}\r\n<\/pre>\n<\/blockquote>\n<p>or a fallback url for IE:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n\/*\r\n * Assume this the HTML is in a directory above this CSS file\r\n *\/\r\n\r\n#dragMe {\r\n    cursor: url('..\/cursors\/customMoveCursor.cur'),     \/* Modern browsers    *\/\r\n            url('cursors\/customMoveCursor.cur'),        \/* Internet Explorer  *\/\r\n            move;                                       \/* Older browsers     *\/\r\n}\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<li><strong>It is best that your .CUR files are 32&#215;32 pixels in size.<\/strong>  IE9 seems to resize cursors that are smaller than this to 32&#215;32, and IE8 and under cannot show cursors larger than this size.  While it is true that you can fit multiple file sizes inside a .CUR file, sticking with one 32&#215;32 image will ensure cross-browser consistency.<\/li>\n<li>Although .CUR files can be saved in either a compressed or uncompressed format, <strong>not all browsers can read the compressed ones<\/strong>.  It is best to save your cursors in uncompressed format.  If you are using the GIMP to save to .ICO format first before you convert to .CUR, make sure that the .ICO is saved without compression.<\/li>\n<\/ol>\n<h2>Performance Issues<\/h2>\n<p>As mentioned earlier, a lot of browsers (like Firefox or IE6) cannot show <em><strong>compressed<\/strong><\/em> .CUR files, but they can show .PNG files.  Since we would like to use a compressed version if possible, one could do this:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n#dragMe {\r\n    cursor: url('\/cursors\/customMoveCursor.png'),      \/* Modern browsers    *\/\r\n            url('\/cursors\/customMoveCursor.cur'),      \/* Internet Explorer  *\/\r\n            move;                                      \/* Older browsers     *\/\r\n}\r\n<\/pre>\n<\/blockquote>\n<p><strong>This works well as long as the cursor hotspot is 0,0.<\/strong>  You can define a PNG hotspot using the CSS3 cursor syntax, but it breaks IE:<\/strong><\/p>\n<blockquote class=\"code\">\n<pre>\r\n#dragMe {\r\n    cursor: url('customMoveCursor.png') 5 15, \/* Modern browsers, hotspot is (5, 15)            *\/\r\n            url('customMoveCursor.cur'),      \/* IE chokes on the above line .. never gets here *\/       \r\n            move;                             \/* Older browsers (IE never gets here either)     *\/\r\n}  \r\n<\/pre>\n<\/blockquote>\n<p>In order to fix this issue, one must you conditional comments to make a separate IE from everyone else.  Let&#8217;s use a variation of <a href=\"http:\/\/paulirish.com\/2008\/conditional-stylesheets-vs-css-hacks-answer-neither\/\">Paul Irish&#8217;s Conditional Comment pattern<\/a> to do this.  Change the <code>html<\/code> tag to this:<\/p>\n<blockquote class=\"code\">\n<pre>\r\n&lt;!--[if (lte IE 9) ]&gt;&lt;html class=\"ie9 oldIE\"&gt;    &lt;![endif]--&gt;\r\n&lt;!--[if (gt IE 9)  ]&gt;&lt;html class=\"modern\"&gt;       &lt;![endif]--&gt;\r\n&lt;!--[!(IE)]&gt;&lt;!--&gt;    &lt;html class=\"notIE modern\"&gt; &lt;!--&lt;![endif]--&gt;\r\n<\/pre>\n<\/blockquote>\n<p>Now we can use this CSS to ensure .PNG loads in non-IE browsers:<\/p>\n<blockquote class=\"code\">\n<pre>\r\nhtml.modern #dragMe {\r\n  cursor: url('customMoveCursor.png') 5 15, \/* Modern browsers, hotspot is (5, 15).   *\/\r\n          move;                             \/* Older browsers                         *\/\r\n}\r\n\r\nhtml.oldIE #dragMe {\r\n  cursor: url('customMoveCursor.cur'),      \/* IE .CUR file loads                     *\/       \r\n          move;                             \/* In case IE can't load the above.       *\/\r\n}  \r\n<\/pre>\n<\/blockquote>\n<p>The extra bytes used to create the conditional comments may or may not be worth the trouble.  If you are using conditional comments (like I do all the time), it may be worth it.<\/p>\n<h2>A Final Word On Testing in IE <\/h2>\n<p>If you edit a .cur file on the web server and reload your page with that cursor in Internet Explorer, you may not see the edited change, since <strong>IE has kept the older cursor in cache and has a hard time letting go<\/strong>, kind of like <a href=\"http:\/\/www.youtube.com\/watch?v=MBHOL1PcPR8\">that person you dated in high-school<\/a>.  You will need to clear IE&#8217;s cache in order to see the new cursor.  This is quite annoying, and it is something you should keep in mind when troubleshooting in IE.<\/li>\n<\/ul>\n<h2>Further Reading<\/h2>\n<ul>\n<li><a href=\"http:\/\/beradrian.wordpress.com\/2008\/01\/08\/cross-browser-custom-css-cursors\/\">Cross-browser custom CSS cursors<\/a> by <a href=\"http:\/\/beradrian.wordpress.com\/\">Adrian Ber<\/a><\/li>\n<\/ul>\n<p><script type=\"text\/javascript\">\ndoOnLoad()\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2011\/12\/intro.png\" \/> When used properly, custom CSS cursors can add a little bit of polish to your web sites and applications.  However, doing this in a cross browser way can be a little confusing unless you know all the gotchas, and this article will go into depth about them.   We will also explore issues such as when to use custom cursors, performance, what makes good cursor design, cursor file formats, and cursor size.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,38,140,23],"tags":[142,141,53,101],"class_list":["post-3893","post","type-post","status-publish","format-standard","hentry","category-css","category-css3","category-cursor","category-images","tag-bugs","tag-custom-cursors","tag-ie","tag-internet-explorer"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=3893"}],"version-history":[{"count":111,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3893\/revisions"}],"predecessor-version":[{"id":4014,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/3893\/revisions\/4014"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=3893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=3893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=3893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}