DEV Community

Cover image for How to create Pure CSS Glitch Animation  for Images and SVG
Roden
Roden

Posted on

How to create Pure CSS Glitch Animation for Images and SVG

Introduction

A few weeks ago, I made a post about how to make a Glitch Effect on pure CSS. But in that post I told you how to make a similar effect only for text. Today I want to tell you about how to implement such animation for images and SVG.

Demo

Images

Here, in fact, everything is very simple. Almost the same technology as with text animation.

HTML

Creating our block with a picture:

<div class="img"></div>
Enter fullscreen mode Exit fullscreen mode

CSS (SCSS)

1) We set styles for it (size and picture)

.img {
    position: relative;
    width: 400px;
    height: 300px;
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
    background-image: url(https://rawcdn.githack.com/Kerthin/links/247cc9065bac7d5c23b45ff677bf1d2bceeb4324/img/glitch/imgTV/vanille.png);
}
Enter fullscreen mode Exit fullscreen mode

Vanilla Image
Alt Text

2) We create 2 copies of ours in the form of pseudo-elements using :before and :after with absolute positioning so that they are placed one after the other.

    &::before,
    &::after {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      width: 400px;
      height: 300px;
      clip: rect(0, 0, 0, 0);
      overflow: hidden;
      background-size: cover;
      background-repeat: no-repeat;
      background-position: center;
    }
Enter fullscreen mode Exit fullscreen mode

3) After that, for each pseudo-element, we create our own horizontal margins from the original coordinates.

We also need to specify our own image for each pseudo-element, which is a modified original image using allow filters.

:before bg-image
Alt Text

:after bg-image
Alt Text

