A medida que avanzamos en el tiempo, las aplicaciones web van cobrando mayor funcionalidad hasta el punto de llegar a ser réplicas exactas de algunas de las aplicaciones de escritorio más conocidas (Google Docs, Zoho…). Todo esto se consigue mediante el uso de técnicas de CSS y Javascript “innovadoras”, recreando controles tan típicos pero ausentes hasta ahora como es el caso del menú contextual, el cual recrearemos en este tutorial.

Autor:

Hola! Soy diseñador, programador web y cofundador de la startup Cokidoo, desarrollamos aplicaciones web a gran escala y comercio electrónico, aplicaciones para móviles y advertising. Puedes seguirme através de mi twitter y ver algunos de mis themes en Themeforest. También soy aficionado a la fotografía.
Descarga Demostración

Introducción: ¿Qué vamos a hacer?

Vivimos en una época en cual las aplicaciones web ganan en usabilidad e interactividad a una velocidad pasmosa. Si hace unos años el Javascript se utilizaba principalmente para crear formularios un poco más interactivos y algunas pequeñas alertas, ahora el Javascript y el CSS nos permiten mucho más, y se están utilizando para recrear auténticas interfaces ricas, funcionales y usables para la mayoría de los navegadores.

En este tutorial aprenderemos a crear paso a paso y desde cero el famoso menú contextual de los distintos sistemas operativos, el cual se activa cuando el usuario hace click con el botón secundario de su ratón.

Nuestro menú contextual soportará:

  • Elementos de tipo enlace
  • Elementos que desencadenan acciones
  • Elementos desactivados (aparecen, pero no se podrán seleccionar)
  • Aparecerá cuando el usuario pinche el botón secundario de su ratón.
  • Desaparecerá cuando el usuario pinche fuera del mismo, en alguna de las opciones activas o cuando se presione la tecla Escape.

Para ello utilizaremos lo mismo que venimos usando en la mayoría de los tutoriales que os he presentado: la librería de javascript jQuery, CSS y HTML.

Paso 1: La estructura

El documento HTML que utilizaremos será bastante sencillo, utilizaremos la misma base que en otras ocasiones y un pequeño menú en forma de lista desordenada. Os dejo con el código para que le echéis un vistazo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="es-ES">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>Creando un menu contextual mediante jQuery | Web.Ontuts</title>
	<link rel="stylesheet" href="main.css" type="text/css" media="screen" />
</head>
<body>
	<div class="wrapper">
		<div class="section">
			<h1>Utiliza el boton derecho del ratón para activar el menú contextual</h1>
		</div>
	</div>
	
	<div id="menu">
		<ul>
			<li id="menu_anterior">Anterior</li>
			<li id="menu_siguiente" class="disabled">Siguiente</li>
			<li id="menu_recargar">Recargar</li>
			<li id="menu_web"><a href="http://web.ontuts.com">Visitar web.ontuts</a></li>
			<li id="menu_favoritos">Agregar a favoritos...</li>
		</ul>
	</div>
	
	<script type="text/javascript" src="jquery.js"></script> 
	<script type="text/javascript" src="menu.js"></script>
</body>
</html>

