Creating dynamic SVG animations through CSS instead of relying on the <animateMotion> tag offer greater flexibility and control

I am attempting to position an arrow at the midpoint of a bezier curve. The method outlined in this StackOverflow question, which involves using <animateMotion> to move a <path> representing the arrow and freezing it at the center of the curve, only works in Firefox. Due to the frequent changes in my curve's points, I prefer not to use marker-mid as recalculating the midpoint each time is costly for me.

<svg viewBox="0 0 500 500">
<g>
    <path id="path1" d="M291.698 268.340 C321.698 268.340, 411.904 93.133 441.904 93.133"></path>
    <path class="path_arrow" d="M0,0 L6,6 L0,12" transform="translate(-3,-6)">
        <animateMotion dur="0s" rotate="auto" fill="freeze" keyTimes="0;1" keyPoints="0.5;0.5">
            <mpath xlink:href="#path1"></mpath>
        </animateMotion>
    </path> 
</g>
<g transform="translate(166.698,243.340)">
    <circle r="5" class="p1"></circle>
</g>
<g transform="translate(441.904,68.133)" >
    <circle r="5" class="p2"></circle>
</g>
</svg>

Is there a way to achieve this using CSS Animations instead of relying on <animateMotion> ?

EDIT 1:

The endpoints of the curve are draggable, causing the curve's points to frequently change. The goal is to animate the arrow to the center of the curve without manually calculating the midpoints.

EDIT 2:

Following Kaiido's suggestion, I added calcMode="linear" resulting in the arrow being correctly positioned along the path. However, when repositioning the endpoint by dragging, the arrow remains in its original position in Chrome instead of moving along with the parent path. This behavior is consistent with Firefox but not Chrome.

Answer №1

If you want to achieve the same result using CSS, you can make use of the offset-path, offset-distance, and offset-rotate properties:

#path1 {
  fill: none;
  stroke: black;
}
.path_arrow {
  transform: translate( -3px, -6px );
  offset-path: path("M220 104C220 144,400 180,400 224");
  offset-rotate: auto;
  offset-distance: 50%;
}
body { background: white; }
<svg width="500" height="500" >
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path class="path_arrow" d="M0,0 L0,12 L12,6 z" />
</svg>

However, it's important to note that the browser support for these CSS properties is lower compared to SVG SMIL, as indicated by their browser support.

In case you need IE support, there is a JavaScript implementation available at this link, which appears to support <animateMotion> and rotate. Please keep in mind that this implementation hasn't been personally tested.



In reference to "EDIT 2" in the question:

It seems that Chrome requires an explicit call to update the <mpath>. This can be achieved by invoking the beginElement() method of the <animationMotion> element after each update:

document.querySelector('svg').onmousemove = function(e) {
  const rect = this.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  path1.setAttribute( 'd', `M ${x} ${y} C 220 144 400 180 400 224` );
  // Chrome requires an explicit update
  document.querySelector('animateMotion').beginElement();
}
<pre style="position: absolute; pointer-events:none">Move your mouse to change the path</pre>
<svg width="500" height="500">
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path d="M0,0 L0,12 L12,6 z" transform="translate(-3,-6)">
    <animateMotion dur="0s" rotate="auto" fill="freeze"
                   keyTimes="0;1" keyPoints="0.5;0.5" calcMode="linear" >
       <mpath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#path1"/>
    </animateMotion>
  </path>
</svg>

Answer №2

To achieve the desired effect, make use of webkit animation in your CSS code. It is also highly recommended to explore resources like https://codepen.io/collection/yivpx/, which is a fantastic open-source project dedicated to SVG optimization. Additionally, remember to assign names to all classes within your SVG file for enhanced flexibility when applying CSS animations, such as using the following snippet:

animation: kaboom 5s ease alternate infinite;

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

Switching the menu based on screen size successfully functions for the div element, however, it does not

Currently, I am working on creating a responsive menu. The structure of my menu is set up as follows: HTML: <ul id="top-menu"> <li class="active"> <a href="#">HOME</a> </li> <li> <a href="#div2">ABOUT</ ...

Unable to match the height of the inner card image in bootstrap with the height of the outer card image

I'm facing an issue with two bootstrap cards, one nested inside the other, both containing images. Check out the StackBlitz here The inner image doesn't flex to the same height as the outer one, resulting in a small space between the two cards ...

Inject environment variable into SCSS file while using webpack

