Hacer un triángulo con CSS3

¿Cómo puedo insertar la imagen de un triángulo en mi web sin usar imágenes? ¿Es posible hacerlo sólo con CSS3? En el pasado vimos como hacer un exágono o un octógono, y el triángulo es todavía más fácil:

Vamos a crear cuatro divs, cada uno de ellos para un triángulo en una dirección. Este sería el marcado HTML:

<div id="triangulo"></div>
<br/>
<div id="trianguloinvertido"></div>
<br/>
<div id="trianguloizquierda"></div>
<br />
<div id="trianguloderecha"></div>

Y ahora veamos el CSS:

#trianguloizquierda{
	  width: 0;
	  height: 0;
	  border-top: 50px solid transparent;
	  border-bottom: 50px solid transparent;
	  border-right:50px solid black;
	}

#trianguloderecha {
	  width: 0;
	  height: 0;
	  border-top: 50px solid transparent;
	  border-bottom: 50px solid transparent;
	  border-left: 50px solid black;
	}

#triangulo {
	  width: 0;
	  height: 0;
	  border-left: 50px solid transparent;
	  border-right: 50px solid transparent;
	  border-bottom: 50px solid black;
	}

#trianguloinvertido {
	  width: 0;
	  height: 0;
	  border-left: 50px solid transparent;
	  border-right: 50px solid transparent;
	  border-top: 50px solid black;
	}

En este jsfiddle le puedes echar un ojo al resultado.

Con este simple truco de CSS podrás crear botones en forma de flecha o triángulo que darán una mejor imagen a tu proyecto,pudiendo jugar con los tamaños y los colores para adaptarlos mejor a tu maquetación.

CSS: el pseudo-elemento ::selection

¿Quieres definir un estilo para el texto seleccionado? ¿que el color de fondo sea verde moco? ¿que la leta se ponga en añil? Con CSS esto es posible utilizando el pseudo-elemento ::selection.

Debemos empezar recalcando que ::selection no pertenece a la especificación standar de CSS3 (estaba presente en los borradores, pero se eliminó de la especificación final), por tanto no está garantizado su funcionamiento en todos los navegadores. A pesar de eso tiene bastante compatibilidad, al menos con los navegadores para sistemas operativos de escritorio (y por otra parte, en un dispositivo móvil no es muy habitual andar seleccionando texto, al menos en mi caso). En caniuse podéis comprobarlo.

Si habéis ojeado el enlace anterior veríais que además en el caso de Firefox hay que usarlo con el prefijo -moz. En todo caso, este pseudo-elemento sólo acepta un pequeño grupo de reglas CSS: color, background, background-color y text-shadow. Ojo con querer utilizar una imagen de fondo, porque background-image será ignorado, igual que el resto de reglas que no sean las cuatro antes citadas.

Vamos con un ejemplillo de cómo funciona esto. Para ello usaremos nombres de clase llamados ejemploN a los que sumaremos el pseudo-elemento:

/*Empezamos por el color de fondo, gris*/
.ejemplo1::selection{
    background-color:#555555;
}
.ejemplo1::-moz-selection{
    background-color:#555555;
}
/*Ponemos la letra en rojo*/
.ejemplo2::selection{
    color:#FF0000;
}
.ejemplo2::-moz-selection{
    color:#FF0000;
}

/*Ponemos la letra en negro y el color de fondo gris claro*/
.ejemplo3::selection{
    background-color:#cccccc;
    color:#000000;
}
.ejemplo3::-moz-selection{
    background-color:#cccccc;
    color:#000000;
}

/*Le ponemos sombra al texto seleccionado*/
.ejemplo4::selection{
    text-shadow: 1px 1px 0 #27ae60;
}
.ejemplo4::-moz-selection{
   text-shadow: 1px 1px 0 #27ae60;
}

Puede ser un efecto interesante, pero repito que no forma parte de la especificación, no es un standar y por tanto puede que en un futuro de problemas o no funcione correctamente. Nos tocará esperar.

