{"id":3830,"date":"2018-07-28T17:50:03","date_gmt":"2018-07-28T17:50:03","guid":{"rendered":"http:\/\/freshinbox.com\/blog\/?p=3830"},"modified":"2018-08-02T21:22:33","modified_gmt":"2018-08-02T21:22:33","slug":"how-to-fix-jittery-css-animations-in-ios-mail","status":"publish","type":"post","link":"https:\/\/freshinbox.com\/blog\/how-to-fix-jittery-css-animations-in-ios-mail\/","title":{"rendered":"How to Fix Jittery CSS Animations in iOS Mail"},"content":{"rendered":"<p>Here is a technique that solves a common kind of animation jitteriness in iOS Mail. Under certain conditions, quick, single iteration (non-repeating) CSS animations in iOS tend to skip &#8211; causing movements to look glitchy and jarring.<\/p>\n<p>I&#8217;m not exactly sure why it occurs, and it only occurs occasionally, so its hard to pin down. I&#8217;m speculating that this occurs when the operating system is under high CPU or memory load (ie. too many background apps running).<\/p>\n<p><H4>Example<\/H4><\/p>\n<p>The following is an example where an element moves from the top to the bottom of a container within one second.<\/p>\n<pre class=\"lang:default decode:true \" >.text{\r\n  animation: slide 1s linear forwards;\r\n}\r\n@keyframes slide{\r\n  0%{ transform:translateY(0); }\r\n  100%{ transform:translateY(350px); }\r\n}<\/pre>\n<p><i>(This example repeats for illustration purposes)<\/i><\/p>\n<style>\n.animcontainer{\n  max-width:300px;\n  height:450px;\n  font-size:25px;\n  font-weight:bold;\n  font-family:Arial,Helvetica,sans-serif;\n  color:#ffffff;\n  background-color:blue;\n  overflow:hidden;\n  text-align: center;\n  padding:10px;\n}\n.normal,.glitch{\n  display:inline-block;\n  background-color:#3375e0;\n  padding:10px;\n  margin:10px;\n}\n.normal{\n  animation: slide 4s 2s linear infinite forwards;\n}\n.glitch{\n  animation: glitch 4s 2s linear infinite forwards;\n}\n@keyframes slide{\n  0%{\n    transform:translateY(0);\n  }\n  100%{\n    transform:translateY(250px);    \n  }\n}\n@keyframes glitch{\n  0%{\n    transform:translateY(0);\n  }\n  13%{\n    transform:translateY(150px);\n  }\n  13.1%,100%{\n    transform:translateY(350px);    \n  }\n}\n@keyframes slide{\n  0%{\n    transform:translateY(0);\n  }\n  30%,100%{\n    transform:translateY(350px);    \n  }\n}\n<\/style>\n<div class=\"animcontainer\">\n<div class=\"normal\">Anim<\/div>\n<\/div>\n<p><BR><BR><\/p>\n<p><b>Glitch<\/b><\/p>\n<p>However, occasionally in iOS Mail, the animation will execute with a glitch where it runs for a bit and jumps right to the end:<\/p>\n<p>(This example repeats for illustration purposes)<\/p>\n<div class=\"animcontainer\">\n<div class=\"glitch\">Anim<\/div>\n<\/div>\n<p><BR><BR><\/p>\n<h4>A Hacky Workaround<\/h4>\n<p>It appears the workaround is to double the duration of the animation, but make the animation complete at the 50% mark. This seems to have tricked iOS into actually running the full animation smoothly.<\/p>\n<p>In the example above the modified code will look the like following code, where the animation duration is set to 2s but the translate transform completes at the 50% mark. Then from 50% to 100% the animation does nothing.<\/p>\n<pre class=\"lang:default decode:true \" >.text{\r\n  animation: slide 2s linear forwards;\r\n}\r\n@keyframes slide{\r\n  0%{ transform:translateY(0); }\r\n  50%,100%{ transform:translateY(350px); }\r\n}<\/pre>\n<p><BR><BR><\/p>\n<p>I&#8217;ve found that you&#8217;ll need to increase the duration by more than double if the animation runs for less than a second. For example for a 0.5s animation, you might have to set the new duration to 2s (4x) and have it complete at the 25% mark.<BR><BR><\/p>\n<h4>Diagostic Test<\/h4>\n<p>The following is a diagnostic test. Both left and right text should take the same amount of time (1 second) to &#8220;drop&#8221;. However the left one is configured to run all the way to 100%. The right has double the duration (2 seconds) but completes at the 50% mark. Under normal conditions both should run parallel to each other. However when iOS glitches, the left image will jump to the bottom unexpectedly. Feel free to send a test to see the effects for yourself.<\/p>\n<p>The best way to see the glitch is to try to launch a few apps (ie. Google Maps, Youtube, a few tabs on Safari) on your device before opening the email.<\/p>\n<p data-height=\"430\" data-theme-id=\"12191\" data-slug-hash=\"WKJdXd\" data-default-tab=\"result\" data-user=\"freshinbox\" data-pen-title=\"CSS Animation Jitter Test for iOS Mail\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/freshinbox\/pen\/WKJdXd\/\">CSS Animation Jitter Test for iOS Mail<\/a> by FreshInbox (<a href=\"https:\/\/codepen.io\/freshinbox\">@freshinbox<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async src=\"https:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<div id=\"email-me\">\n  <input type=email id=\"email-me-email\" placeholder=\"Email address\"> <input id=\"email-me-btn\" type=button value=\"See Example In Your Inbox\" style=\"-webkit-appearance: none;\">\n<\/div>\n<p><BR><\/p>\n<h4>Not All Animations Are Affected<\/h4>\n<p>I&#8217;ve noticed that this does not affect all animations and mostly affect those that involve translate transforms. Also if the animation repeats (ie. animation-iteration-count:infinite), then this issue doesn&#8217;t occur.<BR><BR><\/p>\n<h4>Feedback<\/h4>\n<p>Let me know what you think and whether this has helped you fix some of the glitches you&#8217;ve seen. If you have found other workarounds, let me know too!<\/p>\n<p><BR><BR><BR><\/p>\n<div style=\"color:#888888;\">Credit: <a href=\"https:\/\/www.flickr.com\/photos\/cracklow\/2507793312\/\">laura ammons<\/a> for the jitter image<\/div>\n<p><BR><BR><br \/>\n<div style=\"padding:10px; border: 2px solid #99C731;background-color:#FFF8DC;border-radius:5px;\">\n<form action=\"https:\/\/freshinbox1.createsend.com\/t\/i\/s\/adrmi\/\" method=\"post\" id=\"subForm\">\n<span class=\"fisub_header\" style=\"font-weight:bold;\">Subscribe to the #EmailGeeks Newsletter<\/span>\n<p><input id=\"fieldEmail\" name=\"cm-adrmi-adrmi\" type=\"email\" style=\"width:90%\" required placeholder=\"Your Email Address\" \/><\/p>\n<p><button type=\"submit\">Subscribe<\/button><\/p>\n<\/form>\n<\/div><\/p>\n<style>\n#email-me-email {\n  width:150px;\n  height:20px;\n  margin-bottom: 5px;\n  background-color: #FAFCEF;\n  font-size: 14px;\n  padding: 3px 5px;\n  display:inline-block;\n  border-radius:3px;\n  margin-left:20px;\n}\n#email-me-btn {\n  cursor: pointer;\n  font-size: 14px;\n  color: white;\n  text-decoration:none;\n  text-shadow:#555555 0 1px;\n  background-color: #7DC442;\n  padding: 5px 12px;\n  border:1px solid #559621;\n  border-radius: 5px;\n  display:inline-block;\n}\n#email-me-btn:hover {\n  background-color: #78D62C;\n}\n#email-me{\n  width: 400px;\n  padding:20px 0px;\n  xborder:3px solid #888888;\n  xborder-radius: 5px;\n  margin:0px auto;\n}\n<\/style>\n<p><script src=\"\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.10.2\/jquery.min.js\"><\/script><br \/>\n<script>\n  var theEmail = null;\n  $(document).ready(function(){\n    $('#email-me-btn').click(function(){\n      theEmail = $('#email-me-email').val();\n      sendEmail(theEmail);\n    });\n    $(\"#email-me-email\").keypress(function(e) {\n      if(e.which == 13) {\n        theEmail = $('#email-me-email').val();        \n        sendEmail(theEmail);\n      }\n    });\n  });\n  var sendEmail = function(emailAddr){\n    if(!emailAddr || emailAddr.length < 12){\n      alert('Please enter an email');\n      return;\n    }\n    $('#email-me-email').val('sending...');\n    $.ajax({\n      url: \"https:\/\/freshinbox.com\/examples\/jitter-test\/mail_example.php\",\n      data: {\n        email: emailAddr\n      },\n      success: function( data ) {\n        if(data == null || data.indexOf(\"ERROR\") != -1){\n          alert(\"There was a problem sending the email \\n\"+data);\n        }else{\n          alert(\"An email has been sent to \"+emailAddr+\"!\\n (Be sure to check the spam folder just in case)\");          \n        }\n        $('#email-me-email').val('');\n      }\n    });\n  }\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here is a technique that solves a common kind of animation jitteriness in iOS Mail. Under certain conditions, quick, single iteration (non-repeating) CSS animations in iOS tend to skip &#8211; causing movements to look glitchy and jarring.<BR><BR><br \/>\nA solution is to increase the duration of the animation but make the animation complete faster. Read on for the details&#8230;<\/p>\n","protected":false},"author":2,"featured_media":3820,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[23,28,24,25,47],"tags":[],"_links":{"self":[{"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/posts\/3830"}],"collection":[{"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/comments?post=3830"}],"version-history":[{"count":20,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/posts\/3830\/revisions"}],"predecessor-version":[{"id":3864,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/posts\/3830\/revisions\/3864"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/media\/3820"}],"wp:attachment":[{"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/media?parent=3830"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/categories?post=3830"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/freshinbox.com\/blog\/wp-json\/wp\/v2\/tags?post=3830"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}