How to make the "cursor:" defined cursor-image renders as expected in browser on a retina screen?

380 views Asked by At

Try to copy this CSS definition in body on this page:

div{

    cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEr0lEQVRYR83YXWgcVRQH8P/Zze5km3YbMZ/7Edxq6lcrFPrSaBL6Iiai+BSKgiBCLfjgi4pNsRKrgTbgU0HUor6FKiKixlakuzO7CaVExYogjTVlJps2ia2RhthkZ+6Rmc2GzWZ3Z2a7abyvd+ac35x7z3Bn6OLPc881NAY/BuFzQ/BANFo7gf/RICWhGsFgwNPUFLRYBEwz83ED0kfRKP272VZKJqaGGeJAMBhADrmC0gkkE+NIc8Q3TkTGZmAplUrfL3TjdzN5EWTOdBPASXj874VC9NedhJKZLJnQphncaoO0XAz86mF+oyUifU9E+kZjs0BZfZkZJ3PJylQy37NIwGl4xdutrYErGwW1gPH4ZK2XvOYy1rhEZi9nTBLRwPV53/CuXbRcTawFNIciq2fBeDw/uMNK5t+iM3DGy+hvjvh/IyJxu9hV4Jic3qOz8VNhwAqQuRB/Axhayvjfj8VovlLoKpCZPUlZuw6gvopIawMwcIEhDofDtbLbqq4CrWVWtKMQPFDsaW+jkvnhbgJ0yqdnhhrvqbvqpKprgPH4ZL2XvObSFB1VQmbbCrhEwJstYf+X5V5Xa4DZZtHGwLzvDiBzKZZA+KJG8FuNEekyEZn41bEOmEpMdwroSrnyV7GSBWloBiwGfbXSJ42NZL72zLPB2rHSLDcAbN8cpJWVGRQXrD+/DmjOphTthBD8mt0m3rhK5jLzXFHgeHy6YZH02WIVrvIryKYG9ENRoHlXUtYuMvNuuyqa89WvJM0w8SuhkP+zksBUSusROo84AVYR+aeAOBgO157LdXNJ4EqzLAAIbDiSMA6iQ6GQ/8fCXCWBK8v8ATMfdAp0W0kGnRMsDpX7DioLTKXUkNAx5aRZ8h/CwZ68UZPJPNwU23rN7uHLAq0qKuofLHCvXSDX3c34KhSVnrGLawscVdQDhsCwXaBi83aVZOCbcER6qlxsW2Cx07YbrB2SgK9bI9LTpWLaArPNop5mRp8bmKs9WWa5HQHPy1r7MvOlSoGOursE0hHQTKAkVBVAdEORwEgoIj2Zn8MxMCWnXxRsnLodoKNKEs6EwlJPLo9j4MTEhHQ1LZlnNJ8D5D/ljmt2jQPgu1BE6jXzOAZayyxr34LZurHc8Po8ezjDzwqUPrLZIb3L/pbmHTTjCnhe0R5ZFvxL2fcW0WRnd3SHeU0qoZ2oEHm5NezfaX4BugIyMyVlzTwnNpRC1njwREdX29ncfFLRjrPg10tdv66SjMkl3f9QLEa3XC+xVRVZfVUwhkoknOvsjjYXfvikFPVdIdBviyzAVQSMx2e3eumW2QSewoReD154tKvt02KQpDz1DrM4Uhq55cr2u+5+MFc5112cHzgpawozdxYkW7g2G63v6yv9ozOlqINC4HAhkgBNZ2Pn/v0xa1nzh6s9mLtxdHRqn5ERY/mBPB4cfayr7ZhdhyuKOog8JBPSPh+1d3REi/5urgiYPW2r8wBtWwFlFhaXtvX2ti/ZAc35UXnqmMGiH4T0lrqaB/buDS2Wuq8ioNUseRufiD7s7I6+5ASXu2ZkZELq6blvubChqrLEZpCxMS1gZGD+rvMH6ry7y1XBDbzw2v8AzYPIODUE9pYAAAAASUVORK5CYII="), auto !important;
    height:200px;
    width:200px;
}
<div>hover</div>

The customized cursor works but it's not rendered as a retina image. It's rendered as a blurry, 100% bigger-sized image.

Is there any way to force it to display as a retina image? (I tried both Chrome and Safari)

2

There are 2 answers

0
awholegnuworld On

Here is some CSS. I just converted your PNG to a SVG and resized it. Feel free to decode this and resize the SVG in the XML.

