MKBHD logo animation | Step by step SVG and CSS tutorial

In this post I'll walk through the steps taken to create an animated loading animation in CSS and SVG for MKBHD, or Marques Brownlee. I've been following Marques on YouTube for years. His tech reviews are top notch, and his passion for high quality videos is obvious in every upload. If you don't already subscribe to his channel, go do that now, you won't regret it. For this tutorial, I've included the steps to take in Sketch too since a lot of you were asking for it. Let me know if this is something you'd like to see more of though. :)

I originally posted the animation on Twitter and didn't expect much, until the man himself saw it, replied, and retweeted it. The response was incredible and I'm really greatful. Marques if you're reading this, thank you!

Creating the SVG graphic in Sketch

NB: Click here if you want to skip the actual graphic part of this tutorial and get straight to the code part where we'll animate the logo with some buttery smooth 60FPS CSS animations.

I create all my vector graphics in Sketch. I find it's really great for these types of projects. It's not free, but it has a free trial so you can try it out at no cost. I'm not an affilliate of theirs, but I really should be :D.

To get started, create a new Artboard. Hit "A" on your keyboard and drag a new artboard across the screen.

create-artboard-2

Make the artboard a square shape, 400x400 (1). I find this size works best for most of my loading animation projects. I've also gone ahead and color-picked the dark grey from MKBHD's logo and made the artboard background that colour, 3D4346 (2).

Next, we'll start drawing the actual logo. For the purposes of this animation, I've broken the logo out into 3 pieces.

logo-elements

The #white element sits on top of the #red element in terms of order. Then the #redoverlap element sits on top of them all to achieve the visual effect of one element slotting through the other.

To make the polygon shapes you can use the Rectangle tool and then free transform the element so that it skews to the right angle. Protip: screenshot the logo and trace over it so you get it as close as possible to the real thing.

The final thing we need to do in Sketch is to add the four white progress bar segments that gradually appear as the animation progresses.

To make them, I simply rotated the #red element so that it was level. For me this was about -28 degrees.

angle-comp

I then filled that shape with four equally sized polygons, making sure that they were seated behind the red outer shape.

We're almost finished with Sketch, but first we need to make sure our layers are named appropriately. This makes our lives easier later when we're targeting certain elements with CSS.

names-tiny-1

I named my layers in a way that made sense to me. You can make them whatever makes sense to you, but you'll be referencing those names in the code later so make them easy :)

Next step is to export our creation as SVG.

export-tiny

Make sure you have the format set to SVG (1), and then export your file to a location of your choice (2). Remeber where you save it, you'll need to go there in a second and copy the code to a codepen.

Tools and prerequisites

I use Codepen for most of my animations. It's really handy for seeing your code changes straight away. It also makes it easy to include resources like Bootstrap. Including a whole library is a little overkill, but it gets me set up quickly and I'm familiar with it, so for development purposes, it's fine.

The browser I use is Chrome, for the simple fact that it doesn't need any prefixing for the animations to work. We'll need to remember this when we're finished coding though, and run our CSS through an auto-prefixer so everything works ok in other browsers.

Animating the logo with CSS

Getting started with CodePen

You can use the codepen below to get started. Open it up and click "Fork" in the top right of the screen to create your own version of this pen.

Open up your SVG file in a text editor and copy-paste your SVG code onto the paragraph element in the pen.

See the Pen MKBHD-loading-animation-1 by Chris Dermody (@ChipD) on CodePen.


You should now have something that looks like the below.

start-tiny-1

Initial CSS to hide the progress bars

First things first, we have the 4 progress bars visible at the moment. We need to hide these.

In the HTML section of the pen, you can see that there are 4 elements with ids progress1, progress2, etc. We can add the following CSS to hide them.

#progress1,
#progress2,
#progress3,
#progress4{
  opacity: 0;
}

Your codepen should now look like the pen below.

See the Pen MKBHD-loading-animation-3 by Chris Dermody (@ChipD) on CodePen.

Initial CSS to rotate the 'redOutline' element

