Predicting the width of an HTML element to smoothly transition its opacity and width using CSS - a helpful guide

  • Currently, I am facing a situation where I have a span node with an innerText that I will be changing at runtime.
  • As I change the innerText, the offsetWidth of the node will also change based on the length of the future innerText.
  • In order to handle CSS transitions for both the opacity and width of the span element, I need to anticipate the future offsetWidth.
  • It is crucial in this case to smoothly transition both the opacity and the width of the span element, which is why I cannot change the innerText immediately.

Is there a way for me to accurately predict the exact value of the width?

On a broader scale, is it possible to "simulate" DOM changes to determine the anticipated CSS properties?

Here is a potential starting code snippet:

let h1 = document.getElementsByTagName("h1")[0];
let span = document.getElementsByTagName("span")[0];
h1.addEventListener("click", function() {
  if(span.innerText == "Better") {
    span.innerText = "Awsome";
  } else {
    span.innerText = "Better";
  }
})
h1 span {
  border: 1px solid red;
  display: inline-block;
  padding: 4px;
  transition-property: all;
}
<h1>Hello <span>Awsome</span> World!</h1>

Answer №1

In my response, I suggested a method where you can duplicate the element, update its content to your desired text, and calculate its width. Then, adjust the original width based on the calculated width of the duplicated element.

Here is an example implementation:

let h1 = document.getElementsByTagName("h1")[0];
let span = document.getElementsByTagName("span")[0];
span.style.width = `${span.clientWidth}px`;
h1.addEventListener("click", function() {
  const nextWord = getNextWord();
  const featureWidth = getFeatureWidth(nextWord);
  span.style.color = 'rgba(0, 0, 0, 0)';
  span.style.width = `${featureWidth}px`;
  setTimeout(() => {
    span.textContent = nextWord;
    span.style.color = 'rgba(0, 0, 0, 1)';
  }, 300);
});

function getNextWord() {
  if(span.innerText == "Better") {
    return "Awesome";
  }
  return "Better";
}

function getFeatureWidth(word) {
  const clonedSpan = document.createElement('span');
  clonedSpan.setAttribute('style', 'position: absolute;z-index: -1');
  clonedSpan.textContent = word;
  h1.appendChild(clonedSpan);
  const width = clonedSpan.clientWidth;
  h1.removeChild(clonedSpan);
  return width;
}
h1 span {
  border: 1px solid red;
  display: inline-block;
  padding: 4px;
  transition: all .3s ease;
}
<h1>Hello <span>Awesome</span> World!</h1>

Answer №2

After being inspired by @Mosh Feu's solution, I have put together a revised version of the case:

let h1;
let span;
let width;
let words;
let opacity;
let button;
button = document.getElementsByTagName("button")[0];
element = document.getElementById("word");
width = window.getComputedStyle(element).getPropertyValue("width");
words = [
  'Better',
  'Great',
  'Best Ever',
  'Incredible',
  'Awesome'
];
element.setAttribute('style', `
  color: rgba(0, 0, 0, ${opacity = 1});
  width: ${width};
`);
let iterator = words.values();
function changeWord() {
  let word;
  let next;
  let width;
  next = iterator.next();
  if (next.done) {
    iterator = words.values();
    next = iterator.next();
  }
  word = next.value;
  width = getFeatureWidth(word);
  element.setAttribute('style', `
    color: rgba(0, 0, 0, ${opacity = 0});
    width: ${width};
  `);
  setTimeout(() => {
    element.textContent = word;
    element.setAttribute('style', `
      color: rgba(0, 0, 0, ${opacity = 1});
      width: ${width};
    `);
  }, 300);
}
button.addEventListener("click", changeWord);

function getFeatureWidth(word) {
  let clone;
  let width;
  let parent;
  clone = element.cloneNode(true);
  clone.setAttribute('style', `
    position: absolute;
    z-index: -1
  `);
  clone.textContent = word;
  parent = element.parentElement;
  parent.appendChild(clone);
  width = window.getComputedStyle(clone).getPropertyValue("width");
  parent.removeChild(clone);
  return width;
}
#word {
  border: 1px solid red;
  background-color: rgba(0, 0, 0, .25);
  display: inline-block;
  transition-property: color, width;
  transition-duration: .3s, .3s;
  transition-delay: 0, 0;
  transition-timing-function: ease, ease;
  white-space: nowrap;
  box-sizing: content-box;
}
<h1>
  Hello <span id="word">Awesome</span> World!
</h1>
<button>Next</button>

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

Updating the background image without having to validate the cache

I have implemented a basic image slideshow on my website using a simple Javascript function. The function runs every 5 seconds to update the CSS "background-image" property of a div element. While it is functional, I've noticed that each time the func ...

