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.

Función para convertir valores NaN en 0 en Javascript

Vamos como una minientrada sobre Javascript. Hoy trabajaba con varios sumatorios y en algún momento me «rompía» la cuenta porque intentaba acceder al valor de un campo vacío, recibía un valor NaN… El resultado es que toda la cuenta se iba al carajo.

Javascript nativamente nos ofrece una función llamada isNaN() para comprobar si una variable tiene ese valor (en caso de que lo tenga devolverá un true), por lo que sirviéndonos de ella podemos crear una función que nos devuelva un 0 cuando el valor sea NaN. Tal que así:

function NaN2Zero(n){
    return isNaN( n ) ? 0 : n; 
}

Dicha función llama a isNaN para comprobar el valor. En caso de respuesta afirmativa devuelve un 0, en caso contrario devuelve el valor de la variable recibida.

Crear un elemento arrastrable (drag and drop) con jQuery, sin jQuery UI

jQuery UI nos permite definir un elemento como «draggable» para que podamos «agarrarlo» con el ratón para arrastrarlo por la pantalla y situarlo donde mejor nos convenga. Hoy en el trabajo me veía con la limitación de no poder recurrir a jQuery UI, sólo podía utilizar jQuery 1.11 y tenía que lograr el mismo efecto.

Mentiría si dijera que lo hice yo, básicamente cogí este código de CSS-Tricks que os dejo a continuación y le hice un par de pequeños cambios para que funcionara de la forma deseada en la aplicación.

(function($) {
    $.fn.drags = function(opt) {

        opt = $.extend({handle:"",cursor:"move"}, opt);

        if(opt.handle === "") {
            var $el = this;
        } else {
            var $el = this.find(opt.handle);
        }

        return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
            if(opt.handle === "") {
                var $drag = $(this).addClass('draggable');
            } else {
                var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
            }
            var z_idx = $drag.css('z-index'),
                drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;
            $drag.css('z-index', 1000).parents().on("mousemove", function(e) {
                $('.draggable').offset({
                    top:e.pageY + pos_y - drg_h,
                    left:e.pageX + pos_x - drg_w
                }).on("mouseup", function() {
                    $(this).removeClass('draggable').css('z-index', z_idx);
                });
            });
            e.preventDefault(); // disable selection
        }).on("mouseup", function() {
            if(opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle').parent().removeClass('draggable');
            }
        });

    }
})(jQuery);

Tras esto me bastó aplicar esa función sobre los elementos deseados, en ese caso por medio de una clase:

$('.ElementoMovil').drags();

En este caso dad gracias a esa excelente web que es CSSTricks cargada de trucos para mejorar el diseño y la experiencia del usuario, ya que el trabajo es suyo. En el artículo original podéis probar el funcionamiento de dicha función. Añado que en versiones muy antiguas de jQuery no funciona, al menos con 1.5.2 que fue con la que lo probé en principio. En cualquier caso, es recomendable tener siempre esta librería actualizada.

La regla @page y estilos para impresión en CSS

Si bien es cierto que cada día es menos habitual imprimir cosas desde la web muchas veces puede interesarnos tener un formato específico para la impresora que nos permita ocultar menús. A la hora de meter un formato sólo para la impresora procederemos como con cualquier CSS normal, pero añadiendo en la etiqueta media=»print», como en el ejempo:

<!-- Cargando un CSS externo -->
<link href="paraimprimir.css" type="text/css" media="print" />
<!-- Insertando CSS en la cabecera -->
<style type="text/css" media="print">
/*aquí lo que corresponda*/
</style>
<!--También puede usarse esta sintaxis-->
<style type="text/css"> 
  @media print { 
      /* reglas css */ 
  } 
<style>

Con estos estilos, por ejemplo, podemos hacer que un elemento aparezca en todas las páginas definiéndolo como fixed u ocultar lo que no tenga sentido mostrar en la impresión con display:none.

El uso de media print genera una caja CSS distinta a la de pantalla (media screen) para alojar los contenidos, a pesar de que su boxmodel será el mismo. Esta caja se conoce como page y podremos acceder a ella para modificar sus características mediante el selector @page.

Dicho selector nos permite, por ejemplo, definir la orientación de la página entre normal y apaisada:

/*Orientación vertical*/
@page {size: portrait;}
/*Orientación apaisada*/
@page {size: landscape;}

También podemos utilizar clases ligadas a la regla page, por ejemplo imaginemos que queremos imprimir un informe con todas las páginas en vertical pero con las tablas y las gráficas apaisadas en una hoja aparte:

@page apaisada {size: landscape;}
table {page: apaisada; page-break-before: right;}
/*las gráficas las diferenciaremos con una clase CSS*/
.poll {page: apaisada; page-break-before: right;}