The first part of the animation is to rotate the red element by roughly 28 degrees (remember we found that earlier in Sketch?).

In the CSS panel, add the following rules.

#red {
	transform-origin: 50% 50%;
	transition: 0.25s ease;
}

#red.loading{
	transform: rotate(-27.5deg) translate(-2px,0)
}

Let's walk through the properties here.

transform-origin: 50% 50%; moves the origin of the element to its centre. This sounds complicated, but it just means that when we apply a rotation, it'll rotate about its centre.

transition: 0.25s ease; defines how long a transition applied to this element will take (0.25s, in this case), and then defines the easing. Easings.net is a good resource for visualising the different values that could go here (check browser compatibility though).

transform: rotate(-27.5deg) translate(-2px,0) is what actually does the magic. We're telling it to rotate the element -27.5 degrees (28 was a tad too much), and we're also translating (moving) the element a tiny bit. I had to do this to make it look just right.

The reason we have the transform in a seperate CSS rule is so that we can add and remove the animation with some Javascript, by adding or removing the .loading class.

Some Javascript to make the magic happen

In order to simulate the "loading" state of the animation, we'll add a Javascript function. This function will add the loading class to elements that need it.

At this stage we need to make sure that we have the snapsvg.io library installed. This is essentially jQuery, but for SVG. We can add it to our codepen by clicking the little cog icon beside the JS panel, and adding it via the CDN link:
https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js

If you forked the pen I shared earlier, this will already be done for you :)

Add the code onclick="startLoading()" to the button element. This will call the startLoading() function when it's clicked.

Next, we need to define our startLoading() function in the JS panel. This is where we'll add the loading class to the elements that need it. We'll start by selecting the #red element and adding the loading class to it using Snap. I'll also use jQuery to hide the button element.

function startLoading(){

    // hide button
	$('.btn.start').hide();

    // set loading class on elements
    Snap.select("#red").addClass('loading')
	
}

Click the button to see what adding the loading class to the .redOutline element.

See the Pen MKBHD-loading-animation-4 by Chris Dermody (@ChipD) on CodePen.

We get a simple transition, but it's the start of our animation. Now, let's add some more CSS and JS to really get going.

Next, we need to hide the #redOverlap element when we're 'loading'. In our CSS, add the following code.

#redOverlap {
	transition: 0.25s ease;
}

#redOverlap.loading {
	opacity: 0;
}

This code is basically saying "When the redOverlap element has the class loading, make it invisivle (opacity:0). Also, make it happen over 0.25s with ease easing".

Finally, add an extra line to your JS, to give the redOverlap element the loading class.

function startLoading(){
	
  // set loading class on elements
  Snap.select("#red").addClass('loading')
  Snap.select("#redOverlap").addClass('loading')

}

Your code should now look like the codepen below. Click the button again to see what happens.

See the Pen MKBHD-loading-animation-5 by Chris Dermody (@ChipD) on CodePen.

Sweet! The red line disappears. Now to take care of the large white block. In my SVG, I've simply named this white. So, like before, we'll add some CSS to animate that element when it has the loading class.

In the CSS panel, add the following.

#white {
	transform-origin: 50% 50%;
	transition: all 0.5s ease;
}

#white.loading {
	transform: scaleX(-1) rotate(27.5deg);
	opacity: 0
}

Let me explain each line of this CSS:
transform-origin: 50% 50%; - We're going to be flipping and rotating the element, this code makes sure that we'll be rotating around the centre of the element by making sure the origin is 50% from the left, and 50% from the top of the element

transition: all 0.5s ease; - This is telling the browser that any animation we add to this element, make it half a second long and use ease easing.

transform: scaleX(-1) rotate(27.5deg); - This is the magic of this animation, and gives the white element the cool "flipping" effect.

scaleX(-1) is what "mirrors" the element along its X axis. Then, at the same time, we're rotating the element 27.5 degrees, so that it appears to fit right into the redoutline element.

opacity: 0 is what makes the element invisible.

Then in our JS, we need to add a line that gives the white element the loading class, to apply the animation when the button is clicked.

