CSS Tricks: Before and After!

pica-ae's avatar
By pica-ae   |   Watch
106 40 9K (1 Today)
Published: May 7, 2014
No, this is not about a tv show in which I take a CSS and make it prettier ;)
It is about the pseudo-elements ::before and ::after.

They are similiar for example to the :hover element, meaning that it is not necessary (or possible) to add them to the HTML, but can be controlled purely by writing CSS. They are always there, but whether they are visible depends on whether you code them or not.

::before and ::after are almost self-explanatory pseudo-elements. They define what happens either before or after a regular HTML element. They can be applied to any element.

Let's get right going!

So in the first simple example we are going to add guillemets, also known as French quotation marks, to direct speech in our text. The usefulness of this may stand to debate, you could easily just type it out, but it is a nice and easy way to get started with explaining ::before and ::after.

We will take advantage of the i HTML class for this. Opposed to em it will not add emphasizis to the content, but an indication of different semantic meaning to the rest of the text; direct speech is what we are aiming for.

<i>Lorem ipsum.</i> he said. <i>Lorem ipsum!</i>

Lorem ipsum. he said. Lorem ipsum!

Because i renders text in italics, I will change the font-style to normal. Below that you can see content being added to the :before and :.after elements. You only require one line, which tells what to render, in this case guillemets before and after the direct speech. They will use the same font and text settings as the containing box, unless we specify new ones.