I'm new to webpack and I need help with reading a specific value, which is the env variable from the webpack.config.js file, in a sass file. This will allow me to have different CSS styles based on the environment. For example: If the env is set to ...

Corner of the Border Revealing a Clear Sky above

Looking to enhance my navigation bar (menu) by adding a cornered border when the user hovers over it. <nav> <a href="#home">Home</a> | <a href="#about">About</a> | <a href="#blog">Blog</a ...

Interactive text that changes when hovered over in an HTML document

My table contains text and I have implemented code that displays a small text when hovering over it. I would like the entire column to trigger the text display on hover, ideally in a larger size. Any suggestions on how to achieve this? ...

The menu is about to receive some custom styling

I have come across a webpage where I need to make some modifications, but I am unable to locate the script responsible for applying the inline style. This issue only seems to be occurring on the mobile version with the dropdown menu. <div class="is-dri ...

The effect of iPad screen orientation on CSS styling

Exploring orientation testing using CSS for iPad. Below is the code snippet from the CSS file: @media only screen and (device-width:768px) and(orientation:portrait) { body { background: green; } } @media only screen and (device-width:768px) and(orient ...

Is there a way to preserve the original color format without converting it to RGB

When applying a hsl color in JavaScript, it ends up being converted to RGB instead of staying as an HSL color. document.body.style.backgroundColor = "hsl(0,100%,50%)" document.body.style.backgroundColor; // "rgb(255, 0, 0)" I wanted to set an HSL color a ...

How can I adjust the size of my elements to be responsive in pixels

While browsing through Quora and Facebook feeds, I noticed the fixed size of user display pictures: width: 40px; height: 40px; Even when resizing the browser window for a responsive design, these pictures maintain their size at 40px x 40px. What other f ...

enhancing the functionality of appended children by including a toggle class list

I'm having trouble toggling the classList on dynamically appended children. The toggle works fine on existing elements, but not on those added through user input. Any tips on how I can achieve this? I'm currently stumped and would appreciate any ...

How do I overwrite this calculation using JQuery?

I have a website: link There are two pages on my site that have the same div elements... I want one page to perform a certain calculation on the divs, and another page to perform a different calculation... New JavaScript Code: jQuery(document).ready(fu ...

triangle shape filled with a gradient that transitions between two colors

I have two triangles displayed at the bottom of my page - one on the left and one on the right. The right triangle is currently transparent but I want to add a gradient effect to it. For the triangle-bottom-right, I'd like the gradient to go from rgb ...

Flexbox Columns Maintaining Width when Window is Resized

My current challenge involves utilizing Flexbox to create a responsive layout with 5 boxes that shrink when the browser window is resized. However, 4 of these boxes are not reducing their width as expected when placed in columns. (Despite Bob behaving cor ...

Flexbox is not properly repeating elements horizontally

I am struggling to align text boxes horizontally within ngFor loop, and I can't seem to pinpoint the mistake. Here is the HTML code from the parent component: <div class="maintenance-section"> <div class="yearly"> ...

Specify the input type to occupy the full width and be contained within its parent div

I'm currently dealing with a form that includes input fields for email and password, along with some additional buttons. Here is the HTML code: <div id="login-form"> <form> <input type="email" placeholder="Email" id="email" name= ...

Showcasing Portfolio Work in a User-Friendly Mobile Design

Currently revamping my portfolio website and looking for ways to optimize the display of my personal projects. I have a card-like interface in place that works well on desktop but only shows one project at a time on mobile devices. Seeking solutions to imp ...

What is the best way to align vertically a horizontal list that includes both headers and icon images?

My goal is to create a horizontal navigation bar that features menu options with headings and icons below them. Upon hovering over each option, the block's background color should change and slightly increase in size. I initially used percentages for ...

Submitted input in a text field is automatically displayed in a separate text box

Below is a snippet of HTML code from my AngularJS application <input type="text" class="input-xlarge" id="user_name" ng-model="myModel.text" name="user_name" rel="popover" data-content="Enter your first and last name." data-original-titl ...

HTML block failing to implement Bootstrap styling

I am struggling to integrate Bootstrap into Drupal. I have used the 'row' class for the contact ID and added col-sm-12 for title and desc, but it is not working as expected. The width of the container seems off. Also, the accordion.js script work ...

How can you find the "et-custom-css" section in WordPress?

One of the challenges I'm facing with my WordPress page is that some CSS classes are located under <style type="text/css" id="et-custom-css">. Additionally, there is a comment at the top of the CSS saying: /* - - - - - - Additional page info - ...