Animation effects compatible with iOS devices are professionally crafted using CSS

I just implemented a custom hamburger menu with animation using HTML, CSS, and JavaScript on my website. The animation works perfectly on Android devices but not on iOS. Any suggestions for fixing this issue?

I attempted to add the Webkit prefix to each part of the CSS, but it didn't resolve the problem.

Code Snippet

var state = 0;
var icona = document.getElementById("icon");
var path = document.getElementById("mypath");

icona.addEventListener("click", function(event) {
  event.preventDefault();

  if (state == 0) {
    path.classList.remove('shape2');
    path.classList.add('shape1');
    state = 1;
    console.log("shape1");
  } else {
    path.classList.remove('shape1');
    path.classList.add('shape2');
    state = 0;
    console.log("shape2");
  }
});


icona.addEventListener("touchstart", function(event) {
  event.preventDefault();

  if (state == 0) {
    path.classList.remove('shape2');
    path.classList.add('shape1');
    state = 1;
    console.log("shape1");
  } else {
    path.classList.remove('shape1');
    path.classList.add('shape2');
    state = 0;
    console.log("shape2");
  }
});
body {
  background-color: black;
  font-family: sans-serif;
}

.shape1 {
  -webkit-animation: webkit-apertura 800ms ease-in-out forwards;
  animation: apertura 800ms ease-in-out forwards;
}

.shape2 {
  -webkit-animation: webkit-chiusura 800ms ease-in-out forwards;
  animation: chiusura 800ms ease-in-out forwards;
}

@-webkit-keyframes webkit-apertura {
  0% {
    d: path("M 1 1 L 16 1 M 16 1 L 31 1 M 1 11 L 16 11 M 16 11 L 31 11 M 1 21 L 16 21 M 16 21 L 31 21");
  }
  50% {
    d: path("M 1 11 L 16 1 M 16 1 L 31 11 M 1 11 L 16 11 M 16 11 L 31 11 M 1 11 L 16 21 M 16 21 L 31 11");
  }
  100% {
    d: path("M 16 11 L 6 1 M 26 1 L 16 11 M 16 11 L 16 11 M 16 11 L 16 11 M 16 11 L 6 21 M 26 21 L 16 11");
  }
}

@keyframes apertura {
  0% {
    d: path("M 1 1 L 16 1 M 16 1 L 31 1 M 1 11 L 16 11 M 16 11 L 31 11 M 1 21 L 16 21 M 16 21 L 31 21");
  }
  50% {
    d: path("M 1 11 L 16 1 M 16 1 L 31 11 M 1 11 L 16 11 M 16 11 L 31 11 M 1 11 L 16 21 M 16 21 L 31 11");
  }
  100% {
    d: path("M 16 11 L 6 1 M 26 1 L 16 11 M 16 11 L 16 11 M 16 11 L 16 11 M 16 11 L 6 21 M 26 21 L 16 11");
  }
}

@keyframes chiusura {
  0% {
    d: path("M 16 11 L 6 1 M 26 1 L 16 11 M 16 11 L 16 11 M 16 11 L 16 11 M 16 11 L 6 21 M 26 21 L 16 11");
  }
  50% {
    d: path("M 1 11 L 16 1 M 16 1 L 31 11 M 1 11 L 16 11 M 16 11 L 31 11 M 1 11 L 16 21 M 16 21 L 31 11");
  }
  100% {
    d: path("M 1 1 L 16 1 M 16 1 L 31 1 M 1 11 L 16 11 M 16 11 L 31 11 M 1 21 L 16 21 M 16 21 L 31 21");
  }
}

@-webkit-keyframes webkit-chiusura {
  0% {
    d: path("M 16 11 L 6 1 M 26 1 L 16 11 M 16 11 L 16 11 M 16 11 L 16 11 M 16 11 L 6 21 M 26 21 L 16 11");
  }
  50% {
    d: path("M 1 11 L 16 1 M 16 1 L 31 11 M 1 11 L 16 11 M 16 11 L 31 11 M 1 11 L 16 21 M 16 21 L 31 11");
  }
  100% {
    d: path("M 1 1 L 16 1 M 16 1 L 31 1 M 1 11 L 16 11 M 16 11 L 31 11 M 1 21 L 16 21 M 16 21 L 31 21");
  }
}
<div style="color:white">touch or click to animate</div>

<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 20" id="icon">
    <path id="mypath" d="M 1 1 L 16 1 M 16 1 L 31 1 M 1 11 L 16 11 M 16 11 L 31 11 M 1 21 L 16 21 M 16 21 L 31 21" fill="none" stroke="white" stroke-width="1" />
</svg>

Answer №1

In the observation by A Haworth, it is noted that safari still lacks support for the svg <path> related d property.

One way to overcome this limitation is by combining svg SMIL animation with a simple javascript function to initiate and reverse the path animation:

initNavToogle(navicon);

function initNavToogle(navicon) {
  let aniNav = navicon.getElementById("aniNav");
  
  // extract path data values
  let valueArr = aniNav
    .getAttribute("values")
    .split(";")
    .map((val) => {
      return val.trim();
    });

  navicon.addEventListener("click", (e) => {
    //toggle state
   navicon.classList.toggle("active");

    // start animation
    aniNav.beginElement();
  });
  
    //reverse path data values
    aniNav.addEventListener("endEvent", (e) => {
      aniNav.setAttribute("values", valueArr.reverse().join(";"));
    });
}
body {
  background: #000;
}

svg{
  border: 1px solid #ccc;
  padding:10px;
  width:15vmin;
}
<svg id="navicon" class="navicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 22" stroke-width="2" stroke="#fff" fill="none" style="cursor: pointer">
  <path id="navicon_path" d="m1 1 15 0m0 0 15 0m-30 10 15 0m0 0 15 0m-30 10 15 0m0 0 15 0"  />
  <animate href="#navicon_path"
           id="aniNav"
           dur="0.8s" 
           attributeName="d" 
           values="m1 1 15 0m0 0 15 0m-30 10 15 0m0 0 15 0m-30 10 15 0m0 0 15 0;
                   m1 11 15-10m0 0 15 10m-30 0 15 0m0 0 15 0m-30 0 15 10m0 0 15-10;
                   m16 11-10-10m20 0-10 10m0 0 0 0m0 0 0 0m0 0-10 10m20 0-10-10" 
           fill="freeze" 
           keyTimes="0;0.25;1"
           calcMode="spline"
               keySplines="0.42 0 0.58 1;
                       0.42 0 0.58 1"
           begin="indefinite"
           />
</svg>

Define the different animation states in the values attribute by listing all d path data strings separated by a semicolon:

values="m1 1 15 0m0 0 15 0m-30 10 15 0m0 0 15 0m-30 10 15 0m0 0 15 0;
m1 11 15-10m0 0 15 10m-30 0 15 0m0 0 15 0m-30 0 15 10m0 0 15-10;
m16 11-10-10m20 0-10 10m0 0 0 0m0 0 0 0m0 0-10 10m20 0-10-10" 

Using begin="indefinite" ensures that the animation does not start automatically but only on click.

While SMIL does not support easing functions, a similar effect can be achieved by adjusting keyTimes and keySplines. Check out "How do you add easing to an SVG SMIL animation?" for more information.

Clicking the navicon triggers the animation using the animationElement.beginElement() method.

On reaching the end of the animation, the path data array is reversed:

aniNav.addEventListener("endEvent", (e) => {
   aniNav.setAttribute("values", valueArr.reverse().join(";"));
});

Additional Resources

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Should I convert to an image or utilize the canvas?

I'm debating whether it's more efficient to convert a canvas drawing into an image before inserting it into the DOM, or if it's better to simply add the canvas itself. My method involves utilizing canvas to generate the image. ...

A guide to resizing images in Node.js prior to using the writeFile function