A la hora de definir el tamaño de la página debemos tener en cuenta que su total será la suma del contenido más los bordes (margin y padding), y podemos definirlo con el atributo size. Podemos utilizar valores numéricos (porcentajes, puntos, centímetros, milímetros), excepto píxeles porque pertencen al ámbito de la pantalla, o utilizar los diversos valores que definen tamaños standares de papel (A4, A3, letter). En caso de no especificar nada el tamaño será auto, que es el valor por defecto. Lo suyo es utilizar las medidas de los textos en pt y el alto y ancho de página en cm, mm o in (pulgadas), piensa que trabajamos sobre un medio físico y no sobre una pantalla que puede tener diversos tamaños y resoluciones.

@page {
  size: 8.5in 11in;  /* ancho y alto en pulgadas */  
}
@page {
  size: 21cm 190mm; /*medidas en tamaño*/
}
@page {
  size: A4; /*standar A4*/
}

Disponemos además de las pseudoclases :first, :left y :right que nos permitirán perfeccionar nuestra maquetación para la impresión a dos caras y pudiendo usar unas reglas específicas para la primera página.

/*Para la primera página usaremos un margen superior e izquierdo muy grande*/
@page :first {
  margin-top: 6cm;
  margin-left: 7cm;
}

/*definimos los márgenes de la página izquierda*/
@page :left {
  margin-right: 4cm;
  margin-left: 3cm;
}

/*y para la derecha invertimos los valores
para que la impresión a doble página
quede bien*/
@page :right {
  margin-right: 3cm;
  margin-left: 4cm;
}

Y también podemos definir cuántas líneas de un párrafo queremos dejar al final de una página como mínimo o al principio, con la intención de no dejar líneas huérfanas o viudas. Para ello disponemos de las propiedades orphans y widows (que significan huérfanas y viudas en inglés).

@page{
  orphans:5;
  widows:4;
}

¿Cómo funcionaría el ejemplo de arriba? Imaginemos que al final de una página caben 15 líneas. Si tenemos justo 15 o menos entrarán en esa página. Si tenemos 17 entonces, para no violar la regla, se repartirían 13 en la página 1 y 4 en página 2 (para cumplir el mínimo), y su tuviéramos 19 o más no habría problema: 15 en la primera y el resto en la siguiente.

Finalmente hablaremos de los saltos de página, que ya vimos en uno de los ejemplos de arriba. Y es que los elementos de bloque pueden llevar asociado un salto de página, que puede ir antes, después o dentro del elemento. Para ponerlo antes usaremos page-break-before y para hacerlo después iría page-break-after. Para hacerlo dentro usaremos page-break-inside, que tiene la particularidad de que se puede heredar del elemento contenedor mientras que los otros dos no. Para page-break-after y page-break-before puede haber cuatro valores:

  • always: fuerza siempre un salto de página antes o después del elemento, según corresponda
  • avoid: evita siempre un salto de página antes o después del elemento, según corresponda
  • left: fuerza los saltos de página que sean necesarios para que la siguiente página sea compuesta como una página izquierda
  • right: fuerza los saltos de página que sean necesarios para que la siguiente página sea compuesta como una página derecha

Y creo que con esto hemos recorrido los puntos principales el tema de los estilos CSS para impresión.

Llamar a procedimientos almacenados en PHP

Una entrada que llevaba mucho tiempo en el TODO list, sobre trabajar con procedimientos almacenados con PHP.

Para empezar vamos a plantear un escenario en el que tenemos tres procedimientos almacenados en MySQL (dos selects y un insert) contra una tabla llamada productos, que tiene tres campos (id como clave primaria, descripcion con una descripción del producto, precio con un valor numérico decimal).

El SP de la primera select, que nos devuelve la descripción y el precio del producto según su id, sería este:

CREATE PROCEDURE getProducto(IN id_val INT) 
  BEGIN 
    SELECT descripcion, precio from productos WHERE id = id_val; 
  END;

El SP de la segunda select, que nos devuelve la descripción y el precio todos los productos, por lo que no recibe parámetros:

CREATE PROCEDURE getAllProductos() 
  BEGIN 
    SELECT descripcion, precio from productos ; 
  END;

Y el sp del insert sería este, al que le pasamos los tres valores a meter:

CREATE PROCEDURE addProducto(IN id_val INT,descripcion_in varchar(50), precio_in float) 
  BEGIN 
    INSERT INTO productos VALUES (id_val, descripcion_in, precio_in);
  END;

Bueno, ya tenemos nuestro escenario, entonces ¿cómo hacemos para llamar a estos procedimientos desde nuestro código php? Pues simplemente lanzamos una consulta en la que llamamos a la instrucción CALL de MySQL para que ejecute el procedimiento almacenado que le digamos con los parámetros que tocan.

