How to properly center CSS pseudo elements

Pseudo elements are great when you want to add that something that will make your page or app shine. There times though when you want to center those before or after pseudo elements and using percentages doesn’t do it. Going with the plain old margin: auto trick or using flexbox doesn’t quite work either. In this quick post I’m going to explain how you can perfectly style your pseudo element and be sure that it will work no matter the resolution or font-size or whatever.

Let’s say that we want to create a button like this one below. It kind of looks like an eye.

eye1

Obviously we need to first design the outer circle. Let’s make something big and go for 250 pixels:

width: 250px;
height: 250px;

We want it round so let’s also add 100% border radius:

border-radius: 100%;

White background:

background-color: white;

We will be absolutely positioning a pseudo element later so we need the container element to be positioned relatively:

position: relative;

A subtle border:

border-style: solid;
border-width: 1px;
border-color: #e8eef6;

When it comes to borders I generally try to avoid the shorthand notation because to me it seems easier to comprehend when the properties span different lines.

Also, a subtle box shadow created shamelessly using the Chrome Dev Tools:

box-shadow: 0 0 6px 1px #e8eef6;

And let’s add some typical margin:

margin: 12px;

So with those rules in place you will be getting something like this:

eye2

We’re done with the easy part, we’ve successfully designed the outer circle. Now to the inner one.

Let’s set the size of the inner circle to 50 pixels and use a variation of blue for its background color:

 content: "";
 position: absolute;
 width: 50px;
 height: 50px;
 background-color: #1c5ba2;
 border-radius: 100%; 

Now before doing anything else, if we check the result we have this monstrosity:

eye4

The inner circle naturally resides on the upper left corner of the container element. We need to move it so let’s use the top and left properties:

left: 50%;
top: 50%;

eye5

Well.. It’s actually better than before but we’re nowhere near our desired end result. But why is this happening you might ask? We used percentages right? 50% from the top and 50% percent from the left should be enough to place this pseudo element right at the center of its container. Well this may sound reasonable but it isn’t if you know the internal details of how CSS works. You see, this would work fine if top: 50% meant “Place the center of the pseudo element 50% from the top” and left 50% meant “Place the center of the pseudo element 50% from the left”.

But what top: 50% actually means is: “Place the pseudo element’s 50% from the top” and left: 50% means “Place the pseudo-element’s left-most point 50% from the left”. That’s how CSS works. That’s why the inner circle was placed on the upper left corner of the container element before we moved it. Elements are placed from left to right and from top to bottom.

The solution to this will be to move the center of the inner circle to the center of the outer circle. We can do that by using negative margins. We’ve defined the pseudo-element’s size (width = height since this is a round element) equal to 50pixels. That means the element’s center, the circle’s center is 50/2 =25px from the left and 50/2 = 25 25 pixels from the top. We can add those numbers as negative margins:

margin-top: -25px;
margin-left: -25px;

And poof! Problem solved!

eye1

Bonus: If you’re using a CSS pre-compiler like Sass you can take it one step further and only have one single number that describes your shape. The outer circle’s size. Everything else can be computed using mathematical operations. Check the following fiddle for more on this: