Los pseudo-elementos ::before y ::after ( existen desde CSS2 ) insertan contenido, mediante CSS, delante ( before ) y respectivamente detrás ( after ) del contenido de un elemento html.
li::before{ content: "contenido";}
Los pseudo-elementos tienen que tener un contenido aunque sea solo una cadena de texto vacía.
li::before{ content: "";}
Y lo mejor es que podemos dar formado a estos pseudo-elementos mediante CSS.

¿Tengo que poner los dos puntos dobles?

Los dos puntos dobles ( :: ) fueron introducidos en el CSS3 como un intento de hacer una distinción entre las :pseudo-clases (:link:visited:active:hover:focus:first-child:lang) y los ::pseudo-elementos (::first-letter::first-line::before::after). Por suerte no pasa nada si no ponemos los dos puntos dobles delante de los pseudo-elementos ( ::before ), ya que la mayoría de los navegadores entienden el formato antiguo introducido en el CSS2 ( :before ). Es más: IE8 parece no entender los dos puntos dobles ( ::before ), pero sí entiende los dos puntos ( :before ).

El valor del elemento insertado puede ser:

una cadena de texto: li::before { content: "texto";}
una imagen: li::before { content: url(flecha.gif);}
un contador: li::before { content: counter(index);}
el valor de un atributo: p::before { content: attr(title);}
También puede:
abrir y cerrar comillas: span::before { content:open-quote;} span::after { content:close-quote;}
o restablecer el valor inicial: span::before{ content: initial;}

Insertar un cadena de texto

Veamos como insertar una cadena de texto delante de un párrafo:
p.ejemplo1::before {
   content : "OJO: ";
   color : #d14;
   }
<p class="ejemplo1">Ejemplo de párrafo con texto insertado delante.</p>
Ejemplo de párrafo con texto insertado delante.

Texto con diacríticos o símbolos

Prácticamente podemos insertar cualquier carácter especial, y para insertarlo tenemos que escribir su código hexadecimal precedido por el carácter de escape ( \ )star. En el siguiente ejemplo para escribir la ó de atención utilizamos este código: \0f3.
Una lista de caracteres especiales y el codigo hex para utilizar con los pseudoselectores ::before y ::after en el css.star
  p.ejemplo2::before {
   content : "Atenci\0f3n: ";
   color : #d14;
   }
<p class="ejemplo2">Ejemplo de párrafo con texto insertado delante.</p>
Ejemplo de párrafo con texto insertado delante.

Insertar un contador

Los contadores en CSS son variables que pueden ser manipuladas e incrementadas con reglas CSS como counter-resetcounter-increment y la función counter()
counter-reset
ul{ counter-reset: index;}
En este caso la propiedad counter-reset pone a 0 el contador CSS dentro de la lista <ul class="falso-ol">. La palabra index utilizada con counter-reset es un identificador.
counter-increment
.falso-ol li {counter-increment : index;}
Con esta regla la propiedad counter-increment incrementa el valor del contador "index"
la función counter()
La función counter() toma como argumento el index
.falso-ol li::before {content : counter(index);}
Finalmente la función counter saca en pantalla el valor del contador.
ul.falso-ol{ 
 counter-reset:index;
}
.falso-ol li{
    counter-increment: index;
}
.falso-ol li::before {
   content:counter(index); 
   margin:.5em .5em .5em 1em;
   color : #d14;
}
<ul class="falso-ol">
  <li><a href="http://w3.unpocodetodo.info/svg/trazados.php">Trazados SVG</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/lineas-con-path.php">Dibujar líneas con path</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/cuadratic-bezier.php">Curvas cuadráticas de Bézier</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/cubic-bezier.php">Curvas cúbicas de Bézier</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/arcos-elipticos.php">Arcos elipticos</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/elipse-con-path.php">Dibujar una elipse con path</a></li>
</ul>
  • Trazados SVG
  • Dibujar líneas con path
  • Curvas cuadráticas de Bézier
  • Curvas cúbicas de Bézier
  • Arcos elipticos
  • Dibujar una elipse con path
También podemos especificar el formato de los números del contador, utilizando las mismas palabras clave que las utilizadas con la propiedad list-style-type:
armeniancjk-ideographicdecimaldecimal-leading-zerohebrewhiragana-irohakatakanakatagana-irohalower-alphalower-greeklower-latinlower-romanupper-alphaupper-latinupper-roman.
content:counter(index, decimal);
¡Pero lo podemos hacer más fácil utilizando listas ordenadas <ol>!
Si y NO.
Si queremos dar formato a los números de una lista – y quien no lo quiso alguna vez? – lo podemos hacer utilizando el pseudo-elemento ::before.

Combinando valores

