NovaMonoFix
Errores PHP
X
Usuario
Password
0 FPS

Menu PHP + XML + JQuery + JavaScript + Css

17 de Noviembre del 2011 por Josep Antoni Bover, 17 visitas, 0 comentarios, 0 votos
Categorías : HTML, PHP, JQuery, Programación, XML.
La web está en segundo plano, animación en pausa.
Cargando animación...
Menu PHP + XML + JQuery + JavaScript + Css

Hoy para salir un poco de la rutina de la creación de páginas web desde cero y del objeto canvas 2d, os voy a mostrar cómo crear un menú para vuestra pagina web igual al que tengo en la mía.

Este menú obtiene sus datos a partir de un archivo XML, y puede tener tantos submenús como quepan en pantalla, además es absolutamente recursivo por lo que podemos crear tantos submenús dentro de un submenú como nos hagan falta (siempre que el tamaño de la pantalla nos lo permita).

Por desgracia está pensado para trabajar en una posición fija de la ventana del navegador, por lo que habría que retocarlo para trabajar con posiciones relativas / absolutas (en términos de la propiedad css position).

Para empezar vamos a ver un ejemplo de un archivo XML desde el que se crearían los menús :

Archivo : MenuWebFijo_Ejemplo.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Menu>
<CrearMenu Nombre="Padre 1" Url="">
<CrearMenu Nombre="SubMenu 1.1" Url="">
<CrearMenu Nombre="SubMenu 1.1.1" Url="javascript:alert('SubMenu')">
<CrearMenu Nombre="SubMenu 1.1.1.1" Url="javascript:alert('SubMenu')" />
</CrearMenu>
</CrearMenu>
<CrearMenu Nombre="SubMenu 1.2" Url="" />
<CrearMenu Nombre="SubMenu 1.3" Url="" />
<CrearMenu Nombre="SubMenu 1.4" Url="">
<CrearMenu Nombre="SubMenu 1.4.1" Url="javascript:alert('SubMenu')" />
</CrearMenu>
</CrearMenu>
<CrearMenu Nombre="Padre 2" Url="">
<CrearMenu Nombre="SubMenu 2.1" Url="javascript:alert('SubMenu')" />
</CrearMenu>
</Menu>

Como podéis observar el menú constaría en este caso de dos padres, uno de ellos tiene 4 submenús, uno de los cuales tiene un hijo que a su vez tiene otro hijo. En cualquier submenú se puede especificar una url sea un padre o un submenú con hijos, o un submenú final.

Viendo este archivo XML ya podemos ir pensando en cómo crear una estructura de datos en PHP para almacenar todo esto. A decir verdad en este punto tuve algún que otro problema ya que estoy muy acostumbrado a los punteros en C/C++ pero en PHP no hay punteros... En PHP hay que usar referencias, y a diferencia de C/C++ las referencias pueden ser inicializadas cuando queramos, por lo que al final me sirvieron para este caso en concreto.

La idea es almacenar todos los datos de un submenú dentro de un objeto, y que este objeto tenga una referencia a su menú padre, y una referencia a sus submenús hijos, de forma que podamos recorrer este objeto recursivamente.

Veamos como quedaría creado el objeto que almacenara un submenú con sus referencias a su padre y sus hijos :

