Pseudo-Elements

In this tutorial I talk about Pseudo elements. There are lots of use cases for these elements and in this tutorial I demonstrate one use which is to add a special character to menu items that have sub-menus hidden underneath them.

See the Pen Psuedo-Elements by Lisa Catalano (@lisa_c) on CodePen.

Preferred Learning Method?

Code Snippets
If you just want the code and don’t need a description.

Watching a Video
If you like being shown how something works with some explanation watch the video.

Reading a description
If you learn better by reading, I am including the transcript of the video with corresponding code snippets embedded.

Video

If you would like to follow along with the video:

Starting code here

Code Only

See the Pen Psuedo-Elements by Lisa Catalano (@lisa_c) on CodePen.

See the Pen Psuedo-Elements by Lisa Catalano (@lisa_c) on CodePen.

Transcript

Pseudo-elements are a way to add actual content to your page using CSS only. Of course, in normal circumstances you want your content to be found in the HTML. But there are plenty of use-cases for psuedo-elements where you might want to add something to the page for presentational reasons.

One example is in the Drop Down Navigation that I created in my last tutorial. If we look at the menu, there are two menus with drop down sub-menus that are only displayed when you hover over the menu. There is nothing to indicate to the user that there are more options underneath.

I’m starting with the code from my Drop Down Navigation example. I am going to add a class name to any menu items with a sub-menu. I’ll just call it sub.

Now I can target those items with .sub.

If I add the ::after to the sub selector I will be able to add some content “after” the selector.

I do that by specifying content as the property, and then whatever I want to add as the value, inside quotes. Whatever I type, will get added after the selector that I’m targeting.

This is not really what I want. If I open the Developer Tools, and inspect the item… I do need to refresh the page so I can look without the Live Preview hooks in here. Now we can see this element ::after at the end of the of the li tags with a class of sub. It comes after the sub menu which is why we see it on a new line. We don’t actually see the > that I added, we see the element “::after”. The > comes from the CSS which you can see when you look at the element’s styles.

I really want this to be added at the end of the anchor tag, like this.

You might wonder why not just add it directly to the HTML. Well of course you can do that, but if you have a really complex navigation that changes, it is easier to target all of the menus that need the character with a class name, like ‘sub’ instead of having to update the HTML every time your menu structure changes.

This content could be anything. It could be many characters or an image that you specify with a url.

I’d like this to be a triangle instead of a > symbol. We can use a character for that instead of an image.

There is a nice website that shows you symbols that are available to use using character codes.

www.graphemica.com

If I search for right triangle, I have lots of options. I want to use this small right pointing triangle.

It is telling me the Unicode character, but if I put that in the content it won’t work. It will just display those characters.

We can see the HTML entity, but that doesn’t work here either. We could use that if we were adding the content directly to the HTML, but if we used it here it would just display the characters.

Instead, if I scroll down and find the Source Code section it tells me the way to represent this character in CSS. Basically it is the same number from above “25B8” with a \ 0 in front of it instead of the U+.

So if I make that the content, it works. We see a nice right-triangle right there.

One of the nice things about psuedo-elements is that they can be styled. I’d like to move the triangle over just a bit, so I can add a margin-left of 3px and the character will have a little breathing room.

  .sub a::after {
    content: "025B8";
    margin-left: 3px;
  }

I could change the color also if I wanted.

color: hotpink;

I’d like to change the character to be pointing downward on hover. We could handle that by tranforming the character with a rotate, or we could just find a downward facing triangle to set as the content.

I’ll search for “down triangle” and I can use this character.

I want to target .sub:hover a::after and I can assume the CSS version of this character is \0 plus the characters I copied.

  .sub:hover > a::after {
    content: "25BE";
  }

Now when we hover, the we can see the character change.

I need to fix my selectors so the triangle only gets added to the top anchor tags. I can do that by adding the > to my selector so only anchor tags that are direct descendents of .sub will be targeted.

  .sub > a::after {
    content: "025B8";
    margin-left: 3px;
  }

  .sub:hover > a::after {
    content: "25BE";
  }

Now I’ve been talking about ::after, but there is also a ::before pseudo-element, which as you might guess will add some content right before your element. It works exactly the same.

I mentioned already that you can use an image for the content insert.