And we also need to add the name of our @keyframes animation to each pseudo-element that we will animate using the clip property.

    &::before {
      left: -6px;
      animation: glitch-effect 2s infinite linear alternate-reverse;
      background-image: url(https://rawcdn.githack.com/Kerthin/links/247cc9065bac7d5c23b45ff677bf1d2bceeb4324/img/glitch/imgTV/red.jpg);
    }
    &::after {
      left: 6px;
      animation: glitch-effect 3s infinite linear alternate-reverse;
      background-image: url(https://rawcdn.githack.com/Kerthin/links/247cc9065bac7d5c23b45ff677bf1d2bceeb4324/img/glitch/imgTV/blue.jpg);
    }
Enter fullscreen mode Exit fullscreen mode

4) And now we can just use our clip animation, which we used in the previous post about Glitch Animation for text. But only in the value of the clip property, we must specify the size of our .img element in height and width (see item 1).

$steps: 17;

@keyframes glitch-effect{
    @for $i from 0 through $steps{
        #{percentage($i*(1/$steps))}{
            clip: rect(random(300) + px, 400px, random(300) + px, 0);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Result
Alt Text

SVG

Here the idea is approximately exactly the same, only here it will be more convenient for us not to work with pseudo-elements, but simply to create 3 identical svg elements.

HTML

We create a common container and put 3 copies of our SVG in it.

<div class="svgWrap">
    <svg class="svgWrap__text">
        <use xlink:href="#svgGlitch"></use>
    </svg>
    <svg class="svgWrap__text">
        <use xlink:href="#svgGlitch"></use>
    </svg>
    <svg class="svgWrap__text">
        <use xlink:href="#svgGlitch"></use>
    </svg>
</div>
Enter fullscreen mode Exit fullscreen mode

Using the ID #svgGlitch, we refer to our prepared SVG template, so as not to copy the entire SVG code 3 times in a row.

SVG Template

<svg id="svgGlitch" class="none" width="270" height="76" viewBox="0 0 270 76" xmlns="http://www.w3.org/2000/svg">
        <path d="M0.84 38.288C0.84 49.488 4.376 58.48 11.448 65.264C18.52 72.048 27.64 75.44 38.808 75.44C45.048 75.44 50.536 74.224 55.272 71.792C60.04 69.328 63.64 66.56 66.072 63.488L61.176 59.552C58.936 62.624 55.944 65.04 52.2 66.8C48.488 68.56 44.28 69.44 39.576 69.44C30.392 69.44 23.176 66.4 17.928 60.32C12.712 54.24 10.072 46.512 10.008 37.136C9.944 27.888 12.408 20.656 17.4 15.44C22.392 10.192 29.256 7.568 37.992 7.568C41.288 7.568 44.584 8.032 47.88 8.96C51.208 9.888 53.976 11.232 56.184 12.992L61.032 7.376C58.088 5.328 54.584 3.76 50.52 2.672C46.456 1.584 42.248 1.04 37.896 1.04C27.112 1.04 18.232 4.656 11.256 11.888C4.312 19.12 0.84 27.92 0.84 38.288ZM48.312 47.216L57.864 48.896V65.648L66.072 63.488V48.896L72.36 47.216V42.416H48.312V47.216ZM53.016 10.4L55.896 24.032H61.368V2.62399H56.376L53.016 10.4ZM76.5855 74H100.106V70.16L92.5215 68.48L92.4255 48.704L92.5215 1.952L91.4175 0.463997L89.6415 0.367998L75.4335 1.99999V6.512L84.3615 7.952L84.4575 48.704L84.3615 68.48L76.5855 70.16V74ZM107.009 74H130.817V70.16L123.233 68.48L123.137 48.704L123.473 27.872L122.369 26H120.113L106.769 27.632V32.144L114.833 33.584L115.169 48.704L115.073 68.48L107.009 70.16V74ZM112.865 9.824C112.865 11.584 113.409 13.008 114.497 14.096C115.617 15.184 117.089 15.728 118.913 15.728C120.865 15.728 122.353 15.216 123.377 14.192C124.433 13.168 124.961 11.712 124.961 9.824C124.961 8.064 124.401 6.64 123.281 5.55199C122.193 4.464 120.737 3.92 118.913 3.92C116.961 3.92 115.457 4.432 114.401 5.456C113.377 6.48 112.865 7.936 112.865 9.824ZM134.737 32.144L142.561 32.72V48.704L142.225 66.176C142.225 69.056 142.737 71.152 143.761 72.464C144.817 73.744 146.577 74.384 149.041 74.384L160.225 72.608V68.768H153.409L151.057 66.032L150.625 48.704L151.441 19.28L149.857 17.36H147.601C146.545 19.344 145.073 21.488 143.185 23.792C141.329 26.096 138.513 27.696 134.737 28.592V32.144ZM148.801 32.144H161.329V27.248H148.993L148.801 32.144ZM166.385 51.2C166.385 58.304 168.577 64.064 172.961 68.48C177.377 72.864 182.913 75.056 189.569 75.056C195.265 75.056 199.665 74.048 202.769 72.032C205.873 69.984 208.177 67.952 209.681 65.936L207.233 63.056C205.473 64.688 203.457 66.064 201.185 67.184C198.913 68.272 196.113 68.816 192.785 68.816C187.793 68.816 183.585 67.136 180.161 63.776C176.769 60.384 175.057 55.872 175.025 50.24C174.993 43.68 176.385 38.72 179.201 35.36C182.017 31.968 185.377 30.272 189.281 30.272C192.193 30.272 194.657 30.944 196.673 32.288C198.689 33.6 199.841 35.2 200.129 37.088L205.937 31.184C204.177 29.168 201.921 27.632 199.169 26.576C196.417 25.488 193.121 24.944 189.281 24.944C183.137 24.944 177.777 27.472 173.201 32.528C168.657 37.584 166.385 43.808 166.385 51.2ZM199.313 33.2L201.377 42.944H206.129V25.904H201.761L199.313 33.2ZM215.617 74H237.217V70.16L230.593 68.48L230.497 48.704L230.593 1.904L229.249 0.367998H227.713L214.465 1.99999V6.512L222.433 7.952L222.529 48.704L222.433 68.48L215.617 70.16V74ZM230.353 39.44C231.985 36.912 234.113 35.024 236.737 33.776C239.393 32.496 242.001 31.856 244.561 31.856C247.601 31.856 249.937 32.736 251.569 34.496C253.201 36.224 254.017 38.144 254.017 40.256V48.704L253.921 68.48L246.337 70.16V74H269.185V70.16L262.081 68.48L261.841 48.704C261.841 48.704 261.873 47.568 261.937 45.296C262.033 43.024 262.081 40.704 262.081 38.336C262.081 34.176 260.833 30.912 258.337 28.544C255.873 26.144 252.177 24.944 247.249 24.944C243.345 24.944 239.633 26 236.113 28.112C232.625 30.224 230.161 32.864 228.721 36.032L230.353 39.44Z" />
</svg>
Enter fullscreen mode Exit fullscreen mode

CSS (SCSS)

1) First, we need to specify the dimensions of our container and each SVG block separately. It is better to put the original sizes.

.svgWrap {
    position: relative;
    width: 270px;
    height: 76px;
}
.svgWrap__text {
    position: absolute;
    top: 0;
    left: 0;
    fill: #fff;
    background: #000;
    width: 270px;
    height: 76px;
}
Enter fullscreen mode Exit fullscreen mode

2) Further, by analogy with the pictures, we set separate styles for each element. But this time instead of pseudo elements :before and :after, we will use :nth-child to access each child element separately.

  &:nth-child(2),
  &:nth-child(3) {
    clip: rect(0, 0, 0, 0); 
  }
  &:nth-child(2) {
    fill: #fffafa;
    left: -2px;
    animation: svg-glitch-effect 2s infinite linear alternate-reverse;
  }
  &:nth-child(3) {
    fill: #f5f5f5;
    left: 2px;
    animation: svg-glitch-effect 3s infinite linear alternate-reverse;
  }
Enter fullscreen mode Exit fullscreen mode

In the case of SVG, we do not specify different images, but different colors using the fill property.

3) We animate according to the same principle: as with images. We specify the desired width and height of the elements.