clase devildrey33_SubMenu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/* Clase que contiene los datos de un menu / submenu */
class devildrey33_SubMenu {
// Constructor para crear un SubMenu
public function __construct($nNombre, $nUrl, $nDestino, &$nPadre, $nID = "00") {
$this->_Nombre = $nNombre;
$this->_Url = $nUrl;
$this->_Padre = &$nPadre;
// Establecemos la ID para este submenu
if (strlen($nID) == 1) $nID = "0".$nID;
if ($nPadre != "") $this->_ID = $nPadre->_ID."_".$nID;
else $this->_ID = $nID;
}
// Función para crear un SubMenu
public function CrearSubMenu($nNombre, $nUrl, $nDestino, &$nPadre) {
$this->_SubMenus[$this->_TotalSubMenus] = new devildrey33_SubMenu( $nNombre, $nUrl, $nDestino,
$nPadre, $this->_TotalSubMenus ++ );
}
// Función que devuelve una referencia hacia el menu padre
public function &Padre() { return $this->_Padre; }
// Función que devuelve una referencia hacia el menu hijo especificado
public function &SubMenu($Pos) { return $this->_SubMenus[$Pos]; }
// Función que devuelve el nombre para este menu
public function Nombre() { return $this->_Nombre; }
// Función que devuelve la URL de este menu
public function Url() { return $this->_Url; }
// Función que devuelve el total de hijos de este menu
public function TotalSubMenus() { return $this->_TotalSubMenus; }
// Función que devuelve la ID de este menu
public function ID() { return $this->_ID; }
// Función que devuelve el destino de este menu (se refiere a donde abrira la url, por defecto la abre en la misma ventana)
public function Destino() { return $this->_Destino; }
// Variables protegidas
protected $_ID;
protected $_Nombre;
protected $_Url;
protected $_Destino;
protected $_Padre;
protected $_TotalSubMenus = 0;
protected $_SubMenus = array();
}

Una vez tenemos el contenedor para almacenar el árbol de menús, podemos pasar a ver como leeríamos el archivo XML, y como almacenaríamos los datos en la clase devildrey33_SubMenu :

Funcion devildrey33_Menu::LeerContenidoXML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Funcion para leer el contenido del archivo XML y pasarlo a un array de datos
public function LeerContenidoXML($ArchivoXML) {
// Leemos el archivo XML con todo el contenido del menú
$ArchivoLista = @fopen($ArchivoXML, "r", true);
$DatosArchivo = fread($ArchivoLista, filesize($ArchivoXML));
@fclose($ArchivoLista);
$TotalCaracteres = strlen($DatosArchivo);
// Parseamos el XML y lo dividimos en un array inicial de datos
$Parser = xml_parser_create();
xml_parse_into_struct($Parser, $DatosArchivo, $DatosXML, $Indices);
xml_parser_free($Parser);
// Creo el menu padre superior (que esta por encima de los menus padre que podamos crear)
$PadreP = "";
$this->_Menus = new devildrey33_SubMenu("Padre", "", "", $Padre);
// Enlazo la referencia del MenuActual a padre superior que acabamos de crear
$MenuActual = &$this->_Menus;
// Recorremos el array de datos XML
foreach ($DatosXML as $Etiqueta) {
$Destino = "";
if (isset($Etiqueta['attributes']['DESTINO'])) $Destino = $Etiqueta['attributes']['DESTINO'];
// Empieza un submenu con hijos
if ($Etiqueta['tag'] == "CREARMENU" && $Etiqueta['type'] == "open") {
$MenuActual->CrearSubMenu( $Etiqueta['attributes']['NOMBRE'], $Etiqueta['attributes']['URL'],
$Destino, $MenuActual );
$Pos = 0;
if ($MenuActual->TotalSubMenus()) $Pos = $MenuActual->TotalSubMenus() - 1;
$MenuActual = &$MenuActual->SubMenu($Pos);
}
// Termina un submenu con hijos
else if ($Etiqueta['tag'] == "CREARMENU" && $Etiqueta['type'] == "close") {
$MenuActual = &$MenuActual->Padre();
}
// Empieza y termina un submenu sin hijos
else if ($Etiqueta['tag'] == "CREARMENU" && $Etiqueta['type'] == "complete") {
$MenuActual->CrearSubMenu( $Etiqueta['attributes']['NOMBRE'], $Etiqueta['attributes']['URL'],
$Destino, $MenuActual );
}
}
}

Para empezar utilizo las funciones fopen, fread y fclose para leer todo el contenido del archivo en una variable, luego utilizo las funciones xml_parser_create, xml_parse_into_struct, y xml_parser_free para separar todos los datos leídos del xml en una estructura de datos que resulta mucho mas fácil de utilizar.

A partir de la línea 13 creo lo que será el menú súper padre, que contendrá los menús padre que pueda tener el archivo XML, y dentro a sus hijos, y los hijos de sus hijos, etc...

En la línea 15 creo una referencia que apunta al menú súper padre, para ir moviéndonos dentro del árbol con más comodidad.

En la línea 18 empieza el bucle que escanea toda la estructura de datos previamente creada con las funciones xml_parse*, dentro de este bucle nos podemos encontrar tres tipos de etiquetas fácilmente diferenciables.

Solo buscaremos las etiquetas con el tag "CREARMENU" que pueden ser de tres tipos : "open", "close", y "complete". Las etiquetas del tipo "open" nos indican que dentro encontraremos uno o más hijos por lo que apuntaremos la referencia MenuActual al último hijo de este menú, las etiquetas del tipo "close" nos indican que ya no hay más hijos dentro y que debemos subir un escalón de la jerarquía (dicho de otra forma vamos a hacer que la referencia MenuActual apunte al padre de este menú), y por último las etiquetas del tipo "complete" nos indican que ese submenú no tiene hijos por lo que no necesitamos modificar la referencia del MenuActual.

Una vez hecho este proceso tenemos una variable llamada _Menus dentro de la clase devildrey33_Menu que contiene un árbol a base de objetos devildrey33_SubMenu con todos los datos necesarios para crear los menús.

Ahora veamos las funciones que crearan los menús recursivamente dentro del documento HTML :

Funciones devildrey33_Menu::CrearMenus y devildrey33_Menu::_CrearMenuRecursivo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Función para crear el menu
public function CrearMenus() {
echo $this->_CrearMenuRecursivo($this->_Menus, 0);
}
// Función recursiva para crear los menus
private function _CrearMenuRecursivo(&$Menu, $Escalera) {
$TextoMenu = "";
$TextoSubMenu = "";
if ($Escalera == 0) { // Menu superior
$TextoMenu .= "\n<div class='devildrey33_Menu'>";
for ($i = 0; $i < $Menu->TotalSubMenus(); $i ++) {
// Si existe una URL creamos la etiqueta <a>
if ($Menu->SubMenu($i)->Url() != "") {
// Si existe un destino lo añadimos
if ($Menu->SubMenu($i)->Destino() != "") $Target = " target='".$Menu->SubMenu($i)->Destino()."'";
else $Target = "";
$EtiquetaA1 = "<a href='.$Menu->SubMenu($i)->Url().' ".$Target.">";
$EtiquetaA2 = "</a>";
}
else {
$EtiquetaA1 = "";
$EtiquetaA2 = "";
}
// Creación del div para el menu superior o padre
$TextoMenu .= "\n<div class='devildrey33_MenuSuperior' id='devildrey33_MenuSuperior_".$Menu->SubMenu($i)->ID();
$TextoMenu .= "' onmousemove='devildrey33_MostrarMenu(\"".$Menu->SubMenu($i)->ID()."\")'";
$TextoMenu .= " onmouseout='devildrey33_TemporizadorOcultarMenus(1);'>";
$TextoMenu .= $EtiquetaA1.$Menu->SubMenu($i)->Nombre().$EtiquetaA2;
$TextoMenu .= "\n</div> <!-- FIN devildrey33_MenuSuperior_".$Menu->SubMenu($i)->ID()." -->";
$TextoSubMenu .= $this->_CrearMenuRecursivo($Menu->SubMenu($i), $Escalera + 1);
if (!isset($this->_IDS[$Escalera])) $this->_IDS[$Escalera] = 0;
$this->_IDS[$Escalera] ++;
}
$TextoMenu.= "\n</div> <!-- FIN devildrey33_Menu -->";
}
else { // SubMenu
if ($Menu->TotalSubMenus() > 0) {
$TextoMenu .= "\n<div class='devildrey33_SubMenu' id='devildrey33_SubMenu_".$Menu->ID()."'>";
for ($i = 0; $i < $Menu->TotalSubMenus(); $i ++) {
// Si existe una URL creamos la etiqueta <a>
if ($Menu->SubMenu($i)->Url() != "") {
// Si existe un destino lo añadimos
if ($Menu->SubMenu($i)->Destino() != "") $Target = " target='".$Menu->SubMenu($i)->Destino()."'";
else $Target = "";
$EtiquetaA1 = "<a href='".$Menu->SubMenu($i)->Url()."' ".$Target.">";
$EtiquetaA2 = "</a>";
}
else {
$EtiquetaA1 = "";
$EtiquetaA2 = "";
}
// Creación del div para el submenu
if ($Menu->SubMenu($i)->TotalSubMenus() > 0) {
$TextoMenu .= "\n<div class='devildrey33_SubMenuItem' id='devildrey33_SubMenuItem_".$Menu->SubMenu($i)->ID();
$TextoMenu .= "' onmousemove='devildrey33_MostrarSubMenu(\"".$Menu->SubMenu($i)->ID()."\")'";
$TextoMenu .= " onmouseout='devildrey33_TemporizadorOcultarMenus(1);'>";
$TextoMenu .= $EtiquetaA1.$Menu->SubMenu($i)->Nombre().$EtiquetaA2;
$TextoMenu .= "\n</div> <!-- FIN devildrey33_SubMenuItem_".$Menu->SubMenu($i)->ID()." -->";
$TextoSubMenu .= $this->_CrearMenuRecursivo($Menu->SubMenu($i), $Escalera + 1);
}
else {
$TextoMenu .= "\n<div class='devildrey33_SubMenuItem' id='devildrey33_SubMenuItem_".$Menu->SubMenu($i)->ID();
$TextoMenu .= "' onmousemove='devildrey33_ResaltarMenuItem(\"".$Menu->SubMenu($i)->ID()."\")'";
$TextoMenu .= " onmouseout='devildrey33_TemporizadorOcultarMenus(1);'>";
$TextoMenu .= $EtiquetaA1.$Menu->SubMenu($i)->Nombre().$EtiquetaA2."</div>";
}
}
$TextoMenu .= "\n</div> <!-- FIN devildrey33_SubMenu_".$Menu->ID()." -->";
}
}
return $TextoMenu.$TextoSubMenu;
}

Esta función a simple vista puede parecer un galimatías a causa de los nombres de clase y de id que se utilizan ya que son bastante largos, pero a decir verdad no es que sea muy complicada. Lo más importante es situar todos los divs con su clase e id pertinentes de forma que queden bien enlazados a sus funciones JavaScript, hay varios tipos de clases : "devildrey33_MenuPadre", "devildrey33_SubMenu" y "devildrey33_SubMenuItem". De la misma forma también hay varios tipos de id con los mismos nombres que las clases seguidos de un guion bajo y su ID numérica.

Además también hay varias funciones JavaScript para hacer funcionar este menú que son : "devildrey33_MostrarMenu", "devildrey33_MostrarSubMenu", "devildrey33_MostrarSubMenuItem", y "devildrey33_TemporizadorOcultarMenus". La primera función se utiliza exclusivamente cuando pasamos el mouse por encima del menú padre, y muestra el primer submenú, la segunda función se utiliza para mostrar submenús de segundo nivel, la tercera función se utiliza para resaltar submenús que no tienen hijos, y la cuarta función se utiliza para activar un temporizador que ocultara los menús pasado un segundo.

Con esto ya habéis visto todo lo relacionado con PHP y este menú, ahora tocara ver las funciones javascript, empezaremos por devildrey33_MostrarMenu :

Funcion devildrey33_MostrarMenu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Función para mostrar el primer submenu
function devildrey33_MostrarMenu(ID) {
var MenuSuperior = $("#devildrey33_MenuSuperior_" + ID);
// Normalizo menus superiores
$(".devildrey33_MenuSuperior_Resaltado").prop({ "className" : "devildrey33_MenuSuperior" });
// Normalizo los submenus
$(".devildrey33_SubMenuItem_Resaltado").prop({ "className" : "devildrey33_SubMenuItem" });
// Oculto TODOS los submenus
$(".devildrey33_SubMenu").css({ "display" : "none" });
// Resalto el menu superior seleccionado
MenuSuperior.prop({ "className" : "devildrey33_MenuSuperior_Resaltado" });
// Asigno estilos, posición, y muestro el submenu seleccionado
var SubMenu = $("#devildrey33_SubMenu_" + ID);
SubMenu.css({ "left" : MenuSuperior.offset().left,
"top" : (MenuSuperior.outerHeight() + MenuSuperior.position().top),
"min-width" : MenuSuperior.width()
});
if (SubMenu.width() > MenuSuperior.width()) SubMenu.css({ "border-radius" : "0px 4px 4px 4px" });
else SubMenu.css({ "border-radius" : "0px 0px 4px 4px" });
SubMenu.css({ "display" : "block" });
// Desactivo el temporizador para ocultar todos los menus
devildrey33_TemporizadorOcultarMenus(0);
}

Lo más destacable de esta función son las líneas 5 y 7 en las que selecciono todos los objetos con la clase "devildrey33_MenuSuperior_Resaltado" y "devildrey33_SubMenu_Resaltado" y los cambio a las clases "devildrey33_MenuSuperior" y "devildrey33_SubMenu" respectivamente. De esta forma quitamos todos los efectos de resaltado en todos los menús.

Luego en la línea 9 escondemos todos los objetos que tengan la clase "devildrey33_SubMenu", y finalmente buscamos el menú padre y submenús a mostrar, les asignamos sus estilos, los mostramos, y por ultimo desactivamos el temporizador que oculta los menús.

Inicialmente utilizaba los selectores :hover del CSS para resaltar los menús, pero me encontré con que opera no se lleva bien con los objetos con "position:fixed" y al final tuve que re-escribir todo el código....

Veamos la función devildrey33_MostrarSubMenu :

Funcion devildrey33_MostrarSubMenu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Función para mostrar menus de segundo nivel en adelante
function devildrey33_MostrarSubMenu(ID) {
// Oculto TODOS los submenus
$(".devildrey33_SubMenu").css({ "display" : "none" });
// Des-Resalto todos los submenus
$(".devildrey33_SubMenuItem_Resaltado").prop({ "className" : "devildrey33_SubMenuItem" });
// Busco los sumbenus que deben permanecer visibles
var ID2 = ID;
var TSubMenus = 0;
while (ID2.length > 5) {
TSubMenus ++;
// Asigno la clase resaltada al item que esta seleccionado
$("#devildrey33_SubMenuItem_" + ID2).prop({ "className" : "devildrey33_SubMenuItem_Resaltado" });
// Muestro el submenu inferior
$("#devildrey33_SubMenuItem_" + ID2).parent().css({ "display" : "block" });
// Eliminamos 2 caracteres a la id para ir al menu inmediatamente superior o padre.
ID2 = ID2.substr(0, (ID2.length - 3));
}
if (TSubMenus == 1) TSubMenus = 4;
else TSubMenus = 6 * TSubMenus;
// Localizo el item a mostrar
var SubMenuItem = $("#devildrey33_SubMenuItem_" + ID);
// Localizo el submenu a mostrar
var SubMenu = $("#devildrey33_SubMenu_" + ID);
// Asigno estilos con la posición y hago visible el submenu que toca
SubMenu.css({ "left" : (SubMenuItem.offset().left + SubMenuItem.width()) - 10,
"top" : SubMenuItem.position().top + 40 + TSubMenus,
"border-radius" : "4px",
"border-top-width" : "1px"
});
SubMenu.css({ "display" : "block" });
// Desactivo el temporizador para ocultar todos los menus
devildrey33_TemporizadorOcultarMenus(0);
}

Esta función trabaja de un modo similar a la función devildrey33_MostrarMenu, con la diferencia de que al ocultarlo todo luego tenemos que encontrar los submenús padre y el menú padre para volverlos a mostrar. Este proceso lo podéis ver desde la línea 7 hasta la línea 18, donde a partir de la id voy quitando los tres últimos caracteres para localizar los menús padre hasta que la id solo tiene 5 caracteres.

Veamos la función devildrey33_ResaltarMenuItem :

Funcion devildrey33_ResaltarMenuItem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Función para resaltar items que no tienen submenus
function devildrey33_ResaltarMenuItem(ID) {
// Oculto TODOS los submenus
$(".devildrey33_SubMenu").css({ "display" : "none" });
// Des-Resalto todos los submenus
$(".devildrey33_SubMenuItem_Resaltado").prop({ "className" : "devildrey33_SubMenuItem" });
// Busco los sumbenus que deben permanecer visibles
ID2 = ID;
while (ID2.length > 5) {
// Asigno la clase resaltada al item que esta seleccionado
$("#devildrey33_SubMenuItem_" + ID2).prop({ "className" : "devildrey33_SubMenuItem_Resaltado" });
// Muestro el submenu inferior
$("#devildrey33_SubMenuItem_" + ID2).parent().css({ "display" : "block" });
// Eliminamos 2 caracteres a la id para ir al menu inmediatamente superior o padre.
ID2 = ID2.substr(0, (ID2.length - 3));
}
// Selecciono todos los menuitems del submenu actual y los normalizo
$("#devildrey33_SubMenuItem_" + ID).parent().children().prop({ "className" : "devildrey33_SubMenuItem" });
// Resalto el menuitem actual
$("#devildrey33_SubMenuItem_" + ID).prop({ "className" : "devildrey33_SubMenuItem_Resaltado" });
// Desactivo el temporizador para ocultar todos los menus
devildrey33_TemporizadorOcultarMenus(0);
}

Esta función también trabaja de una forma similar a la función devildrey33_MostrarSubMenu, pero su único objetivo es resaltar un ítem que no tiene hijos. Al igual que en la función devildrey33_MostrarSubMenu también hay que localizar todos los padres y volverlos a mostrar.

Y para terminar con el JavaScript y el JQuery veamos las funciones devildrey33_TemporizadorOcultarMenus y devildrey33_OcultarMenus :

Funciones devildrey33_TemporizadorOcultarMenus y devildrey33_OcultarMenus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Función que activa / desactiva un temporizador que oculta el menu pasado un segundo
// Activar = 0 desactiva el temporizador
// Activar = 1 activa el temporizador
function devildrey33_TemporizadorOcultarMenus(Activar) {
if (devildrey33_TemporizadorOcultarMenu != 0) clearInterval(devildrey33_TemporizadorOcultarMenu);
if (Activar == 1) devildrey33_TemporizadorOcultarMenu = setInterval("devildrey33_OcultarMenus()", 1000);
}
// Función que oculta todos los SubMenus
function devildrey33_OcultarMenus() {
clearInterval(devildrey33_TemporizadorOcultarMenu);
// Normalizo menus superiores
$(".devildrey33_MenuSuperior_Resaltado").prop({ "className" : "devildrey33_MenuSuperior" });
// Oculto TODOS los submenus
$(".devildrey33_SubMenu").css({ "display" : "none" });
}

Lo más destacable de estas funciones es que la función devildrey33_TemporizadorOcultarMenus con el parámetro Activar a 0 desactiva el temporizador utilizando la función clearInterval, y con el parámetro Activar a 1 activa el temporizador utilizando la función setInterval.

La función devildrey33_OcultarMenus simplemente se limita a eliminar el temporizador y a ocultar todos los menús padre y submenús.

Veamos como quedaría el documento PHP final con el menú incluido :

Archivo : Ejemplo.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE HTML>
<html>
<head>
<title>Ejemplo devildrey33_Menu</title>
<link href='devildrey33_Menu.css' rel='stylesheet' type='text/css' />
<script type='text/javascript' src='devildrey33_Menu.js'></script>
<script type='text/javascript' src='jquery-1.7.1.min.js'></script>
</head>
<body style='margin:0px'>
<div style='position:fixed; width:100%; height:40px; background-color:#000; padding-left:10px'>
<?php
include("devildrey33_Menu.php");
$Menu = new devildrey33_Menu("MenuWebFijo_Ejemplo.xml");
$Menu->CrearMenus();
?>
</div>
<br />
<br />
<br />
<p><a href="/Blog/MenuWebFijo">Volver a devildrey33</a>.</p>
</body>
</html>

Por último no creo que sea necesario mostrar los estilos css, pero si os voy a remarcar que están diseñados para trabajar con la propiedad "position:fixed" por lo que el menú tiene que quedar siempre fijo en la ventana.

Y esto es todo por hoy, como siempre podéis ver el ejemplo online (aunque también tenéis otro ejemplo con el menú superior de esta página web), o descargar el ejemplo.

Ver Ejemplo Descargar Ejemplo