Can @keyframes percentage be determined using a CSS variable?

My animation is responsive to the number of characters present

It functions properly with 20 characters:

const text = '20 characters length'

const speed = 0.1

const $container = document.querySelector('.wave')

$container.style.setProperty('--duration', `${speed * text.length}s`)

for (const [index, char] of Object.entries([...text])) {
  const $el = document.createElement('span')
  $el.innerHTML = char === ' ' ? ' ' : char
  $el.style.setProperty('--delay', `${index * speed}s`)
  $container.appendChild($el)
}

This works well because 5% corresponds to 1/20

If I modify the text length, the animation speeds up.

const text = '10 char...'

const speed = 0.1

const $container = document.querySelector('.wave')

$container.style.setProperty('--duration', `${speed * text.length}s`)

for (const [index, char] of Object.entries([...text])) {
  const $el = document.createElement('span')
  $el.innerHTML = char === ' ' ? ' ' : char
  $el.style.setProperty('--delay', `${index * speed}s`)
  $container.appendChild($el)
}

To adjust for this change in text length, I would need to alter 5% to 10% in the @keyframes rule.

I can regulate duration and delay using CSS variables.

Is it possible to do the same for the @keyframes list?

Answer №1

To apply a css variable to the keyframe of an animation is not supported. Instead, utilize the Web Animations API.
I attempted to replicate your animation and it appears to be functional. The original css animation is shown first, followed by the version using JavaScript:

const animateText = (el, options) => {
  options = {
    ...{
      speed: 0.1,
      translateY: '-5px',
    },
    ...options,
  };
  const textContent = el.dataset.text || '';
  const offset = 100 / textContent.length / 100;
  const duration = options.speed * textContent.length * 1000;

  for (const [index, char] of Object.entries([...textContent])) {
    const delayTime = (index - 1) * options.speed * 1000;
    const spanElement = document.createElement('span');
    spanElement.innerHTML = char === ' ' ? ' ' : char;
    el.appendChild(spanElement);
    spanElement.animate(
      [
        { translate: '0 0', offset: offset - 0.0001 },
        { translate: `0 ${options.translateY}`, offset: offset },
        { translate: `0 ${options.translateY}`, offset: offset * 2 - 0.0001 },
        { translate: '0 0', offset: offset * 2 },
      ],
      {
        duration: duration,
        delay: delayTime,
        iterations: Infinity,
      },
    );
  }
};

document.querySelectorAll('.wave').forEach(wave => animateText(wave));
.wave,
.wave-css {
  span {
    display: inline-block;
  }
}

.wave-css span {
  animation: anim var(--duration) step-start var(--delay) infinite;
}

@keyframes anim {
  5% {
    translate: 0 -5px;
  }
}

.waves {
  display: grid;
  grid-template-columns: repeat(2, max-content);
  gap: 2px 8px;
}
<div class="waves">
  <span>wave with css:</span>
  <div class="wave-css" style="--duration: 2s;"><span style="--delay: 0s;">2</span><span style="--delay: 0.1s;">0</span><span style="--delay: 0.2s;">&nbsp;</span><span style="--delay: 0.30000000000000004s;">c</span><span style="--delay: 0.4s;">h</span><span style="--delay: 0.5s;">a</span><span style="--delay: 0.6000000000000001s;">r</span><span style="--delay: 0.7000000000000001s;">a</span><span style="--delay: 0.8s;">c</span><span style="--delay: 0.9s;">t</span><span style="--delay: 1s;">e</span><span style="--delay: 1.1s;">r</span><span style="--delay: 1.2000000000000002s;">s</span><span style="--delay: 1.3s;">&nbsp;</span><span style="--delay: 1.4000000000000001s;">l</span><span style="--delay: 1.5s;">e</span><span style="--delay: 1.6s;">n</span><span style="--delay: 1.7000000000000002s;">g</span><span style="--delay: 1.8s;">t</span><span style="--delay: 1.9000000000000001s;">h</span></div>
  <span>wave with js:</span>
  <div>
    <div class="wave" data-text="20 characters long"></div>
    <div class="wave" data-text="10 chars..."></div>
  </div>
</div>

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

Transform CSS into React.js styling techniques

My current setup involves using Elementor as a REST Api, which is providing me with a collection of strings in React that are formatted like this: selector a { width: 189px; line-height: 29px; } Is there a tool or library available that can conver ...

Manipulating Width in CSS

I am facing a challenge with the HTML code below where an automated software inserts the initial CSS style g2f0 <div class="linelevel row"> <div class="g2f0 col-sm-6 form-group"> <label for="name">Name</label> < ...

Python Selenium returning 'None' when attempting to retrieve the source attribute of an image

