Creemos en la Web: Audio y Video

Incluir un video o audio seria algo tan simple como un tag y la ubicación del archivo.

Por cuestiones históricas hay muchos formatos de audio y video y las organizaciones que desarrollan los navegadores mas usados (Microsoft: Internet Explorer 11 y Microsoft Edge, Apple: Safari, Google: Chrome, Mozilla: Firefox) tienen distintos objetivos e intereses que hacen que soporten algunos formatos y otros no.

Video

Empecemos con un ejemplo que según esta tabla de compatibilidad para el formato webm, no va a andar en IE 11 y Safari.

<video src="/cew_files/12/example.webm" type="video/webm" controls></video>

Viendo la tabla de compatibilidad para el formato mp4 vemos que podemos hacerlo funcionar en mas versiones pero no necesariamente todas.

<video src="/cew_files/12/example.mp4" type="video/mp4" controls></video>

Que pasa si queremos hacerlo funcionar en la mayor cantidad de plataformas posibles priorizando formatos mas livianos y con mejor calidad?

Podemos especificar los videos en orden de preferencia, el navegador va a intentar en orden del primero al ultimo cargarlos, cuando encuentre uno que sirve lo va a usar.

<video controls>
    <source src="/cew_files/12/example.webm" type="video/webm">
    <source src="/cew_files/12/example.mp4" type="video/mp4">
</video>

Otro formato que suele usarse es ogv, acá la tabla de compatibilidad del formato ogv.

Vista Previa

Cuando la pagina carga y el video esta en pausa el navegador va a elegir una vista previa automáticamente, si queremos tener mas control sobre la imagen mostrada podemos especificarsela explícitamente con el atributo poster:

<video controls poster="/cew_files/12/poster.png">
    <source src="/cew_files/12/example.webm" type="video/webm">
    <source src="/cew_files/12/example.mp4" type="video/mp4">
</video>

Subtítulos

Ya sea por cuestiones de accesibilidad o para traducir o explicar el contenido del video, podemos agregar subtítulos a un video usando el tag track.

El formato del archivo es bastante simple:

WEBVTT

00:01.000 --> 00:04.000
Primer mensaje, del segundo 1 al 4

00:05.000 --> 00:08.000
Segundo mensaje, del segundo 5 al 8

...

Empieza con WEBVTT en la primera linea, un salto de linea y luego tantas veces como sea necesario:

[Tiempo comienzo] --> [Tiempo fin]
Texto del subtítulo

Podemos tener mas de un tag track para agregar subtitulos en distintos idiomas y marcar uno por defecto, aca un ejemplo con subtítulos en Español:

<video controls poster="/cew_files/12/poster.png">
    <source src="/cew_files/12/example.webm" type="video/webm">
    <source src="/cew_files/12/example.mp4" type="video/mp4">

    <track src="/cew_files/12/subtitulo.vtt"
        label="Subtitulos en Español"
        kind="captions"
        srclang="es"
        default>

</video>

Fragmentos

Que pasa si tenemos un video bastante largo pero solo queremos mostrar un fragmento?

Para eso podemos especificarle el principio y/o final del fragmento que nos interesa.

Notar que al momento de escribir esto es una característica bastante nueva, (ver tabla de compatibilidad de media fragments al momento de leer esto para ver si sigue siendo nueva y poco soportada).

Podemos indicarle el comienzo (segundo 10) y que reproduzca hasta el final:

t=10

Indicar solo el final, que reproduzca del principio y reproduzca hasta el segundo 20:

t=,20

O el principio y el final, que arranque en el segundo 10 y reproduzca hasta el segundo 20:

t=10,20

Veamoslo en nuestro video, que reproduzca desde el segundo 3 al 8 (puede que no funcione en tu navegador).

<video src="/cew_files/12/example.mp4#t=3,8" type="video/mp4" controls></video>

Embebiendo

Y que pasa si quiero poner en mi pagina un video que esta en una pagina de videos como youtube?

Para eso podemos embeber (embed en ingles) el contenido en nuestra pagina.

Si miras el video de los ejemplos de arriba, podrás ver que si vamos a share y luego seleccionamos embed, youtube nos da un HTML que podemos incluir en nuestra pagina para incluir el video directamente desde youtube.

<iframe width="560" height="315"
    src="https://www.youtube.com/embed/XM3eaJPB2Cc"
    frameborder="0"
    allow="autoplay; encrypted-media"
    allowfullscreen></iframe>

Podemos ver un video de youtube embebido que muestra un video de como embeber un video de youtube :)

El dialogo en youtube nos permite configurar algunos parametros que cambian el HTML que nos muestra, en el resultado de arriba vemos que podemos modificar el ancho, alto, si tiene borde, si hace auto play y si permite ponerlo en pantalla completa.

Audio

Como con video, hay muchos formatos de audio y cada navegador soporta un subset distinto, dado que hay mas formato de audio en uso listo las tablas de compatibilidad primero:

La canción que vamos a usar de ejemplo es Rough Patches de Solstar.

Empezamos con un audio en formato ogg:

<audio controls src="/cew_files/12/example.ogg"></audio>

Como veras el HTML es bastante similar al tag video.

Si no funciona o si tenes un mp3:

<audio controls src="/cew_files/12/example.mp3"></audio>

Pero si viste las tablas de compatibilidad y queres soportar la mayor cantidad de navegadores, al igual que con el tag video se puede incluir mas de un archivo.

<audio controls>
    <source src="/cew_files/12/example.ogg" type="audio/ogg"/>
    <source src="/cew_files/12/example.mp3" type="audio/mpeg"/>
</audio>

Embebiendo

Como con videos, hay paginas web que brindan audios y nos permiten embeberlos, en este caso uno de los mas usados es soundcloud, al igual que en youtube, si hacemos click en share y luego en embed, nos da un fragmento de HTML que podemos incluir en nuestra pagina:

<iframe
    width="100%"
    height="300"
    scrolling="no"
    frameborder="no"
    allow="autoplay"
    src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/72505324&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true">
</iframe>

Aca hay un video de como obtener el HTML:

Creemos en la Web: Dibujando Formas en 3D

Ya dibujamos en 2D, se podrá en 3D?

La respuesta es si, pero como es un área que todavía esta en desarrollo no es soportada 100% y de forma simple en todos los navegadores por lo que nos vamos a ayudar de una librería llamada aframe.

Una librería es uno o mas archivos que al cargarlos en nuestra pagina le agregan funcionalidades.

En este caso nos permiten crear escenas en 3D como si estuvieramos escribiendo HTML.

Como dije esto no esta completamente estandarizado así que aframe define sus propios tags que no son parte de ningún estándar que soporten todos los navegadores.

Entonces empecemos cargando la librería aframe:

<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>

Y luego creamos nuestra escena:

<div style="width: 100%; height: 25em">
        <a-scene embedded>
          <a-box position="-1 0.5 -3" rotation="0 45 0" color="blue"></a-box>
          <a-sphere position="0 1.25 -5" radius="1.45" color="yellow"></a-sphere>
          <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
          <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
          <a-sky color="#BBBBBB"></a-sky>
        </a-scene>
</div>

El tag raíz se llama a-scene, que traducido seria "una escena", el cual contiene a-box "una caja", a-shere "una esfera", a-cylinder "un cilindro", a-plane "un plano" y a-sky "un cielo".

Cada uno con atributos especificando la posicion en 3 dimensiones, su tamaño, ya sea con su radio o su alto y su ancho y su color.

Fijate que con el mouse y las flechas del teclado podes moverte dentro de la escena, no es algo fijo sino algo que podes explorar. Si tenes un dispositivo que soporte Realidad Virtual (los últimos smartphones o anteojos de realidad virtual) apretando el icono en la esquina inferior derecha podes "sumergirte" en la escena en realidad virtual.

La escena de arriba en un proyecto de thimble así podes modificar los colores, formas, posiciones y tamaños.

Abrí https://thimbleprojects.org/marianoguerra/510288/ y hace click en Remix para copiar el proyecto a tu cuenta.

Aframe también puede usarse para imágenes y videos panorámicos, veamos un ejemplo:

<div style="width: 100%; height: 25em">
        <a-scene embedded>
          <a-sky src="https://raw.githubusercontent.com/aframevr/aframe/v0.7.0/examples/boilerplate/panorama/puydesancy.jpg" rotation="0 -130 0"></a-sky>

          <a-text value="Puy de Sancy, Francia" width="6" position="-2.5 0.25 -1.5"
                          rotation="0 15 0"></a-text>
        </a-scene>
</div>

