Etiqueta: css3

  • Upload A File With HTML5 / Subir un archivo con HTML5

    Upload A File With HTML5 (XMLHttpRequest)

    Upload A File With HTML5 / Subir un archivo con HTML5

    The XMLHttpRequest object

    The XMLHttpRequest object has been updated several times since was defined as the WHATWG’s HTML effort using Microsoft technology; then we had the original XMLHttpRequest Level 1 specification as part of W3C, we also had the XMLHttpRequest Level 2 updated specification, and now we have the last version of this object known as XMLHttpRequest Living Specification. We can summarize its advantages in the following points:

    • Allows upload and download files as stream bytes, large binaries (BLOBs) or data forms
    • It has event handlers for progress, errors, abortion, start, and end of operations
    • Cross-domain capabilities (CORS)
    • New type for JSON responses
    • Is a fundamental part of the HTML5 File API specification

    It’s important to emphasize that before HTML5 and the latest versions of XMLHttpRequest object it was required to resort to server-side technology in order to able to perform an uploading file operation, that is, it wasn’t possible to upload a file natively from the client side. Technologies as AJAX and Flash did their own effort but with serious limitations, so XMLHttpRequest comes to cover this old problem in a big way. There are other additional features that come with XMLHttpRequest, if you want to know more you can resort to the official specification.

    Starting

    The first thing we’ll do is to define the user interface for this small implementation starting with the HTML tags, the code is very simple and only includes some form elements, and some div tags that are only used to give a better presentation using CSS3. I won’t analyze in this post anything related to the used cascade style sheets since is not something really necessary for the operation of this example.

    <!DOCTYPE html>
    <html>
        <head>
            <title>Upload File</title>
            <meta charset="iso-8859-1" />
        </head>
        <body>
        <div id="wrap">
           <div class="field">
               <ul class="options">
                  <li><input type="file" id="myfile" name="myfile" class="rm-input" onchange="selectedFile();"/></li>
                  <li><div id="fileSize"></div></li>
                  <li><div id="fileType"></div></li>
                  <li><input type="button" value="Subir Archivo" onClick="uploadFile()" class="rm-button" /></li>
               </ul>
           </div>
           <progress id="progressBar" value="0" max="100" class="rm-progress"></progress>
           <div id="percentageCalc"></div>
        </div>
        </body>
    </html>
    The previous code explains itself, but let’s summarize what is in there:
    • A file-type input which will be used to select the file to be uploaded
    • A div which will be used to print the size of the selected file
    • A div which will be used to print the MIME type of the selected file
    • A button which will fire the uploading process for the selected file
    • A progress bar to indicate the uploading process progress of the selected file
    • Finally, a div where the progress will be shown in a percentage format

    The selectedFile() function

    Each time you select a file using the file element, you also trigger the onchange event which calls the selectedFile() function. In this function very interesting things happen, to start, a reference to a file array instantiated by the HTML5 object FileList is done, the objects that we get as members of FileList are File objects. In this case, we’ll get the size and type properties from the gotten File object.
    Using the information provided by the size property, the size of the selected file is calculated and shown in megabytes or kilobytes within the function. With the type property, the MIME type of the selected files is gotten and showed in the corresponding div.
    function selectedFile() {
    var archivoSeleccionado = document.getElementById("myfile");
    var file = archivoSeleccionado.files[0];
       if (file) {
           var fileSize = 0;
           if (file.size > 1048576)
              fileSize = (Math.round(file.size * 100 / 1048576) / 100).toString() + ' MB';
           else
              fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + ' Kb';
    
           var divfileSize = document.getElementById('fileSize');
           var divfileType = document.getElementById('fileType');
           divfileSize.innerHTML = 'Tamaño: ' + fileSize;
           divfileType.innerHTML = 'Tipo: ' + file.type;
    
        }
    }

    The uploadFile() function

    Esta es la función que hace un mayor uso de las nuevas posibilidades de XMLHttpRequest , y es la que se encargará de disparar el proceso principal del lado cliente.

    function uploadFile(){
     //var url = "/ReadMoveWebServices/WSUploadFile.asmx/UploadFile";
     var url = "/ReadMoveWebSite/UploadMinimal.aspx";
     var archivoSeleccionado = document.getElementById("myfile");
     var file = archivoSeleccionado.files[0];
     var fd = new FormData();
     fd.append("archivo", file);
     var xmlHTTP = new XMLHttpRequest();
     //xmlHTTP.upload.addEventListener("loadstart", loadStartFunction, false);
     xmlHTTP.upload.addEventListener("progress", progressFunction, false);
     xmlHTTP.addEventListener("load", transferCompleteFunction, false);
     xmlHTTP.addEventListener("error", uploadFailed, false);
     xmlHTTP.addEventListener("abort", uploadCanceled, false);
     xmlHTTP.open("POST", url, true);
     //xmlHTTP.setRequestHeader('book_id','10');
     xmlHTTP.send(fd);
    }
    At the beginning, we have the variable url that we’ll use to indicate where is the page o web service which is going to receive the request from this page to do the proper process on server side. Immediately like in the selectedFile() function, a reference to the gotten File object member is also done.
    In the fourth line, there is something new and very useful, that is the FormData object, this object allows to instantiate a web form via JavaScript, that is, is like you put an HTML form using tags, or you can refer to an already existing one assigning it to a FormData object. No doubt this is really helpful since means now you can create a web form y alter the sending values dynamically. To append values to, either instantiated or referenced web form with FormData, use the append(file, object) method, this way in the fifth line our File object is added with the file name.
    This is the code of the function that covers what was just stated:
    //var url = "/ReadMoveWebServices/WSUploadFile.asmx/UploadFile";
    var url = "/ReadMoveWebSite/UploadMinimal.aspx";
    var archivoSeleccionado = document.getElementById("myfile");
    var file = archivoSeleccionado.files[0];
    var fd = new FormData();
    fd.append("archivo", file);

    Event handlers

    Continuing with the rest of the function, we can observe that the XMLHttpRequest object is finally instantiated and is assigned to the xmlHTTP variable, and then we proceed to the next novelty, I mean the possibility of creating new events which are part of XMLHttpRequest thanks to the upload object. The added events for this particular case are:
    • loadstart. Is triggered when the uploading file process initiates.
    • progress. Is triggered each time there is an advance in the file uploading process.
    • load. Is triggered when the transfer is complete successfully.
    • error. Is triggered when the transfer fails
    • abort. Is triggered when the user/developer interrupts the process.
    These aren’t the only available events, check the official specification for more information.
    The event handlers are declared in the following code:
    var xmlHTTP= new XMLHttpRequest();
    //xmlHTTP.upload.addEventListener("loadstart", loadStartFunction, false);
    xmlHTTP.upload.addEventListener("progress", progressFunction, false);
    xmlHTTP.addEventListener("load", transferCompleteFunction, false);
    xmlHTTP.addEventListener("error", uploadFailed, false);
    xmlHTTP.addEventListener("abort", uploadCanceled, false);

    The triggered events functions are the following:

    function progressFunction(evt){
        var progressBar = document.getElementById("progressBar");
        var percentageDiv = document.getElementById("percentageCalc");
        if (evt.lengthComputable) {
            progressBar.max = evt.total;
            progressBar.value = evt.loaded;
            percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
        }
    }
     
    function loadStartFunction(evt){
        alert('Comenzando a subir el archivo');
    }
     
    function transferCompleteFunction(evt){
        alert('Transferencia completa');
        var progressBar = document.getElementById("progressBar");
        var percentageDiv = document.getElementById("percentageCalc");
        progressBar.value = 100;
        percentageDiv.innerHTML = "100%";
    }
     
    function uploadFailed(evt) {
        alert("Hubo un error al subir el archivo.");
    }
     
    function uploadCanceled(evt) {
        alert("La operación se canceló o la conexión fue interrunpida.");
    }

    ProgressFunction() updates the progress bar and percentage which indicate in a graphical and numerical way the process progress, the rest of the functions only display the proper message for each case.

    Commented code

    If you have observed the code you probably noticed some commented lines, this is because this is just the base code to create something a little bit more complex, but I decided to leave those lines because maybe can be useful for someone:

    //var url = "/ReadMoveWebServices/WSUploadFile.asmx/UploadFile";

    The previous line of code is a call to a .Net HTTP service instead of a page. Here is where you should call your own server-side implementation.

    //xmlHTTP.upload.addEventListener("loadstart", loadStartFunction, false);

    This line calls a function that shows a message when the process starts. I commented this line after I executed the code several times because was annoying.

    The completo code

    This is how the complete implementation of the code looks:

    <!DOCTYPE html>
    <html>
        <head>
            <title>Upload File</title>
            <meta charset="iso-8859-1" />
                                        <link rel="stylesheet" type="text/css" href="estilosUploadFile.css" />
            <script type="text/javascript">
     
                  function selectedFile() {
                    var archivoSeleccionado = document.getElementById("myfile");
                    var file = archivoSeleccionado.files[0];
                    if (file) {
                        var fileSize = 0;
                        if (file.size > 1048576)
                            fileSize = (Math.round(file.size * 100 / 1048576) / 100).toString() + ' MB';
                        else
                            fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + ' Kb';
     
                        var divfileSize = document.getElementById('fileSize');
                        var divfileType = document.getElementById('fileType');
                        divfileSize.innerHTML = 'Tamaño: ' + fileSize;
                        divfileType.innerHTML = 'Tipo: ' + file.type;
     
                    }
                  }     
     
                function uploadFile(){
                    //var url = "http://localhost/ReadMoveWebServices/WSUploadFile.asmx?op=UploadFile";
                    var url = "/ReadMoveWebServices/WSUploadFile.asmx/UploadFile";
                    var archivoSeleccionado = document.getElementById("myfile");
                    var file = archivoSeleccionado.files[0];
                    var fd = new FormData();
                    fd.append("archivo", file);
                    var xmlHTTP= new XMLHttpRequest();
                    //xmlHTTP.upload.addEventListener("loadstart", loadStartFunction, false);
                    xmlHTTP.upload.addEventListener("progress", progressFunction, false);
                    xmlHTTP.addEventListener("load", transferCompleteFunction, false);
                    xmlHTTP.addEventListener("error", uploadFailed, false);
                    xmlHTTP.addEventListener("abort", uploadCanceled, false);
                    xmlHTTP.open("POST", url, true);
                    //xmlHTTP.setRequestHeader('book_id','10');
                    xmlHTTP.send(fd);
                }       
     
                function progressFunction(evt){
                    var progressBar = document.getElementById("progressBar");
                    var percentageDiv = document.getElementById("percentageCalc");
                    if (evt.lengthComputable) {
                        progressBar.max = evt.total;
                        progressBar.value = evt.loaded;
                        percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
                    }
                }
     
                function loadStartFunction(evt){
                    alert('Comenzando a subir el archivo');
                }
                function transferCompleteFunction(evt){
                    alert('Transferencia completa');
                    var progressBar = document.getElementById("progressBar");
                    var percentageDiv = document.getElementById("percentageCalc");
                    progressBar.value = 100;
                    percentageDiv.innerHTML = "100%";
                }   
     
                function uploadFailed(evt) {
                    alert("Hubo un error al subir el archivo.");
                }
     
                function uploadCanceled(evt) {
                    alert("La operación se canceló o la conexión fue interrunpida.");
                }
     
            </script>
        </head>
        <body>
            <div id="wrap">
                <div class="field">
                    <ul class="options">
                        <li>
                            <input type="file" id="myfile" name="myfile" class="rm-input" onchange="selectedFile();"/>
                        </li>
                        <li>
                            <div id="fileSize"></div></li>
                        <li>
                            <div id="fileType"></div></li>
                        <li>
                            <input type="button" value="Subir Archivo" onClick="uploadFile()" class="rm-button" /></li>
                    </ul>
                </div>
                <progress id="progressBar" value="0" max="100" class="rm-progress"></progress>
                <div id="percentageCalc"></div>
            </div>
        </body>
    </html>

    I’m not describing the CSS3 code because is irrelevant in terms of functionality, but I share an image that shows how it looks the implementation in the browser and the link to the CSS3 estilosUploadFile.zip.

    I’m also sharing the original HTTP service that I used to test this example -the server-side code, backend file or any name that you prefer 😃- but this won’t be very useful for you unless you use the exact same stack that I was using at the moment- in other words, if you are the kind of person who just wants to copy and paste….hehehe well….maybe you’re not ready for this yet. Here is the file WSUploadFile.zip

    Sorry about my English I’m not a natural speaker (don’t be grumpy, help me to improve).

    This is all for now folks, I hope this can be useful for you.

    Here some books that can help you in your HTML5 journey:

    4 Comments
  • Reseña Adobe Edge Animate 1.5

    Adobe_Edge_Animate

    Desde hace un tiempo todas aquellas personas que coqueteaban con el desarrollo de contenido multimedia pero que no tenían un perfil técnico (o como diría un antiguo colaborador: “programan poquito”) en los últimos años se han visto afectados y frustrados debido a que algunas de las herramientas que ya habían adoptado para estas labores se han visto relegadas para ciertos fines. Por ejemplo, los diseñadores gráficos que hacían elementos web como banners y headers con pequeñas animaciones, se han topado con que los clientes quieren cada vez menos al contenido creado con Flash y si hoy usted desea hacer contenido rico, animado y dinámico con los nuevos estándares sin duda requerirá de conocimientos sólidos de HTML5, Javascript y CSS3. La buena noticia es que están saliendo herramientas, que aunque quizá no cambian esta situación, sí pueden ser alternativas que hagan el terreno un poco más plano.

    Adobe en sus esfuerzos por mantenerse como uno de los líderes en el mercado de herramientas destinadas a la elaboración de recursos gráficos e interactivos, lanzó hace casi 2 años una herramienta llamada Adobe Edge que pretendía ser algo así como la herramienta de autoría sustituta para Flash, lo cual no logró además de ser ampliamente criticada (yo fui uno de esos críticos mala leche), sin embargo Adobe no ha desistido y ha seguido desarrollando su herramienta, pero ahora con el nombre de Adobe Edge Animate, y no solo eso, si no que ahora este programa es parte de una suit de interesantes aplicaciones que juntas forman la “familia” Adobe Edge. Debo mencionar que mi experiencia con este software apenas se ha reiniciado, ya que lo probé cuando salió hace dos años y no me gustó, pero al ver que Adobe seguía trabajando en él, decidí darle otra oportunidad y probarlo nuevamente.

    ¿Pero qué es Adobe Edge Animate?, es una herramienta de desarrollo web basada en HTML5, Javascript-jQuery y CSS3 y por lo tanto hace al contenido que genera “compatible” con cualquier software que pueda interpretar HTML5 (en teoría), su UI es bastante similar a cualquiera familiarizado con las herramientas multimedia basadas en línea de tiempo,  Adobe Edge Animate tiene un “stage” o área de trabajo basada en el motor Webkit que permite colocar y crear gráficos (jpeg, png, gif, svg), colocar texto, previsualizar animaciones, tiene panel de propiedades y desde luego la línea de tiempo.

    Adobe_Edge_Animate02

    La línea de tiempo utiliza “keyframes”, que así somo en Flash, ayudan a generar el “tween” entre ellos automáticamente. También se puede utilizar la herramienta Pin para animar, cada Pin permite modificar las propiedades de un elemento en algún punto de la línea de tiempo sin tener que hacer el “keyframe” de manera manual, de esta manera, usted puede crear una animación desde donde está el “playhead” hasta donde esta el Pin con todo y keyframe en un solo paso. Otra características interesante es que se pueden copiar y pegar animación de un elemento a otro, es decir, si usted tiene un circulo que se mueve de derecha a izquierda, y tiene un triángulo estático pero desea que se mueva de la misma forma que el círculo, usted únicamente copia la animación del círculo (no el elemento) y la pega en el triángulo sin tener que crear o hacer algo más.

    También puede hacer un grupo de elementos y reutilizar este en otra animación, en otras palabras puede crear símbolos (para los acostumbrados a Flash), desde luego estos símbolos pueden tener animación interna. Aunque debo decir que hay algunos problemas de reposicionamiento cuando se cambia el tamaño de la página donde se está desplegando la animación y también cuando veo la animación en Safari, no he logrado encontrar una solución efectiva…aunque como menciono apenas estoy reutilizando la herramienta otra vez…o sea, soy novato en Adobe Edge.

    Triggers!, así es, Adobe Edge utiliza mucho el mecanismo de los “triggers” para indicar que hacer cuando se llega a un determinado punto de la línea de tiempo (stop(), play(), etc.) o bien se pueden aplicar a un elemento en el área de trabajo directamente para dar respuesta a ciertos eventos, como el click del ratón o el “touch” en una tableta, todo ello por medio de una ventana separada (pop-up) de código. Si hay algún veterano del AS2 todo esto le va a recordar a la manera en la que se insertaba código en las versiones 3, 4 y 5 de Flash hace unos 14 años :p .

    He de reconocer que Adobe mejoró bastante su Adobe Edge desde la primera vez que lo utilicé, el flujo de trabajo utilizando la herramienta Pin, las herramientas de “easing” para los elementos, el copiado y pegado de animaciones y algunos otros detalles, hacen de esta aplicación algo interesante para la creación de animaciones HTML5. La parte más decepcionante para mi es que al momento no soporta audio.

    Estas son mis primeras impresiones del programa, y todas ellas las saqué gracias a que elaboré una pequeñísima y muy simple presentación para ilustrar una charla que tuve en la Facultad de Ingeniería Mecánica y Eléctrica de la Universidad de Colima, en ella se puede apreciar como diferentes navegadores responden con diferente rendimiento, lo mas notable son las diferencia en velocidad de despliegue, calidad en el rendereo de imágenes png (que son las que utilicé) y algunos problemas de posicionamiento en Safari, el mejor resultado lo obtuve en Chrome, si alguien desea probar de lo que hablo y descargar este pequeño recurso para estudiarlo, modificarlo y/o destrozarlo adelante (coloco los archivos fuentes (requieren Adobe Edge Animate) y los archivos publicados, en 2 diferentes zips):

    Fuentes

    Publicados

    *Haga clic en el nombre:
    present01

    *Haga click en cada ícono central, de izquierda a derecha:
    present02

    Update. Hace un mes aproximadamente salió Adobe Edge Animate CC que sería la versión 2.0 del programa.

    2 Comments
  • CSS Selectors

    Transiciones y Transformaciones en Botones (CSS3 y HTML5)

    El caso

    Hace un tiempo elaboré un juego interactivo donde utilicé algunos botones que hacen un simple pero atractivo efecto over, es decir, cuando el usuario coloca el puntero del mouse sobre ellos, y un par de personas me preguntaron si esos botones y su efecto habían sido “dibujados” directamente en el elemento canvas, a lo que contesté que no, que en realidad cada botón era un enlace común y corriente utilizando el elemento para hace un enlace “<a></a>” de HTML. Una de estas personas comentó que por lo general solo veía ese tipo de efectos tan “smooth” en cosas realizadas con Flash, a lo cual solo añadí: pues no solo no es Flash sino que tampoco es un elemento del canvas de HTML5, el secreto es el uso de transiciones y transformaciones de CSS3 (aquí las especificaciones oficiales).

    Hay muchos tutoriales y capítulos en los libros de HTML5 y CSS3 para quienes deseen aprender paso a paso de que van las transiciones en las hojas de estilo (incluyendo el mio), así que en esta ocasión me concentraré en el flanco práctico y aplicado para lograr hacer botones con un efecto como los que utilicé en el juego que mencioné inicialmente, puede ver el bótón aquí.
    Esta es la lógica del código:

    Paso No. 1

    En su página coloque un enlace HTML, así es, un llano <a href=”” ></a> en el lugar donde usted desee. Para efectos de este ejemplo utilizaré el siguiente código:

    <a id="miBoton" href="http://internet80.com"></a>

    Paso No. 2

    Ahora hay que colocar un par de elementos <span>, el primero servirá para colocar la imagen del botón en estado off (normal o apagado) y el segundo para la imagen que corresponde al estado over:

    <a id="miBoton" href="http://internet80.com"></pre>
    <span class="off"></span>
    <span class="over"></span>
    <pre></a>

    Los siguientes pasos consisten en crear estilos CSS3 que manipulen el comportamiento del enlace y los span dentro de él.

    Paso No. 3

    El siguiente estilo hace referencia al enlace, se indica que este se debe desplegar en bloque y no in-line y especifica ancho y alto:

    #miBoton {
       display: block;
       width: 141px;
       height: 195px;
    }

    Paso No. 4

    Ahora se indicará que imagen debe utilizar el fondo de cada span, note que sólo utilizo una imagen para ambos span. Recuerde que puede usar la imagen de su preferencia pero manipule las dimensiones de tamaño apropiadamente según el caso:

    #miBoton span {
       background-image: url(http://internet80.files.wordpress.com/2013/04/btn_ok.png);
    }

    Si se verifica el resultado del código como está hasta ahora no visualizará nada, por lo que al igual que se especificó un estilo de bloque y tamaño al enlace, ahora se debe hacer lo mismo con cada span

    #miBoton .off {
       display: block;
       width: 141px;
       height: 195px;
    }
    [/sourcecode]
    [sourcecode language="css"]
       #miBoton .over {
       display: block;
       width: 141px;
       height: 195px;
       background-position: 0 -195px;
    }
    Observe como al segundo span se le indica mover el área desplegada del imagen de fondo a -195, a las imágenes que contienen varios cuadros o estados  dentro de ellas mismas y se les manipula mediante su posición y visibilidad se les suele llamar sprites  (tenga esto en mente si desea desarrollar juegos)Hasta este punto lo visualizará será algo como esto:

    Paso No. 5

    Por ahora ambos span muestran su respectivo contenido uno después de otro, pero lo que en realidad se desea es que ambos ocupen el mismo espacio, por lo que especificará la posición de ellos en la esquina superior izquierda con left y top:

    #miBoton span {
       background-image: url(http://internet80..com/downloads/btn_ok.png);
       position: absolute;
       left: 0; top: 0;
    }

    Si visualiza y observa el progreso hasta ahora verá que solo aparece el estado over en su página, esto es debido a que el segundo span se sobrepone al primero, por lo que hay que indicar que el primero deber ser el inicial y el que debe estar arriba, para ello usamos la propiedad z-index en el estilo para #miBoton .off, entre más alto el valor z-index colocará al elemento referido más al frente:

    #miBoton .off {
       display: block;
       width: 141px;
       height: 195px;
       z-index: 2;
    }

    Paso No. 6

    Ahora utilizará el estado hover de CSS, lo cual asigna el estilo indicado cuando se coloca el puntero del mouse sobre el elemento referido, que en este caso es el span .off

    #miBoton:hover .off {
       opacity: 0;
       filter: alpha(opacity = 0);
    }

    Con esto se logra un comportamiento comparable al que se hubiera podido lograr dando solo un par de estilos a un elemento <button>, sin embargo es a partir del siguiente paso donde se demuestra la “magia”.

    Paso No. 7

    Si observamos el comportamiento del botón hasta ahorita se ve un cambio instantáneo entre el estado off over, para hacer un cambio suave se utilizará un transición, lo que evitará el cambio rápido en los estados hover CSS3 de ambos span, de manera que nuevamente afectaremos el estilo para #miBoton span agregando la transición transition: opacity .25 ease-in-out:

    #miBoton span {
       background-image: url(http://internet80.com/downloads/btn_ok.png);
       position: absolute;
       left: 0; top: 0;
       -webkit-transition: opacity .25s ease-in-out;
       -moz-transition: opacity .25s ease-in-out;
       -ms-transition: opacity .25s ease-in-out;
       -o-transition: opacity .25s ease-in-out;
       transition: opacity .25s ease-in-out;
    }

    Tenga en cuenta que es solo una transición la que está agregando, las líneas con los prefijos -webkit-, -moz-, etc., son solo para aumentar la compatibilidad de la transición a los navegadores más populares.

    Paso No. 8

    Visualice su botón y ahora verá una mucho más suave y elegante transición entre los estados off y over. Pero hagamos las cosas más interesantes, combine un transición con una transformación, en este caso hará que el estado over aumente de tamaño del botón añadiendo el siguiente estilo:

    #miBoton:hover .over {
       -webkit-transform: scale(1.03,1.03);
       -moz-transform: scale(1.1,1.1);
       -ms-transform: scale(1.1,1.1);
       -o-transform: scale(1.1,1.1);
       transform: scale(1.1,1.1);
    }

    Paso No. 9

    El botón está casi listo, ahora el cambio de tamaño sucede pero instantáneamente sin embargo ya conoce la técnica para evitarlo (Paso 7), así es, usará una transición para hacer el cambio de tamaño lentamente utilizando  transition:  transform .25s ease-in-out; , pero ahora no quiere afectar ambos span sino solo el over por lo que el destino adecuado para la transición es #miBoton .over :
    #miBoton .over {
       display: block;
       width: 141px;
       height: 195px;
       background-position: 0 -195px;
       -webkit-transition: -webkit-transform .25s ease-in-out;
       -moz-transition: -moz-transform .25s ease-in-out;
       -ms-transition: -ms-transform .25s ease-in-out;
       -o-transition: -o-transform .25s ease-in-out;
       transition: transform .25s ease-in-out;
    }

    Nota

    Para colocar el botón en su página puede utilizar elementos contenedores como por ejemplo un <div>, también puede propagar los estilos a más botones utilizando selectores CSS3 y/o clases en lugar de un ID como se hizo en este ejemplo para fines prácticos.

    Conclusión.

    El botón fue creado fácilmente sin la necesidad de ningún plug-in (como el Flash Player) y no se utilizó una pizca de programación JavaScript, lo que hace treméndamente eficiente, rápida y ligera esta implementación CSS3, mientras que al mismo tiempo logró convertir un enlace simple en un elegante botón. Si desea la reseña técnica dónde del juego donde implementé ese botón está aquí:

    No Comment
  • CSS

    ¡Use el modelo de caja correcto! (Flexible Box Layout)

    Versiones Flexible Box Layout

    Muchas veces buscamos información, manuales, tutoriales y libros que explican el modelo de caja desde que se incluyó como draft en las especificaciones CSS3 por parte del W3C, mejor conocido como Flexible Box Model o simplemente como Flexbox,. Muchos documentos hacen referencia a las especificaciones anteriores desde su creación en el 2009, por lo tanto y desafortunadamente muy buenos documentos al respecto han quedado sin actualizar con información obsoleta. Es por ello que me parece oportuno prevenir a todos los que están interesados en HTML5 y concretamente en CSS pero no están muy al tanto de estos cambios, para así crear conciencia y no perder tiempo aprendiendo sintáxis y detalles que ya no funcionan o bien pronto quedarán obsoletos.

    ¿Por qué sucede esto?

    Siempre que hablo de HTML5 y CSS en general, trato de ser muy enfático en que los desarrolladores deben estar al pendiente de cambios y mejoras en las especificaciones, ya que es algo que puede suceder en cualquier momento, esto pasa debido a que las organizaciones que se encargan de desarrollar las especificaciones tratan de mejorar activa y rápidamente todas estas tecnologías pero nunca se sabe realmente cuando sucederán estas mejoras ni cuando se adoptarán por parte de los navegadores. Sí, esto a una molestia a veces…díganmelo a mi que he tenido que retrasar y modificar publicaciones por estos cambios :/

    ¿Cómo distinguir modelos viejos?

    Como ya mencioné, si usted hace una búsqueda en la web acerca del modelo de caja de CSS, encontrará mucha información sin actualizar, pero un método para distinguir el código muy viejo es:

    • Si usted observa en el código CSS3 display: box o bien alguna propiedad box-{*} entonces lo que ve es código que utiliza el modelo viejo 2009.
    • Si usted observa en el código CSS3 display: flexbox o una función flex() entonces lo que ve es código que utiliza el modelo viejo 2011.
    • Si usted observa en el código CSS3 display: flex y propiedades flex-{*} entonces lo que ve es código que utiliza el modelo de 2012 a la actualiad (2018 por lo menos).

    Si es usted principiante tenga en cuenta que los navegadores muchas veces utilizan su correspondiente prefijo (-webkit-, -moz-, -ms-, -o- )

    ¿Cómo estar al día?

    La menera menos amable pero más precisa de estar al día es consultar directamente la especificación CSS Flexible Box Layout Module del W3C, pero tenga en cuanta que casi permanentemente este documento tiene el título de Candidate Recomendation, lo que significa, que los navegadores quizá aun no implementan lo que ahí se muestra o no en su totalidad. También debe saber que leer estos documentos no siempre es la manera más amable y fácil.

    Otras consideraciones…

    Hay que poner atención en que la última especificación puede publicarse sin aviso y en cualquier fecha, pero como ya mencione la adopción por parte de los navegadores no es rápida ni sumultanea. El navegador que ha estado soportando más rápido los cambios que se hacen en las especificación HTML5 y CSS es sin duda Chrome,  al momento seguido por Firefox y posiblemente por Maxthon, pero como ya dije, hay que estar atentos.

    En caso de que no lo sepa, también es bueno tener en cuanta que tenemos un nuevo niño en el barrio en cuanto a la distribución de elementos llamado CSS Grid que tiene muchas ventajas. Por ahora este no sustituye a Flexbox, este sigue teniendo un lugar sólido en varios casos e incluso, ambos modelos se pueden complementar uno al otro.

    Por lo anterior, muchos especulamos que eventualmente CSS Grid y Flexbox se funcionaran en el futuro de algún modo en una sola especificación, pero ya veremos. Por ahora y desde el 2012 la especificación CSS Grid está separada.  Si está interesado en que escriba más sobre CSS Grid, déjenmelo saber en los comentarios de esta entrada o en Twitter @ManuGekko 🙂

    Otros enlaces de interés:

    Transiciones y Transformaciones en Botones (CSS y HTML5)

    10 CSS Selectors Que Hay Que Tener En Mente

    Crear Una Barra Emergente Con HTML5, CSS3 y JQuery

    No Comment
  • CSS Selectors

    10 CSS Selectors que hay que tener en mente

    Desde la implementación de hojas de estilo nivel 3 (CSS3) el uso de selectors en páginas web se convirtió en algo muy común, no solo por la versatilidad que ofrecen en cuanto al diseño estético de aplicaciones o páginas, si no por la enorme ventaja que implican desde el punto de vista de codificación, ya que no solo se pueden usar dentro del código CSS, si no también con los métodos de JavaScript querySelector() y querySelectorAll() que permiten un manejo mucho más dinámico de los objetos DOM de una página. Estos métodos se suman a los métodos de selección por id, clase o descendencia, implicando con esto un considerable ahorro de código.

    Cualquier entusiasta de las hojas de estilo o de HTML5 me puede reclamar la existencia de más de 10 CSS3 selectors, lo cual es totalmente cierto, pero hoy no seré tan exigente y sólo le propondré que aprenda 10 CSS selectors de uso común, que creo que todos los desarrolladores deberiamos de tener presentes, aunque claro, si desea aprenderlos  todos ¿qué mejor? (puede consultar la lista completa de selectors en la especificación oficial aquí). Utilizaré la letra E para señalar a cualquier elemento DOM.

    1. Selector E

    Permite seleccionar cualquier elemento del tipo E. Este selector no es nuevo pero si es básico e importante.

    2. Selector E[atr1]

    Selecciona el elemento E que tenga un atributo llamado atr1

    3. Selector E[atr1=”dum”]

    Selecciona el elemento E que tenga un atributo llamado atr1 cuyo valor sea exactamente dum.

    4. Selector E[atr1^=”dum”]

    Selecciona el elemento E que tenga un atributo llamado atr1 cuyo valor sea termine con la cadena de caracteres dum.

    5. Selector E[atr1$=”dum”]

    Selecciona el elemento E que tenga un atributo llamado atr1 cuyo valor sea comience con la cadena de caracteres dum.

    6. Selector E[atr1*=”dum”]

    Selecciona el elemento E que tenga un atributo llamado atr1 cuyo valor  contenga  la cadena de caracteres dum.

    7. Selector E#elid

    Selecciona el elemento E que tenga como valor del atributo id la cadena elid.

    8. Selector E:first-child

    Selecciona el primer elemento descendiente del padre del elemento E (el primer hijo).

    9. Selector E:last-child

    Selecciona el último elemento descendiente del padre del elemento E (el último hijo).

    10. Selector E:nth-child(n)

    Selecciona un elemento descendiente del padre del elemento E que se encuentre en la posición de n.

    Si alguien considera que es importante colocar otro selector en la lista y ejemplificarlo…en el pedir está el dar 🙂 . Para ver el pequeño ejemplo que utiliza todos los selectors expuestos haga click aquí.

    Enlaces de interés:

    Transiciones y Transformaciones en Botones (CSS y HTML5)

    No Comment
  • mega menu

    Cómo construir un megamenú

    Counstruir megamenú

    Megamenú

    Continuamente en la construcción  de sistemas web se requiere de la creación de menús, una necesidad común es tener que hacer menús que contengan submenús a diversos niveles, para este tipo de menús existen diversos recursos en la web que nos muestran cómo hacerlos, incluso hice una entrada donde mostré como crear una barra emergente la cual usualmente se utiliza para colocar botones de menú, ahora quizá por casualidad he visto últimamente los llamados megamenús, los cuales utilizan una estructura o layout más elaborada como los que se muestran aquí, en lugar de solo algunos “hijos” , de manera que en esta ocasión aprenderemos como hacer un bonito menú de este tipo utilizando HTML5 y CSS3 que tien la apariencia mostrada en la portada de esta entrada.

    1. Creación de la barra principal.

    La estructura básica de la barra principal del menú es muy simple, solo consta de una lista no ordenada con el tag <ul> y dentro de cada elemento de la lista se coloca una imagen (o lo que usted prefiera).

    <ul id="menu">
       <li><a href="#"><img src="opc01.png" /></a></li>
       <li><a href="#"><img src="opc02.png" /></a></li>
       <li><a href="#"><img src="opc03.png" /></a></li>
       <li><a href="#"><img src="opc04.png" /></a></li>
    </ul>

    Estilos al contenedor.

    El elemento  <ul id=”menú”> funciona como contenedor, al cual procederemos a darle estilos CSS3. En la siguiente definición se indica la eliminación del bullet que aparece comúnmente en las listas HTML, se coloca una distancia de 10 pixeles en los márgenes izquierdo y derecho, se establece el alto y ancho de la barra, la distancia interna entre el extremo de la barra y los elemento que se coloque dentro de ella, se establece un efecto de gradiente y finalmente se indica el radio para que nuestra barra tenga esquinas redondeadas:

    #menu {
       list-style:none;
       margin: 0px 10px;
       height: 57px;
       width: 900px;
       padding: 3px 5px 0px 5px;
       /*Gradientes*/
       background: -webkit-linear-gradient(top, #7f7e7e, #3f3f3f);
       background: -moz-linear-gradient(top, #7f7e7e, #3f3f3f);
       /*Esquinas redondeadas*/
       border-radius: 10px;
    }

    Estilos a los elemento de la lista.

    La definición del siguiente estilo hará que cada elemento del menú se despliegue uno  a la izquierda de otro y en bloque (como lo hace un encabezado o un párrafo) , la posición será relativa al elemento padre (ul en esta caso), las imágenes que se colocarán tendrá una distancia de 2 pixeles a todos lados excepto arriba que será de 6 pixeles, la distancia entre elementos será de 10 pixeles, se establece el ancho, tipo y color del borde de cada elemento, y por último un fondo con gradiente:

    #menu li {
       float: left;
       display: block;
       position: relative;
       padding: 6px 2px 2px 2px;
       margin-right: 10px;
       border:  1px solid #777777;
       border-radius: 5px 5px 5px 5px;
       background: -webkit-linear-gradient(top, #7f7e7e, #3f3f3f);
       background: -moz-linear-gradient(top, #7f7e7e, #3f3f3f);
    }

    Enseguida agregamos un estilo para exactamente el mismo elementos que afectamos con el estilo anterior, ¿por qué?  podría preguntarse,  la razón es que haremos que el siguiente estilo luzca diferente cuando el usuario coloca el puntero del ratón sobre el elemento del menú actual. El estilo, con la ayuda de pseudoclase hover, cambiará el color del  borde y los colores de gradientes de fondo:

    #menu li:hover  {
       border: 1px solid #bfbfbf;
       /* Color de fondo y gradientes */
       background: -moz-linear-gradient(top, #F4F4F4, #EEEEEE);
       background: -webkit-linear-gradient(top, #F4F4F4, #EEEEEE);
    }

    Para terminar el primer paso agregaremos un sencillo estilo que afectará  a los enlaces que se coloquen dentro de los elementos de menú:

    #menu li a {
       font-size: 14px;
       color: #EEEEEE;
       display: block;
       outline: 0;
       text-decoration: none;
       text-shadow: 1px 1px 1px #000;
    }

    En mi caso estoy utilizando ciertas imágenes  como elementos del menú pero usted puede utilizar las propias o sustituirlas por texto,  la siguiente imagen da una idea de lo que aproximadamente obtendrá:

    2. Haciendo los elementos emergentes (Drop Down).

    La estructura básica de los elementos emergentes consiste únicamente de que un tag <div> donde se coloca todo el contenido del elemento drop down:

    <ul id="menu">
       <li>
          <a href="#"><img src="opc01.png" /></a>
          <div class="emergente_1columna">
             Contenido del elemento emergente
          <div>
       </li>
       <li>
          <a href="#" ><img src="opc02.png" /></a>
          <div class="emergente_2columnas">
             Contenido del elemento emergente
          <div>
       </li>
    </ul>

    En la estructura de un menú drop down tradicional en lugar de divs anidaríamos otra lista, pero como en este caso deseamos un elemento mucho más elaborado utilizamos <div> para colocar lo que deseemos dentro.

    Estilos para contenedor del elemento emergente.

    He de mencionar  que la forma de organizar las columnas en algún momento la vi en el código de alguna página que implementaba un mega menú, pero no recuerdo cual fue esa página, así que espero que el autor no se moleste por la falta de crédito, aunque en realidad, como veremos,  es sencillo.

    El estilo comienza indicando que el posicionamiento es respecto a la ventana del navegador position: absolute, se envía al elemento a una gran distancia a la izquierda para que no se vea en el navegador inicialmente,  se colocan las indicaciones para posicionar los elementos dentro de nuestro contenedor, después se crea un gradiente como fondo y se finalmente redondean las esquinas.

       .emergente_1columna,
       .emergente_2columnas,
       .emergente_3columnas,
       .emergente_4columnas {
       /*Para desaparecer al elemento inicialmente*/
       position: absolute;
       left: -999em;
       text-align: left;
       padding: 10px 5px 0px 5px;
       border:1px solid #777777;
       margin-top: 3px;
       /*Gradiente de fondo*/
       background: -moz-linear-gradient(top, #EEEEEE, #BBBBBB);
       background: -webkit-linear-gradient(top, #EEEEEE, #BBBBBB);
       /*Esquinas redondeadas*/
       border-radius: 5px 5px 5px 5px;
    }

    Lo que resta en este paso es indicar el tamaño para cada elemento emergente (div) y reposicionar al mismo cuando el puntero del mouse está sobre el elemento del menú en la barra principal con la pseudoclase hover.

       .emergente_1columna {width: 160px;}
       .emergente_2columnas {width: 280px;}
       .emergente_3columnas {width: 480px;}
       .emergente_4columnas {width: 640px;}
    
       #menu li:hover .emergente_1columna,
       #menu li:hover .emergente_2columnas,
       #menu li:hover .emergente_3columnas,
       #menu li:hover .emergente_4columnas {
       left:-50%;
       top:auto;
    }

    Estilos para las columnas dentro del contenedor del elemento emergente.

    Como ha podido observar en los estilos anteriores, estamos utilizando clases de acuerdo al número máximo de columnas que habrá dentro del elemento emergente, en este caso usamos solo 4 pero puede usar tantas como usted desee, ahora crearemos contenido y estilos que actuarán sobre la(s) columnas que contiene cada elemento emergente:

    <li>
       <a href="#" title="Opción 1" ><img src="opc01.png" /></a>
       <div class="emergente_1columna">
          <div class="col_1">
              <ul>
                <li><a href="#">Superman</a></li>
                <li><a href="#">Batman</a></li>
                <li><a href="#">GreenLantern</a></li>
                <li><a href="#">Shazam!</a></li>
                <li><a href="#">Wonder Woman</a></li>
                <li><a href="#">Flash</a></li>
                <li><a href="#">Wolverine</a></li>
              </ul>
          </div>
       </div>
    </li>

    Los estilos:

       .col_1,
       .col_2,
       .col_3,
       .col_4 {
       display: inline;
       float: left;
       position: relative;
       margin-left: 5px;
       margin-right: 5px;
    }
    
    .col_1 {width:150px;}
    .col_2 {width:270px;}
    .col_3 {width:410px;}
    .col_4 {width:550px;}

    La manera de usar estos estilos en el código HTML es la siguiente:

    <ul id="menu">
       <li><a href="#" class="drop">5 Columns</a>
       <div class="dropdown_4columns">
       <div class="col_4">

    Esto es un contenido a 5 columnas.

    </div>
        <div class="col_1">

    Esto es un contenido a una columna.

    </div>
        <div class="col_2">

    Esto es un contenido a 2 columnas.

        </div>
       .
       .
       .
       </li>
    </ul>

    Y asi sucesivamente.

    Lo que obtendrá como resultado será algo similar a esto:

    3. Colocando el contenido

    En este tercer y último paso agregaremos contenido a los elementos emergentes y por supuesto haremos los estilos correspondientes, pero antes de continuar debemos de tener claro que aunque hablaremos del contenido creado para el ejemplo esta es la parte donde usted puede crear el propio y sus estilos con total libertad, de manera que los elementos emergentes muestran la información que usted desee  de la forma que más le convenga, el siguiente código es solo un ejemplo.

    Uno de los tags que manejo para mi contenido es <p> para crear párrafos, y les asigno el siguientes estilo con objetivos muy simples, solo se establece el alto de cada renglón del párrafo, el tamaño de la fuente, se orilla a la izquierda y se le coloca una sombra blanca.

    #menu p {
        line-height: 15px;
        font-size: 12px;
        text-align: left;
        text-shadow: 1px 1px 1px #FFFFFF;
    }

    Para el caso de este ejemplo utilizo más listas para incluir dentro del contenido, por lo que se agregan más elementos <ul> y <li>, como estas listas no tienen que ver con las listas que forman parte de la estructura del megamenú se asignan nuevos estilos para evitar usar los estilos de listas para el resto del menú por lo que se refrescan los estilos para tener otro apariencia para estos items:

    #menu li ul {
       list-style:none;
       padding:0px;
       margin:0 0 12px 0;
    }
    
    #menu li ul li {
       font-size: 12px;
       line-height: 25px;
       position: relative;
       text-shadow: 1px 1px 1px #ffffff;
       padding: 5px;
       margin:0 0 5px 0;
       float: none;
       text-align: left;
       width: auto;
    }
    
    #menu li ul li:hover {
       padding: 5px;
       margin:0 0 5px 0;
       width:auto;
       cursor: pointer;
    }

    Y finalmente incluí algunos estilos para un par de imágenes que se utilizan en el ejemeplo con cambios muy simples como orientar a la izquierda e incluir una sombra.

    .img_left {
       width: auto;
       float: left;
       margin: 5px 10px 1px 1px;
    }
    
    .imgshadow {
       background:#FFFFFF;
       padding:4px;
       border:1px solid #777777;
       margin-top:15px;
       -moz-box-shadow:0px 0px 5px #666666;
       -webkit-box-shadow:0px 0px 5px #666666;
       box-shadow:0px 0px 5px #666666;
    }

    El código final.

    El código completo luce como se muestra a continuación, tenga presente que este ejemplo solo ha sido probado en Chrome y en Firefox.

    HTML:

    <!DOCTYPE HTML>
    <html>
       <head>
          <meta charset="iso-8859-1">
          <title>Mega menú</title>
          <link rel="stylesheet" type="text/css" href="styles.css" />
       </head>
       <body>
           <ul id="menu">
               <li>
               <a href="#" title="Opción 1" ><img src="opc01.png" /></a>
                   <div class="emergente_1columna">
                      <div class="col_1">
                         <ul class="simple">
                             <li><a href="#">Superman</a></li>
                             <li><a href="#">Batman</a></li>
                             <li><a href="#">GreenLantern</a></li>
                             <li><a href="#">Shazam!</a></li>
                             <li><a href="#">Wonder Woman</a></li>
                             <li><a href="#">Flash</a></li>
                             <li><a href="#">Wolverine</a></li>
                         </ul>
                      </div>
                  </div>
               </li>
               <li>
                   <a href="#" title="Opción 2" ><img src="opc02.png" /></a>
                   <div class="emergente_2columnas"><!-- Begin 2 columnas container -->
                      <div class="col_2">
                         <h2>Algún Encabezado</h2>
                      </div>
                   <div class="col_2">

    Este es un ejemplo de layout que se puede utilizar, usted puede modificarlo como desee.

    Las posiblidades de CSS3 hace que puede personalizar el texto con resultados agradables.

           .
           .
           .
     
        </div>
    <div class="col_2">
        <h2>Otro encabezado</h2>
    </div>
    <div class="col_1">
        <img src="ChromeFirefox.jpg" class="imgshadow" alt="" /></div>
        <div class="col_2">

    Este menú ha sido probado en Chrome y Firefox.

       </div>
    </div>
    </li>
    <li>
       <a href="#" title="Opción 3" ><img src="opc03.png" /></a>
       <div class="emergente_3columnas"><!-- Begin 3 columnas container -->
       <div class="col_3">
       <h2>Listas</h2>
    </div>
    <div class="col_1">
       <ul class="greybox">
          <li><a href="#">HTML5</a></li>
          <li><a href="#">CSS3</a></li>
          <li><a href="#">JavaScript</a></li>
       </ul>
    </div>
    <div class="col_1">
       <ul class="greybox">
          <li><a href="#">SVG</a></li>
          <li><a href="#">WebGL</a></li>
          <li><a href="#">Más...</a></li>
       </ul>
    </div>
    <div class="col_1">
       <ul class="greybox">
          <li><a href="#">Chrome</a></li>
          <li><a href="#">FireFox</a></li>
          <li><a href="#">Opera</a></li>
       </ul>
    </div>
    <div class="col_3">
       <h2>Otra imagensita en este ejemplo</h2>
    </div>
    <div class="col_3">
       <img src="img1.png" class="img_left imgshadow" alt="" />Dolor hac. Turpis augue nec adipiscing turpis enim porta montes, porttitor integer nisi tincidunt nec nisi, scelerisque duis, in ultricies rhoncus cursus duis nec placerat dignissim cum adipiscing placerat penatibus, egestas massa dolor tincidunt scelerisque scelerisque quis porta phasellus. Auctor cras et. Natoque cursus ridiculus vut urna facilisis! Nunc mattis, tincidunt, platea sed ac? Etiam, turpis! Etiam parturient sed enim? Nisi, integer, aenean augue? Pellentesque, odio pulvinar massa, sit, porttitor urna lorem! Arcu sed et, et non, lectus! Tristique, ultricies cras? Tristique turpis hac. Sociis sit augue! Tristique, dapibus rhoncus aliquet, porta nunc ac, dictumst ac, vel platea tortor, non placerat sagittis, integer auctor mus lundium in enim. Turpis quis. Risus sociis, purus magna, enim, sagittis, mauris, eu in amet.<a href="#">Más...</a>
    
    </div>
       <!-- End 3 columnas container --></li>
       <li>
          <a href="#" title="Opción 4" ><img src="opc04.png" /></a>
          <div class="emergente_4columnas"><!-- Begin 4 columnas container -->
          <div class="col_4">
              <h2>Este es un header cualquiera</h2>
          </div>
          <div class="col_1">
              <h3>Lista de enlaces</h3>
              <ul>
                  <li><a href="#">Warcraft</a></li>
                  <li><a href="#">Starcraft</a></li>
                  <li><a href="#">Diablo</a></li>
                  <li><a href="#">Halo</a></li>
                  <li><a href="#">Ninja Gaiden</a></li>
              </ul>
          </div>
          <div class="col_1">
             <h3>Otra lista</h3>
             <ul>
                <li><a href="#">Android</a></li>
                <li><a href="#">iOS</a></li>
                <li><a href="#">Windows</a></li>
                <li><a href="#">WebOS</a></li>
                <li><a href="#">BlackBerry</a></li>
             </ul>
          </div>
          <div class="col_1">
              <h3>Más enlaces</h3>
              <ul>
                  <li><a href="#">C++</a></li>
                  <li><a href="#">C#</a></li>
                  <li><a href="#">Java</a></li>
                  <li><a href="#">HTML5</a></li>
                  <li><a href="#">ActionScript</a></li>
              </ul>
          </div>
          <div class="col_1">
              <h3>Otros...</h3>
              <ul>
                 <li><a href="#">Candice</a></li>
                 <li><a href="#">Adriana</a></li>
                 <li><a href="#">Joanna</a></li>
                 <li><a href="#">Marissa</a></li>
                 <li><a href="#">Otros...</a></li>
              </ul>
          </div>
       </div>
    <!-- End 4 columnas container --></li>
        </ul>
        </body>
    </html>

    CSS3:

    @charset "iso-8859-1";
    /* CSS Document */
    
    body{
        font-size:14px;
        font-family:Arial, Helvetica, sans-serif;
        text-align:left;
    }
    
    #menu {
        list-style:none;
        margin: 0px 10px;
        height: 57px;
        width:900px;
        padding: 3px 5px 0px 5px;
        /*Gradientes*/
        background: -webkit-linear-gradient(top, #7f7e7e, #3f3f3f);
        background: -moz-linear-gradient(top, #7f7e7e, #3f3f3f);
        /*Esquinas redondeadas*/
        border-radius: 10px;
    }
    
    #menu li {
       float:left;
       display:block;
       position:relative;
       padding: 6px 2px 2px 2px;
       margin-right: 10px;
       border: 1px solid #777777;
       border-radius: 5px 5px 5px 5px;
       background: -webkit-linear-gradient(top, #7f7e7e, #3f3f3f);
       background: -moz-linear-gradient(top, #7f7e7e, #3f3f3f);
    }
    
    #menu li:hover {
        border: 1px solid #bfbfbf;
        /* Color de fondo y gradientes */
        background: -moz-linear-gradient(top, #F4F4F4, #EEEEEE);
        background: -webkit-linear-gradient(top, #F4F4F4, #EEEEEE);
    }
    
    #menu li a {
        font-size: 14px;
        color: #EEEEEE;
        display: block;
        outline: 0;
        text-decoration: none;
        text-shadow: 1px 1px 1px #000;
    }
    
    /* Estilos para las columnas */
        .emergente_1columna,
        .emergente_2columnas,
        .emergente_3columnas,
        .emergente_4columnas {
        /*Para desaparecer al elemento inicialmente*/
        position: absolute;
        left: -999em;
        text-align: left;
        padding: 10px 5px 0px 5px;
        border:1px solid #777777;
        margin-top: 3px;
        /*Gradiente de fondo*/
        background: -moz-linear-gradient(top, #EEEEEE, #BBBBBB);
        background: -webkit-linear-gradient(top, #EEEEEE, #BBBBBB);
        /*Esquinas redondeadas*/
        border-radius: 5px 5px 5px 5px;
    }
    
    .emergente_1columna {width: 160px;}
    .emergente_2columnas {width: 280px;}
    .emergente_3columnas {width: 480px;}
    .emergente_4columnas {width: 640px;}
    
    #menu li:hover .emergente_1columna,
    #menu li:hover .emergente_2columnas,
    #menu li:hover .emergente_3columnas,
    #menu li:hover .emergente_4columnas {
       left:-50%;
       top:auto;
    }
    
    .col_1,
    .col_2,
    .col_3,
    .col_4 {
       display:inline;
       float: left;
       position: relative;
       margin-left: 5px;
       margin-right: 5px;
    }
    
    .col_1 {width:150px;}
    .col_2 {width:270px;}
    .col_3 {width:410px;}
    .col_4 {width:550px;}
    #menu li ul {
       list-style:none;
       padding:0px;
       margin:0 0 12px 0;
    }
    
    #menu li ul li {
       font-size: 12px;
       line-height: 25px;
       position: relative;
       text-shadow: 1px 1px 1px #ffffff;
       padding: 5px;
       margin:0 0 5px 0;
       float: none;
       text-align: left;
       width: auto;
    }
    
    #menu li ul li:hover {
       padding: 5px;
       margin:0 0 5px 0;
       width:auto;
       cursor: pointer;
    }
    
    #menu p {
       line-height: 15px;
       font-size: 12px;
       text-align: left;
       text-shadow: 1px 1px 1px #FFFFFF;
    }
    
    /*Para las imagenes en los submenus*/
    .img_left {
       width: auto;
       float: left;
       margin: 5px 10px 1px 1px;
    }
    
    .imgshadow {
       background:#FFFFFF;
       padding:4px;
       border:1px solid #777777;
       margin-top:15px;
       -moz-box-shadow:0px 0px 5px #666666;
       -webkit-box-shadow:0px 0px 5px #666666;
       box-shadow:0px 0px 5px #666666;
    }

    Código descargable aquí.

    Estos son algunos libros que le pueden ayudar:

    No Comment
  • Barra Emergente

    Crear una barra emergente con HTML5, CSS3 y JQuery

    Barra emergente con html5

    ¿De que va esta barra emergente?

    Hoy mostraré como hacer una barra emergente que aparece en la parte superior del navegador, este tipo de barras pueden ser útiles para colocar mensajes, botones de herramientas, etc. La idea surgió cuando vi la llamada “Hello Bar” de este sitio hellobar.com, de manera que me dí a la tarea de crear algo similar.

    HelloBar
    Barra de hellobar.com

    He probado el resultado del código que le presentaré únicamente en Chrome y en Firefox, por lo que podría no funcionar adecuadamente en otros navegadores, pero si usted desea hacer las adecuaciones necesarias en esos casos…¡adelante! y espero comparta sus resultados 🙂 .

    Puede ver el demo de la barra en jsfiddle.net:

    1. Creación de la estructura del documento HTML5.

    Primeramente elabore la estructura general de su página, para ello cree un nuevo archivo HTML y coloque el siguiente código en el:

    <!DOCTYPE html>
    <html>
       <head>
          <meta "charset=iso-8859-1" />
          <script src='libs/jquery-1.7.1.min.js'></script>
          <script src='libs/jquery-ui-1.8.18.custom.min.js'></script>
          <title>Barra Emergente</title>
       </head>
      <body>
        <header>
          <div id="popup">
            <a href=# class="hide"></a>
            <nav id="header_nav_menu">
    
              <a href="#" class="btn_new_page" title="New Book"></a>
              <a href="#" class="btn_page" title="New Page"></a>
    
              <div class="dropdown_area">
                <div class="dropdown-content">
                  <div class="header">
                    <h2>Mega Menu</h2>
                  </div>
                  <div class="row">
                    <div class="column">
                      <h3>Category 1</h3>
                      <a href="#">Link 1</a>
                      <a href="#">Link 2</a>
                      <a href="#">Link 3</a>
                    </div>
                    <div class="column">
                      <h3>Category 2</h3>
                      <a href="#">Link 1</a>
                      <a href="#">Link 2</a>
                      <a href="#">Link 3</a>
                    </div>
                  </div>
                </div>
              </div>
    
    
            </nav>
            <div id="hide_area">&and;</div>
          </div>
          <div id="showpop">
            <a href="#" class="showpoplink"></a>
            &or;
          </div>
        </header>
        <article>
          <p>
            <br/>Contenido en la página</p>
          <p>Más cóntenido en la página</p>
        </article>
    
      </body>
    </html>

    Analicemos un poco, si nunca ha hecho páginas HTML5 antes, entonces no sobra decir que la etiqueta <!DOCTYPE html> es la “señal” que utilizan los navegadores para saber que el código del archivo es HTML5 y no una versión previa. Por otro lado, el fragmento de código que contiene los elementos que conforman la barra emergente en si misma es:

    <div id="popup">
       <a href=# class="hide"></a>
       <nav id="header_nav_menu">
    
         <a href="#" class="btn_new_page" title="New Book"></a>
         <a href="#" class="btn_page" title="New Page"></a>
    
         <div class="dropdown_area">
           <div class="dropdown-content">
             <div class="header">
               <h2>Mega Menu</h2>
             </div>
             <div class="row">
               <div class="column">
                 <h3>Category 1</h3>
                 <a href="#">Link 1</a>
                 <a href="#">Link 2</a>
                 <a href="#">Link 3</a>
               </div>
               <div class="column">
                 <h3>Category 2</h3>
                 <a href="#">Link 1</a>
                 <a href="#">Link 2</a>
                 <a href="#">Link 3</a>
               </div>
             </div>
           </div>
         </div>
    
    
       </nav>
     <div id="hide_area">&and;</div>
    

    El código anterior básicamente crea un elemento div que contiene un enlace que servirá para ocultar la barra cuando se hace clic en el, adicionalmente se colocan otros tres enlaces, que solo sirven como ejemplo de contenido que aparece dentro de la barra emergente en este ejercicio, estos enlaces pueden ser sustituidos por el contenido que más le convenga.

    Note también este código:

    <div id="showpop" >
    <a href="#" class="showpoplink"></a>
    &or;
    </div>

    Este div aparacerá cuando la barra esté escondida y servirá para mostrarla de nuevo cuando se hace clic.

    Ahora bien, para hacer funcional a nuestro ejercicio hecharemos mano de la popular librería JQuery y su complemento para efectos visuales JQuery UI, si no esta familiarizado con con JQuery lo único que debe de saber al momento es que, fundamentalmente, JQuery es un conjunto de funciones JavaScript que conforman una amplia librería que le puede evitar una gran cantidad de trabajo, que de otra manera tendría que desarrollar usted mismo.

    Para este ejercicio descargué y coloqué ambas librerías en una carpeta llamada libs, pero puede colocarlas donde usted desee haciendo la corrección pertinente en la siguientes líneas de código.

    Para JQuery:

    <script src='libs/jquery-1.7.1.min.js'></script>

    Para JQuery UI:

    <script src='libs/jquery-ui-1.8.18.custom.min.js'></script>

    2. Agregar funcionalidad

    Para lograr que el código creado reaccione a las acciones del usuario, que para el caso son solo dos, ocultar y mostrar la barra, utilizaremos el siguiente código:

    <script type="text/javascript">
       $(document).ready(function(){
          $('#popup').show("bounce", { times:3 }, 350);
          $('#showpop').hide();
          $('.hide').click(function(){
             $('#popup').slideUp();
             $('#showpop').fadeIn('slow');
             return false;
          });
          $('a.showpoplink').click(function(){
             $('#popup').show("bounce", { times:3 }, 350);
             $('#showpop').hide();
            return false;
          });
        });
    </script>

    Lo que sucede gracias a este código es lo siguiente, cuando el documento HTML5 es reportado como “listo” por parte del navegador, inmediatamente la barra se muestra con en efecto de rebote, mientras que el enlace que sirve para mostrar la barra se oculta ya que no es necesario cuando la barra está visible:

    $('#popup').show("bounce", { times:3 }, 350);
    $('#showpop').hide();

    Al mismo tiempo se indica cual botón dentro de la barra debe servir para ocultarla haciendo clic:

    $('.hide').click(function(){
        $('#popup').slideUp();
        $('#showpop').fadeIn('slow');
        return false;
    });

    Finalmente, se hace los mismo pero para el caso del enlace que servirá para mostrar la barra cuando esta está oculta, utilizando el mismo efecto de rebote se ve en la carga inicial:

    $('a.showpoplink').click(function(){
        $('#popup').show("bounce", { times:3 }, 350);
        $('#showpop').hide();
        return false;
    });

    3. Estilizar y ordenar los elementos.

    Finalmente no queda más que darle belleza y orden a nuestros elementos HTML utilizando una hoja de estilos, veamos estos poco a poco para tener mejor idea de que hacemos.

    body {
       margin:0;
       padding:0;
    }
    
    #popup {
       top: 0;
       width: 100%;
       padding: 20px 0px 0px 0px;
       height: 50px;
       background-image: linear-gradient(bottom, rgb(238,238,238) 14%, rgb(249,249,249) 60%);
       background-image: -o-linear-gradient(bottom, rgb(238,238,238) 14%, rgb(249,249,249) 60%);
       background-image: -moz-linear-gradient(bottom, rgb(238,238,238) 14%, rgb(249,249,249) 60%);
       background-image: -webkit-linear-gradient(bottom, rgb(238,238,238) 14%, rgb(249,249,249) 60%);
       background-image: -ms-linear-gradient(bottom, rgb(238,238,238) 14%, rgb(249,249,249) 60%);
       -moz-box-shadow: 0 0 5px 5px #bfbfbf;
       -webkit-box-shadow: 0 0 5px 5px#bfbfbf;
       box-shadow: 0 0 5px 5px #bfbfbf;
       display: block;
       /*position: fixed;*/
    }

    Los estilos anteriores se encargan primeramente de eliminar cualquier espacio entre el cuerpo del documento HTML y los elementos que contiene mediante la personalización de la etiqueta body. Enseguida se indica el aspecto que tendrá el div que contiene a la propia barra con el estilo #popup, ahí se indica la posición, el ancho y alto de la misma. Utilizamos las nuevas características de CSS3 para dar un gradiente al fondo de la barra y darle un discreto sombreado; en versiones anteriores de CSS esto no hubiera sido posible y tendría que haber creado una imagen previamente, tendría que colocarla y repetirla como fondo, esto ya no es necesario gracias a CSS3.

    Ahora toca el turno de configurar el tamaño de el área sensible dentro de la barra para poder ocultarla:

    #hide_area{
       width: inherit ;
       background: #666;
       padding: 0px;
       margin: 20px 0px 0px 0px;
       color:#FFF;
       font-family:Verdana, Geneva, sans-serif;
       font-size:10px;
       font-weight:bold;
       text-align:center;
       /*border:solid;*/
    }
    
    a.hide {
       top: 0;
       width: 100%;
       margin-top: 50px;
       padding: 8px 0px 8px 0px;
       display: block;
       cursor:default;
       position: fixed;
       /*border:solid;*/
    }

    Los estilos anteriores solo se encargan de definir el tamaño, posición y colores utilizados por el enlace que funciona como área sensible para poder ocultar la barra al hacer clic.

    Ahora se hace lo mismo pero para el enlace que muestra la barra cuando se hace clic:

    #showpop{
       top: 0;
       width: 100%;
       height: 14px;
       background: #666;
       padding: 0px;
       margin: 0px 0px 0px 0px;
       -moz-box-shadow: 0 0 5px 5px #bfbfbf;
       -webkit-box-shadow: 0 0 5px 5px#bfbfbf;
       box-shadow: 0 0 5px 5px #bfbfbf;
       color:#FFF;
       font-family: Verdana, Geneva, sans-serif;
       font-size: 10px;
       font-weight: bold;
       text-align: center;
       position: fixed;
      /*border:solid;*/
    }
    
    a.showpoplink {
       top: 0;
       width: 100%;
       margin-top: 0px;
       padding: 5px 0px 5px 0px;
       display: block;
       cursor:default;
       position: fixed;
       /*border:solid;*/
    }

    Para terminar, he agregado unos botones que funcionan como contenido dentro de la barra emergente que se ha creado, para definir su aspecto utilicé los siguientes estilos, por supuesto usted tendrá que desarrollar los suyos para su propio contenido:

    #header_nav_menu a {
      padding: 0px 13px 10px 13px;
      background-repeat: no-repeat;
      cursor: pointer;
      /*border:solid;*/
    }
    
    #header_nav_menu a.btn_new_page {
      background-image: url('http://icons.iconarchive.com/icons/gakuseisean/ivista-2/24/Files-New-File-icon.png');
    }
    
    #header_nav_menu a.btn_page {
      background-image: url('http://icons.iconarchive.com/icons/dryicons/aesthetica-2/24/page-icon.png');
    }
    
    
    /* Dropdown content (hidden by default) / Contenido del dropdown escondido por default*/
    
    .dropdown-content {
      display: none;
      position: absolute;
      background-color: #f9f9f9;
      width: 50%;
      left: 0;
      box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
      z-index: 1;
    }
    
    .dropdown_area {
      padding: 0px 13px 25px 13px;
      background-repeat: no-repeat;
      cursor: pointer;
      background-image: url('http://icons.iconarchive.com/icons/double-j-design/super-mono-3d/24/button-dropdown-icon.png');
      float: left;
    }
    
    
    /* Show the dropdown menu on hover / Muestra del dropdwon al colar el mouse sobre el botón*/
    
    .dropdown_area:hover .dropdown-content {
      display: block;
      margin-top: 25px;
    }
    
    
    /* Mega Menu header, if needed */
    
    .dropdown-content .header {
      background: gray;
      padding: 10px;
      color: white;
    }
    
    h3 {
      padding: 5px;
    }
    
    
    /* Create two equal columns that floats next to each other / Crear dos columnas iguales que flotan una junto a la otra */
    
    .column {
      font-size: 14px;
      float: left;
      width: 50%;
      background-color: #ccc;
      height: 100px;
    }
    
    
    /* Style links inside the columns / Estilos para los enlaces dentro de columnas */
    
    .column a {
      float: none;
      color: black;
      padding: 16px;
      text-decoration: none;
      display: block;
      text-align: left;
    }
    
    
    /* Add a background color on hover / Añade color a los enlaces cuando se pone el mouse encima */
    
    .column a:hover {
      background-color: #ddd;
    }
    
    
    /* Clear floats after the columns / Limpia los floats despues de las columnas */
    
    .row:after {
      content: "";
      display: table;
      clear: both;
    }

    Conclusión.

    Si llegó hasta este punto es porque seguramente ha hecho un buen trabajo, siéntase libre de jugar con este pequeño ejemplo, me encantaría ver sus resultados así que no dude en compartirlos.

    Enlaces de interes:

    Subir un archivo con HTML5

    Arrastrar y Soltar HTML5

    Aquí algunos libros que le pueden ayudar:

    No Comment
  • Utilice getElementsByClassName

    JScode

    JavaScript y DOM han ido mejorando con el tiempo, y especialmente en la marco de HTML5, una de esas mejoras es el método getElementsByClassName(NombreClase) el cual nos permite obtener varios elementos al mismo tiempo. Desde hace años los desarrolladores contamos con getElementById con la limitante de obtener únicamente un solo elemento; más recientemente QuerySelector y QuerySelectorAll los cuales son métodos poderosos y flexibles. Sienodo así ¿porque deberiamos usar getElementsByClassName?

    Los casos donde pude preferir utilizar getElementsByClassName son aquellos donde usted tiene un árbol de elementos extenso y/o complejo, si ese es el caso y usted desea modificar elementos independientemente de su posición y sin usar selector complejos, entonces usted puede recuperar esa colección con todos elementos que utilizan la clase o clases seleccionadas. Cabe destacar que bajo ese escenario las pruebas de benchmarking tienden a favorecer a getElementsByClassName sobre QuerySelector y QuerySelectorAll.

    Esto supone una gran ventaja en términos de cantidad de código, ya que el método puede seleccionar varios elemento de una sola vez pero también discriminar implicitamente algunos sin usar selectors elaborados. El comportamiento de getElementsByClassName  es básicamente buscar en todo el documento a todos los elementos que cumplan con el criterio de búsqueda  que se proporcionó como parámetro.

    Por ejemplo, digamos que queremos seleccionar todos los elementos que usan la clase prueba:

    document.getElementsByClassName('prueba');

    También se pueden seleccionar múltiples clases, si deseara obtener los elementos que usan una clase jovenes y una clase adultos lo lograría utilizando solo la siguiente línea de código

    document.getElementsByClassName('jovenes adultos');

    Hagamos la cosas más interesantes,  le propongo una página con diferentes párrafos (<p>) pero solo aquellos que utilizan la clase contenido deben ser seleccionados para cambiar el tamaño de la fuente que usan. Para lograr tal objetivo podría hacer uso del siguiente código JavaScript:

    //se asignan todos los botones que permiten cambiar el tamaño de la fuente a variables
    var BotonFontSize1 = document.getElementById("btnFontSize1");
    var BotonFontSize2 = document.getElementById("btnFontSize2");
    var BotonFontSize3 = document.getElementById("btnFontSize3");
    var BotonFontSize4 = document.getElementById("btnFontSize4");
    
    //se vincula el evento click a cada botón
    BotonFontSize1.addEventListener('click', function(){
       CambiaTamano(10);
    }, false);
    BotonFontSize2.addEventListener('click', function(){
       CambiaTamano(12);
    }, false);
    BotonFontSize3.addEventListener('click', function(){
       CambiaTamano(14);
    }, false);
    BotonFontSize4.addEventListener('click', function(){
       CambiaTamano(17);
    }, false);
    
    //funcion que utiliza getElementsByClassName para buscar todos los elementos que usan la clase contenido y asignar el tamaño de fuente especificado según el botón presionado
    function CambiaTamano(size) {
       contenidos = document.getElementsByClassName("contenido");
       //alert(contenidos.length);
       contenidos[0].style.fontSize = size + "px";
       contenidos[1].style.fontSize = size + "px";
    }

    Para ver en funcionamiento este código puede visitar el siguiente enlace: ejemplo getElementsByClassName (botón “+” para ver el código completo incluyendo HTML y CSS).

    Sin duda esta mejora en JavaScript nos ahorra mucho código, si usted tiene algo de experiencia con JavaScript se dará cuenta de que existen varias maneras creativas de utilizar getElementsByClassName, experimente y sin duda encontrará muchas de ellas. Si desea ver la especificación oficial al respecto visite:  HTML5 – getElementsByClassName.

    Algunos enlaces de relacionados:

    10 CSS Selectors Que Hay Que Tener En Mente

    Document.getElementsByClassName() (Mozilla.org)

    HTML 5.1 2nd Edition

    HTML DOM getElementsByClassName() Method (W3Schools)

    Algunos libros de interés:

    Algunos buenos libros que pueden ser de su interés:

    No Comment
  • Mitos y Realidades del HTML5 (Presentación)

    Durante mis últimas visitas a algunas instituciones de educación superior he utilizado como material de apoyo durante las charla sobre HTML5 una presentación que elaboré basado en la idea original de Marcin Wichary.

    He de aclarar que  la versión original está muy bien y el código está disponible de forma  libre, pero no utilicé nada del código de Wichary debido  a que es un poco extenso y un tanto desordenado (me parece),  por lo que hice mi propia implementación pero manteniendo el mismo concepto visual, de manera que mi versión no sirve para entender la versión de Wichary así que sugiero que los vea como ejemplos distintos si desea meterse al código.

    Una vez aclarado lo anterior, la presentación muestra una serie láminas o slides que hablan de los mitos y realidades que rodean a HTML5, cada lámina tiene un comentario que le da contexto, para ver los comentarios hay que presionar la tecla 2 y para navegar entre slides simplemente hay que usar las teclas direccionales.

    El contenido de esta presentación fué creada con la idea de servir como introducción al HTML5 utilizando al mismo HTML5 como medio, es decir,  es una presentación creada usando HTML5 para enseñar HTML5 (interesante ¿no?), de manera que puede servir como presentación de introducción al HTML5 o como ejemplo de código HTML5 implementado para una pequeña aplicación multimedia.

    Pongo a su disposición esta ejemplo para que haga con el ¡lo que quiera!, modifíquelo, bórrelo, descompóngalo, recompóngolo, increméntelo, decreméntalo…en fin, lo que usted quiera, si desea darme crédito se lo agredeceré y si no, no importa porque seguramente nunca me enteraré  :)))

    No he comentado bien el código (¡sorry!) y normalmente casi todo los nombres de variables y funciones los hago en inglés, espero que esto no le represente mayor problema,  en realidad la lógica es sencilla (si se le complica siempre puede enviarme un mensaje y trataré de ayudarle con algún tip), pero no se desanime, si tiene bases de programación y le dedica un poco de tiempo estará manejando y modificando el código antes de lo que cree.

    Debo aclarar también que este código fué creado para Google Chrome por lo que podría no verse adecuadamente en otros navegadores, sin más le dejo el enlace para descargar el código:  HTML5MitosRealidades.rar

    2 Comments
  • Arrancar con HTML5

    Mi Libro: Arrancar con HTML5

    Puede ser un poco difícil hablar “bien” de tu propio trabajo, especialmente cuando se busca promocionarlo, pero además de ser necesario para vivir, creo que está bien cuando crees que ese trabajo puede servirle a alguien más y de esa forma se crea un círculo virtuoso donde todos ganan (al menos esa es mi intención).

    Continuamente estoy experimentando con nuevas tecnologías de desarrollo para aplicaciones (multimedia y web principalmente), lo que constantemente me lleva buscar información de utilidad en todas las fuentes que tengo a mi alcance. La información que se puede encontrar está escrita predominantemente en inglés, lo cual no me representa problema hoy en día, pero en algún momento fue una difícil barrera.

    Además del lenguaje, otro problema que sufrí en mi vida como simple estudiante mexicano con cierta curiosidad por las tecnologías de información, era la falta de interés del ambiente que me rodeaba (para ser honesto) y por lo tanto la falta de disponibilidad de información reciente, de punta y veraz acerca de algunos temas de tecnología. Aunque Internet ha llegado para ayudar a mitigar este inconveniente de gran manera, la selección, interpretación, exactitud y orden de la información no siempre es sencilla y es en estos casos en los que un simple libro es aun algo muy útil.

    Entre otros, estos inconvenientes siguen existiendo el día de hoy en la vida de muchas personas, sobre todo cuando somos “principiantes”. Es por todo esto que decidí crear un libro que abordara el tema de HTML5 y así apoyar  a todas las personas de habla hispana que estén interesadas en iniciarse en el fascinante mundo del desarrollo web, pero que también desean hacerlo con tecnologías de vanguardia y así ser competitivas casi desde el inicio.

    Aunque este libro (Arrancar con HTML5) enfatiza en desarrolladores que comienzan, definitivamente también es una buena alternativa para el programador con experiencia pero que también comienza con HTML5. Aunque lo anterior indica el nicho principal al que apunta Arrancar con HTML5, el programador ya iniciado en HTML5 puede usar el libro como una referencia rápida para algunos puntos precisos.

    Sin más, las personas que conforman AlfaOmega Grupo Editor, a las cuales agradezco, y su servidor ponen a su disposición Arrancar con HTML5 – Curso de programación en toda latinoamerica. En España este libro está diponible gracias a la editorial Marcombo.

    No Comment