I could add an image before my navigation items by specifying a url for the content. I’m using the direct descendent selector again so I don’t get the sub menu items.

  .nav > ul > li > a::before {
    content: url(http://css-snippets.com/favicon.ico);
    margin-right: 3px; 
  }

I don’t really want this image, but just wanted to demonstrate how that works. This technique could be used for navigational icons.

So that’s a quick look at pseudo-elements. You probably don’t want to use them to insert real content into your web-sites, but for adding some presentational elements or decoration, they can be very useful. There are many interesting things that have been done using these elements and you can find many examples all over the web.

One of the most common uses is to use an ::after element as a clearfix solution when you are using floats. I have talked about that solution in a previous tutorial, called Clearfix Solution.

If you have any questions, please let me know.

Drop-Down Navigation with CSS only

Note: This is an update of an old popular post.

In this tutorial I show how to make drop-down navigation using CSS only. This tutorial starts with the code that I presented in the Simple Horizontal Navigation tutorial.

See the Pen Drop Down Navigation (CSS Only) by Lisa Catalano (@lisa_c) on CodePen.

Preferred Learning Method?

Code Snippets
If you just want the code and don’t need a description.

Watching a Video
If you like being shown how something works with some explanation watch the video.

Reading a description
If you learn better by reading, I am including the transcript of the video with corresponding code snippets embedded.

Code Only

See the Pen Drop Down Navigation (CSS Only) by Lisa Catalano (@lisa_c) on CodePen.

See the Pen Drop Down Navigation (CSS Only) by Lisa Catalano (@lisa_c) on CodePen.

Video

If you would like to follow along with the video:

Starting code here
Ending code here

Transcript

In this video I’m going to talk about how to create a Drop Down navigation menu using CSS only.

Before I start I should mention that this technique is not great for small screens or mobile websites. I’ll still approach this from a mobile-first perspective, but the solution I present is not perfect for small screens. I’ll tackle how to make it better in a future video.

I’m starting with code I presented in my Simple Horizontal Navigation tutorial. You might want to watch that video first if you don’t understand all of the code I am starting with.

If you want to follow along you can grab the code from my GitHub repository named “dropdown”. I’ll post a link.

I’m using the Brackets code editor so I can see the Live Preview as I work. You can see that this is a simple navigation that has different colors on the active item and also when you hover.

When I created this navigation I used a mobile-first approach and I started with a simple vertical navigation menu that changes to horizontal on larger screens.

HTML Changes

To add sub-menus, you simply need to add a nested unordered list inside the top menu item.

So if I want a sub-menu under Tutorials, I can go to that li tag and inside of it, insert another ul tag and some li tags for each menu item with a link inside. The syntax is just like the top level menu, just nested inside. I’m adding 3 menu items with some Emmet shortcuts.

I will also create a sub-menu for Newsletters.

          <ul>
            <li><a href="#">Tutorial #1</a></li>
            <li><a href="#">Tutorial #2</a></li>
            <li><a href="#">Tutorial #3</a></li>
          </ul>

Now this looks terrible on both the small screen and larger screen.

I’ll work on the small screen first.

CSS Changes for the Small Screen

The reason this is unreadable is because the sub-menus are rendering on top of the main menu. That is because there is a height property under .nav li. The list items with sub-menus are only given 40px which is not enough to contain the sub-menus.

If I remove it, the height will default to auto instead which means the browser will calculate the height needed based on its contents. Now we can see all the menu items.

The new problem is that the font size for the sub menu is larger than the top menu.

That is because I specified the font-size with the em unit. Ems are calculated based on the font-size of the parent. And when you have nested elements, that can cause a multiply effect. In this case, the sub menus are getting a font-size that is 1.2 times as large as the main menu.

So using ems can be frustrating when you are nesting things that specify a font-size.

There is another unit of measure called rems which stands for “root ems” and will always base its value on the root element instead of the parent. That means you avoid the cascade and the multiplier effect.

I will change the unit of measure to rem.

Now all the items are the same size.

However, rem does not work in IE8 and below so if you need to support that you need a different solution. You could use px instead.

I actually want the sub-menus to be smaller text, to help distinguish them from the top menus. So I am going to create a new selector for the sub menu li tags and then I can specify a different font-size.

If I specify the li that is inside of another li it will target the nested lists items only.

When I set it to 1em, you can see that the size is consistent.

/* Sub Menu code */
.nav li li {
  font-size: 1em;
}

But I’ll set this to .8em so that it is a little smaller.

I don’t like the text centered with this longer menu. This is coming from this text-align: center here on the unordered list. I want to leave this on the ul tag because I want this menu centered on big screens, but I will make the li tags have left alignment.

So I’ll add text-align: left to .nav li.

Then I need to add some padding so it doesn’t hug the left. If I add that to the list item, the border gets mess up, so I will move that line to the anchor tags.

(.nav a)

padding-left: 15px;

The final problem on the small screen menu is that the border is not showing up in between all the lines.

I have the border at the bottom of the list items, but since the bottom of the Tutorials or Newsletter list item is underneath the sub menu, the main menu list item doesn’t get the border.

Instead I’ll move that line of code down to the a tag also.

Now the small menu looks better.

CSS Down-Down Navigation on Larger Screens

So finally, I can tackle the main topic of this tutorial and that is how to make the sub-menus only show on hover on larger screens. That actually won’t take much time.

This next part of the code is happening inside of the media query. I am using a breakpoint of 650px because that is how much space the menu needs to be displayed horizontally on one line based on the width of the menu items. You can use ems or whatever breakpoint makes sense for your design.

This code inside the media query will only happen on screens that have 650 pixels or more.

The first thing I’ll do is set the positioning of the sub-menu to absolute, so that the sub menu is taken out of the flow of the document and doesn’t take up height anymore on the main nav bar.

I targeted the ul tags inside of li so that this only applies to the nested menus.

Now I want to hide these sub-menus. I can set the display property to none so the sub-menu does not display.

.nav li ul {
  position: absolute;
  display: none;
}

It is a little hard to see, but the bottom border is peeking out from the main navigation bar, so I want to turn that off on larger screens.

.nav a {
  border-bottom: none;
}

You can see the difference when I toggle this line on and off.

Next we want to display the menu when we hover on the parent menu. So we can target hover on the parent li and then the unordered list.

.nav li:hover ul {
  display: block;
}

The sub-menu is displaying on hover, but it is a horizontal menu. That might be what you want. If so, you could stop and style it so it is placed where you want and looks better.

But I want a vertical navigation.

The reason it is horizontal is because I am using display: inline-block on all li tags inside of .nav. That was to make the main navigation horizontal.

If I want this sub navigation to be vertical I need to target the sub li tags and display them as block;

.nav li ul li {
  display: block;
}

The width of sub-menu is a little short. That is because li’s have a width of 130px, but the background color is coming from the ul tag, which does not have a width set and therefore defaults to auto.

I want the sub-menu ul tags to have the same width as the parent li. If I say width: inherit it inherits the width of its parent, or the list item.

Now everything lines up nicely.

I don’t like that the text is now left-aligned. Remember I fixed that for the small screen.

If I add this code in the media query

  .nav ul  li {
    text-align: center;
  }

It still doesn’t look like the items are centered aligned because of the left-padding I added for the small screen menu. I’m going to ignore that briefly and will fix that in a moment.

Now all menu items are aligned to the center, including the sub-menu. It is not very noticable when all my text is the same width, but if I change one line, you can see it.

I want to center the top menu only. It is easy to target the child menus by adding more selectors, but I can’t do that on the top menu. I could add a class, or I can target the direct descendants of the nav class by using the child selector, which is the >.

See how when I add the child selector, only the top navigation is centered. Well, centered plus 15px of padding on the left.

I can use the child selector again to remove that padding.

  .nav > ul > li > a {
    padding-left: 0;
  }

When I’m using this child selector it will not target the sub-menu anchor tags because they are not direct descendents underneath the .nav div.

The padding-left of 15px will remain on the child menus.

Of course the styling of your menus depends on your actual content and design. You may not like the styles I’m using here and you should adjust to your own preference and design.

The main concept is the hidden menu that displays on hover. And that part of the code is right here. We hide the nested menu in the normal state, and we display it on hover. If you want it displayed vertically, you want to set display to block on the menu items.

The important thing to notice in this code is the selector. I am selecting ul tags inside of li tags. That means it is only targeting the nested sub-menus. It gets a little confusing looking at the different li and ul tags, so make sure you understand that. You could add classes to the sub menus to make things more clear if you want.

Browser Support

This will work in all browsers except IE8. That is because IE8 doesn’t recognize media queries. So we need to put all the code from the media query in the IE8 and below style sheet.

If you are using a pre-processor, you can avoid maintaining duplicate code, by putting the code in a separate file, and importing it into both the main style sheet and the IE style sheet.

So things are looking decent in both sizes.

What’s Next

There are more things to do to this to make it better. As I mentioned the small screen shouldn’t be displayed at the top of the page as is. On a phone, it would probably take up the entire screen. Also, some indicators that there are hidden menus would be useful here so the user knows they can hover to see more. Some transitioning on the drop-downs menus would be nice as well.

I plan on tackling these concepts in future tutorials coming soon.

Thanks for watching, please let me know if you have any questions.