Hadi Rajabi
Hadi Rajabi

Reputation: 62

CSS Check If Element Is Overflowing Then Animate Back And Forth

I have some short and long text in html with max-width and overflow styles. i want to check if an element is overflowing then start back and forth animation to users can see all contents.

Please see this demo:

.animated {
  position: relative;
  white-space: nowrap;
  max-width: 150px;
  overflow: hidden;
  background: #0c0c0c;
}

.text-animated{
  color: #fff;
  animation: backAndForth 5s linear infinite;
}

@keyframes backAndForth {
    0% { transform: translateX(0); }
    10% { transform: translateX(0); }
    45% { transform: translateX(calc(100% - 340px)); }
    55% { transform: translateX(calc(100% - 340px)); }
    90% { transform: translateX(0); }
    100% { transform: translateX(0); }
}
<div class="animated">
  <h3 class="text-animated">
    Some Short Text
  </h3>
</div>
<span>Must be fixed</span>

<br><br><br>

<div class="animated">
  <h3 class="text-animated">
    Some Long And Bigger Text To Animate
  </h3>
</div>
<span>Must be Animated to view all text</span>

Can anybody help me?

Thanks

Upvotes: 1

Views: 4582

Answers (3)

A Haworth
A Haworth

Reputation: 36522

Although a max width is set it is not being taken up on the smaller text - notice the widths of both examples are the same.

This snippet gives both the div and the h3 a position so that the widths are taken up and the div is set to have width fit-content (it will still obey the max-width).

The animation needs to take into account both the width of the container and the width of the text. It therefore uses left positioning and transition. For the shorter text they balance out so there is no movement. For the longer text the amount of movement is just the extra length of the text compared to the container.

.animated {
  position: relative;
  white-space: nowrap;
  max-width: 200px;
  overflow: hidden;
  background: #0c0c0c;
  display: inline-block;
  width: fit-content;
  position: relative;
}

.text-animated {
  color: #fff;
  animation: backAndForth 5s linear infinite;
  display: inline-block;
  position: relative;
}

@keyframes backAndForth {
  0% {
    transform: translateX(0);
    left(0);
  }
  10% {
    transform: translateX(0);
    left: 0;
  }
  45% {
    transform: translateX(calc(-100%));
    left: 100%;
  }
  55% {
    transform: translateX(calc(-100%));
    left: 100%;
  }
  90% {
    transform: translateX(0);
    left: 0;
  }
  100% {
    transform: translateX(0);
    left: 0;
  }
}
<div class="animated">
  <h3 class="text-animated">
    Some Short Text
  </h3>
</div>
<span>Must be fixed</span>

<br><br><br>

<div class="animated">
  <h3 class="text-animated">
    Some Long And Bigger Text To Animate
  </h3>
</div>
<span>Must be Animated to view all text</span>

UPDATE: a couple of additional requirements have been added (in the comments below).

The max-width needs to change from a fixed px width to be relative to container size. The snippet below demonstrates this by putting the divs in a container whose width depends on viewport size.

The text direction has changed from left to right to right to left. The settings for left and transform/translate therefore have to swap signs compared to tehe original code above:

.container {
  width: 40vw;
  position: relative;
}

.animated {
  position: relative;
  white-space: nowrap;
  /* max-width: 200px; */
  max-width: calc(100% - 5rem);
  overflow: hidden;
  background: #0c0c0c;
  display: inline-block;
  width: fit-content;
  position: relative;
  white-space: no-wrap;
  direction: rtl;
}

.text-animated {
  color: #fff;
  animation: backAndForth 5s linear infinite;
  display: inline-block;
  position: relative;
  direction: rtl;
}

@keyframes backAndForth {
  0% {
    transform: translateX(0);
    left(0);
  }
  10% {
    transform: translateX(0);
    left: 0;
  }
  45% {
    transform: translateX(calc(100%));
    left: -100%;
  }
  55% {
    transform: translateX(calc(100%));
    left: -100%;
  }
  90% {
    transform: translateX(0);
    left: 0;
  }
  100% {
    transform: translateX(0);
    left: 0;
  }
}
<div class="container">
  <div class="animated">
    <h3 class="text-animated">
      Some Short Text
    </h3>
  </div>

  <br><br><br>

  <div class="animated">
    <h3 class="text-animated">
      Some Long And Bigger Text To Animate
    </h3>
  </div>
</div>

Upvotes: 2

Laaouatni Anas
Laaouatni Anas

Reputation: 3855

scrollWidth is the width of elements with also not showable content.

and offsetWidth is the only showable content width.


so if the scrollWidth is different than offsetWidth, this means that is overflowing!

if (childEl.scrollWidth > childEl.offsetWidth) {
      childEl.classList.add("text-animated");
}

enter image description here

/* choose your parent element (that can be also a <body> if you want all elements) */
let parent = document.querySelectorAll(".animated");

parent.forEach((el) => {
  /* get all h3 from parent (if you want all elements use "*" selector)*/
  let childs = el.querySelectorAll("h3");

  childs.forEach(childEl => {
    /* if overflow then add class */
    if (childEl.scrollWidth > childEl.offsetWidth) {
      childEl.classList.add("text-animated");
    }
  });
});
.animated {
  position: relative;
  white-space: nowrap;
  max-width: 150px;
  overflow: hidden;
  background: #0c0c0c;
}

.text-animated {
  color: #fff;
  animation: backAndForth 5s linear infinite;
}

@keyframes backAndForth {
  0% {
    transform: translateX(0);
  }
  10% {
    transform: translateX(0);
  }
  45% {
    transform: translateX(calc(100% - 340px));
  }
  55% {
    transform: translateX(calc(100% - 340px));
  }
  90% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(0);
  }
}
<!-- 1 -->
<div class="animated">
  <h3>
    Some Short Text
  </h3>
</div>
<span>Must be fixed</span>

<br><br><br>

<!-- 2 -->
<div class="animated">
  <h3>
    Some Long And Bigger Text To Animate
  </h3>
</div>
<span>Must be Animated to view all text</span>

Upvotes: 1

IT goldman
IT goldman

Reputation: 19483

HTML text-overflow ellipsis detection says you can detect if element has overflown content:

function isEllipsisActive(e) {
     return (e.offsetWidth < e.scrollWidth);
}

Upvotes: 0

Related Questions