Having trouble retrieving the src of images in the class "KfFlO" using selenium. Whenever I try to print for the source, Python keeps returning "none." Can anyone help me identify the problem? Below is my code snippet: from selenium import webdriver from s ...

Press the html button and activate the button using Visual Basic

Being new to Visual Basic, I have created a simple app using the WebBrowser component. The web page that loads contains an HTML button. I want this HTML button press to enable a button in Visual Basic, but I don't know how to do it. I have researched ...

Arrange radio buttons vertically in a table

I am attempting to display a vertical list of radio buttons within a table cell. Is this achievable? Here is the code snippet I am currently working with: <table> <tr> <td> First Name </td> ...

`How can parameters be passed to a controller while utilizing routes?`

Within my application, I am utilizing ngRoute to load views. .state('ReportViewer', { url: "/ReportViewer", controller: 'ReportViewerControl', templateUrl: "views/Report_viewer.html" }) The ...

Perform a bash command using PHP when an HTML button is clicked

Today, my brain seems to be on vacation. Currently, I have set up a Raspberry Pi with vlc running and connected to a mounted screen on the wall. There is a web page with simple controls to manage the pi, switch between different vlc streams, or stop stream ...

Choose the data attributes you want to include and attach them to input elements using plain JavaScript

Creating a User Information form with a select element containing four options, each with data attributes. Under the select are input types to populate the data attributes when selected. Looking for help in achieving this using plain JS and onchange event. ...

List style image does not serve its intended purpose

I attempted to personalize my webpage by adding an image to a list, but I couldn't get the list-style image to work. You can view the page at Below is the code I used: CSS /* Fleet List */ ul#flotta li { list-style-image:url("http://ctp.serviziew ...

parsedhtml is no longer providing responses

Hello, I am facing an issue while trying to extract text from a website using powershell. Whenever I attempt to return an object with ParsedHtml, powershell becomes unresponsive (even after letting it run in the background for some time). What could be cau ...

Navigating to a sub-directory using a relative URI

Apologies if this is a simple question, but I haven't been able to find the answer through searching. How can we access the sub-directory http://www.example.com/a-dir-without-trailing-slash/pic from the page http://www.example.com/a-dir-without-trail ...

The Bootstrap row fails to align elements side by side as intended

I'm trying to arrange elements in my navigation menu side by side, so I decided to use the row class from Bootstrap 5.0. However, they are still stacking on top of each other. I am currently working on a Flask project and using Jinja to some extent. ...

Is there a way to work around the CORS policy in order to fetch data from URLs?

I have been developing a tool that can analyze URLs from an uploaded CSV file, search the text content of each URL, and calculate the total word count as well as the occurrences of "saas" or "software". The goal is to generate a new CSV file with the origi ...

Tips on maintaining and hiding the vertical scrollbar when a popup is open, alongside the navigation bar positioned at the top of the page

After reviewing this pen, my goal is to create a popup that maintains access to the navigation bar (hence avoiding Bootstrap's Modal). However, I am facing the challenge of keeping the scrollbar visible while preventing scrolling in the background whe ...

How to Customize the Size and Color of secureTextEntry Inputs in React Native

When it comes to styling a password input like the one below: <TextInput name="Password" type="password" mode="outline" secureTextEntry={true} style={styles.inputStyle} autoCapitalize="none" autoFocus={true} /> I also ap ...

Having trouble getting dynamic values to render properly in Ionic select? Find a solution in Ionic 4

Encountering an issue with Ionic 4 and ion-select. The problem arises when attempting to bind data, specifically when preselecting data. In this scenario, the ion-select element fails to render properly. <ion-item class="transparent"> ...

Troubleshooting Issues with CSS3PIE and border-radius

Trying to implement CSS3PIE for my website to enable border-radius in IE8 (and older versions). The code works perfectly on all other browsers except IE. Below is the CSS I am using: #body_text_design{ border:2px solid black; background-color:#CCC ...

Modifying the HTML <select> element with JavaScript

[resolved] I'm encountering an issue with the code below that is supposed to dynamically change the options in a second drop-down menu based on the selection made in the first menu. I've tried to troubleshoot the problem but haven't been suc ...

stepper vue with previous and next buttons

I am trying to create previous and next buttons in Vue, but I am struggling a bit because I am new to learning Vue. I have some methods like this.activeIndex < this.activeIndex - 1 that I need to implement. Can someone help me with how to do this? cons ...

How Webpack 4 Utilizes splitChunks to Create Numerous CSS Files

I need to create multiple CSS files using webpack 4 with the min-css-extract-plugin and splitChunks plugin. Here is my webpack configuration. const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const path = require("path"); module.exports = ...