Por el momento aframe solo soporta una escena por pagina, por lo que no muestro el resultado directamente, abrí https://thimbleprojects.org/marianoguerra/511087/ y hace click en Remix para copiar el proyecto a tu cuenta.

Podes ver mas ejemplos en https://aframe.io/examples/showcase/snowglobe/

Creemos en la Web: Dibujando Formas en 2D

Hasta ahora la mayoría del contenido que creamos consiste principalmente en texto y "cajas", es decir, cuadrados dentro de cuadrados.

Pero que pasa si quiero una linea, un triangulo o un circulo en mi pagina?

Para eso existe un set de tags llamado SVG que nos permite crear dibujos "vectoriales", es decir que su contenido son las formas en si y se ven bien en cualquier resolución de pantalla, no como las imágenes hechas de pixeles, donde si la imagen es chica y la agrandamos empezamos a perder calidad.

Empecemos con un ejemplo simple:

<svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

Los tags son nuevos y específicos de SVG, es decir, solo los podemos usar dentro de un tag raíz svg, lo bueno es que son bastante descriptivos.

En el ejemplo arriba decimos que queremos dibujar en svg, dentro de un cuadro de 100x100.

El dibujo consiste de un circulo (circle en ingles) con centro x=50 y centro y=50, con un radio de 40, borde de 3 negro y relleno rojo.

Veamos algunos otros ejemplos:

<svg width="400" height="180">
  <rect x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:blue;stroke:pink;stroke-width:5;opacity:0.5" />
</svg>

Acá vemos un rectángulo (rect) posicionado en x=50, y=20, con ancho de 150 y alto de 150 y bordes redondeados.

Como veras el resto de las propiedades se las define con el atributo style al igual que en HTML, algunos atributos son nuevos pero el resto sigue aplicando.

Algunos mas:

<svg height="250" width="500">
    <ellipse cx="240" cy="100" rx="220" ry="30" style="fill:purple" />
    <ellipse cx="220" cy="70" rx="190" ry="20" style="fill:lime" />
    <ellipse cx="210" cy="45" rx="170" ry="15" style="fill:yellow" />

    <polygon points="200,10 250,190 160,210" style="fill:lime;stroke:purple;stroke-width:1" />

    <line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
    <polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" style="fill:white;stroke:red;stroke-width:4" />

    <text x="0" y="15" fill="red" transform="rotate(30 20,40)">Texto en SVG</text>
</svg>
Texto en SVG

Pero lo mejor que tiene SVG es que hay editores libres y gratuitos que nos permiten dibujar como cualquier editor de imágenes y luego ver el código SVG generado.

Este editor se llama Inkscape y lo podes descargar desde la pagina.

Luego de instalarlo se ve algo así:

/galleries/cew/10/inkscape.png

Abriendo el editor XML de Inkscape podemos ver como se crea cada forma, que tags y atributos se usan.

/galleries/cew/10/inkscape-xml.gif

Si usamos un editor para crear un SVG que queremos insertar en nuestra pagina tenemos dos opciones:

  • Guardar el dibujo como un archivo SVG y copiar el contenido del archivo abriendolo con un editor de texto y pegandolo en nuestra pagina
  • Insertandolo como una imagen externa

Ya vimos como insertar SVG directamente en el HTML, ahora veamos como incluirlo como una imagen externa:

<img src="/galleries/cew/10/example.svg" width="475" height="336">

Fuente

Una ultima observación sobre SVG, si bien son parecidos a HTML, SVG es mas estricto en cuanto a los nombres y atributos de tags permitidos y con la necesidad de "cerrar" todos los tags, si cometemos un error en HTML, el navegador va a hacer lo mejor que pueda para presentar el contenido igual, en SVG muy probablemente no se dibuje nada.

Creemos en la Web: Filas, columnas y pantallas de todos los tamaños

Hasta ahora hemos creado paginas con HTML donde el documento tiene una estructura básica: una cosa debajo de la otra.

Si prestas atención a sitios que visitas notaras que la estructura de esas paginas es mas complejas, la forma principal de organizarlas es con filas y columnas.

El lenguaje HTML provee algunos tags para indicar la intención del contenido dentro de esos tags pero no provee la estructura en si misma, para eso usamos CSS, el tema con los atributos CSS para definir estructura es que son muy específicos y flexibles, la idea es que con ellos podamos lograr cualquier tipo de estructura que deseemos, pero con gran flexibilidad viene gran complejidad.

Por esta razón han surgido distintas librerías CSS que permiten describir la estructura de un documento en términos mas generales (lo que los hace menos flexibles) pero de una forma que sirven para la mayoría de los casos que necesitamos.

Esta sección va a explorar como usar bootstrap para definir la estructura de nuestra pagina.

Vocabulario

Cuando definimos la estructura de un documento con bootstrap las palabras que aparecen son las siguientes:

Contenedor (container en ingles)
La raiz de una estructura con filas y columnas, podemos tener contenedores dentro de columnas pero no es algo común
Fila (row en ingles)
Una sección horizontal dentro de un contenedor o dentro de una columna
Columna (col/column en ingles)
Una sección vertical dentro de una fila
Puntos de corte (breakpoints en ingles)
Limites de resolución horizontal en la cual ciertas reglas cambian de significado (si, suena vago, vamos a ver esto en detalle luego)

Empezando

Estructura básica

Vamos a empezar con el ejemplo mas básico, un contenedor que tiene una fila que tiene una columna.

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col">
    Columna 1
  </div>
 </div>
</div>

Nada raro, simplemente esta estructura definida con divs y clases:

  • container
    • row
      • col

Agregue una clase cew-9 a container-fluid para poder resaltar los distintos tags con css ya que si no lo hago es difícil percibir la estructura, los colores son los siguientes:

  • container-fluid: rojo
  • row: gris y blanco
  • col: verde
Columna 1

Usamos la clase container-fluid para que el contenedor se estire el 100% del ancho del tag que lo contiene, la clase container puede ser usada cuando queremos mas control sobre el ancho del contenedor.

Dos columnas

Un paso mas, dos columnas, que ya es algo que nos permite replicar bastantes estructuras encontradas en la web.

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col">
    Columna 1
  </div>
  <div class="col">
    Columna 2
  </div>
 </div>
</div>
Columna 1
Columna 2

La estructura es

  • container
    • row
      • col 1
      • col 2

Normalmente en la web encontramos esta estructura de dos columnas pero donde una de ellas es una especie de menú o contenido secundario y la otra es el contenido principal, por lo cual el contenido principal usa mas espacio.

Para poder indicar esto de una forma que se adapte a todas las resoluciones de pantalla bootstrap define que una fila puede estar dividida en 12 "columnas", si no lo indicamos cada columna toma una cantidad igual de esas 12 columnas, por lo que si tenemos una columna tomara las 12, si tenemos 2 cada una tomara 6.

En nuestro caso queremos que la segunda sea la columna principal, por lo que le vamos a indicar que queremos que tome 8 de esas 12 columnas.

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col">
    Columna 1
  </div>
  <div class="col-8">
    Columna 2
  </div>
 </div>
</div>
Columna 1
Columna 2

Para hacerlo cambiamos la clase col por la clase col-8 que indica que queremos que tome 8 de las 12 columnas disponibles.

Dos columnas con cabecera y pie de pagina

Esta estructura es la mas común para blogs o artículos, arriba tenemos una cabecera que ocupa todo el ancho con logo, titulo, navegación y algunas otras cosas, luego el contenido en si con dos columnas, luego un pie de pagina con información extra.

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col">
   Cabecera
  </div>
 </div>

 <div class="row">
  <div class="col">
    Columna 1
  </div>
  <div class="col-8">
    Columna 2
  </div>
 </div>

 <div class="row">
  <div class="col">
   Pie de pagina
  </div>
 </div>
</div>
Cabecera
Columna 1
Columna 2
Pie de pagina

La estructura queda así:

  • container
    • row (cabecera)
      • col (contenido de cabecera)
    • row (cuerpo)
      • col 1 (contenido secundario)
      • col 2 (contenido principal)
    • row (pie de pagina)
      • col (contenido de pie de pagina)

Tortugas hasta el fondo

Un célebre científico dio una conferencia sobre astronomía.
Describió cómo la Tierra gira alrededor del Sol y cómo éste, a su vez,
gira alrededor de un inmenso conjunto de estrellas al que llamamos nuestra galaxia.

Al final de la conferencia, una vieja señora se levantó del fondo de la sala y dijo:

- Todo lo que nos ha contado son disparates.
  En realidad, el mundo es una placa plana que se sostiene sobre el caparazón
  de una tortuga gigante

El científico sonrió con suficiencia antes de replicar:

- ¿Y sobre qué se sostiene la tortuga?
- Sobre el caparazón de otra torguta gigante. -respondió la señora
- ¿Y qué sostiene a esa otra tortuga? volvió a preguntar el científico.
- Se cree usted muy agudo, joven, dijo la anciana,
  pero hay tortugas hasta el fondo.

Como hacemos si queremos tener una columna que a su vez tiene su propia estructura?

Podemos tener filas dentro de columnas.

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col">
   Cabecera
  </div>
 </div>

 <div class="row">
  <div class="col">
    Columna 1
  </div>
  <div class="col-8">
   <div class="row">
    <div class="col">
     Columna 2.1.1
    </div>
    <div class="col">
     Columna 2.1.2
    </div>
   </div>

   <div class="row">
    <div class="col">
     Columna 2.2.1
    </div>
    <div class="col">
     Columna 2.2.2
    </div>
    <div class="col">
     Columna 2.2.3
    </div>
   </div>
  </div>
 </div>

 <div class="row">
  <div class="col">
   Pie de pagina
  </div>
 </div>
</div>
Cabecera
Columna 1
Columna 2.1.1
Columna 2.1.2
Columna 2.2.1
Columna 2.2.2
Columna 2.2.3
Pie de pagina

La estructura queda así:

  • container

    • row (cabecera)

      • col (contenido de cabecera)
    • row (cuerpo)

      • col 1 (contenido secundario)
      • col 2 (contenido principal)
      • row 2.1
        • col 2.1.1
        • col 2.1.2
      • row 2.2
        • col 2.2.1
        • col 2.2.2
        • col 2.2.3
    • row (pie de pagina)

      • col (contenido de pie de pagina)

Resoluciones de pantalla

Con este nuevo conocimiento creamos una pagina con una estructura perfecta para la pantalla que estamos usando y orgullosamente la compartimos con gente para que la vean, el primer mensaje que recibimos es:

- No se ve bien en mi celular, todo es muy chico y con poco espacio

No pensamos en que la pagina va a ser vista por personas usando un smartphone viejo, uno de ultima generación, una tablet, una laptop chica, una grande, una PC y la pantalla de un diseñador con mas pixeles de los que podemos contar.

Como hacemos para que nuestra pagina se adapte a la resolución de cualquier dispositivo que quiera visitar nuestra pagina?

Una idea seria ver cuales son las resoluciones mas comunes en pixeles y aplicar reglas para esos, si bien eso funcionaba en la prehistoria de la web (esto es, hace 10 años), ya no es así, veamos algunas de las resoluciones mas comunes disponibles actualmente:

/galleries/cew/9/resoluciones.png

Intentando hacer esto manejable entran en juego los puntos de corte que mencionamos al principio del articulo.

Los puntos de corte son limites de resolución que agrupan a la resolución de los dispositivos en 5 grandes grupos, similares a los de la ropa:

  • xs: Extra Small
    • Extra pequeño, dispositivos con menos de 576 pixeles de ancho
  • sm: Small
    • Pequeño, dispositivos con menos de 768 pixeles de ancho
  • md: Medium
    • Medio, dispositivos con menos de 992 pixeles de ancho
  • lg: Large
    • Grande, dispositivos con menos de 1200 pixeles de ancho
  • xl: Extra Large
    • Extra Grande, dispositivos con 1200 pixeles de ancho o mas

Como los usamos? indicando el ancho de la columna con el tipo de dispositivo mínimo para el cual el tamaño aplica, entonces podemos decir algo como:

"Esta columna ocupa 12 columnas si es una resolución xs y 6 si no"

lo expresamos en clases: .col-12 .col-sm-6

O mas complejas como

"Esta columna ocupa 12 columnas si es una resolución xs, 8 si es una resolución sm y 6 si no"

lo expresamos en clases: .col-12 .col-sm-8 .col-md-6

Control completo si especificamos todas:

"Esta columna ocupa 12 columnas si es una resolución xs, 8 si es una resolución sm, 6 si es una resolución md, 4 si es lg y 2 si es xl"

lo expresamos en clases: .col-12 .col-sm-8 .col-md-6 .col-lg-4 .col-xl-2

Bootstrap va a buscar el grupo mas cercano a la resolución actual y aplicar esa regla, si nuestro dispositivo tiene una resolución de 1000 pixeles y hay una regla para md (< 992px) va a aplicar esa, sino va a buscar la regla sm y sino la xs.

Probemos un ejemplo:

<div class="container-fluid cew-9">
 <div class="row">
  <div class="col-12 col-sm-6 col-md-3">
       Reglas: col-12 col-sm-6 col-md-3
  </div>
  <div class="col-12 col-sm-6 col-md-6">
       Reglas: col-12 col-sm-6 col-md-6
  </div>
  <div class="col-12 col-sm-12 col-md-3">
        Reglas: col-12 col-sm-12 col-md-3
  </div>
 </div>
</div>
Reglas: col-12 col-sm-6 col-md-3
Reglas: col-12 col-sm-6 col-md-6
Reglas: col-12 col-sm-12 col-md-3

Si estas viendo esto en una PC o una laptop probablemente la regla que aplique sea md, donde vas a ver 3 columnas, la del medio el doble de ancho que las laterales.

Pero como probamos para distintas resoluciones sin tener disponibles dispositivos para cada punto de corte?

En Firefox en el menú Herramientas > Desarrollador web > Vista de diseño adaptable o el atajo de teclado Ctrl+Shift+M

/galleries/cew/9/firefox-ctrl-shift-m.png

En Chrome en el menú Menú > Mas Herramientas > Herramientas para desarrolladores y al abrirse seleccionamos el segundo icono de arriba a la derecha o el atajo de teclado Ctrl+Shift+M

/galleries/cew/9/chrome-ctrl-shift-m.png

Esto va a abrir una herramienta que nos permite simular distintas resoluciones y ver como la pagina se adapta a los cambios, lo único que vamos a usar ahora es cambiar la resolución manualmente o elegir un dispositivo predeterminado.

Así es como se ve en mi computadora en firefox:

/galleries/cew/9/ff-xs.png

Resolución xs: 320x480

/galleries/cew/9/ff-sm.png

Resolución sm: 760x480

/galleries/cew/9/ff-md.png

Resolución md: 800x480

Te recomiendo que lo pruebes vos, actividad extra, navega por paginas que visites frecuentemente con esta herramienta abierta, fijate como se adapta (o no) a la resolución que elegiste.

Creemos en la Web: Si son datos, hay tabla

Como presentamos muchos datos en una pagina? con tablas!

Partes de una tabla

Tabla de datos

Vamos de menos a mas, la tabla mas simple que podemos tener solo tiene una parte, el cuerpo de la tabla. Es decir, los datos.

Los datos en una tabla son cero o mas filas, cada fila puede tener cero o mas columnas:

Osea que las partes de una tabla por ahora son:

  • Tabla
    • Cuerpo (1)
      • Filas (0 o mas)
        • Columnas (0 o mas)

Si alguna vez usaste una planilla de cálculos, las tablas son una forma de presentar información que presentarías en una planilla de cálculos.

Vamos a ver una tabla de ejemplo:

<table>
  <tr>
    <td>Arenita</td>
    <td>Ardilla</td>
    <td>Marron</td>
  </tr>
  <tr>
    <td>Bob</td>
    <td>Esponja</td>
    <td>Amarillo</td>
  </tr>
  <tr>
    <td>Patricio</td>
    <td>Estrella</td>
    <td>Rosa</td>
  </tr>
</table>

Que se ve algo así:

Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa

Como vemos en el código, el tag table indica que vamos a usar una tabla, si solo vamos a mostrar datos el tag que indica el cuerpo tbody (table body, cuerpo de tabla) es opcional, luego tenemos el tag que indica una fila tr (table row: fila de tabla), dentro del tenemos el tag para una celda de datos td (table cell data: celda de datos de tabla), uno por cada celda.

Cabecera

En la tabla anterior, como sabemos que significa cada columna? para eso necesitamos una cabecera, esto se hace con el tag thead (table head, cabecera de tabla)

  • Tabla
    • Cabecera (0 o 1)
      • Filas (1 o mas)
        • Columnas (1 o mas)
    • Cuerpo (1)
      • Filas (0 o mas)
        • Columnas (0 o mas)
<table>
  <thead>
    <tr>
      <th>Nombre</th>
      <th>Tipo</th>
      <th>Color</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr>
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
  </tbody>
</table>
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa

Como podemos ver, en este caso tenemos que indicar explicitamente el cuerpo de la tabla con el tag tbody (table body, cuerpo de tabla).

Lo hacemos para poder tambien indicar la cabecera con el tag thead (table head, cabecera de tabla).

El cuerpo ya lo vimos antes, la cabecera es muy similar, solo que en lugar de usar el tag td para las columnas usamos el tag th (table cell header, celda de cabecera de tabla)

Pie de Tabla

Algunas tablas que presentan datos suelen tener al final una fila de sumarización que presenta valores resumidos para toda la columna.

Obviamente se puede usar para otras cosas, pero normalmente se usa para eso.

Vamos a ver un ejemplo que no aplica mucho a nuestro caso porque no estamos presentando valores que se puedan sumarizar.

  • Tabla
    • Cabecera (0 o 1)
      • Filas (1 o mas)
        • Columnas (1 o mas)
    • Cuerpo (1)
      • Filas (0 o mas)
        • Columnas (0 o mas)
    • Pie (0 o 1)
      • Filas (1 o mas)
        • Columnas (1 o mas)
<table>
  <thead>
    <tr>
      <th>Nombre</th>
      <th>Tipo</th>
      <th>Color</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr>
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <td>Nombre</td>
      <td>Tipo</td>
      <td>Color</td>
    </tr>
  </tfoot>
</table>
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Como podemos ver, el pie de tabla se define con el tag tfoot (table footer, pie de tabla), dentro usamos los mismos tags que en el cuerpo.

Un poco de estilo

Los ejemplos que vimos hasta ahora tienen un aspecto simple pero agradable, eso es porque estaba usando una clase de bootstrap para darle un aspecto aceptable, la clase que estaba usando es la clase table.

<table class="table">

En esta sección vamos a explorar otras clases que podemos aplicarle a una tabla.

Con bordes

<table class="table table-bordered">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Colores invertidos

<table class="table table-dark">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Cabecera invertida

<table class="table">
  <thead class="thead-dark">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Filas "rayadas como una zebra"

Cambiar el color de filas adyacentes es útil para que el usuario pueda seguir las columnas de una fila sin perderse o empezar a leer celdas de las filas cercanas sin darse cuenta.

<table class="table table-striped">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Énfasis en fila con foco del mouse

Resaltar la fila que tiene el foco del mouse es útil para que el usuario pueda seguir las columnas de una fila sin perderse o empezar a leer celdas de las filas cercanas sin darse cuenta.

<table class="table table-hover">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Compacta

Una tabla con menos espacios, si es necesario mostrar mas datos.

<table class="table table-sm">
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Resaltando filas

Si necesitamos indicar algo en una fila lo podemos hacer agregando una clase.

<tr class="table-active">
  <td>Arenita</td>
  <td>Ardilla</td>
  <td>Marron</td>
</tr>
<tr class="table-primary">
  <td>Bob</td>
  <td>Esponja</td>
  <td>Amarillo</td>
</tr>
<tr class="table-secondary">
  <td>Patricio</td>
  <td>Estrella</td>
  <td>Rosa</td>
</tr>
<tr class="table-success">
  <td>Arenita</td>
  <td>Ardilla</td>
  <td>Marron</td>
</tr>
<tr class="table-danger">
  <td>Bob</td>
  <td>Esponja</td>
  <td>Amarillo</td>
</tr>
<tr class="table-warning">
  <td>Patricio</td>
  <td>Estrella</td>
  <td>Rosa</td>
</tr>
<tr class="table-info">
  <td>Arenita</td>
  <td>Ardilla</td>
  <td>Marron</td>
</tr>
<tr class="table-light">
  <td>Bob</td>
  <td>Esponja</td>
  <td>Amarillo</td>
</tr>
<tr class="table-dark">
  <td>Patricio</td>
  <td>Estrella</td>
  <td>Rosa</td>
</tr>
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Todo junto!

<table class="table table-bordered table-striped table-sm table-dark table-hover">
  <thead class="thead-light">
    <tr>
      <th>Nombre</th>
      <th>Tipo</th>
      <th>Color</th>
    </tr>
  </thead>

  <tbody>
    <tr class="table-active">
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr class="table-primary">
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr class="table-secondary">
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
    <tr class="table-success">
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr class="table-danger">
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr class="table-warning">
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
    <tr class="table-info">
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr class="table-light">
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr class="table-dark">
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <td>Nombre</td>
      <td>Tipo</td>
      <td>Color</td>
    </tr>
  </tfoot>
</table>
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Subtítulo

Es útil indicar que datos se están mostrando en la tabla, para eso hay un tag llamado caption que puede ser usado para tal fin.

<table class="table">
  <caption>Personajes de Bob Esponja</caption>

  <thead>
    <tr>
      <th>Nombre</th>
      <th>Tipo</th>
      <th>Color</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Arenita</td>
      <td>Ardilla</td>
      <td>Marron</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>Esponja</td>
      <td>Amarillo</td>
    </tr>
    <tr>
      <td>Patricio</td>
      <td>Estrella</td>
      <td>Rosa</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <td>Nombre</td>
      <td>Tipo</td>
      <td>Color</td>
    </tr>
  </tfoot>
</table>
Personajes de Bob Esponja
Nombre Tipo Color
Arenita Ardilla Marron
Bob Esponja Amarillo
Patricio Estrella Rosa
Nombre Tipo Color

Celdas vacías y celdas unidas

En algunos casos podemos querer dejar algunas filas con menos celdas que otras, en otros casos queremos que una celda ocupe mas de una columna.

Usar menos celdas es fácil, simplemente no las escribimos.

<table class="table table-bordered">
  <tbody>
    <tr>
      <td>1.1</td>
    </tr>
    <tr>
      <td>2.1</td>
      <td>2.2</td>
    </tr>
    <tr>
      <td>3.1</td>
      <td>3.2</td>
      <td>3.3</td>
    </tr>
  </tbody>
</table>
1.1
2.1 2.2
3.1 3.2 3.3

Si queremos que una celda ocupe mas de una columna, tenemos que usar el atributo colspan (extensión de columnas) e indicarle cuantas columnas queremos que ocupe, por defecto cada celda tiene un colspan de 1.

<table class="table table-bordered">
  <tbody>
    <tr>
      <td colspan=3>1.1</td>
    </tr>
    <tr>
      <td>2.1</td>
      <td colspan=2>2.2</td>
    </tr>
    <tr>
      <td>3.1</td>
      <td>3.2</td>
      <td>3.3</td>
    </tr>
  </tbody>
</table>
1.1
2.1 2.2
3.1 3.2 3.3

Esto lo podemos usar en la cabecera para crear cabeceras multinivel:

 <table class="table table-bordered">
   <thead class="thead-dark">
     <tr>
       <th colspan=3>Lugar</th>
       <th rowspan=2 style="vertical-align: middle">Población</th>
     </tr>
     <tr>
       <th>Continente</th>
       <th>Pais</th>
       <th>Ciudad</th>
     </tr>
   </thead>

  <tbody>
    <tr>
      <td>America</td>
      <td>México</td>
      <td>Ciudad de México</td>
      <td>8 918 653</td>
    </tr>
    <tr>
      <td>America</td>
      <td>Argentina</td>
      <td>Buenos Aires</td>
      <td>2 890 151</td>
    </tr>
    <tr>
      <td>America</td>
      <td>Brasil</td>
      <td>Brasilia</td>
      <td>2 789 761</td>
    </tr>
  </tbody>
</table>
Lugar Población
Continente Pais Ciudad
America México Ciudad de México 8 918 653
America Argentina Buenos Aires 2 890 151
America Brasil Brasilia 2 789 761

Quizás notaste que use rowspan (extensión de fila) para "unir" las dos celdas de población verticalmente, también use el css vertical-align (alineación vertical) para que el texto este en el medio verticalmente.

Creemos en la Web: Haciendo Lugar

En la sección Creemos en la Web: Lo espacial es invisible a los ojos vimos como indicar que queremos mas espacio entre el borde y otros elementos (margin/margen), en el borde (border) o entre el borde y el contenido interno (padding/relleno).

Cuando yo era joven y el pasto era mas verde, las paginas web se hacían asumiendo una o dos resoluciones de pantalla, ya que los navegadores solo funcionaban en PCs y todas las PCs tenían una resolución casi estándar (800 pixeles de ancho por 600 de alto).

En esas épocas mas simples la unidad que se usaba para indicar espacio/distancia eran los pixeles, una unidad absoluta que se refiere a cada puntito de la pantalla que puede mostrar un color.

Como todas las pantallas tenían cantidades similares de pixeles horizontales y verticales, la cosa funcionaba bastante bien para todos.

No hace falta que les cuente que hoy la web se accede de una cantidad impresionante de dispositivos y resoluciones.