/*Empezamos con el procedimiento de inserción*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para hacer la inserción*/
/*Si falla imprimimos el error*/
if (!$mysqli->query("CALL addProducto(1001, 'Nueces de Macadamia', 12.23)")) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

La propia función query del objeto mysqli nos devolverá TRUE si no viene con errores y FALSE si pasa algo inesperado.

¿Y qué pasa con la recuperación de datos? Ahí nos vamos a un terreno más pantanoso. Para una consulta con un solo resultado no es problema:

/*Empezamos con el procedimiento de recuperación de una fila*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para recoger los datos*/
/*Si falla imprimimos el error*/
if (!($res = $mysqli->query("CALL getProducto(1001)"))) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

/*E imprimimos el resultado para ver que el ejemplo ha funcionado*/
var_dump($res->fetch_assoc());

Pero claro, en este caso podemos hacerlo así porque esperamos un solo resultado, pero si esperamos varias filas la cosa es distinta ya que mysqli->query() devuelve sólo el primer conjunto de resultados. Tenemos dos alternativas para esta situación: mysqli_real_query() o mysqli_multi_query(). En el ejemplo usaremos la segunda, y veremos también la forma de recorrer este resultado:

/*Empezamos con el procedimiento de recuperación de una fila*/
/*Lo primero es crear un objeto mysqli*/
$mysqli = new mysqli("servidor", "usuario", "pass", "db");

/*Y llamamos al procedimiento para recoger los datos*/
/*Si falla imprimimos el error*/
if (!$mysqli->multi_query("CALL getAllProductos()")) {
    echo "Falló la llamada: (" . $mysqli->errno . ") " . $mysqli->error;
}

/*Ahora con este bucle recogemos los resultados y los recorremos*/
do {
    /*En el if recogemos una fila de la tabla*/
    if ($res = $mysqli->store_result()) { 
        /*Imprimimos el resultado de la fila y debajo un salto de línea*/
        var_dump($res->fetch_all());
        printf("\n");
        /*La llamada a free() no es obligatoria, pero si recomendable para aligerar memoria y para evitar problemas si después hacemos una llamada a otro procedimiento*/
        $res->free();
    } else {
        if ($mysqli->errno) {
            echo "Store failed: (" . $mysqli->errno . ") " . $mysqli->error;
        }
    }
} while ($mysqli->more_results() && $mysqli->next_result());
/*El bucle se ejecuta mientras haya más resultados y se pueda saltar al siguiente*/

Añadiré a esto que también es posible utilizar las llamadas a procedimientos almacenados usando sentencias preparadas, procediendo del modo habitual a la hora de pasar los parámetros.

Cambiar la contraseña de la base de datos en Prestashop

Pongámonos en situación: has cambiado la contraseña de la base de datos de MySQL que usabas para tu instalación de Prestashop. Con el cambio verás que tu vieja instalación no funciona, ¿solución? Cambiar la configuración de la contraseña. ¿Cómo? Con los siguientes pasos:

  • Busca la carpeta config.
  • Busca en dicha carpeta el archivo settings.inc.php.
  • En ese archivo busca las líneas BD_USER y DB_PASSWD, ahí tienes definidos los nombres de usuario y las contraseñas, basta con cambiarlos ahí

Y con esto ya está la cosa listas para funcionar otra vez.

Etiquetas para convertir webs en web-apps Android

No hace mucho os hablaba aquí de una serie de etiquetas creadas por Apple que permitían hacer que una web luciera como una aplicación nativa de iOS, y comentaba que era una pena que no hubiera algo así para Android… pero lo cierto es que lo hay. A partir de la salida de Chrome 31 para Android el sistema operativo de Google también da opción a hacer esto mismo, aunque he de admitir que no dan tanto juego como las de Apple, y como estos se han dedicado (como es su filosofía de empresa hermética/cabrona/malvada) a no documentar ni compartir una mierda hay que andar buscándose la vida. Por cierto que Mozilla también nos permite crear web-apps facilitas tanto para su sistema operativo FirefoxOS como para Amazon Kindle Fire y Android si usas Firefox.

De primeras no hay una etiqueta especial para el título del app, deberéis utilizar la meta etiqueta title normal. Tampoco existe un equivalente de la propiedad navigator.standalone de iOS, que nos devuelve un boolean si estamos ejecutando el app a pantalla completa. En todo caso, con este truquito podemos lograr lo mismo:

navigator.standalone = navigator.standalone || (screen.height-document.documentElement.clientHeight<40)

El Javascript ejecutadlo siempre después de que la página esté totalmente cargada (tras el evento onload()), por si los scrolls.

