Fecha de publicación: 2008/12/02
He aquí una función en PHP para generar un calendario con XHTML semántico y accesible, y con clases e identificadores adecuados para aplicarle rápidamente el CSS.
La función lleva cuatro parámetros, todos ellos opcionales, en el siguiente orden:
Ejemplo de llamada a la función con el mes de febrero de 2009, los fines de semana desactivados, los días nulos activados y un encabezado de nivel 3:
calendario(2009,2,0,1,3);
Descargar archivo con ejemplo funcional o verlo en acción (abre en ventana nueva).
Funciones para generar el calendario (para mayor seguridad, utilizar el código del ejemplo descargable):
function calendario ($year,$mes,$finDeSemana=1,$mostrarDiasNulos=1,$nivelH=2) {
if (strlen($year)!=4) {$year=date('Y');}
if (($mes<1 or $mes>12) or (strlen($mes)<1 or strlen($mes)>2)) {$year=date('n');}
// Listados: días de la semana, letra inicial de los días de la semana, y meses
$dias = array('Lunes','Martes','Miércoles','Jueves','Viernes','Sábado','Domingo');
$diasAbbr = array('L','M','M','J','V','S','D');
$meses = array('Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiempre','Octubre','Noviembre','Diciembre');
// Se sacan valores que se utilizarán más adelante
$diaInicial = gmmktime(0,0,0,$mes,1,$year); // Primer día del mes dado
$diasNulos = (date("N",$diaInicial))-1; // Con 'N' la semana empieza en Lunes. Con 'w', en domingo
if($diasNulos<0){$diasNulos = 7-abs($diasNulos);}
$diasEnMes = date("t",$diaInicial); // Número de días del mes dado
// Se abre la capa contenedora y se genera el encabezado del bloque de calendario
$html .= '<div id="calendario">';
$html .= '<h'.$nivelH.' class="encabezadoCalendario">Calendario</h'.$nivelH.'>';
// Párrafos con la fecha actual y la fecha seleccionada
$html .= '<p>Fecha actual: '.date('j').' de '.$meses[(intval(date('n'))-1)].' de '.date('Y').'</p>';
$html .= '<p>Fecha seleccionada: ';
if (isset($_GET['dia'])) {$html .= ''.$_GET['dia'].' de ';} // El día solo sale si se ha definido previamente en el parámetro 'dia' de la URL
$html .= ''.$meses[($mes-1)].' de '.$year.'</p>';
$html .= '<div class="tabla">';
// Enlaces al mes anterior y al siguiente
$html .= '<p>Navegación por meses:</p>';
$html .= '<ul id="calNavMeses">';
$enlaceAnterior1 = gmmktime(0,0,0,($mes-1),1,$year);
$mesAnterior = date('n',$enlaceAnterior1);
$yearMesAnterior = date('Y',$enlaceAnterior1);
$enlaceSiguiente1 = gmmktime(0,0,0,($mes+1),1,$year);
$mesSiguiente = date('n',$enlaceSiguiente1);
$yearMesSiguiente = date('Y',$enlaceSiguiente1);
$html .= '<li class="anterior"><a href="?mes='.$mesAnterior.'&ano='.$yearMesAnterior.'"><span>Mes anterior ('.$meses[($mesAnterior-1)].')</span></a></li>';
$html .= '<li class="siguiente"><a href="?mes='.$mesSiguiente.'&ano='.$yearMesSiguiente.'"><span>Mes siguiente ('.$meses[($mesSiguiente-1)].')</span></a></li>';
$html .= '</ul>';
// Enlaces al año anterior y al siguiente
$html .= '<p>Navegación por años:</p>';
$html .= '<ul id="calNavYears">';
$enlaceAnterior2 = gmmktime(0,0,0,$mes,1,($year-1));
$yearAnterior = date('Y',$enlaceAnterior2);
$enlaceSiguiente2 = gmmktime(0,0,0,$mes,1,($year+1));
$yearSiguiente = date('Y',$enlaceSiguiente2);
$html .= '<li class="anterior"><a href="?mes='.$mes.'&ano='.$yearAnterior.'"><span>Año anterior (</span>'.$yearAnterior.'<span>)</span></a></li>';
$html .= '<li class="siguiente"><a href="?mes='.$mes.'&ano='.$yearSiguiente.'"><span>Año siguiente (</span>'.$yearSiguiente.'<span>)</span></a></li>';
$html .= '</ul>';
// Se abre la tabla que contiene el calendario
$html .= '<table>';
// Título mes-año (elemento CAPTION)
$mesLista = $mes-1;
$html .= '<caption>'.$meses[$mesLista].'<span> de</span> '.$year.'</caption>';
// Se definen anchuras en elementos COL
$cl=0; $anchoCol=100/7; while ($cl<7) {$html .= '<col width="'.$anchoCol.'%" />'; $cl++;}
// Fila de los días de la semana (elemento THEAD)
$html .= '<thead><tr>';$d=0;
while ($d<7) {$html .= '<th scope="col" abbr="'.$dias[$d].'">'.$diasAbbr[$d].'</th>';$d++;}
$html .= '</tr></thead>';
// Se generan los días nulos (días del mes anterior o posterior) iniciales, el TBODY y su primer TR
$html .= '<tbody>';
if ($diasNulos>0) {$html .= '<tr>';} // Se abre el TR solo si hay días nulos
if ($diasNulos>0 and $mostrarDiasNulos==0) {$html .= '<td class="nulo" colspan="'.$diasNulos.'"></td>';} // Se hace un TD en blanco con el ancho según los día nulos que haya
if ($mostrarDiasNulos==1) { // Generación de los TD con días nulos si está activado que se muestren
$dni=$diasNulos;$i=0;
while ($i<$diasNulos) {
$enSegundosNulo = gmmktime(0,0,0,$mes,(1-$dni),$year);
$dmNulo = date('j',$enSegundosNulo);
$idFechaNulo = 'cal-'.date('Y-m-d',$enSegundosNulo);
$html .= '<td id="'.$idFechaNulo.'" class="diaNulo"><span class="dia"><span class="enlace">'.$dmNulo.'</span></span></td>';
$dni--;
$i++;
}
}
// Se generan los TD con los días del mes
$dm=1;$x=0;$ds=$diasNulos+1;
while ($dm<=$diasEnMes) {
if(($x+$diasNulos)%7==0 and $x!=0) {$html .= '</tr>';} // Se evita el cierre del TR si no hay días nulos iniciales
if(($x+$diasNulos)%7==0) {$html .= '<tr>';$ds=1;}
$enSegundosCalendario = gmmktime(0,0,0,$mes,$dm,$year); // Fecha del día generado en segundos
$enSegundosActual = gmmktime(0,0,0,date('n'),date('j'),date('Y')); // Fecha actual en segundos
$enSegundosSeleccionada = gmmktime(0,0,0,$_GET['mes'],$_GET['dia'],$_GET['ano']); // Fecha seleccionada, en segundos
$idFecha = 'cal-'.date('Y-m-d',$enSegundosCalendario);
// Se generan los parámetros de la URL para el enlace del día
$link_dia = date('j',$enSegundosCalendario);
$link_mes = date('n',$enSegundosCalendario);
$link_year = date('Y',$enSegundosCalendario);
// Clases y etiquetado general para los días, para día actual y para día seleccionado
$claseActual='';$tagDia='span';
if ($enSegundosCalendario==$enSegundosActual) {$claseActual=' fechaHoy';$tagDia='strong';}
if ($enSegundosCalendario==$enSegundosSeleccionada and isset($_GET['dia'])) {$claseActual=' fechaSeleccionada';$tagDia='em';}
if ($enSegundosCalendario==$enSegundosActual and $enSegundosCalendario==$enSegundosSeleccionada and isset($_GET['dia'])) {$claseActual=' fechaHoy fechaSeleccionada';$tagDia='strong';}
// Desactivación de los días del fin de semana
if (($ds<6 and $finDeSemana==0) or $finDeSemana!=0) { // Si el fin de semana está activado, o el día es de lunes a viernes
$tagEnlace='a';
$atribEnlace='href="?dia='.$link_dia.'&mes='.$link_mes.'&ano='.$link_year.'"';
} if ($ds>5 and $finDeSemana==0) { // Si el fin de semana está desactivado y el día es sábado o domingo
$tagEnlace='span';
$atribEnlace='';
$paramFinde='0';
}
// Con las variables ya definidas, se crea el HTML del TD
$html .= '<td id="'.$idFecha.'" class="'.calendarioClaseDia($ds).$claseActual.'"><'.$tagDia.' class="dia"><'.$tagEnlace.' class="enlace" '.$atribEnlace.'>'.$dm.'</'.$tagEnlace.'></'.$tagDia.'></td>';
$dm++;$x++;$ds++;
}
// Se generan los días nulos finales
$diasNulosFinales = 0;
while((($diasEnMes+$diasNulos)%7)!=0){$diasEnMes++;$diasNulosFinales++;}
if ($diasNulosFinales>0 and $mostrarDiasNulos==0) {$html .= '<td class="nulo" colspan="'.$diasNulosFinales.'"></td>';} // Se hace un TD en blanco con el ancho según los día nulos que haya (si no se activa mostrar los días nulos)
if ($mostrarDiasNulos==1) { // Generación de días nulos (si se activa mostrar los días nulos)
$dnf=0;
while ($dnf<$diasNulosFinales) {
$enSegundosNulo = gmmktime(0,0,0,($mes+1),($dnf+1),$year);
$dmNulo = date('j',$enSegundosNulo);
$idFechaNulo = 'cal-'.date('Y-m-d',$enSegundosNulo);
$html .= '<td id="'.$idFechaNulo.'" class="diaNulo"><span class="dia"><span class="enlace">'.$dmNulo.'</span></span></td>';
$dnf++;
}
}
// Se cierra el último TR y el TBODY
$html .= '</tr></tbody>';
// Se cierra la tabla
$html .= '</table>';
// Se cierran la capa de la tabla y la capa contenedora
$html .= '</div>';
$html .= '</div>';
// Se devuelve la variable que contiene el HTML del calendario
return $html;
}
function calendarioClaseDia ($dia) {
switch ($dia) {
case 1: $clase = 'lunes semana'; break;
case 2: $clase = 'martes semana'; break;
case 3: $clase = 'miercoles semana'; break;
case 4: $clase = 'jueves semana'; break;
case 5: $clase = 'viernes semana'; break;
case 6: $clase = 'sabado finDeSemana'; break;
case 7: $clase = 'domingo finDeSemana'; break;
}
return $clase;
}
Actualizado 2008-12-03: Se añade la posibilidad de desactivar los fines de semana.
Actualizado 2008-12-04: Se añade la posibilidad de desactivar o activar los días de la primera semana que son del mes anterior y los de la última que son del mes siguiente (denominados como días nulos). Se explican los parámetros a introducir al llamar a la función.
Actualizado 2008-12-05: Mejoras de accesibilidad.
Actualizado 2009-02-01: Corregido el fragmento de código expuesto en la página.
A diferencia de otros contenidos la licencia para este artículo y el ejemplo adjunto es Reconocimiento-Compartir bajo la misma licencia 3.0 España.
Fecha de publicación: 2007/10/03
Tengo unos enlaces dentro de elementos de lista, para un menú de navegación.
Esos enlaces se convierten en bloque mediante CSS, con la propiedad display:block;
.
En Firefox, Opera e Internet Explorer 7 el enlace funciona correctamente, aunque no se pase el puntero por encima del texto de enlace.
En Internet Explorer 6 hay que pasar el puntero por encima del texto de enlace, en caso contrario el enlace no se activa.
ul {list-style-type: none; margin:0; padding:0; width:160px;}
ul li {background:#FFFF99; margin-bottom:3px; border-bottom:1px solid #fff;}
ul li a {display:block; padding:4px;}
ul li a:hover {background-color:#FFCC66;}
Darle una anchura fija al enlace:
ul {list-style-type: none; margin:0; padding:0; width:160px;}
ul li {background:#FFFF99; margin-bottom:3px; border-bottom:1px solid #fff;}
ul li a {display:block; padding:4px;width:160px;width:152px;}
ul li a:hover {background-color:#FFCC66;}
Atención: el efecto solo se observará en Internet Explorer 6 y anteriores.
Fecha de publicación: 2007/09/18
Este artículo es una ampliación a CSS Sprites: rollover utilizando una sola imagen.
En el artículo anterior se daban valores negativos para el eje de coordenadas Y en la propiedad CSS background-position
. En este caso el valor se puede obtener de la siguiente forma: se resta a la altura total de la imagen la altura del sprite que se quiere ver y la coordenada Y de la propiedad background-position
.
Ejemplo: la altura total de una imagen con 2 sprites es de 100px. Cada sprite tiene una altura de 6px, y el sprite que está inicialmente tiene un background-position:0 4px;
. Entonces se hará la siguiente resta: 100px-6px-4px=90. La posición del eje Y que habrá que dar será -90px.
Fecha de publicación: 2007/07/31
El atributo scope
se utiliza para vincular la información contenida en las diferentes celdas de una tabla.
Este atributo especifica el conjunto de celdas cuya información se refiere a la celda que contiene este atributo.
Supone una alternativa simple al atributo headers
.
El atributo scope
puede tomar uno (solamente uno) de los siguientes valores:
Fecha de publicación: 2007/06/26
Las interfaces web se componen de tres capas:
Presentación y comportamiento son opcionales.
Se trata del contenido y de su estructuración semántica: el documento HTML. Cada porción de texto deberá ser contenida en el elemento adecuado a su contexto (párrafos, listas, encabezados, etc.), o llevar la información adicional que sea necesaria (el texto alternativo en las imágenes, por ejemplo).
Aquí no se definirá absolutamente nada relacionado con la presentación: nada de configurar colores, tipografías, fondos, etc. Nada.
Si todo esto se hace correctamente se habrá dado un paso muy importante hacia la accesibilidad, y también en cuanto al posicionamiento en buscadores. El documento será legible sin necesidad de las otras dos capas.
En esta capa se definirá el aspecto del contenido, mediante hojas de estilo CSS.
El CSS se introduce preferentemente en un archivo, o varios, separados del contenido.
Se pueden aplicar hojas de estilo para dispositivos específicos: pantalla (la más habitual), PDA, impresoras, lectores de pantalla, etc. De esta forma se podrá optimizar el aspecto de un sitio web atendiendo a las necesidades específicas de cada dispositivo.
Además hacer la capa de presentación separada de la de contenido tiene otra ventaja importante: con solo cambiar la hoja de estilo, cambia el aspecto de todo el sitio al que se aplique la misma. Un ejemplo interesante de esta ventaja es el CSS Zen Garden, donde con un mismo contenido pero con diferentes hojas de estilo se consiguen resultados muy variados.
Se trata de añadir funcionalidades con algo más de complejidad, como elementos desplegables, rollovers, etc. Se hace mediante Javascript que interactue con el DOM.
El código Javascript deberá estar contenido en archivos externos, igual que las hojas de estilo en la capa anterior.
La adición de esta capa no debe impedir el correcto acceso al contenido.
Fecha de publicación: 2007/06/07
Actualizado 2010-06-02: solución del color de fondo.
Hay ocasiones en las que Internet Explorer 6 duplica caracteres. Se trata de un molesto bug que se da, en principio, ante las siguientes condiciones:
Con un solo comentario no ocurre nada, pero con dos o más comentarios seguidos se manifiesta este molesto bug. A mayor cantidad de comentarios, mayor cantidad de caracteres repetidos.
Ejemplo de código para que aparezca el problema descrito:
<div style="float:left">De esta no se repiten</div>
<!-- Ambos comentarios deben incluirse para que salga el fallo -->
<!-- Ambos comentarios deben incluirse para que salga el fallo -->
<div style="float:left; width:100%">
En esta se van a repetir caracteres.
</div>
Y sale algo como esto en IE6 (la última línea es lo que se repite):
repeated characters
s.
Hay dos soluciones:
Otra posible solución será asignarle al elemento un color de fondo en la CSS.
Un ejemplo del comentario condicional:
<!--[if !IE]>Inserta aquí el comentario<![endif]-->
Fecha de publicación: 2007/06/05
Existen al menos dos formas:
onload
en el elemento body
. El valor de dicho atributo será la función Javascript que se quiera ejecutar.window.onload
, y mencionando a continuación la función que se desea ejecutar.Un ejemplo del uso del onload
:
<body onload="funcion_a_ejecutar(parametro)">[...]</body>
Un ejemplo para hacerlo desde un archivo Javascript:
window.onload = funcion_a_ejecutar;
Lo adecuado sería usar la segunda opción, ya que ayuda a mantener limpio el código HTML.
Fecha de publicación: 2007/05/16
Cuando el contenido de un encabezado de tabla (TH
) es muy extenso se puede recurrir a su abreviatura, mediante el atributo abbr
.
Esta técnica tiene sentido para los usuarios que utilizan lectores de pantalla, ya que dichos lectores repiten el contenido de los encabezados de tabla al referirse a una celda asociado a los mismos.
Ejemplo de tabla accesible con abreviaturas en los encabezados de tabla (la tabla la he tomado prestada de 456 Berea St.):
<table summary="Número de empleados y años de fundación de
empresas ficticias.">
<caption>Tabla 1: Datos de las empresas</caption>
<tr>
<th abbr="Empresa">Nombre de la empresa</th>
<th abbr="Empleados">Número de empleados</th>
<th abbr="Fundación">Año de fundación</th>
</tr>
<tr>
<td>ACME Inc</td>
<td>1000</td>
<td>1947</td>
</tr>
<tr>
<td>Compañía XYZ</td>
<td>2000</td>
<td>1973</td>
</tr>
</table>
Fecha de publicación: 2007/05/07
Supongamos que tenemos un párrafo (elemento P
) dentro de una capa (elemento DIV
) y quueremos una alineación vertical centrada para el párrafo dentro de esa capa.
Existe una solución con CSS: display:table;
. Pero tiene el problema habitual de CSS: el excelente soporte de CSS en Internet Explorer, que, para variar, no es compatible con display:table;
.
Pero utilizando algunos hacks CSS y metiendo una capa adicional se puede dar solución al centrado vertical, manteniendo compatibilidad con la mayor parte de los navegadores.
Este sería el HTML:
<div class="t1">
<div class="t2">
<p>Párrafo a centrar</p>
</div>
</div>
Y este el CSS:
div.t1 {
height:12em; /*Altura de la capa*/
overflow:hidden;
position:relative;
}
html>/**/body div.t1 {
display:table;
position:static;
}
div.t2 {
position:absolute;
top:50%;
}
html>/**/body div.t2 {
display:table-cell;
position:static;
vertical-align:middle;
}
p {
position:relative;
top:-50%;
}