i {

font-style: normal;


i::before {

content: "«";


i::after {

content: "»";


Lorem ipsum.
he said.
Lorem ipsum!

The guillemets may not display on your browser, they sometimes do on mine, sometimes they don't. I cannot use the ASCII code for them either, dA does not validate the skin if I do that.

This is the most basic way of using the ::before and ::after to your advantage. The content can be any written content or nothing.
By not adding any other styling except for the content, the text inside the content will be styled the same way as the text in the element it refers to; In our example i.

If you do not add the line content: " ";, nothing will be displayed!

But we can do far more with these two pseudo-elements as they can be styled with all possible properties.

Practical Usage

There are many ways in which you can use the ::before and ::after elements to your advantage.
  • Indicators on links, f.e. here on dA you will find username icons [ pica-ae ] and external links [ google.com ] are using the ::after element.
  • To add appearence or content to HTML elements you can only edit via CSS. This is the case for most Content Managment System based websites, on dA it means: if you are using someone else's HTML (like when creating a journal skin on dA) you cannot add HTML elements like <span> to the title of the journal.

Application of ::before and ::after

Here are some examples of how to use these pseudo-elements in your designs.

Using images in ::before and ::after

The scenario in the first example is a short paragraph with a headline. You may want to add images to the headline to highlight it further than just with a bigger font size.

<h1>Sed ut perspiciatis unde omnis</h1>
Iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.

So this is how the HTML for our content could look like. I added the regular text just for demonstration purposes, we won't do anything with it.

The CSS may seem a bit more complex at first, but it can be broken down into bits that will all come together as being really simple.

The <h1> element will be blue, bold and bigger than the copy. What we want is two different images to be displayed before and after the headline.

One way of solving this issue is by using the ::before and ::after pseudo-elements.

h1 {

color: #2864ff ;

font-size: 18px;

font-weight: bold;


h1::before {

content: " ";

display: inline-block;

background: url("…/img_before.png");

height: 20px;

width: 12px;

margin: 0 0 -3px 4px;


h1::after {

content: " ";

display: inline-block;

background: url("…/img_after.png");

height: 20px;

width: 12px;

margin: 0 4px -3px 0;


And as easy as that, we have two cats facing away from our headline on each side!

Sed ut perspiciatis unde omnis.

Iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.

Here's why I did what I did:

This has to be set to at least " ". Without that line, nothing will appear, no matter what else you write. Yes, I am repeating this. I have forgotten it often enough and got mad not realizing what was wrong.

In order to actually see the element, if it has no content, you will also have to tell it to be visible. I am going for inline-block, because it creates a block element BUT it does not create a whole width element.
If I was to use block, I would also have to use floats to place the element and I want to save that line of code.

height & width
They are needed to display the element as well. If they are not set, they are assumed to both be 0. It is best to set them to the exact dimensions of your image.

Vertical margin is applied to position our cats better according to the text. The surface the cats are sitting on was supposed to be at the same height as the baseline of the text. This may require some adjustments and testing out.
Horizontal margin is applied on one side only, to create a better spacing between cat and headline.

Bullet points

If you have ever wanted to change the color of a bullet point in a list, but not the color of the font, the first thing to do is go to change the bullet to an image. The problem with that is, if you decided you need the bullet in a different color, you have to change the image and the image URL. Ugh, that's annoying :stare:

<ul><li>Glomtom</li><li>Aferraron</li><li>They name the ship Titanic. Charlie left the door open. We called her "the careless car mechanic". They found the box empty. Those taxi drivers appointed him committee chairman.</li></ul>

:lightbulb: Read up on lists in my CSS Tricks: Lists article.

First thing we do is disable the default bullet points for an undordered list. I am not doing this on the list element, because I may want to display the type for ordered lists still in my CSS.

I do not have to add any CSS to the list elements, they stay default.

The ::before element will now become our bullet point replacement. We can apply any styling we want to this, and it will not be applied to the list element's text.

There is a bit of math required for all the positioning, but it's not that bad ;)

ul {

list-style-type: none;

margin-left: 14px;


ul li::before {

content: " ";

display: block;

float: left;

background: #2864ff;

height: 8px;

width: 8px;

margin: 6px 6px 0 -14px;


  • Glomtom
  • Aferraron
  • They name the ship Titanic. Charlie left the door open. We called her "the careless car mechanic". They found the box empty. Those taxi drivers appointed him committee chairman.

list-style-type: none;
This line gets rid of the bullet points. The default bullet would be a filled circle in the color of the list element's text.

Here is where the math starts. The values you use here, depend on the values you apply to the bullet point itself. In this case the value comes from the addition of width and margin-right: 8px + 6px = 14px.

Again, content: " "; is necessary to display the ::before or ::after pseudo-element.

For this example I am using display: block;, to demonstrate the different effects of using different values for display.

Because we have used display: block;, we need to use float: left; to position the bullet points before the list element, yet allowing it to be "inline" with it.

The margin helps further position the bullet point's ::before element. In the example I have applied it top and to right of the element.
You may have to adjust the margin-top depending on the size of the bullet point; margin-right is more a question of preference, as to how far away the text should be from the bullet point.
To make up for the margin-left we applied to the li element we have to add margin-left: -14px; to the ::before element if we want everything to be aligned nicely. (Which is the whole purpose of all this margin-left stuff we're doing here.)

The famous arrow & and hover effects

This is a small weak point of mine, that I like to pursue a lot :XD: It is a bit more advanced, as it not only uses ::before and ::after but the appearance actually depends on border values; we merely use ::before and ::after for where we want it to be :D

You'll also see how to code :hover behaviour on elements using ::before and ::after. It is not harder than any other hover, just needs the proper syntax. (Which tbh can be a mind bender sometimes :P )

I will create a custom button class without styling and add the link inside the button div. This I do to seperate between regular links in texts and links in buttons.

<div class="button"><a href="[URL]">I am a button with an arrow end!</a></div>

The simplicity of the HTML unfortunatley is not reflected in the CSS ;)

.button a {

background: #2864FF;

color: #FFFFFF;

display: inline-block;

height: 40px;

line-height: 40px;

padding: 0 10px 0 10px;

position: relative;


.button a::after {

content: " ";

background: transparent;

border-top: solid transparent 20px;

border-right: none;

border-bottom: solid transparent 20px;

border-left: solid #2864FF 20px;

position: absolute;

right: -20px;


.button a:hover {

background: #183d99;


.button a:hover::after {

border-left: solid #183d99 20px;


link display
display: inline-block; will make our element only as long as its content, plus margins and other horizontal elements. block would make the element full width, and we don't want that right now. Not styling this will cause our set height not to render.

link height, line-height & padding
In order to have clean results, we need to set a fixed height for our element. Applying a line-height of the same value as the height will help us center the text vertically.
Since we have a fixed height with a new line-height, we only have to set padding to the right and left of our element.

link position
Applying position: relative; here, will make it possible to position the ::after element absolute later in the CSS.

::after content
Again, again, content: " "; is necessary to display the ::after pseudo-element.

::after borders
It may come as a surprise that we can use borders to create arrow shapes :XD: But the way borders are set up makes this possible.
If you ever looked closely at a picture frame, you will have noticed how for the corners the seperate pieces of wood are cut at a 45° angle. The same thing is going on with borders in CSS. Now if you now imagine a frame that has no content, the seperate pieces of wood become basically just 4 triangles whose tips meet in the middle.
What we have to do in CSS to make this work is quite simple: The border we want to be the pointy bit has to have a border-color, while those who are on each side of our pointy site have to have a transparent border-color. The fourth side we don't need to touch, if we don't define it, it simply won't show. (I have set it to none in the given example, just to cover everything.)
All "visible" borders need to be solid and not bigger than half the height of our element; in this case they are 20px wide, half of our element's height: 40px;.
Because it is possible to set a border-color to transparent, we can create the pointy shape we want.

::after position
We are using position: absolute; to place the ::after element exactly where we need it. It will by placed right: -20px;, outside of our link. The value is the negative version of our pointy border-width we used before.

As a hover effect we will only change the background of the button link. For a, we will do it normally, simply adding on to the end of our selector .button a:hover.
In order to change the border-color of our arrow, we stick the ::after behind the regular hover: .button a:hover::after.
As normally, we only write the values we want to change, the background-color of the link and only the styling of the border for border-left.

Disclaimer: I did not come up with the idea to create arrows this way. But I can't remember where I read it for the first time. But considering the history of CSS, this method of creating arrow shapes is around for ages already. Longer than ::before and ::after I am sure.


  • ::before and ::after are always avaiable for all elements and do not require HTML code to be written.
  • When using ::before and ::after it is necessary to always add content: " "; declaration or it will not show.
  • The ::before and ::after pseudo-elements can display text, images or shapes; basically anything that can be created with CSS.

Do not hesitate to ask me questions if you don't understand anything or want clarification :)

Happy creating :peace: :heart:

Have a suggestion?

Let me know in a comment or a note. I'd love to hear what you want to know and learn. With your input and suggestions this series can continue and grow.

© 2014 - 2019 pica-ae
Covering the ::before and ::after pseudo-elements.
Learn how to add images, create custom bullet points and arrow shapes to these elements. Actually the arrow thing works with borders, but no need to be nitpicky here :P
It's a rather long tutorial in the end and may not be for beginner level. Knowing your way around CSS helps to code the pseudo-elements and it will save you some frustration :)

If there is something you want to know/learn about regarding journal skins and/or CSS/HTML, let me know and I will add it to future tutorials La la la la
I am always looking for ideas for new tutorials and by knowing what you want to learn, I can do so in a much better way :XD: 

Previous CSS Tricks

:bulletgreen: Limiting .text width

Any questions? Just ask :eager: by darkmoon3636

I hope you like this and find it helpful Heart Peace
anonymous's avatar
Join the community to add your comment. Already a deviant? Sign In
ShinobiWarriorDance's avatar
ShinobiWarriorDanceStudent General Artist
Shame we cannot use filter property here on DA Would have been nice to do some animation stuff aswell.
TopHat-Queen's avatar
TopHat-Queen Digital Artist
The content glitches when you have ::after and ::before in the yellow space; it's covering up the 'the'.
pica-ae's avatar
pica-aeProfessional Interface Designer
Oh I see... I need to fix that! Thanks for spotting it :) 
TopHat-Queen's avatar
TopHat-Queen Digital Artist
Sure c:
lauraypablo's avatar
lauraypabloHobbyist Digital Artist
thank you so much for all your tricks :heart:
pica-ae's avatar
pica-aeProfessional Interface Designer
I am just glad they are helpful :aww: :hug:  Thank you! :la: 
MurPloxy's avatar
MurPloxyHobbyist Artist
Are there any list of Div Classes in Deviantart? Cuz customizing the Custom box is totally harder than the Journal.
pica-ae's avatar
pica-aeProfessional Interface Designer
You should check out CustomizeYourProfile. They have galleries full of tutorials on custom boxes :) 
There is no official list, I've also been collecting information from various of their resources :nod: It's a bit trickier, cos as opposed to skins, styling custom boxes is actually a bug that's accepted by DA, so it's not as easy :B 
MurPloxy's avatar
MurPloxyHobbyist Artist
awww. well that's why.

I only need some specific class that will position my div on the left side of the box...cuz im putting another div just beside it. The problem is , is that my code centers the div on the custom box. And when i try to attach another div, it goes on the bottom of it.

Srsly they need to list these things up XD
pica-ae's avatar
pica-aeProfessional Interface Designer
Yeah, so most resources are just "work-arounds" really :B

Maybe this can help you with the problem: Fun with Columns . It gives some code for div-elements that can appear side by side.
By default div-elements always take up a whole line, unless specifically coded to not do that. So if you put two divs into the same line, that work the default way, there will be a line break after the first div.
MurPloxy's avatar
MurPloxyHobbyist Artist
NOICE! this will work well for my 3rd custom box(which i've been working on for a while XD). I wonder if i can make 3 of those columns

Hope this works well on mobile. Cuz i found a way how to solve this, but when i looked at my mobile...oh god, what a mess. :iconfuckyeahguyplz:
pica-ae's avatar
pica-aeProfessional Interface Designer
I think any code that changes the width of the widget's content, will not display properly on mobile browser. 
Actually I just noticed that some code must have changed, cos some of my own boxes are displayed weirdly now :lol: That's the problem with widgets, since coding them is only an accepted bug by DA, they may change a class's styling in the CSS and then a widget code may not work anymore. :shrug:
MurPloxy's avatar
MurPloxyHobbyist Artist
Somehow, from the moment of the first converse line, This is slowly making sense for me XD

now you're saying that coding the widgets are hella buggy. Makes sense why i have to do some kind of  Mano-a-mano with it all the time.
pica-ae's avatar
pica-aeProfessional Interface Designer
It took me ages to understand all that stuff about coding profile widgets :slow: Cos it's stealing code that exists and it may be more complex or weird than you would do it yourself.

The thing is just that any code used in widgets is just using some code from DA. And that code is not "safe", it may change at any time, because it's not intended to be used in widgets the way we use it. So, a lot of the deviations and tutorials may not work anymore, because the underlying CSS/HTML was changed by DA. 
View all replies
ptrckr's avatar
ptrckrHobbyist Photographer
Super awesome, huge respect for all the work you did there. :thumbsup:

Just two things that you surely already knew but content can be empty and does not have to contain a space, and also not all browsers are supporting the :: syntax right? dA dropped support for older browsers so it shouldn't matter here, just in case someone is using it for anything else then dA. :iconumplz:
pica-ae's avatar
pica-aeProfessional Interface Designer
Thank you :hug:

I never managed to make it work with nothing between the quotation marks, but sometimes I used the wrong quotation marks, so who knows :lol: … actually they are not really quotation marks, typographically speaking. Not the German ones anyway, different story :stare: some fucked up thing they did with keyboards :shrug:

For Firefox and Chrome it's pretty much safe, IE is as always a problem, but it does after IE9. I could add as a tip that you can do both by a comma in the same rule. 

Well, it's not like DA doesn't work at all on older browsers. They tell you to upgrade and that some things won't work, but the main functions remain. And the browsers not supported by DA anymore are the same ones most other websites don't offer support for, either. I've got my old Mac and I have the warning on pretty much every site I visit :lol: 

But it's a good hint either way, I always tend to ignore support on different browsers :B
ptrckr's avatar
ptrckrHobbyist Photographer
You're welcome. :hug:

Really? It worked for me every time. I'm just using the same quotation marks as always while coding. «'» and «"».
Yeah, those punctuation is some serious business, especially those dashes. /facepalm I've been using the wrong ones all the time.

That would work, yes. :'D I also think the new syntax with the double colon looks way nicer. :'B

Some website do have some really awesome messages which tell you to upgrade. :giggle:
What old mac do you have, I'm curious? :'D

pica-ae's avatar
pica-aeProfessional Interface Designer
Might be some time ago, since that made issues. Haven't tried it with „German“ ones yet :lol:

In the editor the colon and semicolon look so similar, I spent so much time getting mad at something not working, only to find out I made a typo :|

That is the old old one again, since the new one broke, so it's about 8 years old or something. PowerPC G5 (I think) without Intel chip, so my OS is 5 years old or something :slow: BUT a new PS is on its way :eager:  (omg windows :fear: )
ptrckr's avatar
ptrckrHobbyist Photographer
Haha, yes. That happens to me also from time to time. :giggle:

Nice. :'D
PS? :paranoid: Power Station or do you mean PC? :slow:

Eeeek, Windows. :B
pica-ae's avatar
pica-aeProfessional Interface Designer
PC and PS actually :slow: 

Yeah, I let myself get talked into it, cos money :B 
ptrckr's avatar
ptrckrHobbyist Photographer
PS for Photoshop, right? :'D

Ugh, money.
Have Fun with your new machine then. :giggle:
pica-ae's avatar
pica-aeProfessional Interface Designer
yes :XD:

I am sure I will have fun :la: 
TarynNefdt's avatar
TarynNefdt Digital Artist
Well done. I love this series. I would really love you to do a CSS Tutorial on Vertical Navigation and Horizontal Navigation Menu Bars as well - if you don't mind :-)
pica-ae's avatar
pica-aeProfessional Interface Designer
Thank you :)

I've sort of covered the horizontal menu in the previous tutorial fav.me/d6ub7t1 about lists, but I could do something about those two in special. Thanks for the idea! :la: 
I could reuse some of that, and add the vertical menu :nod: 
Did you mean in general on in regards to installable journal skins on dA? Because the one's on dA may require a slightly different approach as we are applying a CSS to an existing layout. 
anonymous's avatar
Join the community to add your comment. Already a deviant? Sign In