var file_path = files.file.path; fs.readFile(file_path, function (err, data) { fs.writeFile(file_path, data, function (err) { res.end(JSON.stringify({ message: 'file uploaded successfully', success: true }); }); }); I exp ...

Dealing with performance issues in VueJS and Vuetify's data-table component, especially when trying to implement

In my VueJS and Vuetify project, I encountered an issue. I am trying to create a table with expandable rows for displaying orders and their associated products. The table needs to show at least 100 rows of orders on one page. To achieve this, I utilized th ...

Adjust the position of an image in both the x and y axes based on the mouse hover location using jQuery

I am attempting to develop a unique interactive experience where an image placed within a container extends beyond its boundaries. The concept involves moving the image in the opposite direction of my mouse as I hover over the container. The speed and inte ...

A dynamic input field will appear on the page following the closing </form> tag

I encountered an unusual situation where upon clicking a button with the id #fusk, dynamic elements are added. Here is the code snippet: $('#imgc').append( "<div class='divi'>" + "<input type='hidden' name=' ...

AngularJS: How do I stop the $interval from running indefinitely?

After spending hours reading the documentation, it's now 3am and I'm at my wit's end. Below is my controller code: controller('makeDashCtrl', function ($scope, $rootScope, $cookies, $location, $http, $interval) { var userId ...

Activate the div when hovering over the span

Experiencing an issue with triggering a visible div while hovering over a span. Here is the code structure: <ul class="products"> <li> <a href="somelink"> <img src="some image"> <div class="overlay"> Some Text</div> & ...

Utilizing Emotion CSS to incorporate images into buttons

I'm trying to add some style to two buttons, Up and Down, by using emotion CSS but I'm having trouble. Currently, I typically style my elements within a function. Is there a way for me to accomplish this with emotion CSS? I checked out but still ...

"Utilizing a JavaScript array to track the start of the week and

I am encountering a logic problem with determining the start of the week. Below is a snippet of the code: WeekStarts(WeekN) { let WeekBD = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Sa ...

Customizing Bootstrap Navigation: Creating Space Between Menu Items

I've configured my Bootstrap navigation with a dropdown toggle for "Coverage". I'm looking to decrease the spacing between each list item (li) under this dropdown. What CSS setting should I use to achieve this? Interestingly, when I apply float: ...

Guide to assigning an integer value to a string in Angular

Is there a way to change integer values in a table to actual names and display them on a webpage by setting a scope in the controller and passing that string to the HTML? For example, this is an example of the HTML code for the table row: <thead> ...

Encountering an issue when trying to run npm run dev-server on Windows 10

Having trouble running the dev-server for superset-frontend. Encountering this error message. Any assistance would be greatly valued.https://i.stack.imgur.com/zsVU4.png ...

How can TypeScript rules be incorporated into a Next.js project without compromising next/core-web-vitals?

In my current NextJS project which is in typescript, I have the following configuration in my .eslintrc.json: { "extends": "next/core-web-vitals" } Now, I want to include additional typescript rules, such as enforcing the rule of n ...

Glitches of white light during loading screens on your Prestashop website

There's a strange occurrence on the website where it flashes white DURING (not just at the start) every time a page loads. Initially, the page seems to load smoothly and almost completely, but then there is a sudden flash before all elements are disp ...

Template Function Problem Detected in AngularJS Formatting

I'm struggling to incorporate my scope attributes into a template function within my custom directive. The formatting for the return section in my template is not working as expected. This is how it currently looks: angular .module(' ...

Transferring the dirty state of the view to the parent form

Within my main form's markup, there is a specific structure that includes a tabset and a selectView method in the controller: <tabset vertical="true" type="pills"> <tab ng-repeat="tab in tabsViews" sele ...

Skipping every third index in a JQuery .each loop after removing an element

I have a project where I need to display elements in rows of 4, and when an element is deleted, I want the remaining elements to shift up. To achieve this, I am currently assigning a class "last" to every fourth item after a deletion and inserting a spacer ...

Is Next.js Dynamic Routing Failing You?

Recently, I attempted to implement Dynamic routing for a recipe app but encountered an issue where the page was not found. This problem has left me puzzled as I am fairly inexperienced with TypeScript, although not with React. // pages/recipes/[recipeId].t ...

Setting the height of the text area in a three-column layout cannot be achieved using a percentage value

I'm working on creating a 3-column layout with two text areas. The issue I'm facing is that when I adjust the width of the text areas to create columns, the height shrinks. I need a solution that will be compatible with HTML5 browsers - support f ...

Having difficulty accessing the 'makeCurrent' property of an undefined object in Angular mobile application

I have followed the steps outlined in the Angular mobile toolkit guide found at https://github.com/angular/mobile-toolkit/blob/master/guides/cli-setup.md My Node version is v4.4.3 NPM version is 2.15.1 The issue arises when I run the command $ ng serve, ...