$steps: 20;

@keyframes svg-glitch-effect{
    @for $i from 0 through $steps{
        #{percentage($i*(1/$steps))}{
            clip: rect(random(75) + px, 270px, random(75) + px, 0);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Result
Alt Text

The End

Well, that's it. Some of you may have a question, why not just specify all these possibilities for creating Glitch animations in the previous post, if all these soposoby differ little from each other? Or why not just supplement the previous post with this information?

I will answer honestly, I was too lazy.
Alt Text

I can advise you to subscribe to my Twitter, I also post my works there.

Discussion (9)

Collapse
inhuofficial profile image
InHuOfficial • Edited

Awesome. 毋

Quick suggestion, you can save 2 network requests for the jpgs (about 450kb!) by simply using CSS filters.

It also saves you some time having to create the images.

All I did was use the same background image and then rotate the hue 120deg and 240deg.

You have to add a few more properties to make it "tint" the colour so I ended up with:

.img::before {
  left: -6px;
  animation: glitch-effect 2s infinite linear alternate-reverse;
  background-image: url(https://rawcdn.githack.com/Kerthin/links/247cc9065bac7d5c23b45ff677bf1d2bceeb4324/img/glitch/imgTV/vanille.png);
  filter: grayscale(100%) sepia(100%) saturate(250%) hue-rotate(120deg) brightness(121%) contrast(121%);
}
.img::after {
  left: 6px;
  animation: glitch-effect 3s infinite linear alternate-reverse;
  background-image: url(https://rawcdn.githack.com/Kerthin/links/247cc9065bac7d5c23b45ff677bf1d2bceeb4324/img/glitch/imgTV/vanille.png);
  filter: grayscale(100%) sepia(100%) saturate(250%) hue-rotate(240deg) brightness(121%) contrast(121%);
}
Enter fullscreen mode Exit fullscreen mode

I am sure with a bit of fine tuning it could be made to be perfectly the same, but for now it was close enough as an example.

Collapse
kerthin profile image
Roden Author

Yes, I wanted to use filters, but in my opinion it was better to use images, because CSS filters require some performance of the browser itself to render these same filters. This means that there may be performance problems on mobile versions if the site uses several similar elements that have CSS filters. But you are absolutely right that it is often better to use filters instead of multiple images.

Collapse
inhuofficial profile image
InHuOfficial

I think you would be fine with a filter on an image as I am (almost) certain that the browser will apply the filter once and then cache the image as we don't change the filters.

It is a good point though and probably one that would need testing if you use this extensively.

I realised I didn't say it in the original comment, but the way you implemented it is great, one of the better glitch effects I have seen!

Thread Thread
kerthin profile image
Roden Author

Thank you. I should supplement the article and point out the possibility of using a filter instead of images, although people can use your comment as one of the options for implementing pseudo-elements without images. Thank you for your detailed opinion about the post.

Collapse
guscarpim profile image
Gustavo Scarpim

Very nice!

Collapse
kerthin profile image
Roden Author

Thanks

Collapse
dev_sarkar123 profile image
Dev Sarkar

Wow. Really It is a very interesting Animation. Thanks for sharing this.

Collapse
bryanmatthews23 profile image
Bryan Matthews

CodePen keeps giving me an 'Unknown word' message for this line of code:

{percentage($i*(1/$steps))}{

Collapse
bryanmatthews23 profile image
Bryan Matthews

The SVG version in CodePen also keeps giving me an 'Unknown word' message for this line of code:

{percentage($i*(1/$steps))}{