function startLoading(){
	
  // set loading class on elements
    Snap.select("#red").addClass('loading')
	Snap.select("#redOverlap").addClass('loading')
	Snap.select("#white").addClass('loading')

}

And now, you should have a codepen that looks like the one below. Click the simulate loading button to see what our recently added code does.

See the Pen MKBHD-loading-animation-6 by Chris Dermody (@ChipD) on CodePen.

Adding the "progress" steps

We've gotten a lot done! But there's more to do. Now, we need to add the 4 white elements that appear as the "loading" completes. For the purposes of this animation, all I did was add a Javascript function that sequentially reveals the elements in order.

But first, the CSS. Add class="progressBlock"to each progress element in the HTML.

Next, the CSS to reveal the elements. Earlier we added the rule to hide the .progressBlock elements. We'll add another CSS rule under that one that will animate those elements when the loaded class is applied.

.progressBlock {
    opacity: 0;
    transition: 0.25s ease;
}

.progressBlock.loaded {
	opacity: 1;
}

We've used these rules before, you should know them off by now. :)

And finally, the JS to give them the loaded class. For the purpose of the animation, I just created an interval that would run every 500ms and add the loaded class to each element in sequence.

Here's the full JS so far.

let timerId;
let progress;

function startLoading() {
	// set loading class on elements
	Snap.select("#red").addClass("loading");
	Snap.select("#redOverlap").addClass("loading");
	Snap.select("#white").addClass("loading");
	
	progress = 0;
	timerId = setInterval(frame, 500);
	

}

function frame() {
			
	if(progress === 25 ){
		Snap.select("#progress1").addClass('loaded')
	} else if (progress === 50){
		Snap.select("#progress2").addClass('loaded')
	} else if (progress === 75) {
		Snap.select("#progress3").addClass('loaded')
	} else if (progress === 100) {
		Snap.select("#progress4").addClass('loaded')
		clearInterval(timerId);
	}

	progress += 25;
			
}

You can see that I have 2 global variables, timerId and progress. The frame() function is where the magic happens. It runs every hald a second (500ms), and checks the value of progress. It then reveals the appropriate element by giving it the loaded class we defined earlier.

The effect can be seen in the pen below.

See the Pen MKBHD-loading-animation-7 by Chris Dermody (@ChipD) on CodePen.

It's starting to look pretty good, but we're not finished yet.

We need to add a little more Javascript to remove the loading and loaded classes from all of the elements we just added them to. This will effectively reverse the animations they had earlier.

In the JS pane of your codepen, add the code below.

function finishLoading() {
	// remove loading/loaded classes from all elements
	Snap.select("#red").removeClass("loading");
	Snap.select("#redOverlap").removeClass("loading");
	Snap.select("#white").removeClass("loading");
	Snap.select('#progress1').removeClass('loaded')
	Snap.select('#progress2').removeClass('loaded')
	Snap.select('#progress3').removeClass('loaded')
	Snap.select('#progress4').removeClass('loaded')
	
	// show button again
	$('.btn.start').show();
	
}

See what this does in the codepen below.

See the Pen MKBHD-loading-animation-8 by Chris Dermody (@ChipD) on CodePen.

One last thing - cross-browser compatibility

At the start I mentioned how Chrome is the best browser to use for making these animations as it doesn't need any prefixes. But, we need to consider all browsers, or at least as many as we can.

Thankfully, this is fairly quick and easy with online prefixers. My current go-to is autoprefixer.github.io. I just copy-paste the CSS in there, and it adds all the prefixes we need.

And that's it! We've used some fairly simple CSS animations to make an animated loading animation with SVG, with only some Javascript for adding and removing classes as required, and made it all cross-browser compatible.

What did you think of this write-up? I hope I covered everything you came here for. Let me know in the comments below, and if you want to learn more about how I make these animations, make sure you subscribe below.

I'm @cderm on Twitter, or if you'd like to get in touch by email just reply to the welcome email you'll get after you subsribe. I read and reply to all of them.

If you'd like to know how to make this into a GIF, check out my quick post on that here.

You've successfully subscribed to Chris Dermody
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.