0

(Note: the example may not work in some browsers due to the poor support table.)

I'm trying to animate an inline-block span from whatever was the default width, to width 300px.

let div = document.getElementsByTagName("div")[0];
let span1 = document.getElementsByTagName("span")[0];
let span2 = document.getElementsByTagName("span")[1];

const switchClass = (element, class1, class2) => {
  const elementHasClass = element.classList.contains(class1) && class1 || class2;
  const elementNotHasClass = elementHasClass === class1 ? class2 : class1;
  element.classList.remove(elementHasClass)
  element.classList.add(elementNotHasClass)
}

div.addEventListener('click', event => {
  switchClass(event.currentTarget, "less-text", "more-text")
  switchClass(span1, "visible", "not-visible")
  switchClass(span2, "visible", "not-visible")
});
@property --anime-duration {
  syntax: '<time>';
  inherits: false;
  initial-value: 0.3s;
}

div {
  display: inline-block;
  border: 2px solid black;
}

.less-text {
  width: 40px;  /* auto; */
  height: 20px; /* auto; */
  user-select: none;
  transition: width var(--anime-duration), height var(--anime-duration);
}

.more-text {
  width: 400px;
  height: 60px;
  overflow-x: hidden;
  overflow-y: scroll;
  transition: width var(--anime-duration), height var(--anime-duration);
}

.visible {
  opacity: 0;
  animation: add-visibility forwards var(--anime-duration);
}

.not-visible {
  display: none;
}

@keyframes add-visibility {
  to {
    opacity: 1;
  }
}

span>span {
  display: inline-block;
  width: 370px;
}
<div class="less-text">
  <span class="visible">Text</span>
  <span class="not-visible"><span>A string with a supported syntax as defined by the specification. Supported syntaxes are a subset of CSS types. These may be used along, or a number of types can be used in combination.</span></span>
</div>

But the border outside of Text is not perfect; it is a fixed width. But I want it to be rendered as width: auto (as well as with height). How do I do it? Width auto cannot be animated.

Replacing them with min-width and max-width (as well as height) does not give proper animation.

let div = document.getElementsByTagName("div")[0];
let span1 = document.getElementsByTagName("span")[0];
let span2 = document.getElementsByTagName("span")[1];

const switchClass = (element, class1, class2) => {
  const elementHasClass = element.classList.contains(class1) && class1 || class2;
  const elementNotHasClass = elementHasClass === class1 ? class2 : class1;
  element.classList.remove(elementHasClass)
  element.classList.add(elementNotHasClass)
}

div.addEventListener('click', event => {
  switchClass(event.currentTarget, "less-text", "more-text")
  switchClass(span1, "visible", "not-visible")
  switchClass(span2, "visible", "not-visible")
});
@property --anime-duration {
  syntax: '<time>';
  inherits: false;
  initial-value: 0.3s;
}

div {
  display: inline-block;
  border: 2px solid black;
}

.less-text {
  max-width: 40px;  /* auto; */
  max-height: 20px; /* auto; */
  user-select: none;
  transition: max-width var(--anime-duration), max-height var(--anime-duration);
}

.more-text {
  max-width: 400px;
  max-height: 60px;
  overflow-x: hidden;
  overflow-y: scroll;
  transition: max-width var(--anime-duration), max-height var(--anime-duration);
}

.visible {
  opacity: 0;
  animation: add-visibility forwards var(--anime-duration);
}

.not-visible {
  display: none;
}

@keyframes add-visibility {
  to {
    opacity: 1;
  }
}

span>span {
  display: inline-block;
  width: 370px;
}
<div class="less-text">
  <span class="visible">Text</span>
  <span class="not-visible"><span>A string with a supported syntax as defined by the specification. Supported syntaxes are a subset of CSS types. These may be used along, or a number of types can be used in combination.</span></span>
</div>

let div = document.getElementsByTagName("div")[0];
let span1 = document.getElementsByTagName("span")[0];
let span2 = document.getElementsByTagName("span")[1];

const switchClass = (element, class1, class2) => {
  const elementHasClass = element.classList.contains(class1) && class1 || class2;
  const elementNotHasClass = elementHasClass === class1 ? class2 : class1;
  element.classList.remove(elementHasClass)
  element.classList.add(elementNotHasClass)
}

div.addEventListener('click', event => {
  switchClass(event.currentTarget, "less-text", "more-text")
  switchClass(span1, "visible", "not-visible")
  switchClass(span2, "visible", "not-visible")
});
@property --anime-duration {
  syntax: '<time>';
  inherits: false;
  initial-value: 0.3s;
}

div {
  display: inline-block;
  border: 2px solid black;
}

.less-text {
  min-width: 40px;  /* auto; */
  min-height: 20px; /* auto; */
  user-select: none;
  transition: min-width var(--anime-duration), min-height var(--anime-duration);
}

.more-text {
  min-width: 400px;
  min-height: 60px;
  overflow-x: hidden;
  overflow-y: scroll;
  transition: min-width var(--anime-duration), min-height var(--anime-duration);
}

.visible {
  opacity: 0;
  animation: add-visibility forwards var(--anime-duration);
}

.not-visible {
  display: none;
}

@keyframes add-visibility {
  to {
    opacity: 1;
  }
}

span>span {
  display: inline-block;
  width: 370px;
}
<div class="less-text">
  <span class="visible">Text</span>
  <span class="not-visible"><span>A string with a supported syntax as defined by the specification. Supported syntaxes are a subset of CSS types. These may be used along, or a number of types can be used in combination.</span></span>
</div>
Book Of Flames
  • 316
  • 3
  • 13

1 Answers1

0

You can do it using javascript. Read the width of the element, then set this width in pixels, and finally set the new width (delaying it using setTimeout).

var newWidth = '300px';
function resize() {
  var t = document.getElementById('txt');
  var width = t.offsetWidth;
  console.log('width is: ' + width);
  t.style.width = width + 'px';
  // Delays the second width to the next render (does not work without this)
  setTimeout(function() {
    t.style.width = newWidth;
  }, 1)
  
}

document.getElementById('txt').addEventListener('click', resize);
#cont {
  width: 500px;
}

#txt {
  display:inline;
  width: auto;
  transition: width 1s;
}

/* Just for styling */
div {
  font-family:sans-serif;  
  background-color: #aaa;
  display:flex;
}
div > div {
  background-color: #ea9;
}
span {
  display:inline-block;
  padding: 0 15px;
  margin: 15px 0;
}
<div id="cont"><div id="txt"><span>Text</span></div></div>
Conrado Lopez
  • 131
  • 1
  • 6