Triángulos con CSS: Creando el logotipo de Wextensible

Figura. Logotipos Wextensible hechos con CSS que se escalan con el tamaño de la fuente

Inicialmente tenía un logotipo de este sitio que aparecía en la barra superior con una imagen PNG insertada con Sprites CSS. En Julio 2013 experimentando con animaciones CSS se me ocurrió replicar ese logotipo sólo con con CSS. En Diciembre 2013 lo usé definitivamente como logotipo del sitio, pues sólo con <div class="logowx"></div> será insertado en cualquier punto de la página. Y lo más importante, no necesitan descargar recursos de imagen adicionales. Además son fácilmente escalables a distintos tamaños con la propiedad font-size, tal como muestra la Figura. El contenedor exterior tiene font-size: 16px, el primer logotipo tiene font-size de 0.5em, el del centro 1em y el último 2em. El CSS necesario para esto es el siguiente:

[class~=logowx] {
    display: inline-block;
    background-color: white;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 1em;
    border-color: cyan rgb(0,128,129) black silver;
    vertical-align: middle;
    outline: white solid 0.1em;
}

Si no se especifica otra fuente el logotipo tendrá un ancho de borde de 1em, que con fuente de 16px suponen un cuadrado de 32px píxeles de lado. Por lo tanto es más que posible usar CSS para representar iconos basados en formas geométricas sencillas.

Formas geométricas creadas con CSS
Figura. Es posible crear formas geométricas sólo con CSS, como éstas de la herramienta Diagramas

Las posibilidades gráficas son limitadas, pero son varias las formas geométricas sencillas que podemos crear como se observa en la Figura. Es una captura de pantalla de un ejemplo en la herramienta Diagramas, donde uso CSS para construir líneas en cualquier dirección, círculos, elipses rombos o triángulos. Veámos como funcionan los triángulos, pues en el fondo el logo de Wextensible puede verse como cuatro triángulos.

En el siguiente ejemplo tenemos un DIV de 100×50 píxeles con un borde sólido de 50 píxeles. Cada lado del borde tiene un color diferente. Y es una característica de CSS que las uniones en las esquinas sean ingletadas.

Ejemplo: Bordes CSS se unen en esquinas ingletadas

<style>
#div100x50 {
    width: 100px;
    height: 50px;
    border-width: 50px;
    border-style: solid;
    border-color: cyan rgb(0,128,129) black silver;
}
</style>
...
<div id="100x50"></div>

De ahí a construir el logotipo es tan sencillo como poner ancho y alto cero:

Ejemplo: Elemento con sólo bordes, sin ancho ni alto

<style>
#div0x0 {
    width: 0;
    height: 0;
    border-width: 50px;
    border-style: solid;
    border-color: cyan rgb(0,128,129) black silver;
}
</style>
...
<div id="div0x0"></div>

Y ya es obvio como construir un triángulo, por ejemplo el de la derecha, tras cambiar el color y las dimensiones del triángulo:

Ejemplo: Un triángulo con CSS

<style>
#div0x0 {
    width: 0;
    height: 0;
    border-width: 20px;
    border-style: solid;
    border-color: transparent blue transparent transparent;
    outline: red dotted 1px;
}
</style>
...
<div id="div0x0">

Los bordes, al igual que otras propiedades, se enumeran en el orden arriba, derecha, abajo e izquierda. Por lo tanto los ponemos todos transparentes a excepción del color blue para el de la derecha. El borde de color rojo con puntos realmente es un contorno (outline) que he puesto para observar el área del elemento. El ancho efectivo es de 40 píxeles pues los bordes son de 20 píxeles y el elemento no tiene ancho (width: 0). El triángulo azul tiene por tanto unas medidas de 20×40 píxeles.

Ese triángulo podría servirnos como botón Previous o anterior de nuestra barra de navegación de registros. Sólo faltaría posicionarlo en el centro horizontal del elemento e incluir todo en un elemento <button> para conseguir un botón con un icono. Si esto no parece que sea díficil de conseguir, hacer los otros iconos para la barra de navegación no puede ser tan díficil pues principalmente son triángulos y una barra vertical. Veámos de que forma posicionamos los iconos.

Posicionando elementos con CSS: Posicionamiento absoluto