Repetitive ajax requests using jquery

When users select multiple checkboxes, I need to make a jQuery ajax call based on their selections. To achieve this, I have implemented a FOR loop to iterate through the selected elements array and send an ajax request for each checkbox. However, each requ ...

Can you please explain the purpose of the mysterious JavaScript function f => f?

Currently, I am utilizing a third-party library that utilizes a function with functions as arguments. During my conditional checks, I determine whether to add a particular function as a parameter or not. However, providing null in these cases results in er ...

A tag that does not adhere to the background color's rgba opacity restrictions

Can you believe what's happening to me? Check out this code snippet. I'm trying to apply an rgba color to my a tag, but it's acting like an rgb color instead of the intended rgba. The text background is solid, but the rest of the background ...

Extract the value from JSON data

I am faced with the challenge of extracting the value of slug from each child in a JSON dataset. The issue lies in the fact that I cannot predict how many children will be generated whenever new data is received. The generation of nested children is dynam ...

Creating unique styles for mat-option with Active and Hover effects in Angular Materials

Struggling to find a CSS solution for changing the text color of the active option and on hover. The lack of documentation on styling angular materials in CSS is proving to be an issue. I've tried using .mat-option.mat-selected { background: red; ...

Instructions on setting a photo as a background image using a text-based model

I'm a beginner with Angular so I may have a simple question. I am using an image from the Google API, which is not a URL. How can I set this image as the background-image in a CSS tag that only accepts URIs? Thank you! ...

Searching for images in the filesystem using a recursive deferred approach

I've been attempting to iterate through the Android file system in search of any images. I created the following recursive method, but it's not functioning as expected. I've been struggling to determine a condition that can identify the end ...

Is it a common issue that sound.stop() doesn't seem to function properly, while sound.play() operates successfully within Howler

I am having trouble utilizing Howler.js in Reactjs with typescript. While I can successfully play the sound, pausing or stopping it seems to be an issue. Below is the code snippet: This component takes all the audio details as props. I used console.log() ...

What is the best way to retrieve and display database values for bootstrap dropdown items using an ajax request?

For my HTML page, I have set up a Bootstrap dropdown that should display values from my Postgres database when clicked using an AJAX request. <div class="dropdown"> <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="drop ...

Transfer information through the react-native-ble-plx module

To initiate a project involving connected devices, I must establish a Bluetooth connection among the different devices. The objective is to develop an application using React Native and then transmit data from this application to my Raspberry Pi. The Rasp ...

Struggling to design a button that can delete tasks from the list, but encountering issues with the filter function

Although I am able to push values, I seem to be struggling with the filtering process. Can anyone provide guidance on whether I am using the filter method incorrectly or if there is another issue at play? import { useState } from 'react'; const ...

In-depth CSS Reset for specific tags

Creating a Firefox extension that inserts HTML elements into web pages poses the challenge of ensuring consistent styling across various websites. The CSS rules must be robust enough to override any potential modifications introduced by developers. This ta ...

The proper method for redirecting the view after a successful AJAX request in a MVC application

Explanation of the Issue: I have added a search function to the header section of my MVC website. It includes an input text box and a 'Search' button. The Problem at Hand: Currently, I have incorporated an AJAX function in the shared master la ...

Create a bootstrap table with td elements that have no wrap for their content

I am currently developing an application using springboot, thymeleaf, and bootstrap. Here is the snippet of the html code I'm working with: <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <h ...

What is the best way to insert objects into another array of objects at alternating positions?

I'm currently developing a React component and have a requirement to insert a new object at alternate positions within an array of objects. For example: arr1 = [{test: 1},{test: 2},{test: 3},{test: 4}] The expected output should look like this: arr ...

Working with arrays and elements in JavaScript using regular expressions

The programming language is JavaScript. Imagine we have an array filled with positive and negative integers mixed in with other letters (e.g. 1a or -2d). The challenge is to figure out how to select all the strings that start with or contain positive inte ...

Tips for effectively passing query string parameters in Angular

I am looking to make an HTTP request with parameters through a query For instance: URL: https://api/endpoint?d=1&value=2 ...

HTML script tag failing to load

As a beginner in using scripts in HTML, I'm currently following a tutorial that suggests loading the script after the body for certain reasons. In my own code, I found that I need to place the script both in the head section and after the body. Remov ...

Transform JSON array containing identical key-value pairs

My array is structured as follows: [ { "time": "2017-09-14 02:44 AM", "artist": "Sam", "message": "message 1", "days": 0 }, { "time": "2017-09-14 02:44 AM", " ...