El menú contextual, representado con una lista desordenada

    tiene los siguientes elementos:

    • Anterior: Regresa a la página anterior
    • Siguiente: Deshabilitado
    • Recargar: Recarga la página actual
    • Visitar web.ontuts: Enlace que lleva a web.ontuts.com
    • Agrevar a favoritos…: Abre el diálogo de agregado a favoritos

    Cada elemento de la lista desordenada de id=”menu” representa cada una de las opciones del menú. Todas contienen un id que nos servirá posteriormente para detectar su selección. La clase “disabled” del elemento “Siguiente” indica que está deshabilitado.

    Los elementos del menú tienen un id asociado para reconocer su selección. La clase “disabled” indica que la opción está deshabilitada.

    Una vez tenemos claro qué hará cada opción de nuestro menú, sólo nos queda gestionar todo este compartamiento mediante Javascript, pero antes y como de costumbre, vamos a echar un vistazo rápido al código CSS que hemos utilizado.

    Paso 2: Añadiendo estilo con CSS a nuestro menú contextual

    En este caso, el código CSS es muy básico y sólo hay un par de puntos a resaltar, echemos un vistazo al código antes de resaltar dichos puntos:

    @CHARSET "UTF-8";
    /*
    Author: Adrian Mato
    Author URI: http://www.yensdesign.com & http://web.ontuts.com
    */
    
    /******* GENERAL RESET *******/
    html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em,
    font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody,
     tfoot, thead, tr, th, td {
    border:0pt none;
    font-family:inherit;
    font-size:100%;
    font-style:inherit;
    font-weight:inherit;
    margin:0pt;
    padding:0pt;
    vertical-align:baseline;
    }
    body{
    	line-height: 1em;
    	font-size: 12px;
    	background: #262626 url(img/bg.png) repeat scroll 0 0;
    	font-family: Myriad Pro, Arial, Helvetica, sans-serif;
    	margin: 0pt;
    	cursor: default;
    }
    table{
    	border-collapse: separate;
    	border-spacing: 0pt;
    }
    strong{
    	font-weight: 700;
    }
    caption, th, td{
    	font-weight:normal;
    	text-align:left;
    }
    blockquote:before, blockquote:after, q:before, q:after{
    	content:"";
    }
    blockquote, q{
    	quotes:"" "";
    }
    pre{
    	font-family: Arial, Helvetica, sans-serif;
    }
    input{
    	border: 0;
    	margin: 0;
    	font-family: Arial, Helvetica, sans-serif;
    }
    textarea{
    	font-family: Arial, Helvetica, sans-serif;
    	color: #888888;
    	padding: 7px 3px 0 4px;
    	font-size: 11px;
    }
    select{
    	font-size: 11px;
    	color: #888888;
    	background: #fff;
    	font-family: Arial, Helvetica, sans-serif;
    	border: 1px solid #CAD2CE;
    }
    ul{
    	list-style: none;
    	list-style-type: none;
    	list-style-position: outside;
    }
    a{
    	cursor: pointer;
    	color: #296ba5;
    	text-decoration: none;
    	outline: none !Important;
    }
    html,body{
    	height:100%;
    }
    .clear{
    	clear: both;
    	height: 0;
    	visibility: hidden;
    	display: block;
    	line-height: 0;
    }
    .clearfix{
    	overflow: hidden;
    }
    .fleft{
    	float: left;
    }
    .fright{
    	float: right;
    }
    .italic{
    	font-style: italic;
    }
    /******* /GENERAL RESET *******/
    
    /******* CONTENT *******/
    .wrapper{
    	width: 800px;
    	margin: 0pt auto;
    	padding-top: 50px;
    }
    h1{
    	color: #fff;
    	font-size: 18px;
    	line-height: 3em;
    }
    .section{
    	margin-bottom: 25px;
    }
    /******* /CONTENT *******/
    
    /******* MENU *******/
    #menu{
    	display: none;
    	width: 165px;
    	padding: 6px;
    	background: #171717;
    	border: 1px solid #3e3e3e;
    	border-radius: 5px;
    	-moz-border-radius: 5px;
    	-webkit-border-radius: 5px;
    	-khtml-border-radius: 5px;
    	position: absolute;
    }
    #menu ul{
    	font-family: Tahoma, Arial, Helvetica, sans-serif;
    	color: #6d6d6d;
    	background: #fff;
    	border: 1px solid #171717;
    	border-radius: 5px;
    	-moz-border-radius: 5px;
    	-webkit-border-radius: 5px;
    	-khtml-border-radius: 5px;
    }
    #menu ul li{
    	line-height: 1.5em;
    	padding: 5px 5px 5px 25px;
    	font-size: 11px;
    	border-bottom: 1px solid #fff;
    	border-radius: 5px;
    	-moz-border-radius: 5px;
    	-webkit-border-radius: 5px;
    	-khtml-border-radius: 5px;
    }
    #menu ul li:hover{
    	background-color: #fff8cc;
    	border-bottom: 1px solid #ffe222;
    	color: #000;
    	cursor: pointer;
    }
    #menu ul li a{
    	color: #6d6d6d;
    	display: block;
    }
    #menu ul li.disabled, #menu ul li.disabled a{
    	color: #bbbbbb;
    	cursor: default;
    }
    #menu ul li.disabled:hover{
    	background: #fff;
    	border-bottom: 1px solid #fff;
    }
    #menu ul li{
    	background-position: 3px 6px;
    	background-repeat: no-repeat;
    }
    #menu ul li#menu_anterior{
    	background-image: url(img/anterior.png);
    }
    #menu ul li#menu_recargar{
    	background-image: url(img/refresh.png);
    }
    #menu ul li#menu_web{
    	background-position: 3px 5px;
    	background-image: url(img/web.png);
    }
    #menu ul li#menu_favoritos{
    	background-image: url(img/fav.png);
    }
    /******* /MENU *******/
    

    Para los más despistados me gustaría recordaros que estamos utilizando una serie de propiedades que no se consideran estándar, se trata de una serie de propiedades enfocadas a recrear el redondeado de los bordes de nuestro menú contextual, hablamos de las propiedades:

    • -moz-border-radius: Para navegadores mozilla
    • -webkit-border-radius: Para navegadores webkit
    • -khtml-border-radius: Para el navegador Konqueror

    La propiedad CSS estándar border-radius permite definir el radio de los bordes redondeados de nuestros elementos. Debido a que algunos navegadores todavía no soportan de forma oficial el redondeado, se utilizan propiedades no estándar como: -moz-border-radius, -webkit-border-radius o -khtml-border-radius.

    Si os habéis fijado, también estamos definiendo una imagen de fondo para todos los elementos del menú, salvo para la opción deshabilitada “Siguiente”. Es algo estético, pero dotará de mayor vistosidad a nuestro menú contextual :)

    Ahora sí, vamos a por la funcionalidad de nuestro menú, ¡vamos a la parte de javascript con jQuery!

    Paso 3: Dándole vida y funcionalidad a nuestro menú contextual mediante Javascript

    Hemos dejado pasar por alto un pequeño detalle en la sección del CSS que me gustaría comentaros ahora. El menú contextual tiene por defecto aplicada la propiedad de CSS “display: none“, con ello conseguimos que el menú esté oculto hasta que el usuario lo llame mediante el botón secundario de su ratón.

    El menú contextual está por defecto oculto mediante CSS (display: none), alterando esta propiedad mediante javascript haremos que se muestre donde el usuario haga click.

    Vamos a definir y recordar de forma breve qué es lo que hará nuestro menú contextual:

    • Aparecerá cuando el usuario haga click con el botón secundario de su ratón.
    • Desaparecerá cuando el usuario seleccione una opción, pinche fuera del menú contextual o presione la tecla Escape.

    Vamos a abordar las distintas partes del código de nuestro menu.js, pero recordad que todo este código irá como siempre dentro del evento $(document).ready. Es decir:

    //Cuando el documento esté listo...
    $(document).ready(function(){
    	//todo el código aquí
    )};
    

    Aclarado esto, vamos a ello.

    Desactivando el menú contextual por defecto

    Como bien sabréis, al pinchar en el botón secundario de vuestro ratón en una web se muestra por defecto un menú contextual correspondiente al navegador. Mediante la función bind de jQuery vamos a cancelar este menú contextual, en pro de mostrar nuestro propio menú contextual personalizado.

    Mediante la función bind de jQuery cancelaremos el menú contextual por defecto. Esto funciona en la mayoría de navegadores pero el navegador Opera no lo admite, por lo que se seguirá mostrando el menú contextual por defecto.

    Con este sencillo código cancelaremos el menú contextual por defecto y además mostraremos nuestro menú contextual:

    //EVITAMOS que se muestre el MENU CONTEXTUAL del sistema operativo al hacer CLICK con el BOTON DERECHO del RATON
    $(document).bind("contextmenu", function(e){
    	menu.css({'display':'block', 'left':e.pageX, 'top':e.pageY});
    	return false;
    });
    

    Como podréis leer en los comentarios del código de arriba, estamos alterando varias propiedades del CSS para mostrar correctamente nuestro menú. Modificando la propiedad display: block del CSS estamos mostrando la división que contiene a nuestro menú contextual.

    Además estamos situando el menú de forma que la esquina superior izquierda, coincide con donde el usuario hace click.

    El objeto “e” devuelto por la función bind permite reconocer la posición exacta del click del usuario. Las propiedades e.pageX y e.pageY nos dicen la distancia horizontal y vertical (respectivamente) que hay en pixels desde la esquina superior izquierda (punto 0,0).

    Ahora que ya sabemos mostrar nuestro menú contextual, vamos a ver cómo gestionar las acciones de los elementos del menú.

    Controlando las acciones de los elementos del menú contextual

    Vamos a utilizar una sentencia del tipo switch, de esta forma controlaremos para cada caso / opción del menú contextual las acciones que deseemos, y además será muy fácil añadir nuevas acciones a futuros elementos nuevos:

    //variables de control
    var menuId = "menu";
    var menu = $("#"+menuId);
    
    //Control sobre las opciones del menu contextual
    menu.click(function(e){
    	//si la opcion esta desactivado, no pasa nada
    	if(e.target.className == "disabled"){
    		return false;
    	}
    	//si esta activada, gestionamos cada una y sus acciones
    	else{
    		switch(e.target.id){
    			case "menu_anterior":
    				history.back(-1);
    				break;
    			case "menu_siguiente":
    				alert("ha seleccionado siguiente");
    				break;
    			case "menu_recargar":
    				document.location.reload();
    				break;
    			case "menu_favoritos":
    				var title = "Tutoriales de Desarrollo y Diseño Web | Web.Ontuts";
    				var url = "http://web.ontuts.com";
    				//para firefox
    				if(window.sidebar)
    					window.sidebar.addPanel(title, url, "");
    				//para Internet Explorer
    				else if(window.external)
    					window.external.AddFavorite(url, title);
    				break;
    		}
    		menu.css("display", "none");
    	}
    });
    

    Como véis, estamos guardando en dos variables dos referencias al menú, simplemente y como hacemos siempre para optimizar un poco el código y evitar que jQuery busque el elemento cada vez que se ejecuta el código javascript.

    Mediante la función click de nuestro menú contextual sabremos en todo momento cuándo se está haciendo click en alguna de las opciones del menú, para poder decidir en cada caso qué hacer. ¿Cómo sabemos cuál ha sido seleccionada? Muy fácil: el objeto “e” de la función click nos permitirá explorar el elemento en el cual se ha hecho click y además, conocer su id.

    Nuevamente el objeto “e” (de la función click) nos permitirá reconocer el elemento del menú que se ha seleccionado. Según el valor del id del elemento, ejecutaremos unas acciones u otras.

    En caso de que el elemento seleccionado tenga asignada la clase CSS “disabled” sabremos que esta opción está desactivada y no ocurrirá absolutamente nada (ni si quiera se cerrará el menú contextual).

    Las acciones de los elementos son triviales, así que os dejo que investiguéis un poco vosotros mismos, pero los nombres son muy sugerentes :)

    Ocultando el menú contextual

    La lógica nos dice que el menú contextual y su comprobación de ocultado sólo tendríamos que aplicarla cuando el menú estuviese visible, pero en nuestro caso, no necesitamos gestionar el estado del menú, ya que variando las propiedades de CSS será suficiente.

    Los dos casos en los que debería desaparecer el menú contextual serían:

    • Usuario hace click en alguna zona de la página que no sea el menú
    • Si el usuario pulsa la tecla Escape
    • Habría un tercer caso, que hemos puesto antes, que sería cuando se ha seleccionado una opción del menú activada (en las deshabilitadas no se oculta).

    He aquí los dos casos que acabamos de comentar:

    //controlamos ocultado de menu cuando esta activo
    //click boton principal raton
    $(document).click(function(e){
    	if(e.button == 0 && e.target.parentNode.parentNode.id != menuId){
    		menu.css("display", "none");
    	}
    });
    //pulsacion tecla escape
    $(document).keydown(function(e){
    	if(e.keyCode == 27){
    		menu.css("display", "none");
    	}
    });
    

    Nuevamente el objeto “e” en las dos funciones utilizadas nos permiten acceder a las propiedades button y keyCode para saber qué botón y tecla se ha pulsado, en nuestro caso el botón principal y la tecla Escape. También es interesante ver cómo vamos accediendo desde el elemento sobre el que se ha hecho click, hasta el elemento padre “menu” mediante “e.target.parentNode.parentNode.id, de esta forma podremos comprobar si se el usuario ha pinchado encima / dentro de alguna parte del menú contextual.”

    La propiedad button con valor 0 nos indica que se está pulsando el botón principal del ratón. La propiedad keyCode con valor 27 indica que se ha pulsado la tecla Escape. Ambas propiedades provienen del objeto “e” de sus respectivas funciones.

    Y esto es todo lo que hemos de tener en nuestro código javascript… una vez más es menos de lo que en un principio pudiese parecer.

    Reflexión final

    Ahora que sabemos cómo crear las bases para nuestro menú contextual sólo queda pensar en formas de mejorarlo, por ejemplo, si un usuario pincha en la parte de la derecha de la pantalla, se activaría el scroll horizontal, seguramente fuese conveniente detectarlo y mostrar un poco más a la izquierda el menú, etc…

    Hemos retomado por mi parte los tutoriales con javascript y jQuery, la verdad es que me encanta escribir sobre estos tutoriales, son detalles y pequeñas mejoras que dan mucha calidad a las aplicaciones. Seguramente siga profundizando en distintos tipos de controles para tratar de recrear interfaces ricas y útiles para vuestros proyectos.

    ¡Un saludo y nos vemos en el próximo tutorial!