CSS3 Media Queries para Moto 360 Watch

Si el otro día os comentaba que había estado ojeando el tema de las media queries para los dispositivos de Apple, vamos ahora con el wearable de Motorola. ¿Qué resulución usaría en CSS para este dispositivo? Pues esta:

@media 
  (max-device-width: 218px)
  and (max-device-height: 281px) { 
/*Aquí lo que toque*/
}

Conforme me vaya enterando de más dispositivos los iré compartiendo por aquí.

Media Queries para Apple Watch

Minientrada sobre CSS (y maquera muy a mi pesar) rápida mientras cocino una más musical para esta semana. ¿Cuál sería el tamaño de pantalla en una media query para aplicar un estilo CSS concreto a algo que se visualice en un dispositivo Apple Watch (aka El Reloj Manzanita)? Pues segú veo en github sería lo siguiente:

@media
  (max-device-width: 42mm)
  and (min-device-width: 38mm) { 
/*Aquí el código css a implementar*/
}

Si me voy enterando de otros dispositivos os los iré anunciando.

Creando una tabla con los bordes redondos con CSS3

¿Cómo puede redondear los bordes de una tabla con CSS? Ponerle bordes al objeto table o al tr no va a funcionar, hay que hacerlo sobre el primer o el último td de la fila.

table { border-collapse: separate; }
td { border: solid 1px #000; }
/*PARA LA PRIMERA FILA TIENES DOS OPCIONES*/
/*Así sería la cosa
si has empezado con un tr
*/
tr:first-child td:first-child { border-top-left-radius: 10px; }
tr:first-child td:last-child { border-top-right-radius: 10px; }
tr:first-child td:only-child { border-top-right-radius: 10px;
border-top-left-radius: 10px; }
/*si en lugar de eso has usado la etiquetas thead y th es más
sencillo todavía*/
th:first-child { border-top-left-radius: 10px; }
th:last-child { border-top-right-radius: 10px; }
th:only-child { border-top-right-radius: 10px;
border-top-left-radius: 10px; }

/*Y ASÍ PONEMOS EL PIE*/
tr:last-child td:first-child { border-bottom-left-radius: 10px; }
tr:last-child td:last-child { border-bottom-right-radius: 10px; }
tr:last-child td:only-child { border-bottom-right-radius: 10px;border-bottom-left-radius: 10px; }

Centrando verticalmente elementos de bloque en CSS

Si bien centrar elementos horizontalmente no suele suponer un problema cuando trabajamos con CSS, el hacerlo verticalmente es mucho más puñetero. Desde que se jubilaron las engorrosas tablas, que todo hay que decirlo para el tema del centrado eran bastante cómodas, son muchos los que llevan buscando una solución. Con los elementos inline la cosa no es tan pesada, pero con los elementos de bloque puede tonarse desquiciante.

Si trabajamos con navegadores modernos, con total soporte de CSS3, la solución nos llega de la mano de Flexbox con unas pocas líneas. Basta con definir la alineación usando esta propiedad en el elemento contenedor como podéis ver en este fiddle:

.contenedor {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

Con flexbox la alineación vertical es tan simple como en las viejas tablas. Pero ¿y si no podemos contar con flexbox?… el horror, el horror… Bueno, no tanto, también hay una solución. En este caso lo primero será definir la posición del contenedor como relativa, y el elemento a centrar de forma absoluta, situado en la mitad de la altura del padre y a su vez desplazando su eje Y otro 50% (suena más rollo de lo que es, la idea es poner el borde superior en la mitad del contenedor y luego desplazarlo la mitad de su propia altura de forma que el centro del elemento queda en el centro del contenedor, viendo el código a continuación se entiende, y podéis ver el resultado en un fiddle)

.contenerdor {
  position: relative;
}
.elementoACentrar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

Listo, dos métodos para alinear verticalmente un elemento de bloque en CSS que te pueden ahorrar mucho tiempo.

Crear un hexágono o un octógono con CSS

Se está poniendo de moda el usar formas geométricas en las maquetaciones así que ¿cómo podemos crear un hexágono para nuestra web? ¿o un octógono? En el último año de hecho los hexágonos han estado bastante de moda (parece un chiste, pero no, pensad en múltiples diseños que habéis visto)

Entonces ¿cómo creo un hexágono con CSS? Pues aquí va un ejemplo de código, basándose en un la idea de que, a fin de cuentas, un hexágono se hace con un cuadrado con un triángulo encima y otro debajo:

#hexagono { 
  width: 150px; 
  height: 90px; 
  background: #666; 
  position: relative; 
}

#hexagono:before { 
  content: ""; 
  position: absolute; 
  top: -50px; 
  left: 0; 
  width: 0; 
  height: 0; 
  border-left: 75px solid transparent; 
  border-right: 75px solid transparent; 
  border-bottom: 50px solid #666; 
} 
#hexagono:after { 
  content: ""; 
  position: absolute; 
  bottom: -50px; 
  left: 0; 
  width: 0; 
  height: 0; 
  border-left: 75px solid transparent; 
  border-right: 75px solid transparent; 
  border-top: 50px solid #666;  
}