div{

    cursor: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjE2cHgiIGhlaWdodD0iMTZweCIgdmlld0JveD0iMCAwIDMyIDMyIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAzMiAzMiIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+ICA8aW1hZ2UgaWQ9ImltYWdlMCIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiB4PSIwIiB5PSIwIg0KICAgIGhyZWY9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQ0FBQUFBZ0NBTUFBQUJFcElyR0FBQUFCR2RCVFVFQUFMR1BDL3hoQlFBQUFDQmpTRkpODQpBQUI2SmdBQWdJUUFBUG9BQUFDQTZBQUFkVEFBQU9wZ0FBQTZtQUFBRjNDY3VsRThBQUFDaTFCTVZFVkhjRXpTeit6bDVQam01UG5tDQo0dmpqM2ZibTQvbkJ2dUhsNC9qbTVQbm80L3JtNC9uQ3dPTFF6K3ZtNVBubTVQbm01UG5tNVBuazVQcm01UG5uNVBuRHdPUEF2dUhSDQp6K3ZtNVBubTQvam00L2puNVBubjVQamw0L3JGeE9IQ3dPTEF2dUhtNVBubDQvam01UGpsNC9qbTR2ckN3T0xDd09MQXZ1SG00L2psDQo1UGptNC9ubDQvbmw0L2pGd3VUQ3YrTEN3T0xsNC9ubTVQamw0L25sNVByazQvakR3ZUhEd09MbTQvam00L25tNC9ubTVQakJ3ZUxCDQp2K0xsNVBubTQvbm00L2ptNC9uQnYrSEJ3T0xCditIbDQvbmw0L2ptNVBqbTVQbm01UGp3NHZiQ3dPUEN3T0xtNC9qbTVQbmw0L25tDQo1Zm5rNWYzQ3dPTER3ZVBCditIbTQvbm00L2ptNVBubDQvYmwwdkxDd09MbDVQam01UGptNVBqQ3dlTER3T0xCditMbDQvbmw1UG5tDQo1UHZFdytQQ3dlTEN3T0xtNVBubDQvaS92dUxDd09MbDQvbmw0L25sNVBqbTUvckR3ZVBDditMQ3YrTG00L2psNC9uaDQvcm00L2puDQo0UGZEd2VIbDQvbkN3T0hDd09IbTQvbm00dmpDd09MbDQvbm00dm5DditMbDQvbm01UG5KdytmQ3dPTEN3T0xCd09MQnYrTEN3T0xDDQp3T0xtNHZyRHdlTEV3dVBDd09MQnYrSEN3ZUxDditMQndPTEN3T0xDd09MRnd1UEN3T0xsNC9uRHdPTEN3T0hDditMRncrTEN3T0xtDQo0L25Ed2ViUHpldlN6K3pEd2VQQ3dPTEZ4T0xDd2VMQ3dPSER3ZUhEdnVQQndPSEV3dVBZMXZUNitQL3E2UDdRenZQeThQL3Q2Ly9GDQp3K2JwNS8zcjZmL3U3UC9NeWUzUnordm01UG4xOC8vSXh1bmw0L2p6OGYvQXZ1SEd4T2ZvNXZ2czZ2L281L3pKeCt2Q3dPTHY3Zi80DQo5Zi9Ed2VQUXp2TEV3dVhzNmYvdzdmL096UEQwOGYvTXl1N0J2K0hMeWUzdjdQL3I2ZjdOeSsvSHhlalQwZmJMeWV6THlPekt5T3ZLDQp5T3pGdytYTHl1Ny8vLytxN0R0eUFBQUFxWFJTVGxNQTIrYVRYd1lCNk11VUpRT1U5UDN4eWxFU0JRSmYvZjc4OG9JOUNRSUV5L3YrDQovclYwSXBMOS92cjczS3hLSWZEKytPQjdIQVFCeHY3OCsweE0vZjdTaFVNUTYvNysvUG04Y1FoNSt2bnJwekVMQXpuOC92MzdVUUtyDQovdjMxQlczNy9JZ25GdFg4N1k0Rm8vM1dpUkEzOVA3VWFSamRHMlBvK3Y3a0wvdmlMa0xqTUE2N2QvNysydGNYQWluaCtuM1IvTEhqDQpMTXh2VVBrSkhzcHhISEVEZmJNZGN6R21EQjg4WVZIVVRBQUFBQUZpUzBkRTJBQU5SNjRBQUFBSmNFaFpjd0FBQ3hJQUFBc1NBZExkDQpmdndBQUFBSGRFbE5SUWZsQlFZT0NqbklvcjIxQUFBQ2hVbEVRVlE0eTNXVGlWdE1VUmpHUDltTGthMlphSEV1bWluSlFVMkZ4amIyDQprR21VWFZGRDJjcWVKSVRRUW5heWxiMnBHWk5PaTJsMDJpeUpyaEwvam5ObnVYTmJuUHM4OXpuM2VYL1ArZDczKzg2RklSNURodzBIDQpHQUgvV3lQZlZSaEhqZllVdGw2RFVtTXF4OHFxVE9POHgwOWdIeE1uRFFRbW0zM2tDdGw3UzdYdmxLbCtEUEh2RHdRRWZwaFdneEFuDQpJN1hWMDJmTUhLUkdVSjFTVlVOUVBRb09hYWlkRlRyYjdrWjZUdGdjTS83SUNJNXd3U0dtaHJuejVvZEhzRkplTGwwTmtWWXNFS1FlDQprYWpvQlkwVzI2ZlFoZUVBRVNLeXFDbUdPZ21PYURpa2lXcHVXYnhrS1lqTldiYThWWXVwbldEUENnYXRYR1dyOEYyOVppMFQ3Ym5YDQp0Y1ZTTjBFSUlwcm85WTBOWk1QR3VFMU0xa0Y4dXg1cnFaUkFtelVKaWNUeStZdjNGdUdFcmR1K3h0SStCQ0hiRVVFN0ZOeTNuVXpmDQpCYnM3a2pEK0xpVTBSSk9jWURTUlBYdnRRVk5TbXd5VXVna3VpaVFITjF2MjdROTN4RWlEOUU0OWxoQ0VIUGpSY3ZEUVlhYjVPM3AxDQpKS01kWjdvSmxQRHo2TEhqa2t1aWhsUXJhNFZJY0RMamlaUGdKNTNZcVRvbHBXNmlYbUU2SFFjUkVpQWxpNTdCSW9FRUl2dHNIeUtvDQpLNGQxazJaU1ZrcmxJTTdsdWdrZG5PK0lGVnhncXRRTEJMc2ZDdHVGaStBbHVzeTcxSmxqMTgyODNqbVhSSnRIbkJna0RTNVhabDNKDQoxeXI1cTlmcTlNTDBoU3EyN091dUdnVlFXTVFiS0M3K2RTUHZabmNKcFNvNVltbXJQRVdUYVhDckswZHI0Ry9mZ2JDN1BVbUNENW1zDQorWjQ3UlFIY2Y5Q0tTMzZudzBONFZOcGJqS21QM1BSWTJpbzFGUEhLUHhtRm9OYkJrOUxlSkJ6VDh4U2U5Ym4vejNrRFg4WkFGcm84DQpzTnZ3OTBVL0hjcXQrVTB2blcwcGoyd2JvRVBBcTY2eUFKZWoxMjhHL0dFRkVOLzZscjJkamx6ckgxUzROZ1VZUHRrSkFBQUFKWFJGDQpXSFJrWVhSbE9tTnlaV0YwWlFBeU1ESXhMVEExTFRBMlZERTBPakV3T2pVM0t6QXdPakF3WjlDQ3BnQUFBQ1YwUlZoMFpHRjBaVHB0DQpiMlJwWm5rQU1qQXlNUzB3TlMwd05sUXhORG94TURvMU55c3dNRG93TUJhTk9ob0FBQUFBU1VWT1JLNUNZSUk9IiAvPg0KPC9zdmc+DQo="), auto;
    height:200px;
    width:200px;
}
0
Brandon McConnell On