Con CSS podemos posicionar los elementos de forma estática, relativa, absoluta o fija. Decimos que un elemento está posicionado si tiene una posición distinta de estática. Si al contenedor exterior le damos un posicionamiento relativo entonces podemos posicionar sus hijos con respecto a este padre, dándole a los hijos posicionamiento absoluto como en el siguiente ejemplo:

Ejemplo: Posicionamiento absoluto con CSS

Ejemplo para posicionar horizontalmente con CSS de forma absoluta un elemento.

el triángulo azul

El contenedor exterior tiene position: relative.

Propiedades CSS actuales del elemento con triángulo azul en su contenedor con contorno de puntos:

  • position: static
  • left: -10px
<style>
    #conten-rel {
        position: relative;
        font-size: 16px;
        border: rgba(255,0,0,0.3) solid 4px;
        width: 46px;
        height: 46px;
        margin: 1em; /* solo para presentar el ejemplo */
    }
    #triang-abs {
        display: inline-block;
        border-width: 20px;
        border-style: solid;
        border-color: transparent blue transparent transparent;
        margin: 3px;
        /* esto se pone con un botón en el ejemplo interactivo 
        position: absolute; */
        left: -10px; 
        outline: green dotted 1px; /* solo para presentar el ejemplo */
    }
</style>
...
<div id="conten-rel"><div id="triang-abs"></div></div>
    

En el ejemplo anterior el contenedor exterior id="conten-rel" tiene posicionamiento relativo. Su hijo id="triang-abs" tiene inicialmente posicionamiento estático. Aunque se le dota de posición en el punto (-10, 0) realmente está propiedad no tiene ahora ningún efecto. Al centrar el triángulo le ponemos posición absoluta y es cuando la propiedad left: -10px entra en juego. Las posiciones (x, y) se corresponden con (left, top) para la separación desde la izquierda y arriba, siendo el punto (0, 0) la esquina superior izquierda del interior del contenedor con posición relativa. Esa posición izquierda negativa supone trasladar el triángulo la mitad de su ancho efectivo que es de 20 píxeles.

Posicionamiento con márgenes CSS en elementos Block

Con el posicionamiento absoluto conseguimos ubicar el elemento. Pero también es posible posicionar de alguna forma actuando sobre los márgenes, es decir, la propiedad CSS margin. Entender como actúan los márgenes es bastante complejo. Antes de aplicarlo al ejemplo que estamos desarrollando, hagamos uno interactivo para ver el funcionamiento.

El siguiente jemplo interactivo sirve para posicionar horizontalmente el logotipo de 50×50 píxeles que es un elemento con display: block dentro de un un contenedor de 200×50 píxeles. El comportamiento de márgenes es diferente según sea el tipo de elemento block, inline, inline-block, reemplazados, etc. En este ejemplo el elemento es del tipo bloque (block).

Ejemplo: Posicionamiento con márgenes CSS en tipo block

en un lugar a editar.
Margen desde la izquierda Ponemos margen izquierdo con "X ? Y N[px|%]", donde "X" e "Y" son los márgenes verticales mientras que con "Npx" o "N%" especificamos el margen izquierdo siendo el derecho "?" cualquier cosa que será ignorada.
  • Alinea a la izquierda. Posiciona a la izquierda interior (valor por defecto).
  • Desarrollado es 0 10px 0 10px. Si se especifica un valor para el margen izquierdo siendo el derecho distinto de auto, entonces este margen derecho será ignorado. Por lo tanto algo como 0 Npx siempre será aplicado como margen izquierdo.
  • A -50 px lo ubica a la izquierda exterior, pues el elemento tiene 50 px de ancho.
  • A 50 px lo ubica antes del centro.
  • a partir del centro.
  • a la derecha interior.
  • a la derecha exterior.
Margen desde la derecha Para poner margen derecho usamos "X N[px|%] Y auto", pues con valor auto para el izquierdo se aplicará el margen derecho.
  • Alinea a la derecha. Para posicionar con margen derecho necesitamos poner auto al margen izquierdo. Este separa 0 px desde la derecha, con lo que lo alinea a la derecha.
  • Separa 10 px desde la derecha.
  • Separa 200 px desde la derecha llevándolo totalmente a la izquierda.
  • Separa -50 px desde la derecha por lo que lo pone por fuera del contenedor a la derecha dado que el elemento tiene ese mismo ancho.