Ya véis la idea: usando :after y :before metemos dos triángulitos sobre un cuadrado y ya tenemos hexágono.

El octógono ya es más jodón, que tiene más lados, pero tampoco entraña mucha más complejidad. Eso sí, vas a necesitar jugar con más colores, ya que las formas se hacen a base de bordes, como en el ejemplo anterior:

#octogono { 
  width: 150px; 
  height: 150px; 
  background: #999; 
  position: relative; 
} 
#octogono:before { 
  content: ""; 
  position: absolute; 
  top: 0; 
  left: 0; 
  border-bottom: 44px solid #999; 
  border-left: 44px solid #fff;/*Para el ejemplo he elegido blanco, poned vosotros el color de fondo de vuestra web. No uséis transparent porque entonces se verá el color de fondo del cuadrado*/ 
  border-right: 44px solid #fff; 
  width: 63px; height: 0; 
} 

#octogono:after { 
  content: ""; 
  position: absolute; 
  bottom: 0; 
  left: 0; 
  border-top: 44px solid #999; 
  border-left: 44px solid #fff; 
  border-right: 44px solid #fff; 
  width: 63px; 
  height: 0; }

AngularJS: animaciones con scroll

No tenía muy claro cómo titular esta entrada, dado que su título original es AngularJS: Scroll Animations. Como en ocasiones anteriores se trata de una «traducción-no-literal»/explicación de un artículo tutorial en inglés.

En fin, ¿a qué nos referimos con esto de animaciones con scroll? Seguro que habéis visto más de una página que las tiene. Se trata de animaciones que se activan conforme vas haciendo scroll en la página, al alcanzar una determinada posición. La web Let’s Free Congress es presentada con ejemplo de esto en el texto original.

AngularJS logo

La idea es que la animación comience cuando el usuario llegue a la parte de la pantalla, para lo cual nos serviremos de la directiva scrollPosition, que se nos presenta así en el ejemplo original

