Skip to content
Advertisement

issue with line through animation

I want to create a simple line through animation and so far I’m here:

.strikethrough {
    display: inline-block;
    position: relative;
    line-height: 1.5em;
}

.strikethrough:after {
    content: '';
    position: absolute;
    display: block;
    width: 100%;
    height: 1px;
    box-shadow: 0 1px rgba(252, 3, 3,0.7);
    margin-top: -0.7em;
    background: rgba(252, 3, 3,0.8);
    transform-origin: center left;
    animation: strikethrough 1s 0.5s cubic-bezier(.55, 0, .1, 1) 1;

}

@keyframes strikethrough {
    from {
        transform: scaleX(0);
    }
    to {
        transform: scaleX(1);
    }
}
<span class="strikethrough">Favor packaging over toy</span>

As you see everything works fine except two things:

  1. Now we can see the line at first then it hides and starts the animation, I want to see only the animated line.

  2. I want to initiate the animation using javascript… but with this pseudo-element (after) it seems complicated!

Answer

You can fix your animation using animation-fill-mode:

animation-fill-mode: backwards;

To trigger your animation, just add the strikethrough class. The thing where I think this won’t work is when you have a multiline text, as your ::after won’t cover that.

document.querySelector( '.strikethrough' ).addEventListener( 'click', event => { event.target.classList.toggle( 'strikethrough' ); });
.strikethrough {
    display: inline-block;
    position: relative;
    line-height: 1.5em;
}

.strikethrough:after {
    content: '';
    position: absolute;
    display: block;
    width: 100%;
    height: 1px;
    box-shadow: 0 1px rgba(252, 3, 3,0.7);
    margin-top: -0.7em;
    background: rgba(252, 3, 3,0.8);
    transform-origin: center left;
    animation: strikethrough 1s 0.5s cubic-bezier(.55, 0, .1, 1) 1;
    animation-fill-mode: backwards;
}

@keyframes strikethrough {
    from {
        transform: scaleX(0);
    }
    to {
        transform: scaleX(1);
    }
}
<span class="strikethrough">Favor packaging over toy</span>

Personally, I would take this simpler tack to reduce the amount of actual objects on screen, and the amount of code, by using a background image to scale. If cleverly set up, you could even multi-line this (by making the background the line height and having a middle pixel in it – and with SVGs you could ensure it was only 1px regardless of the stretching etc…).

document.querySelector( 'p' ).addEventListener( 'click', event => {
  
  event.target.classList.toggle( 'strikethrough' );
  
})
@keyframes stretch {
  to { background-size: 100% var(--line-height); }
}

:root {

  --line-height: 1.2em;
  
}

p {

  line-height: var(--line-height);
  
}

.strikethrough {
  
  line-height: 1.2em;
  background: url('data:image/svg+xml;charset=utf8,<svg  xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none"><line x1="0" y1="50%" x2="100%" y2="50%" stroke="black" stroke-width="1px" /></svg>') repeat-y 0 0 / 0 var(--line-height);
  animation: stretch 4s;
  animation-fill-mode: forwards;
  
}
<p>Hello World!<br />Another line, does it work?</p>
Advertisement