En el ejemplo anterior seria interesante poder añadir un punto detrás de cada numero. Podemos combinar varios valores separándolas por un espacio en blanco.
content:counter(index, decimal) ".";
ul.falso-ol1{ 
 counter-reset:index1;
}
.falso-ol1 li{
    counter-increment: index1;
}
.falso-ol1 li::before {
   content:counter(index1, decimal) "."; 
   margin:.5em .5em .5em 1em;
   color : #d14;
   }
<ul class="falso-ol1">
  <li><a href="http://w3.unpocodetodo.info/svg/trazados.php">Trazados SVG</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/lineas-con-path.php">Dibujar líneas con path</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/cuadratic-bezier.php">Curvas cuadráticas de Bézier</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/cubic-bezier.php">Curvas cúbicas de Bézier</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/arcos-elipticos.php">Arcos elipticos</a></li>
  <li><a href="http://w3.unpocodetodo.info/svg/elipse-con-path.php">Dibujar una elipse con path</a></li>
</ul>
  • Trazados SVG
  • Dibujar líneas con path
  • Curvas cuadráticas de Bézier
  • Curvas cúbicas de Bézier
  • Arcos elipticos
  • Dibujar una elipse con path

El valor de un atributo

En el siguiente ejemplo insertamos el valor del atributo data-title delante del párafo.
p::before { content:attr(title);}
Es interesante remarcar que esta vez para insertar símbolos o diacriticos hay que utilizar el nombre mnemotécnico ( &oacute; ) o el código numérico decimal ( &#243; ) o hex ( &#xf3; ) del glifo.
p.atributo::before{content:attr(data-title); color:#f00; margin-left:1em;}
<p class="atributo" data-title="Atenci&oacute;n: ">Esto es peligroso.</p>
Esto es peligroso.

Como van apilados los pseudo-elementos

En el siguiente ejemplo los pseudo-elementos ::before y ::after insertan contenido, mediante CSS, delante ( before ) y respectivamente detrás ( after ) del contenido del <div id="pila">. Los dos pseudo-elementos tienen display:block, y las dimensiones width y height iguales a las del <div id="pila">. Manipulamos la posición de los pseudo-elementos para que las cosas sean claras. Observamos que <div id="pila"> se queda detrás del pseudo-elemento ::before, mientras que el pseudo-elemento ::after aparece encima del pseudo-elemento ::before.
div#pila{ 
  width:200px; 
  height:100px;
  background-color:yellow; 
  color:#ccc;
  margin:0 auto;
  position:relative;
}
div#pila::before{
  content:"::before"; 
  width:200px; 
  height:100px; 
  background-color:red; 
  display:block; 
  position:absolute; 
  top:25px; 
  left:25px;
}
div#pila::after{
  content:"::after";  
  width:200px; 
  height:100px; 
  background-color:blue; 
  display:block; 
  position:absolute; 
  top: 50px; 
  left:50px;
}
<div id="pila"> Contenido</div>
Contenido
A continuación especificamos para cada elemento el valor de z-index de esta manera: para la caja ( div id="pila" ): z-index = 1 y para los pseudo-elementos: z-index = -1. El resultado: solo el contenido de <div id="pila"> aparece encima de los pseudo-elementos.
div#pila1{ 
  width:200px; 
  height:100px;
  background-color:yellow; 
  color:#ccc;
  margin:0 auto;
  position:relative;
  padding-top:60px;
  text-align:center;
  z-index:1;
}
div#pila1::before{
  content:""; 
  width:200px; 
  height:100px; 
  background-color:red; 
  display:block; 
  position:absolute; 
  top:25px; 
  left:25px;
  z-index:-1;
}
div#pila1::after{
  content:"";  
  width:200px; 
  height:100px; 
  background-color:blue; 
  display:block; 
  position:absolute; 
  top: 50px; 
  left:50px;
  z-index:-1;
}
<div id="pila1"> Contenido</div>
Contenido

Limpiar los floats

La propiedad float especifica si una caja  tiene que flotar o no. Esto ya lo sabemos. También sabemos que es muy importante limpiar los floats para que los elementos posteriores a una caja flotada dejen de hacer cosas extrañas. El método tradicional es insertar un elemento  - por ejemplo un salto de línea: <br class="clearfloats"> - que limpie los floats.
.clearfloats{ clear:both;}
Nicolas Gallagherstar tiene un método mejor que utiliza los pseudo-elementos ::before y ::after.
Solamante hay que aplicar una clase – por ejemplo .clearfix – a la caja padre.
<div class="clearfix">
    <div class="flotado"></div>
    <div class="flotado"></div>
</div>
<p class="floats">párafo test</p>
.clearfix:before,
.clearfix:after {
    content: "";
    display: table;
}

.clearfix:after {
    clear: both;
}
.clearfix {
    background: #f5f5f5;
 width:280px;
 margin:0 auto;

}

.flotado {
    float: left; 
    width: 100px; 
    height: 50px; 
    margin: 20px; 
    background: #d9d9d9;
}

p.floats {
    margin-top: 20px;
 text-align:center;
}
párafo test