Yes, this is fully possible using SVG, which displays in crisp definition on screens of any pixel density, standard (@1x), retina (@2x), and even 4k and 8k displays (@3x, @4x+).

You also don't have to use Base64, and it may be easier without relying on Base64. Here is an example without Base^4, where I simply pull the cursor SVG image in via URL. I also have a dynamic Base64 example below this first example, so scroll down for that.

div {
  cursor: url('https://assets.codepen.io/1580009/stackoverflow-67356313-cursor.svg'), auto;
  height: 200px;
  width: 200px;
}
<div>hover</div>

If you would prefer to Base64 encode your SVG, that will work too, though it's not always performant (Probably Don't Base64 SVG). Below is an example which uses Base64 dynamically. For the sake of this example, I've added the SVG itself into the body of the HTML, along with a field that you can use to control the size of the cursor. As you adjust the input field's cursor size, the Base64 string will automatically recompute the new Base64 string for the updated cusror size and rewrite that style on the hover-div.

const input = document.querySelector('input'),
      svgCursor = document.querySelector('svg#cursor'),
      hoverDiv = document.querySelector('div');

const setCursor = (size = 16) => {
  svgCursor.setAttribute('width', size);
  svgCursor.setAttribute('height', size);
  const base64cursor = window.btoa(new XMLSerializer().serializeToString(svgCursor));
  hoverDiv.style.setProperty('cursor', `url('data:image/svg+xml;base64,${base64cursor}'), auto`);
};
setCursor();

input.addEventListener('change', () => setCursor(input.value));
div {
  margin-top: 20px;
  height: 200px;
  width: 200px;
  border: 2px dashed #f00;
}
svg#cursor {
  display: none;
}
<label>Cursor size: <input value="16" type="number"></label>

<div>hover</div>

<svg version="1.1" id="cursor" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve" width="16" height="16"><polygon fill="#D0CBE7" points="0,0 13,32 17,23 25,32 32,25 23.7,17.1 32,13 "/><g><polygon fill="#EDE9FA" points="24,17 32,13 0,0 29,28 32,25"/></g></svg>