.directive('scrollPosition', ['$window', '$timeout', '$parse', function($window, $timeout, $parse) {
    return function(scope, element, attrs) {

        var windowEl = angular.element($window)[0];
        var directionMap = {
          "up": 1,
          "down": -1,
          "left": 1,
          "right": -1
        };

        // Recuperamos el elemento con el scroll
        scope.element = angular.element(element)[0];

        //Almacenamos los elementos que escuchan a este evento
        windowEl._elementsList = $window._elementsList || [];
        windowEl._elementsList.push({element: scope.element, scope: scope, attrs: attrs});

        var element, direction, index, model, scrollAnimationFunction, tmpYOffset = 0, tmpXOffset = 0;
        var userViewportOffset = 200;

        function triggerScrollFunctions() {

          for (var i = windowEl._elementsList.length - 1; i >= 0; i--) {
            element = windowEl._elementsList[i].element;
            if(!element.firedAnimation) {
              directionY = tmpYOffset - windowEl.pageYOffset > 0 ? "up" : "down";
              directionX = tmpXOffset - windowEl.pageXOffset > 0 ? "left" : "right";
              tmpXOffset = windowEl.pageXOffset;  
              tmpYOffset = windowEl.pageYOffset;  
              if(element.offsetTop - userViewportOffset < windowEl.pageYOffset && element.offsetHeight > (windowEl.pageYOffset - element.offsetTop)) {
                model = $parse(windowEl._elementsList[i].attrs.scrollAnimation)
                scrollAnimationFunction = model(windowEl._elementsList[i].scope)
                windowEl._elementsList[i].scope.$apply(function() {
                  element.firedAnimation = scrollAnimationFunction(directionMap[directionX]);  
                })
                if(element.firedAnimation) {
                  windowEl._elementsList.splice(i, 1);
                }
              }
            } else {
              index = windowEl._elementsList.indexOf(element); //TODO: Add indexOf polyfill for IE9 
              if(index > 0) windowEl._elementsList.splice(index, 1);
            }
          };
        };
        windowEl.onscroll = triggerScrollFunctions;
      };   
    }]);

Tal directiva se ha utilizado en este ejemplo. En ella podéis ver como la barra de la pantalla del móvil progresa según bajáis la barra.

En fin, la cosa es explicar ahora como usar esto. Como en el ejemplo original, iremos desgranando poco a poco el código, despedazándolo para ver cómo funciona.

Lo principal es añadir la directiva al elemento que queremos animar:

.row.show-for-large-up
  .teaser(scroll-position, scroll-animation='fireupApplicationDesignAnimation')
    .row
      .large-6.columns.left-align.margin-top
        h1(data-i18n="_CareerDesign_APPLICATIONDESIGNTITLE")

Esto le dice a AngularJS que cuando el usuario llegue al área determinada del DOM debe dispararse la animación. En vuestro controlador deberíais tener algo así

$scope.fireupApplicationDesignAnimation = function(scrollDirection) {
        scrollDirection > 0 ? reduceAmount() : aumentAmount(); // We want to increase on scrollDown
        setOffsetForImage();
    };

La directiva envía al controlador la dirección del scroll, lo que permite mostrar animaciones basadas en él. En ocasiones querrás ejecutar la animación sólo una vez en lugar de que ocurra cada vez que el scroll esté a su altura. Puedes lograrlo devolviendo un valor true y chequeándolo antes de lanzar la animación, como en este ejemplo:

$scope.fireupMarketingDesignAnimation = function() {
      if(!firedMarketingAnimation) {
        window.animations.marketingAnimation.init();
        firedMarketingAnimation = true;
        return firedMarketingAnimation;  
      }
    }

Como podéis ver en el ejemplo la función que lanza la animación está dentro de un if que hará que sólo se ejecute una vez.

En fin, resumiendo ¿Cómo funciona la directiva?. El proceso es el siguiente:

  • Crea un array de elementos que requieren un eventListener del tipo onScroll. Puedes tener varios almacenados, y si devuelves un true para una sola ejecución serán eliminados para reducir el uso de memoria.
  • Añade un eventListener onScroll que comprueba en qué parte de la página está el usuario.
  • Recorre tus elementos vinculados con la directiva comprobando si se han activado las animaciones.
  • Si no lo han hecho y el usuario se posiciona junto a ellas con el scroll entonces se activan. Esto obliga a hacer mucho uso de $parse, así que léete bien su documentación para entenderlo al 100%.
  • Si la animación llamada a través de scope devuelve true, la extrae del array, como dijimos en el primer punto.

La conclusión:

La directiva es útil cuando necesitas lanzar varias animaciones en un periodo de tiempo específico. También te permitirá definir un comportamiento específico según la posición del scroll o hasta para realizar cambios en propiedades CSS3 relacionándolas con la posición de la página.

