Cómo hacer un ribbon destacado usando solo CSS y el pseudoelemento ::before

13/09/2018
Artículo original

En este post vamos a aprender una técnica muy sencilla pero resultona para simular una cinta (ribbon, en inglés) con un texto superpuesta con CSS sobre un elemento del contenido.

La aplicación práctica más habitual para esta técnica es la clásica cinta que pone Nuevo por encima de un producto (o cualquier otra característica que se quiera destacar) en un e-commerce, pero realmente se puede aplicar en muchos otros casos, como posts de un blog, imágenes o vídeos de una galería, un listado de usuarios…

Existen muchos tutoriales y generadores online para que no tengas que partir de cero para hacer esto, aunque la mayoría de estos te añaden marcado extra porque presuponen que puedes tocar el HTML directamente. En la mayoría de casos va a ser así, pero a veces hay situaciones especiales en las que el HTML viene impuesto desde el backend (cof, cof, webforms...), y mire usted por dónde, no se puede cambiar tan alegremente.

La técnica de este post es muy similar a los ribbons que usamos en nuestro propio catálogo de cursos de programación. Para el ejemplo (y para simplificar el código HTML) voy a usar una imagen que representa la ficha de uno de nuestros cursos:

Lo que representa esta imagen, en realidad también serían varios elementos HTML, pero poniéndolo como una imagen lo verás todo más claro en el código del ejemplo. Por cierto, el ribbon que vamos a hacer no es el que ve abajo a la derecha. Vamos a colocar uno nuevo arriba a la izquierda, completamente editable desde nuestro CSS. Esta cinta llevará escrita la palabra "¡Nuevo!" para, obviamente, destacar novedades.

Las claves de esta técnica son varias. Si ya las conoces te resultará muy sencillo, pero lo desgloso aquí para los más novatos:

  • Como no podemos tocar el HTML, vamos a incluir el contenido (es solo una palabra) dentro del pseudoelemento ::before
  • El pseudoelemento ::before por defecto es una "caja" como cualquier elemento CSS, así que primero le daremos esa apariencia biselada en los extremos con un truco de magia de CSS
  • Finalmente giraremos el pseudoelemento 45º en sentido contrario a las agujas del reloj y posicionaremos nuestra cinta arriba a la izquierda de manera absoluta con respecto al contenedor del producto. Así crearemos la ilusión de una cinta envolviendo el extremo de la caja.

Preparando el contenedor y el ribbon (la cinta)

Bien, primero el HTML. Aquí tenemos nuestro producto envuelto por el div "curso":


<div class="curso">
    <img src="ficha-curso.png" />
</div>

El pseudoelemento ::before  lo añadimos y mostramos desde nuestro CSS:


.curso {
            /*Le damos al contenedor las medidas de la imagen y lo centramos*/

            width:351px;
            height:170px;
            box-sizing:border-box;
            margin: calc(50vh - 170px) auto;

            /* Esto es importante. Para posicionar el ::before
            de forma absoluta, necesitamos que el contenedor
            tenga position:relative */

            position:relative;
        }

.curso::before { position:absolute; top:0; left:0; display: block; box-sizing:border-box; content:"¡Nuevo!"; text-transform:uppercase; font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 13px; text-align:center; font-weight: 700; color: #fff; /*Le damos medidas estas y color para verlo ahora más claro, pero luego lo modificaremos*/ background: purple; height:40px; width:150px;
}

Como puedes ver, le he dado provisionalmente un ancho y un alto de 40px y un color de fondo para que veas claramente lo que vamos a hacer a continuación.

Ahora modificaremos esto. Le damos un alto igual a cero y añadimos bordes de 25px de ancho del mismo color, y el color de fondo lo pondremos transparente:


.curso::before {
    
        [...]

        background: transparent; 
        height:0;
        width:150px;                      
        border:25px solid purple;
    }

Jugando con los bordes del ::before

El resultado visualmente es similar. Pero ahora viene "la magia", fíjate qué ocurre si ponemos todos los bordes amarillos excepto el inferior (y de paso ajustamos la altura de línea del texto):


.curso::before {

        [...]
                    
        border:25px solid yellow;
        border-bottom:25px solid purple;
        line-height:23px;
    }

Ahora la forma del borde inferior con respecto a los otros tiene los extremos biselados. ¿Ves a dónde quiero llegar? A continuación convertimos los bordes amarillos en transparentes y Voilà!


.curso::before {
    
        [...]    
                  
        border:25px solid transparent;
        border-bottom:25px solid purple;
        line-height:23px;
    }

Bien, nos aprovechamos de la forma que toma el borde inferior para crear nuestra cinta. Ahora la giramos 315 grados, o, lo que es lo mismo, -45 grados (45 grados en sentido contrario a las agujas del reloj)


.curso::before {
    
        [...]    
               
        transform: rotate(-45deg);
    }

Si lo inspeccionas con las herramientas de desarrollo de tu navegador, verás claramente cómo se ha girado el elemento.

Ajustes finales

Por defecto se gira respecto al centro, pero si quieres especificar el centro del giro puedes usar la propiedad transform-origin. En nuestro caso no lo usaremos y lo que haremos será ajustar los valores del posicionamiento absoluto de nuestra cinta con top y left para colocarlo arriba a la izquierda. 

Si quisieras colocarlo en otra de las esquinas solo tendrías que jugar con estos valores y/o usar el borde superior como fondo. Por cierto, también podrías usar ::after en lugar de ::before, o incluso usar ambos a la vez en diferentes esquinas.

Otro detalle final podría ser añadirle un poquito de sombra para enfatizar la superposición, y te quedaría así:


    .curso::before {
    
        [...]    
               
        box-shadow: 0px 3px 5px -3px #000;
    }

Por cierto, puedes descargarte aquí el ejemplo completo (ZIP 25KB) de este tutorial.

Importante: Esto no lo puedes hacer directamente sobre una imagen

En las imágenes no funcionan los pseudoelementos ::before y ::after, necesitas un elemento contenedor que la envuelva para usarlos. Lo explica perfectamente nuestro tutor José Manuel Alarcón en este post de su blog. Por cierto, que con él puedes aprender muchísimo sobre CSS y JavaScript (y te resolverá directamente tus dudas) en nuestro VIII Máster de Front End (aprovecha ahora que tenemos las inscripciones abiertas).

Si puedes tocar HTML aún se puede hacer mejor

Como comentaba al principio, en este tutorial lo hemos hecho de la forma más espartana, tocando solo CSS porque es como lo hemos hecho en nuestro catálogo. Pero si tienes la posibilidad de añadir HTML, por ejemplo, un simple span, puedes colocar en él el texto y usar los pseudoelementos ::before y ::after para crear unos pliegues que den efecto 3D.

A mí me parece más divertido el desafío de hacerlo sin añadir más HTML, pero si quieres que lo desgranemos en otro post, déjanoslo en los comentarios.