Para poder escribir estilo que se adapte a la resolución de cada dispositivo usamos otras unidades, llamadas relativas, ya que son relativas a algo presente en la pagina, las mas usadas son relativas al ancho del elemento que contiene nuestro tag o al ancho de una letra en el texto.

Pixeles

Esta es la unidad mas común, un pixel es un punto en la pantalla, el cual puede mostrar un color, la cantidad horizontal y vertical de pixeles en una pantalla se llama resolución, por ejemplo, una pantalla de una laptop puede tener 1280 pixeles de ancho por 800 de alto, lo que se escribe abreviado 1280x800.

cuando especificamos el estilo de un tag y le decimos que su borde, margen o relleno es de 15px (15 pixeles), le estamos diciendo que queremos 15 puntos de espacio, pero no sabemos cuantos pixeles tiene la pantalla en total, asi que eso puede ser bastante para la pantalla de un celular básico que puede tener una resolución de 320x240 o muy poco para la pantalla de una computadora de escritorio avanzada que pueden tener 3840x2160 (mas de 10 veces mas resolución!).

Idealmente vamos a usar esta unidad muy poco, yo lo uso solo para especificar el ancho de los bordes y muchas veces no debería :)

em

Esta es la unidad mas usada y la mas recomendada, su nombre según tengo entendido viene de lejos, 1em es el alto en pixeles de la letra M mayúscula, si nombramos la letra M "eme" en ingles es "em".

el alto de que M mayúscula? de la M si estuviera en el tag en el que estamos actualmente, osea que esta unidad es relativa al tamaño de texto del tag en el que nos encontramos, el cual lo puede haber establecido cualquiera de los tags padres, o ninguno, siendo asi el estándar de 16px.

rem

Pero que pasa si no sabemos que estilos se aplicaron a tags padres y queremos estar mas seguros del tamaño que vamos a obtener? para eso existe la unidad rem, que es el alto de la letra M según el tamaño de texto definido en la base del documento (el tag <body>), de no estar definido va a ser también 16px.

Su nombre viene de "root em" (em de la raíz).

Esto nos permite saber que no importa que tamaños de fuente se hayan redefinido hasta nuestro tag, su tamaño va a ser siempre fijo relativo al tamaño base del texto del documento.

Porcentajes

Otra unidad útil, pero usada normalmente cuando estamos definiendo tamaños de la estructura de nuestro documento como ancho de columnas es el porcentaje %.

El porcentaje se refiere al ancho del tag que contiene al tag actual, si decimos que el ancho de nuestro tag es 50%, este ocupara la mitad del tag padre, si decimos que el margen horizontal es de 5%, el padding horizontal es del 2.5%, entonces nos queda 75% para el contenido:

5% margen izquierdo + 2.5% padding izquierdo + 2.5% padding derecho + 5% margen derecho = 15%

Ejemplos que no se entiende nada!

Las unidades de espacio se entienden mas usandolas y a puro prueba y error, la recomendación es usar em y rem siempre que se pueda, porcentajes cuando estamos definiendo posicionamiento de cosas en la pagina y pixeles si tenes una buena razón.

El div azul que contiene a todos los otros divs establece el tamaño de la fuente a 16 pixeles:

<div style="font-size: 16px; width: 90%; padding: 2.5%; margin: 2.5%; border: 1px solid blue;">
    <div style="width: 5em;  background-color: red; color: white; margin: 1em 0;">5em</div>
    <div style="width: 5rem; background-color: red; color: white; margin: 1em 0;">5rem</div>
    <div style="width: 50px; background-color: red; color: white; margin: 1em 0;">50px</div>
    <div style="width: 50%;  background-color: red; color: white;">50%</div>
</div>
5em
5rem
50px
50%

El div azul que contiene a todos los otros divs establece el tamaño de la fuente, notar que los divs interiores tienen el mismo estilo que los de arriba:

<div style="font-size: 32px; width: 90%; padding: 2.5%; margin: 2.5%; border: 1px solid blue;">
    <div style="width: 5em;  background-color: red; color: white; margin: 1em 0;">5em</div>
    <div style="width: 5rem; background-color: red; color: white; margin: 1em 0;">5rem</div>
    <div style="width: 50px; background-color: red; color: white; margin: 1em 0;">50px</div>
    <div style="width: 50%;  background-color: red; color: white;">50%</div>
</div>
5em
5rem
50px
50%

El primer div tiene un ancho de 5em, como el div padre establece el tamaño de la fuente a distintos valores en los dos ejemplos, el ancho resultante es distinto.

El segundo div tiene un ancho de 5rem, como ambos están en el mismo documento raíz, tienen el mismo ancho, aun cuando el texto interior cambia, ya que "hereda" el tamaño del div padre.

El tercero esta en pixeles, así que va a ser igual, el cuarto esta en porcentaje, y ya que ambos divs padres tienen el mismo ancho, su ancho es igual.

Probemos algo un poco distinto:

<div style="font-size: 32px; width: 50%; padding: 2.5%; margin: 2.5%; border: 1px solid blue;">
    <div style="width: 5em;  font-size: 1rem; background-color: red; color: white; margin: 1em 0;">5em</div>
    <div style="width: 5rem; font-size: 1rem; background-color: red; color: white; margin: 1em 0;">5rem</div>
    <div style="width: 50px; font-size: 1rem; background-color: red; color: white; margin: 1em 0;">50px</div>
    <div style="width: 50%;  font-size: 1rem; background-color: red; color: white;">50%</div>
</div>
5em
5rem
50px
50%

El div padre ahora ocupa el 50% del ancho de la pagina, por lo que el ancho del ultimo div hijo debería ser la mitad de los anteriores, para "estandarizar" em y rem, seteo el tamaño de fuente de los divs hijos a 1rem.

Como no se en que pantalla estas viendo esto no te puedo decir mucho sobre que ancho van a tener, lo único que se, es que como la fuente de ambos tiene 1rem de tamaño, el ancho de los dos debería ser el mismo.

Si el tamaño de la fuente del documento resulta ser 10px, entonces el tercer div tendrá el mismo ancho.

Como siempre, no hace falta que se entienda todo ahora, solo saber las unidades mas usadas, las recomendadas y mas o menos como se comportan, el resto es prueba y error.

Creemos en la Web: Colores

Estamos creando una pagina y vemos o nos imaginamos un color que queremos usar, como se lo comunicamos a la computadora?

Las computadoras son buenas manipulando números, los colores, al menos como nosotros los usamos al comunicarnos, no tienen mucho de números.

En la búsqueda por encontrar un compromiso que funcionara tanto para humanos como para computadoras surgieron diferentes "representaciones", formas de describir unívocamente a que color nos referimos.

En esta sección vamos a explorar estas distintas representaciones.

Una herramienta online para elegir colores es Mozilla Color Picker podes usar esta o buscar alguna con la que ya hayas trabajado, intenta que permita ver las representaciones que vamos a explorar en esta sección.

Usando colores

Los siguientes son algunos de los atributos CSS que requieren colores, todos soportan todas las representaciones que vamos a explorar a continuación.

  • color
  • background-color
  • border-color
  • outline-color
  • text-decoration-color
  • text-emphasis-color
  • text-shadow

Un ejemplo que algunos de los atributos listados:

<span style="border: 1px solid; text-decoration: underline; color: red; background-color: lightgrey; border-color: blue; text-decoration-color: green; text-shadow: yellow 0.6em 0.6em; padding: 1em;">Hello Color</span>
Hello Color

Colores con nombres

La mas fácil y la que hemos usado hasta ahora es simplemente dar el nombre del color en ingles cuando necesitamos referirnos a el.

Esta representación es simple para los humanos pero tiene un par de limitaciones:

  • Hay que mantener una lista de nombres a colores
  • No todos los colores tienen nombre
  • Como me acuerdo de tantos nombres?
  • Tampoco queremos una lista de colores eterna
  • Cuando busco un color, como lo busco rápido en la tabla?
  • Cuando digo rojo, que rojo es?

A continuación la lista de colores