¿Necesitas desarrollar un proyecto web o para móviles? ¡Estamos disponibles!

Visitar Cokidoo

Cokidoo, los creadores de Ontuts, desarrollamos proyectos tecnológicos centrados en redes sociales y aplicaciones web, aplicaciones móviles y consultoría web y bases de datos.

Somos jóvenes, inquietos, versátiles, apasionados por la innovación y enfocados en las nuevas tecnologías. Con Ontuts tratamos de compartir nuestro conocimiento adquirido en los distintos proyectos, ayudando a la comunidad y mostrando nuestra capacidad tecnológica.

Si necesitas un presupuesto sin compromiso, estamos disponibles, no dudes en contactar con nosotros.

Comentarios en esta publicación (16 comentarios)

¿Te ha gustado esta publicación? ¡Puedes compartir tu opinión con todos nosotros! Simplemente pincha aquí mismo.

beto

apenas voy aprender y me parecio sencillo y claro tu ejemplo, gracias

Ing. Braulio Olan

Que tal, gracias nuavamento por estos increibles tutoriales, funciona a la perfeccion, pero al querer usarlo en mi aplicacion he cambiado el parametro de document por solo ciertos elementos (li, a, div, etc.) para que el menu emergente solo funcione con los tag o elementos que deseo, me he encontrado con el problema de que no funciona al estar adentro de varios divs (tres para ser exacto), es decir funciona estando afuera con los elementos principales del arbol, sin embargo si el elemento se encuentra en niveles mas adentro (body/div1/div2/div3/elemento), este me muestra el meno del navegador. He utilizado distintas formas de acceder a ellos pero ninguna funciona, espero me puedas auxiliar con la solucion.