En el centro Todos los siguientes son equivalentes.
  • Alinea al centro
  • Centrado a 75 px desde la derecha. Cuando el izquierdo es auto, se aplica el margen derecho, siendo en este caso de 75 px que son los necesarios para llevar el elemento al centro.
  • Centrado a 75 px desde la izquierda, porque si el izquierdo no es auto el margen derecho se ignora siempre, por lo que se aplica margen izquierdo que coincide con los 75 px necesarios para el centrado.
  • Este es igual que el anterior, pues desarrollado es 0 75px 0 75px, pero cualquier cosa como 0 ? 0 75px sólo aplicará margen izquierdo dado que el margen derecho es ignorado.
  • . Es el resultado de 75 / 200 = 0.375 pues el elemento centrado estará a 75 píxeles y supone un 37.5% sobre los 200 píxeles de ancho del contenedor que lo alberga. Nuevamente sólo aplica margen izquierdo, como antes, pues el derecho se ignora.
A la mitad del triángulo izquierdo Todos los siguientes son equivalentes. El valor de 88 píxeles se obtiene viendo que si centramos el elemento estará a 75 píxeles desde la izquierda y tenemos que agregarle la mitad del triángulo izquierdo (el del color gris claro) que es de 50×50 píxeles, con lo que resulta 75 + 25/2 = 75 + 12.5 = 87.5 y redondeamos por encima a 88 píxeles.
  • El anterior equivale a este, pero el margen derecho es ignorado, aplicándose sólo margen izquierdo.
A la mitad del triángulo derecho Todos los siguientes son equivalentes. Similar operación resulta 75 - 25/2 = 62.5 que redondeamos a 62 píxeles.

Podemos especificar valores en píxeles, porcentajes y la palabra clave auto. El porcentaje se calcula sobre las medidas del contenedor que alberga al elemento. Los valores también pueden ser negativos.

Cómo se calcular los márgenes se explica en CSS2 Calculating widths and margins. Podemos resumir que para elementos de bloque no reemplazados en flujo normal (y principalmente orientado a márgenes horizontales) sucede lo siguiente:

  1. El valor para el margen acepta unidades positivas y negativas como 10px o -10em.
  2. El valor también acepta porcentajes como 10%, en cuyo caso se refiere al diez por ciento del ancho del contenedor tanto para el margen horizontal como vertical. Esto es importante, aunque sean márgenes verticales el porcentaje se calculará sobre el ancho del contenedor.
  3. También es posible la palabra clave auto.
  4. Para margin podemos declarar uno, dos, tres o cuatro valores. Con cuatro valores los impares primero y tercero son para el margen superior e inferior respectivamente. Los pares segundo y cuarto son para el margen derecho e izquierdo respectivamente. Esto se memoriza con el sentido de la agujas de reloj recorriendo el rectángulo del elemento: arriba, derecha, abajo e izquierda (top, right, bottom, left y tambén TRBL), pues la misma disposición se usa para otras propiedades como rellenos o bordes. Las otras posibilidades son:
    • margin: 10px equivale a margin: 10px 10px 10px 10px.
    • margin: 10px 5px equivale a margin: 10px 5px 10px 5px.
    • margin: 10px 7px 5px equivale a margin: 10px 7px 5px 7px.
  5. Si el margen izquierdo tiene un valor distinto de auto, el margen derecho será ignorado, aplicándose sólo margen izquierdo. Con margin: T R B 0 alineamos el elemento de bloque a la izquierda, siendo el valor cero el que por defecto tienen los elementos (los T R B son los otros márgenes que son indiferentes para la alineación horizontal, e incluso en este caso también es indiferente el margen derecho).
  6. Si el margen izquierdo es auto se aplicará sólo margen derecho. Por eso algo como margin: T 0 B auto alinea horizontalmente el elemento de bloque a la derecha.
  7. Si ambos márgenes izquierdo y derecho son auto el elemento se centrará en su contenedor. Esta es la forma clásica de centrar elementos de bloque con algo como margin: T auto B auto.

Posicionamiento con márgenes CSS en elementos Inline