black
silver
gray
white
maroon
red
purple
fuchsia
green
lime
olive
yellow
navy
blue
teal
aqua
orange
aliceblue
antiquewhite
aquamarine
azure
beige
bisque
blanchedalmond
blueviolet
brown
burlywood
cadetblue
chartreuse
chocolate
coral
cornflowerblue
cornsilk
crimson
cyan (synonym of aqua)
darkblue
darkcyan
darkgoldenrod
darkgray
darkgreen
darkgrey
darkkhaki
darkmagenta
darkolivegreen
darkorange
darkorchid
darkred
darksalmon
darkseagreen
darkslateblue
darkslategray
darkslategrey
darkturquoise
darkviolet
deeppink
deepskyblue
dimgray
dimgrey
dodgerblue
firebrick
floralwhite
forestgreen
gainsboro
ghostwhite
gold
goldenrod
greenyellow
grey
honeydew
hotpink
indianred
indigo
ivory
khaki
lavender
lavenderblush
lawngreen
lemonchiffon
lightblue
lightcoral
lightcyan
lightgoldenrodyellow
lightgray
lightgreen
lightgrey
lightpink
lightsalmon
lightseagreen
lightskyblue
lightslategray
lightslategrey
lightsteelblue
lightyellow
limegreen
linen
magenta (synonym of fuchsia)
mediumaquamarine
mediumblue
mediumorchid
mediumpurple
mediumseagreen
mediumslateblue
mediumspringgreen
mediumturquoise
mediumvioletred
midnightblue
mintcream
mistyrose
moccasin
navajowhite
oldlace
olivedrab
orangered
orchid
palegoldenrod
palegreen
paleturquoise
palevioletred
papayawhip
peachpuff
peru
pink
plum
powderblue
rosybrown
royalblue
saddlebrown
salmon
sandybrown
seagreen
seashell
sienna
skyblue
slateblue
slategray
slategrey
snow
springgreen
steelblue
tan
thistle
tomato
turquoise
violet
wheat
whitesmoke
yellowgreen
rebeccapurple

RGB: Combinando Rojo, Verde y Azul

Otra forma de especificar colores es describir una mezcla de colores "básicos", en este caso rojo (Red), verde (Green) y azul (Blue).

Como lo describimos?

Necesitamos indicar la cantidad de cada color en la combinación, lo podemos hacer de dos formas:

  • Con números
    • 0: nada de color
    • 255: máximo de color
  • Como porcentaje
    • 0%: nada de color
    • 100%: máximo de color

Como lo escribimos?

La forma mas fácil de escribirlo si sabemos los valores individuales y dado que hay múltiples formas de indicarlo es:

  • Indicar de que forma vamos a describir el color, en nuestro caso rgb
  • Indicar los 3 valores

Veamos algunos ejemplos

R G B Formato Color
0 0 0 rgb(0, 0, 0)
255 255 255 rgb(255, 255, 255)
255 0 0 rgb(255, 0, 0)
0 255 0 rgb(0, 255, 0)
0 0 255 rgb(0, 0, 255)
255 255 0 rgb(255, 255, 0)
255 0 255 rgb(255, 0, 255)
0 255 255 rgb(0, 255, 255)
128 128 128 rgb(128, 128, 128)
128 0 0 rgb(128, 0, 0)
0 128 0 rgb(0, 128, 0)
0 0 128 rgb(0, 0, 128)
80 160 255 rgb(80, 160, 255)
80 255 160 rgb(80, 255, 160)
255 160 80 rgb(255, 160, 80)
160 255 80 rgb(160, 255, 80)
160 80 255 rgb(160, 80, 255)
255 80 160 rgb(255, 80, 160)
0% 0% 0% rgb(0%, 0%, 0%)
100% 100% 100% rgb(100%, 100%, 100%)
100% 0% 0% rgb(100%, 0%, 0%)
0% 100% 0% rgb(0%, 100%, 0%)
0% 0% 100% rgb(0%, 0%, 100%)
100% 100% 0% rgb(100%, 100%, 0%)
100% 0% 100% rgb(100%, 0%, 100%)
0% 0% 0% rgb(0%, 0%, 0%)
50% 50% 50% rgb(50%, 50%, 50%)
50% 0% 0% rgb(50%, 0%, 0%)
0% 50% 0% rgb(0%, 50%, 0%)
0% 0% 50% rgb(0%, 0%, 50%)
50% 50% 0% rgb(50%, 50%, 0%)
50% 0% 50% rgb(50%, 0%, 50%)

Alternativa: Hexadecimal

Este formato suele estar disponible en herramientas que usan o manipulan colores, es compacta pero difícil de interpretar a menos que entiendas la numeración hexadecimal fluidamente.

La mencionamos porque te la vas a encontrar en muchos lugares y hay que saber que es un formato de color valido, que lo podes usar en lugar de cualquiera de los otros y que hay muchas herramientas que la usan.

Nota muy resumida para los curiosos:

En hexadecimal en lugar de contar del 0 al 9 y al quedarnos sin dígitos ponemos un 1 adelante y empezamos de nuevo como lo hacemos en decimal, se cuenta del 0 a la F, porque tiene como base 16 y no 10 como el decimal, contando en hexadecimal seria algo como: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11 ... 1F, 20 ... 2F, 30 ... F0 ... FF, 100 etc.

Lo que cambia es que el 255 de antes se convierte en FF y ponemos los 3 valores todos juntos luego del símbolo #, que indica que estamos usando este formato, el formato debe tener o 3 o 6 caracteres, de ser necesario llenamos los valores restantes con 0.

Algunos ejemplos de la sección anterior convertidos a formato hexadecimal:

R G B Formato Color
00 00 00 #000000
FF FF FF #FFFFFF
FF 00 00 #FF0000
00 FF 00 #00FF00
00 00 FF #0000FF
FF FF 00 #FFFF00
FF 00 FF #FF00FF
00 FF FF #00FFFF
80 80 80 #808080
80 00 00 #800000
00 80 00 #008000
00 00 80 #000080

HSL: Tono, Saturación y "Liviandad/Brillo"

En esta representación tenemos 3 valores, llamados H (Hue), S (Saturation), L (Lightness).

H
Numero de 0 a 360 (angulo en un circulo de colores), indica el tono base que queremos
S
Porcentaje de saturación del color elegido, 0% va a ser un gris, 100% va a ser el color puro.
L
Porcentaje de liviandad/brillo del color elegido, 0% va a ser negro, 100% va a ser blanco, 50% (y 100% de saturación) va a ser el color puro.

Algunos colores "puros":

hsl(0, 100%, 50%)
hsl(30, 100%, 50%)
hsl(60, 100%, 50%)
hsl(90, 100%, 50%)
hsl(120, 100%, 50%)
hsl(150, 100%, 50%)
hsl(180, 100%, 50%)
hsl(210, 100%, 50%)
hsl(240, 100%, 50%)
hsl(270, 100%, 50%)
hsl(300, 100%, 50%)
hsl(330, 100%, 50%)
hsl(360, 100%, 50%)

Cambiando la saturación:

hsl(0, 0%, 50%)
hsl(0, 25%, 50%)
hsl(0, 50%, 50%)
hsl(0, 75%, 50%)
hsl(0, 100%, 50%)

Cambiando el "brillo":

hsl(0, 100%, 0%)
hsl(0, 100%, 25%)
hsl(0, 100%, 50%)
hsl(0, 100%, 75%)
hsl(0, 100%, 100%)

Alpha: Transparencia/Opacidad

Un ultimo componente del color común a todos los que vimos es la transparencia/opacidad, es decir, cuanto del contenido que se encuentra "detrás" del color que estamos mostrando es visible.

La transparencia/opacidad va de 0% (ausencia absoluta de color, como un vidrio) a 100% (color solido, nada se "transluce")

Cuando indicamos la transparencia en rgb y hsl puede ser:

  • Numero entre 0 y 1
  • Porcentaje de 0% a 100%

Ejemplos:

/* transparente */
rgba(255, 0, 153, 0)
rgba(255, 0, 153, 0%)

/* semi translucido */
rgba(255, 0, 153, 0.5)
rgba(255, 0, 153, 50%)

/* opaco */
rgba(255, 0, 153, 1)
rgba(255, 0, 153, 100%)
/* transparente */
hsla(240, 100%, 50%, 0)
hsla(240, 100%, 50%, 0%)

/* semi translucido */
hsla(240, 100%, 50%, 0.5)
hsla(240, 100%, 50%, 50%)

/* opaco */
hsla(240, 100%, 50%, 1)
hsla(240, 100%, 50%, 100%)

En el formato hexadecimal simplemente agregamos dos dígitos mas al final entre 00 (0%) y FF (100%) indicando el nivel de transparencia

/* transparente */
#FFFFFF00

/* semi translucido */
#FFFFFF80

/* opaco */
#FFFFFFFF

Y así llegamos al final, no hace falta que intentes aprender, entender o memorizar esto, solo saber que hay distintas formas de especificar colores, mas o menos cuales son, para el resto esta tu motor de búsqueda amigo.

Riak Core Tutorial Part 2: Starting

This is part of a series, see the previous one at Riak Core Tutorial Part 1: Setup

Creating our Project

Now that we have our tools and our template installed we can start by asking rebar3 to create a new project we will call tanodb using the riak_core template we just installed:

rebar3 new rebar3_riak_core name=tanodb

If it fails saying it can't find rebar3 check that it's in your $PATH environment variable and that you have Erlang activated.

The output should be something like this:

===> Writing tanodb/apps/tanodb/src/tanodb.app.src
===> Writing tanodb/apps/tanodb/src/tanodb.erl
===> Writing tanodb/apps/tanodb/src/tanodb_app.erl
===> Writing tanodb/apps/tanodb/src/tanodb_sup.erl
===> Writing tanodb/apps/tanodb/src/tanodb_console.erl
===> Writing tanodb/apps/tanodb/src/tanodb_vnode.erl
===> Writing tanodb/rebar.config
===> Writing tanodb/.editorconfig
===> Writing tanodb/.gitignore
===> Writing tanodb/README.rst
===> Writing tanodb/Makefile
===> Writing tanodb/config/admin_bin
===> Writing tanodb/priv/01-tanodb.schema
===> Writing tanodb/config/advanced.config
===> Writing tanodb/config/vars.config
===> Writing tanodb/config/vars_dev1.config
===> Writing tanodb/config/vars_dev2.config
===> Writing tanodb/config/vars_dev3.config

Note

The content of this chapter is in the 01-template branch.

https://gitlab.com/marianoguerra/tanodb/tree/01-template

Building and Running

Before explaining what the files mean so you get an idea what just happened let's run it!

cd tanodb
make
make console

make runs rebar3 commands to build a release of our project, for that it uses a tool called relx.

The initial build may take a while since it has to fetch all the dependencies and build them.

After the release is built (you can check the result by inspecting the folder _build/default/rel/tanodb/) we can run it.

When we run make console we get some noisy output that should end with something like this:

Eshell V9.3  (abort with ^G)
(tanodb@127.0.0.1)1>

This is the Erlang shell, something like a REPL connected to our system, we now can test our system by calling tanodb:ping() on it.

(tanodb@127.0.0.1)1> tanodb:ping().
{pong,1347321821914426127719021955160323408745312813056}

The response is the atom pong and a huge number that we will explain later, but to make it short, it's the id of the process that replied to us.

Exploring the Template Files

The template created a lot of files and if you are like me, you don't like things that make magic and don't explain what's going on, that's why we will get a brief overview of the files created here.

First this files are created:

apps/tanodb/src/tanodb.app.src
apps/tanodb/src/tanodb.erl
apps/tanodb/src/tanodb_app.erl
apps/tanodb/src/tanodb_sup.erl
apps/tanodb/src/tanodb_console.erl
apps/tanodb/src/tanodb_vnode.erl

Those are the meat of this project, the source code we start with, if you know a little of erlang you will recognice many of them, let's explain them briefly, if you think you need more information I recommend you this awesome book which you can read online: Learn You Some Erlang for great good!

tanodb.app.src
This file is "The Application Resource File", you can read it, it's quite self descriptive. You can read more about it in the Building OTP Applications Section of Learn You Some Erlang or in the man page for app in the Erlang documentation.
tanodb.erl
This file is the main API of our application, here we expose all the things you can ask our application to do, for now it can only handle the ping() command but we will add some more in the future.
tanodb_app.erl
This file implements the application behavior it's a set of callbacks that the Erlang runtime calls to start and stop our application.
tanodb_sup.erl
This file implements the supervisor behavior it's a set of callbacks that the Erlang runtime calls to build the supervisor hierarchy.
tanodb_console.erl
This file is specific to riak_core, it's a set of callbacks that will be called by the tanodb-admin command.
tanodb_vnode.erl
This file is specific to riak_core, it implements the riak_code_vnode behavior, which is a set of callbacks that riak_core will call to accomplish different tasks, it's the main file we will edit to add new features.

Those were the source code files, but the template also created other files, let's review them

rebar.config
This is the file that rebar3 reads to get information about our project like dependencies and build configuration, you can read more about it on the rebar3 documentation
.editorconfig
This file describes the coding style for this project, if your text editor understands editorconfig files then it will change it's setting for this project to the ones described in this file, read more about editor config on the editorconfig website
.gitignore
A file to tell git which files to ignore from the repository.
README.rst
The README of the project
Makefile
A make file with some targets that will make it easier to achieve some complex tasks without copying and pasting too much.
config/admin_bin
A template for the tanodb-admin command.
priv/01-tanodb.schema
The cuttlefish schema file that describes what configuration our application supports, it starts with some example configuration fields that we will use as the application grows.
config/advanced.config
This file is where we configure some advanced things of our application that don't go on our tanodb.config file, here we configure riak_core and our logging library
config/vars.config
This file contains variables used by relx to build a release, you can read more about it in the rebar3 release documentation

The following files are like vars.config but with slight differences to allow running more than one node on the same machine:

config/vars_dev1.config
config/vars_dev2.config
config/vars_dev3.config

Normally when you have a cluster for your application one operating system instance runs one instance of your application and you have many operating system instances, but to test the clustering features of riak_core we will build 3 releases of our application using offsets for ports and changing the application name to avoid collisions.

Those are all the files, follow the links to know more about them.

Playing with Clustering

Before starting to add features, let's first play with clustering so we understand all those config files above work.

Build 3 releases that can run on the same machine:

make devrel

This will build 3 releases of the application using different parameters (the dev1, dev2 and dev3 files we saw earlier) and will place them under:

_build/dev1
_build/dev2
_build/dev3

This is achived by using the profiles feature from rebar3.

Now open 3 consoles and run the following commands one on each console:

make dev1-console
make dev2-console
make dev3-console

This will start the 3 nodes but they won't know about each other, for them to know about each other we need to "join" them, that is to tell one of them about the other two, this is achieved using the tanodb-admin command, here is how you should run it manually (don't run them):

_build/dev2/rel/tanodb/bin/tanodb-admin cluster join tanodb1@127.0.0.1
_build/dev3/rel/tanodb/bin/tanodb-admin cluster join tanodb1@127.0.0.1

We tell dev2 and dev3 to join tanodb1 (dev1), to make this easier and less error prone run the following command:

make devrel-join

Now let's check the status of the cluster:

make devrel-status

You can read the Makefile to get an idea of what those commands do, in this case devrel-status does the following:

_build/dev1/rel/tanodb/bin/tanodb-admin member-status

You should see something like this:

================================= Membership ===============
Status     Ring    Pending    Node
------------------------------------------------------------
joining     0.0%      --      'tanodb2@127.0.0.1'
joining     0.0%      --      'tanodb3@127.0.0.1'
valid     100.0%      --      'tanodb1@127.0.0.1'
------------------------------------------------------------
Valid:1 / Leaving:0 / Exiting:0 / Joining:2 / Down:0

It should say that 3 nodes are joining, now check the cluster plan:

make devrel-cluster-plan

The output should be something like this:

=============================== Staged Changes ==============
Action         Details(s)
-------------------------------------------------------------
join           'tanodb2@127.0.0.1'
join           'tanodb3@127.0.0.1'
-------------------------------------------------------------


NOTE: Applying these changes will result in 1 cluster transition

#############################################################
                         After cluster transition 1/1
#############################################################

================================= Membership ================
Status     Ring    Pending    Node
-------------------------------------------------------------
valid     100.0%     34.4%    'tanodb1@127.0.0.1'
valid       0.0%     32.8%    'tanodb2@127.0.0.1'
valid       0.0%     32.8%    'tanodb3@127.0.0.1'
-------------------------------------------------------------
Valid:3 / Leaving:0 / Exiting:0 / Joining:0 / Down:0

WARNING: Not all replicas will be on distinct nodes

Transfers resulting from cluster changes: 42
  21 transfers from 'tanodb1@127.0.0.1' to 'tanodb3@127.0.0.1'
  21 transfers from 'tanodb1@127.0.0.1' to 'tanodb2@127.0.0.1'

Now we can commit the plan:

make devrel-cluster-commit

Which should say something like:

Cluster changes committed

Now riak_core started an internal process to join the nodes to the cluster, this involve some complex processes that we will explore in the following chapters.

You should see on the consoles where the nodes are running that some logging is happening describing the process.

Check the status of the cluster again:

make devrel-status

You can see the vnodes transfering, this means the content of some virtual nodes on one tanodb node are being transferred to another tanodb node:

================================= Membership =============
Status     Ring    Pending    Node
----------------------------------------------------------
valid      75.0%     34.4%    'tanodb1@127.0.0.1'
valid       9.4%     32.8%    'tanodb2@127.0.0.1'
valid       7.8%     32.8%    'tanodb3@127.0.0.1'
----------------------------------------------------------
Valid:3 / Leaving:0 / Exiting:0 / Joining:0 / Down:0