Espero haberme explicado y reafirmo, muchas gracias porestos magnificos tutoriales.

@Braulio Buenas y gracias por tus comentarios! Es importante que entiendas cómo funcionan los selectores de jQuery, de lo contrario estarás buscando solución a un problema bastante sencillo.

Si cambias divisiones, lo más seguro es que también tengas que cambiar los selectores del ejemplo, por lo que te aconsejo que le eches un vistazo a esto: http://docs.jquery.com/Selectors

Un saludo!

zeres

que tal, esta chido el ejemplo, lo tratede usar pero no me funciona, cargo un menu desde ajax y quiero que solo en este menu funcione el menu contextual pero no me funca. solo funciona con los elementos que tengo en mi html, si cargo alguno por ajax no, supongo que debe ser pq no son cargados al inicio, que se podria hacer
gracias!!!

@zeres Eso es un error común, creo que con la última versión de jQuery no ocurre. Si aún así no te funciona, debes utilizar el plugin “jQuery Live” que te solventa el problema de asignar eventos a selectores que todavía puedan no existir. http://docs.jquery.com/Events/live

Hola, soy nobel en esto de Jquery, tenía una duda, y la verdad es que me gustaría que me hecharas una pequeña mano. Tengo un blog en blogger y la verdad, no sé como enfocar todos los datos en la plantilla etc. ¿Podrías hecharme una mano? Si me pudieses contestar al correo te lo agradecería muchisimo. En cualquier caso, muchas gracias de antemano y felicitarte por tu web que es muy interesante.