En el caso de elemento inline o inline-block (en general Inline) los márgenes horizontales no se comportan igual que para los elementos de bloque, pues ahora sí que podemos declarar ambos márgenes horizontales. Éstos se suman entre elementos contiguos en la misma línea. Se debe a que los elementos Inline se disponen en una línea, a diferencia de los de bloque en flujo estático normal que sólo hay uno en una línea. Así para los Inline el margen derecho de un elemento se suma con el izquierdo del siguiente de tal forma que el margen resultante entre ambos es esa suma. Vea el siguiente ejemplo:

Ejemplo: Posicionamiento con márgenes CSS en tipos inline-block

123

El primer elemento se dispone a 20px desde el origen porque su margen izquierdo tiene ese valor. El margen resultante entre el primero y el segundo elemento es la suma de 10px + 40px de los márgenes colindantes de ambos. Sumando el ancho del primer elemento posicionará el segundo a los 100px. Vea como para el tercero la suma con signo 30px - 20px resultará en una separación de 10px entre estos dos últimos elementos.

Por lo tanto es posible posicionar horizontalmente un elemento con márgenes si son elementos Inline. Y especialmente inline-block, pues éstos permiten además dotarles de dimensiones (width y height). Intentemos aplicarlo a nuestro objetivo de crear botones para la barra de navegación de registros:

Ejemplo: Márgenes CSS y centrado con Text-align

Márgenes de la flecha azul:

Valores obtenidos del navegador para la flecha azul tras actualizar:

  • margin-left: 0px
  • margin-right: 0px

Se observa que lo único que necesitamos para posicionar la flecha azul orientada a la izquierda es darle un margin-left de -20px. Este valor es la mitad del ancho del elemento, lo que hace que la flecha azul contacte con la barra roja a la izquierda. Respectivamente para la flecha orientada a la derecha, le damos un margin-right de -20px para que contacte con la barra roja que en este caso está a la derecha de la flecha.

Además si una vez ajustado el margen de la flecha centramos el contenedor exterior con text-align, veremos que la composición barra más flecha azul se centra en el punto de su mitad geométrica. Como la barra tiene 6px de ancho y la flecha tiene 20px, la mitad de su suma es 13px. Observamos que antes y después del punto central del ancho del contenedor a 100px hay 13px por cada lado del conjunto barra más flecha. Esto es una característica de CSS para text-align con su valor center. Recuerda que es una propiedad que sólo puede aplicarse a la alineación de elementos inline o inline-block, tal como son estos elementos que estamos usando.

Construyendo una barra de navegación de registros

En el último ejemplo del apartado anterior vimos el estilo para los cuatro botones de la barra de navegación de registros. Ya tenemos todo lo necesario para construir un primer prototipo:

Ejemplo: Barra de navegación de registros en píxeles (sin botones)

En el código están todos los detalles necesarios. En este ejemplo todas las medidas están en píxeles. Los contenedores con borde rojo son DIV por ahora (clase conten-ext), porque en el ejemplo siguiente lo sustituiremos por BUTTON. Son inline-block, con medidas de 46×46 píxeles y bordes de 2 píxeles. Es especialmente importante el text-align para centrar texto y box-sizing: content-box para establecer el área de contenido de 46×46 como referencia de medidas.

Mejorando la barra de navegación de registros

El último paso consistirá en introducir algunas mejoras, como sustituir los DIV por BUTTON, pasar los píxeles a em's y reducir la cantidad de HTML usando pseudo-elementos before y after.

Ejemplo: Barra de navegación de registros con botones en em's

El contenedor de borde gris es la barra de navegación. Le damos color: black y font-size: 16px inicialmente. Traspasamos este estilo a sus hijos que ahora son elementos BUTTON, poniéndoles font-size: 1em y color: inherit heredarán su estilo de tamaño de fuente y color de primer plano. Ambos se heredan de padres a hijos, por lo que podemos especificarlos en el contenedor de la barra y los heredarán los botones o directamente en los botones. De todas formas los hemos replicado ahí para acordarnos de su importancia en el contexto del componente.

El color de primer plano se puede transferir al color del borde mediante el nuevo valor de CSS3 currentcolor. Navegadores antiguos no lo soportarán y lo sobrescribimos a un color negro. El ejemplo interactivo permite cambiar el color y el tamaño de la fuente del contenedor exterior con borde gris que se replicará a los iconos de los botones.