En este ejemplo en Codepen, creado por el autor del artículo original, podéis ver cómo también funciona en horizontal. Si movéis el scroll lentamente veréis como el balón lo sigue. Eso sí, probad con Chrome porque a mi en Firefox en lugar de una pelota se me ve una especie de mojón raro.

En fin, finalmente recomendar el blog de jjperezaguinaga Surviving by Coding, donde podréis encontrar mucha info sobre AngularJS y otros temas de desarrollo web, en inglés.

CSS3 Box Shadow: sombras sin usar imágenes

Seguimos otra vez con truquillos de CSS3 para vuestra web. Mientras me desquicio usando un teclado de silicona para escribir (cosa incómoda donde las haya) vamos a comentar el uso de la propiedad box-shadow de CSS3. Como siempre, ojo con IE que es puñetero cuando se trata de trabajar con stándares.

En su uso básico box-shadow necesita al menos tres parámetros, si bien acepta hasta cinco.

  • Desplazamiento horizontal: Define la posición horizontal de la sombra respecto al elemento al que se la aplicamos. Si le enviamos un valor positivo la sombra se situará a la derecha del elemento. Si el valor es negativo se situará a la izquierda.
  • Desplazamiento vertical: Define la posición vertical de la sombra. Si recibe un valor positivo la sombra se situará debajo del elemento, y con uno negativo encima.
  • Radio de desenfoque: Cuanto mayor sea, más transparente será la sombra. En caso de 0 la sombra será totalmente nítida. Se trata de un valor opcional y 0 es su valor por defecto.
  • Radio de dispersión: Cuanto mayor sea, mayor dispersión tendrá la sombra. Es opcional y el valor por defecto es cero. En ese caso el tamaño será igual al desenfoque.
  • Color: Finalmente el color que tendrá la sombra. Es el tercer valor obigatorio.
  • Inset: Existe un parámetro más, que es este inset. Si lo incluimos al principio hará que la sombra en lugar de estar en el exterior se sitúe en el interior del elemento..

La sintaxis sería como en este ejemplo:

/*Sombra gris abajo derecha*/
.sgad{
    box-shadow: 5px 5px 2px #666;
}

/*Sombra azulada arriba izquierda muy dispersa*/
.saaid{
    box-shadow: -5px -5px 5px 14px #99C;
}

/*Sombra interna gris*/
.sig{
    box-shadow: inset 0 0 10px #666;
}

Si queréis una buena serie de ejemplos y trucos los podéis encontrar en este enlace. Y recordad, ojo con el Explorer.

Zoom sobre texto con CSS3 usando transiciones

Otra nueva entrada sobre las virtudes de CSS3, en este caso vamos a hacer una pequeña introducción a las transiciones creando un código que nos permita que la letra de un párrafo aumente de tamaño cuando el ratón esté sobre ella.

Para ello por un lado tendremos que definir la transición sobre el elemento a modificar y luego la modificación cuando se produzca el evento.

Lo primero sería así:

.aumenta {
    font-size: 1.1em;
    width: 300px;
 
    -moz-transition: font-size 500ms linear 0s; 
    -webkit-transition: font-size 500ms linear 0s;
    -o-transition: font-size 500ms linear 0s;
    transition: font-size 500ms linear 0s;
}

Explicación: tras definir el tamaño del texto para la clase aumenta (1.1 em) definimos la transición. Hay varios métodos para la transición, así que he usado la propiedad shorthand de transition. El primer parámetro (font-size) es para especificar a qué propiedad se aplicará la transición, el segundo el tiempo que tardará, el tercero que se hará siempre a la misma velocidad (linear) y el cuarto que se haga sin delay.

Y ahora que tenemos la transición definida para todos los navegadores (ojo!!! Explorer 9 no soporta todavía transiciones, dice Bill Gates que igual para la 10) toca definir cómo se transformará el texto cuando esté sobrevolado por el ratón:

.aumenta:hover{
    font-size:1.6em;
}

Definimos que en el evento hover la fuente pase a ser más grande. Con esto ya tenemos nuestra transición lista.