At some point you should see something like this, which means that the nodes are joined and balanced:

================================= Membership ==============
Status     Ring    Pending    Node
-----------------------------------------------------------
valid      34.4%      --      'tanodb1@127.0.0.1'
valid      32.8%      --      'tanodb2@127.0.0.1'
valid      32.8%      --      'tanodb3@127.0.0.1'
-----------------------------------------------------------
Valid:3 / Leaving:0 / Exiting:0 / Joining:0 / Down:0

When you are bored you can stop them:

make devrel-stop

Building a Production Release

Even when our application doesn't have the features to merit a production release we are going to learn how to do it here since you can later do it at any step and get a full release of the app:

make prod-release

In that command rebar3 runs the release task using the prod profile, which has some configuration differences with the dev profiles we use so that it builds something we can unpack and run on another operating system without installing anything.

Let's package our release:

cd _build/prod/rel
tar -czf tanodb.tgz tanodb tanodb_config
cd -
mv _build/prod/rel/tanodb.tgz .

You can copy it to a clean OS and run:

tar -xzf tanodb.tgz
./tanodb/bin/tanodb console

And it runs!

Note

You should build the production release on the same operating system version you are intending to run it to avoid version problems, the main source of headaches are C extensions disagreeing on libc versions and similar.

So, even when you could build it on a version that is close and test it it's better to build releases on the same version to avoid problems. More so if you are packaging the Erlang runtime with the release as we are doing here.

Wrapping Up

Now you know how to create a riak_core app from a template, how to build a release and run it, how to build releases for a development cluster, run the nodes, join them and inspect the cluster status and how to build a production release and run it on a fresh server.

Riak Core Tutorial Part 1: Setup

This is the first chapter in a series that will explore how to use riak_core to build a distributed key-value store.

We first need to have Erlang installed and rebar3 installed.

The Easy Way

If you don't have Erlang installed or you don't have problem to install the latest one system wide you can try installing it with your package manager:

  • For Homebrew on OS X: brew install erlang
  • For MacPorts on OS X: port install erlang
  • For Ubuntu and Debian: apt-get install erlang
  • For Fedora: yum install erlang
  • For FreeBSD: pkg install erlang

Please check that the package version is 20.x, if not, check for instructions on how to install the Erlang Solutions package for Ubuntu, CentOS, Mac OS X, Debian or Fedora here: https://www.erlang-solutions.com/resources/download.html

Setting up rebar3

Now we have Erlang, we need a build tool, we are going to use rebar3:

# download rebar3 to our bin directory
wget https://s3.amazonaws.com/rebar3/rebar3 -O $HOME/bin/rebar3

# set execution permissions for our user
chmod u+x rebar3

Just in case you have problems running the rebar3 commands with a different version, here's the version I'm using:

rebar3 version

Output:

rebar 3.5.0 on Erlang/OTP 20 Erts 9.2

Install Riak Core Rebar3 Template

To create a Riak Core project from scratch we will use a template called rebar3_template_riak_core.

we need to clone its repo in a place where rebar3 can see it:

mkdir -p ~/.config/rebar3/templates
git clone https://github.com/marianoguerra/rebar3_template_riak_core.git ~/.config/rebar3/templates/rebar3_template_riak_core

The Hard Way: Building Erlang with kerl

Note

If you installed Erlang with the instructions above, skip until the Test that Everything Works section below.

If you have or want to have more than one version running side by side you can use kerl, from its github README:

Easy building and installing of Erlang/OTP instances.

Kerl aims to be shell agnostic and its only dependencies, excluding what's
required to actually build Erlang/OTP, are curl and git.

Note

On Mac you can install it with homebrew: brew install kerl

First we need to fetch kerl:

# create bin folder in our home directory if it's not already there
mkdir -p ~/bin

# cd to it
cd ~/bin

# download kerl script
curl -O https://raw.githubusercontent.com/kerl/kerl/master/kerl

# set execution permitions for our user
chmod u+x kerl

You will need to add ~/bin to your PATH variable so your shell can find the kerl script, you can do it like this in your shell:

# set the PATH environment variable to the value it had before plus a colon
# (path separator) and a new path which points to the bin folder we just
# created
PATH=$PATH:$HOME/bin

If you want to make this work every time you start a shell you need to put it it the rc file of your shell of choice, for bash it's ~/.bashrc, for zsh it's ~/.zshrc, you will have to add a line like this:

export PATH=$PATH:$HOME/bin

After this, start a new shell or source your rc file so that it picks up your new PATH variable, you can check that it's set correctly by running:

echo $PATH

And checking in the output if $HOME/bin is there (notice that $HOME will be expanded to the actual path).

Building an Erlang release with kerl

We have kerl installed and available in our shell, now we need to build an Erlang release of our choice, for this we will need a compiler and other tools and libraries needed to compile it:

This are instructions on ubuntu 17.10, check the names for those packages on your distribution.

# required: basic tools and libraries needed
# (compiler, curses for the shell, ssl for crypto)
sudo apt-get -y install build-essential m4 libncurses5-dev libssl-dev

# optonal: if you want odbc support (database connectivity)
sudo apt-get install unixodbc-dev

# optonal: if you want pdf docs you need apache fop and xslt tools and java (fop is a java project)
sudo apt-get install -y fop xsltproc default-jdk

# optional: if you want to build jinterface you need a JDK
sudo apt-get install -y default-jdk

# optional: if you want wx (desktop GUI modules)
sudo apt-get install -y libwxgtk3.0-dev

Now that we have everything we need we can finally build our Erlang release.

First we fetch an updated list of releases:

kerl update releases

The output in my case:

The available releases are:

R10B-0 R10B-10 R10B-1a R10B-2 R10B-3 R10B-4 R10B-5 R10B-6 R10B-7 R10B-8
R10B-9 R11B-0 R11B-1 R11B-2 R11B-3 R11B-4 R11B-5 R12B-0 R12B-1 R12B-2 R12B-3
R12B-4 R12B-5 R13A R13B01 R13B02-1 R13B02 R13B03 R13B04 R13B R14A R14B01
R14B02 R14B03 R14B04 R14B_erts-5.8.1.1 R14B R15B01 R15B02
R15B02_with_MSVCR100_installer_fix R15B03-1 R15B03 R15B
R16A_RELEASE_CANDIDATE R16B01 R16B02 R16B03-1 R16B03 R16B 17.0-rc1 17.0-rc2
17.0 17.1 17.3 17.4 17.5 18.0 18.1 18.2.1 18.2 18.3 19.0 19.1 19.2 19.3
20.0 20.1 20.2 20.3

Let's build the 20.3 version:

# this will take a while
kerl build 20.3 20.3

And install it:

kerl install 20.3 ~/bin/erl-20.3

Now everytime we want to use this version of Erlang we need to run:

. $HOME/bin/erl-20.3/activate

Test that Everything Works

We have installed several tools:

kerl
Let's you install multiple Erlang releases that can live side by side
Erlang 20.3
The version of erlang we are going to be using
Rebar 3
Our build tool
rebar3_template_riak_core
Rebar 3 Template that will make it easy to setup fresh riak_core projects for experimentation

Now we need to check that everything is setup correctly, we will do that by creating a template and building it.

Remember to have $HOME/bin in your $PATH and Erlang 20.3 activated, cd to a folder of your choice to hold this project and run:

rebar3 new rebar3_riak_core name=akv

Output should be similar to this one:

===> Writing akv/apps/akv/src/akv.app.src
===> Writing akv/apps/akv/src/akv.erl
===> Writing akv/apps/akv/src/akv_app.erl
===> Writing akv/apps/akv/src/akv_sup.erl
===> Writing akv/apps/akv/src/akv_console.erl
===> Writing akv/apps/akv/src/akv_vnode.erl
===> Writing akv/rebar.config
===> Writing akv/.editorconfig
===> Writing akv/.gitignore
===> Writing akv/README.rst
===> Writing akv/Makefile
===> Writing akv/config/admin_bin
===> Writing akv/priv/01-akv.schema
===> Writing akv/config/advanced.config
===> Writing akv/config/vars.config
===> Writing akv/config/vars_dev1.config
===> Writing akv/config/vars_dev2.config
===> Writing akv/config/vars_dev3.config

Now let's try to build it:

cd akv
make

Output is to long to list, after it ends, near the end you should see this line:

===> release successfully created!

Now let's try to run it:

make console

Last lines should be:

Eshell V9.3  (abort with ^G)
(akv@127.0.0.1)1>

You can exit with q(). and pressing enter or hitting Ctrl-C twice.

We're ready to start!