Vamos ahora con los puntos fundamentales. El primero: forzar el modo web-app, que se consigue con la siguiente etiqueta:

<meta name="mobile-web-app-capable" content="yes">

Vamos, lo mismo que la de iOS quitándole el prefijo «apple». El segundo punto clave ¿cómo añadir al escritorio el app? Bueno, la primera vez que llegáis a la página, en el menú del navegador os encontráis una opción que será “Add to homescreen” (lo he probado en emulador y tengo Chrome en inglés, no estoy seguro de cómo se llama la opción en castellano). En cuanto al icono, si habéis puesto el de Apple Touch lo cogerá por defecto, si bien la especificación de google recomienda incluir uno cuadrado de 196*196, tal que aśi:

<link rel="shortcut icon" sizes="196x196" href="vuestroIcono.png">

Un último punto, los enlaces se abrirán por defecto en el contexto de la aplicación, si queréis abrir un enlace concreto en una ventana de Chrome (por ejemplo una referencia a una web externa) insertad el atributo target=»_blank» en el link.Otro punto, no tenéis el botón de recargar del navegador (al estar en ese contexto sin marco), así que si queréis tener una opción de «refresh» tendréis que implementar una solución en javascript.

En fin, queda mucho por andar en este terreno, pero parece que Google se pone al fin las pilas, y Mozilla ya lleva mucho currando (y al contrario que Apple ellos sí hacen las cosas de forma abierta).

PHP: Diferencia entre == y ===

A la hora de realizar comparaciones en PHP disponemos de dos operadores == y ===, hoy me han preguntado en qué se diferencian, así que he pensado que no es mala idea explicarlo también aquí.

PHP es un lenguaje muy flexible en cuanto a los tipos de datos, puedes tener una variable con una cadena y compararla con un entero… y no sufrirás la hecatombe que te encontrarías con C o ASP. Y esto es lo que explica la existencia de dos operadores de comparación: == comprueba que los valores sean iguales, independientemente del tipo ya que realiza una conversión antes de comparar. En cambio el operador === comprueba que además de coincidir los valores también coincidan los tipos. Con un pequeño ejemplo se entiende perfectamente

/*Damos a una variable un valor entero*/
$var1 = 0;
/*Damos a otra un valor booleano*/
$var2 = FALSE
/*Si los comparamos con == verás como cumple el condicional, ya que tratará a ambos como booleanos*/
if($var1 == $var2){
  echo "Son iguales"
}
/*En cambio con === no entraría porque no realiza la conversión, de esta forma al tratarse de tipos distintos no entra*/
if($var1 === $var2){
  echo "Son idénticos"
}

CouchCMS: Creando una región editable con sólo una etiqueta

No hace mucho me hablaron de CouchCMS en Facebook, un CMS open source (que no libre) ligero y flexible. Apenas he podido trabajar con él todavía porque cada día ando más liado con proyectos varios (y en el curro, de momento, el que quiera CMS va a chupar WordPress por un tubo, que para algo es por el que mejor me muevo de momento).

En todo caso una de las ventajas de este cms es que nos permite fácilmente definir una región de nuestro HTML como editable, de forma que el usuario pueda cambiar fácilmente su contenido desde el panel de administración, como si de una publicación en un blog se tratara.

Vamos a suponer que ya tienes instalado el CMS en tu servidor y que dispones de una web estática HTML, en la que quieres declarar como editable una región. Lo primero es cambiar la extensión de tu archivo .html por .php y, lo siguiente, es añadir antes de la cabecera del HTML el script cms.php desde la carpeta donde guardaras el Couch:

<?php require_once( 'couch/cms.php' ); ?>

Y al final del archivo, en la última línea, la llamada a ejecución de Couch:

<?php COUCH::invoke(); ?>

Con esto tenemos CouchCMS funcionando sobre nuestra vieja página HTML estática. Ahora vamos a con el siguiente paso: declarar editable una región. Para esto basta con usar un par de etiquetas.

<!-- Imaginemos que este es nuestro código inicial -->
<h3>Le título!</h3>
<p>Un parrafillo estático del todo</p>

<!-- Con estas etiquetas ya sería editable la región -->
<h3>Le título!</h3>
<cms:editable name='contenido' type='richtext'>
<p>Un parrafillo estático del todo</p>
</cms:editable>

La etiqueta cms:editable es la que define como tal una región (ok, esto es de captain obvious). El nombre que le demos debería ser único, ya que cuando entremos a la zona de administración del cms la región será identificada con dicho nombre en el editor. En el type hemos puesto, ya que será un texto, richtext para poder modificarla y formatear con un editor WYSIWYG, si bien existen muchas posibilidades.

Próximamente, cuando vaya explorando un poco, iré añadiendo más cosas sobre este cms.