Excelente y funciona de lujo, ahora estoy intentando agregarle nuevas funciones, la que no logro hacer funcionar bien es la que abrir un link otrra ventana.. intente con este metodo poer no hay manera de que funcione. no logro que funcione con el menu del clic derecho. alguna ayuda?

$(document).ready(function() {
$(“a”).each(function() {
$(this).attr(“target”, “_blank”);
});
});

Cmdog

Me encanto tu explicacion muchas gracias por el aporte!!

Tony

Hola Adrián, muy interesante el tutorial, es realmente algo muy útil. Solo tengo una inquietud, hay alguna forma de que tambien funcione agregar marcadores para Chrome, Safari…?
Un saludo y felicitaciones por el sitio!

@Tony gracias por tus comentarios! Te recomiendo que te pases por este post que he encontrado via google: http://bytes.com/topic/javascript/answers/596395-help-javascript-add-bookmark-firefox-mozilla-safari-opera

A ver si tienes suerte,

¡Un saludo!

Genial, coloqué buscar en google y saliste tu con esta maravilla :D era lo que estaba buscando ;)
Gracias

Israel Gaytán

Excelente tutorial, no se puede pedir más!

Buenisimo!!! Gracias por compartir tus conocimientos….

Kalitoo

Excelente brother, que bueno el hecho d q existan personas a las q les guste enseñar y compartir ideas. gracias por el tutorial, creo q voy a tomar tambien la iniciativa de compartir mis conocimientos blogueando, ya q asi nos enriquecemos todos de los beneficios… saludos :D

kres

muy Bien Explicado Tienes un 10 este Menú Contextual.

Execelente y FELICITACIONES por el Tutorial.

Michel

Una pregunta ^^ como puedo hacer que copie el texto seleccionado? ya agregue en el menu copiar pero no se como hacer que funcione u.u soy nuevo disculpa! Saludos! :3