MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Los componentes básicos del diseño adaptable

Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.

En este artículo vamos a discutir los componentes principales del diseño adaptable, con algunos enlaces a "más información" cuando sea necesario.

Para los desarrolladores Web, es muy común que se les pida crear  un sitio web o aplicación que cambie su interfaz dependiendo del navegador o del dispositivo que accede al sitio para proporcionar una experiencia optimizada. Una posibilidad es crear diferentes versiones de un sitio / aplicación para diferentes plataformas o navegadores y así servirlos apropiadamende después de detectar qué navegador o plataforma está mirando su sitio. Pero esto es cada vez más ineficiente: el "escaneo del navegador" es inherentemente propenso a errores, y mantener múltiples copias de su código puede llegar a ser una pesadilla.

Normalmente es mucho mejor crear una única versión de su código, a la que no le importe qué navegador o plataforma esta  accediendo al sitio, sino que utilice las pruebas de función para averiguar qué código soporta el navegador o cuáles son los valores de ciertas funciones del navegador, y luego ajuste el código de forma apropiada. Esto suele ser llamado diseño de respuesta o diseño adaptativo, dos enfoques diferentes pero relacionados. Para una discusión sobre las diferencias entre los dos, leer Diferencias entre diseño de respuesta y diseño adaptativo.

Esto es mucho más fiable, más fácil de mantener y más preparado para el futuro. No caiga en el error de tener que crear más versiones diferentes del sitio a medida que más navegadores y plataformas nuevas aparecen, y ajuste el código como soporte de las funciones en los cambios de los navegadores existentes.

Esta opción también tiene desventajas. Si el contenido, el diseño y la funcionalidad tiene que cambiar mucho para distintos dispositivos, puede no ser una opción tan buena. Además, tomar un sitio que ya existe y añadirle capacidad de respuesta, para hacerlo adecuado para móvil/tablet, puede requerir mucho más esfuerzo que simplemente crear un sitio o aplicación móvil separado, especialmente si se trata de un sitio de una empresa en expansión. Lea más acerca de Ventajas y desventajas del diseño de respuesta.

También puede leer nuestra discusión sobre los conceptos básicos del Diseño de respuesta, si necesita más información sobre los antecedentes y conceptos básicos.

AQUI!!!Diseños de cuadricula

La mejor forma de empezar es con las mediciones para nuestro diseño. En esencia, esto significa utilizar una combinación de porcentajes, ems / rems, ver el tamaño del texto, ver los anchos, ver los píxeles. Todo esto tiene una gran cantidad de ventajas, pues la disposición de todos los objetos de la pagina Web, se adaptarán a las diferentes dimensiones de ventanas gráficas. Para entender mejor las unidades graficas mire: Medidas de paginas Web.

Ahora veamos un ejemplo:
Hemos escrito un prototipo simple pero divertido para una aplicación llamada: Snapshot, que tiene una secuencia de vídeo desde tu cámara Web (usando getUserMedia() le permite capturar imágenes fijas a partir de ese flujo de vídeo  (using HTML5 <canvas>), y guardarlos en una galería. A continuación, puede ver las imágenes previamente capturadas y eliminarlas. Otros artículos discutirán la funcionalidad con más detalle, pero aquí estamos enfocados en el diseño.

Nota: Puedes buscar la Aplicación Snapshot en Github; comprueba el código, y ayuda a mejorarlo. También puedes ver la  aplicación Snapshot funcionando en vivo. Fijate que getUserMedia() es una tecnología experimental, que actualmente sólo funciona en Google Chrome y Firefox de escritorio. El soporte de Firefox OS está planeado para la versión 1.3. Se planea agregarle más funcionalidades para una fecha futura.

Nuestro diseño para escritorio de Snapshot consiste en tres columnas, una contiene el visor de la cámara, otra la imagen capturada, y por último la galería, respectivamente.

 El marcado es muy facil:

<x-deck selected-index="0">
  <x-card>
    …
  </x-card>
  <x-card>
    …
  </x-card>
  <x-card>
    …
  </x-card>
</x-deck>

Vocabulario:

Deck: cubierta, Selected: seleccionado, Index: índice, Card: tarjeta

Nota: Los elementos "x" pueden no ser muy conocidos para usted, la razón es porque son parte de una colección de elementos llamada "Brick" que forman parte de la interfaz de usuario de Mozilla para aplicaciones Web moviles. Hemos utilizado "brick" para crear el diseño móvil de Snapshot. Usted leera más acerca de esto más abajo.

Para obtener estos resultados con distribución lado a lado, hemos utilizado las siguientes reglas:

x-card {
  width: 100%;
}

x-card:nth-child(1), x-card:nth-child(2) {
  width: 30%;
  float: left;
  padding: 2rem;
}

x-card:nth-child(3) {
  width: 40%;
  float: left;
  height: 100%;
  overflow: auto;
  padding: 2rem;
}

Vocabulario:

Width: Ancho, Float: Flotante, Padding: acolchado/relleno, Height: Altura, Overflow: Desbordarse/rebosar, Border: Borde.

Así que le estamos dando a las dos primeras columnas: width de 30%, y a la tercera: width  de 40%, Todas las columnas quedaran flotando a la izquierda. Y sus proporciones seran proporcionales al tamaño de la ventana del navegador, esto es solo un simple ejemplo, pero se puede utilizar para todas las cosas que necesites.

Medición de bordes de caja

El relleno no afecta a la anchura total, ni a la altura de los contenedores, ya que nos hemos fijado el apresto de la caja de todos los elementos de el border-box: (borde de la caja).

*, *:before, *:after {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

Vocabulario: Before: Antes, After: Despúes, Sizing: Apresto.

Esto básicamente significa que ancho y altura ahora determinan las dimensiones de un elemento de todo el camino hasta e incluyendo la frontera, no sólo el contenido. Así que si ajusta el ancho: 40%, el ancho de la caja será siempre el 40% de su padre, y cualquier relleno y frontera anchuras determinadas en el cuadro de la voluntad debe restarse del ancho del contenido, no se añade a la misma. ¡Muy útil! Lea más sobre esto en * { Dimensionado de la caja : Borde de la caja  } FTW (artículo en inglés), Por: Paul Irish.

Elementos reemplazados flexibles

Todo funciona bastante bien, por lo menos hasta este momento, pero hay algunos problemas que aún no se nos han presentado. Echemos un vistazo a lo que ocurre cuando incluimos <video> y <img> dentro de nuestras dos primeras columnas, sin configurar nada.

Debido a que el tamaño de los elementos reemplazados es dictado por el tamaño de los medios insertados en ellos, y los medios de comunicación son un tamaño fijo, explotan de los elementos que contienen y hacen un lío en la disposición. Esto es bastante horrible, pero en general este tipo de problema se resuelve fácilmente con algunos simples CSS:

img, video {
  max-width: 100%;
}

Este código obliga a los elementos a estar dentro de un limite establecido, sin embargo si en este caso la imagen fuera más grande, el texto no se adaptara a la imagen. Aquí tenemos más código:

x-card:nth-child(1) video, x-card:nth-child(2) img {
  width: 100%;
    …
}

Esto es así porque en nuestro caso, de hecho queremos que el vídeo y la imagen se estiren para llenar siempre sus contenedores sin importar cuáles sean — una diferencia sútil pero importante con max-width — y por tanto que siempre tengan el mismo tamaño. El vídeo siempre cambia de tamaño dinámicamente, pero las capturas de pantalla tomadas de él no lo hacen,  por lo que al redimensionar la pantalla es posible que se acabe con un diseño desordenado con elementos de diferentes tamaños al usar max-width: 100%, como por ejemplo:

Consultas multimedia

Las redes fluídas son un gran comienzo, pero usted se dará cuenta de que en ciertos puntos (conocidos como puntos de ruptura) el diseño comienza a romperse. En estos puntos usted querrá cambiar el diseño para rectificar el problema, y esto puede ser hecho usando las consultas multimedia.

Nota: Las consultas multimedia son una característica CSS3 que le permite aplicar CSS slectivamente dependiendo de los resultados de las pruebas de función multimedia — para más información sobre los conceptos básicos, lea Consultas multimedia.

Diseño de escritorio típico

En nuestro ejemplo, tenemos un diseño de escritorio, como siempre hemos visto. Esto está creado usando las reglas CSS incluídas al comienzo de la hoja de estilo, antes de que aparezca ninguna consulta multimedia.

Diseño de media anchura

También tenemos diseño de media anchura, el cual está dirigido al buen trabajo en tablets y pantallas de ordenador portátil pequeñas. Esto está creado por la totalidad del CSS dentro de la primera consulta multimedia:

@media all and (max-width: 1024px) {
  x-card:nth-child(1), x-card:nth-child(2) {
    width: 50%;
  }

  x-card:nth-child(3) {
    width: 100%;
    clear: left;
  }
 
  x-card:nth-child(3) img {
    width: 20%;
  }
}

Por lo tanto aquí estamos alterando los anchos de las columnas y eliminando el flotador de la tercera columna (y añadiendocompensación para protegernos de cualquier negocio flotante divertido). Además hemos alterado la anchura de las imágenes que se encuentran en el tercer contenedor (ya no es una columna — esto es la galería) porlo que ahora usted tiene cinco por línea (previamente eran tres por línea).

Diseño de pantalla estrecha/móvil

Después tenemos un diseño de pantalla estrecha, diseñado  para ajustarse a la experiencia de aplicación móvil/aplicación de open Web (por ejemplo, una aplicación de Firefox OS). Esto es creado en múltiples partes. Primero de todo, como es esperado, hay una consulta multimedia en nuestro CSS principal, la cual es bastante pesada, así que la examinaremos por partes:

@media all and (max-width: 480px) {  
  x-card:nth-child(1), x-card:nth-child(2), x-card:nth-child(3) {
    width: 100%;
    float: none;
    padding: 0;
  }
 
  button {
    margin-top: 0;
    border-radius: 0;
  }
 
  x-card:nth-child(1) video, x-card:nth-child(2) img {
    border-radius: 0px;
    border: none;
    padding: 0;
    background-color: 0;
  }

Este primer bloque restablece una serie de cosas diferentes de los diseños de pantalla ancha que no eran requeridas para la aplicación móvil.

  x-card:nth-child(1) video, x-card:nth-child(2) img, x-card:nth-child(3) {
    margin-top: 17.5vw;
  }
 
  x-card:nth-child(1) button, x-card:nth-child(2) button {
    position: absolute;
    bottom: 0;
  }
 
  x-card:nth-child(2) button:nth-of-type(2) {
    bottom: 5.9rem;
  }
  
  x-card:nth-child(1) button {
    font-size: 7vw;
  }
 
  x-card:nth-child(2) button {
    font-size: 7vw;
  }

The next rules do some sizing on the buttons inside the first two cards, and give all card contents a top margin so that their content won't be lost under the navigation buttons (see below). This was necessary because Mozilla Brick (also see below) forces its components to be 100% of the screen width and height. We have used vw (viewport width) units for these — 1vw is equivalent to  1% of the viewport width. This makes the dimensions scale up and down nicely along with the viewport width. Last for this section, we absolutely positioned all buttons at the bottom of the cards they are in, so the layout looks OK at different viewport size variations. We then add a rule that postions the second button in any card a button's width higher up the card. When you click on an image in the gallery it brings up options to delete or cancel deletion of the card, and you don't want two buttons on top of one another.

x-card:nth-child(3) img {
  width: 50%;
}

This rule simply changes the width of the gallery images so now there are two per line.

  nav {      
    width: 100%;
    position: absolute;
    z-index: 1000;
     
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
  }
 
  nav button {
    font-size: 6.8vw;
    
    -webkit-flex: 1;
    -moz-flex: 1;
    -ms-flex: 1;
    flex: 1;
    
    border-left: 1px solid rgba(100,100,100,0.4);
  }
 
  nav button:first-child {
    border-left: 0;
  }
}

In this last set of rules, we change the display value of the <nav> to flex to make it show (it was set to none in the default CSS at the top of the stylesheet, as it wasn't needed for the other views.) We then use absolute positioning and z-index to make it take up no space in the document flow,  and sit on top of the x-cards (this is why we gave the x-cards that top-margin earlier).

Next up, the font-size of the buttons is set to 6.8vw. Why? Because the top-margin of the x-cards was set to 17vw earlier on. All buttons in the app have been set to have a line-height of 2.5, in the default CSS at the top of the stylesheet (check if you don't believe me.) And 6.8 x 2.5 = 17.

Last, we have used flex: 1; to make the buttons always take up the same proportion of space on the line. Let's have a look at the mobile layout, in the below image.

single column layout for mobile app view, with three buttons to navigate between cards, an image viewer, and a Save Picture button at the button.But there are more tricks up our sleeves for this mobile app layout! As mentioned above, we used Mozilla Brick, a collection of ready-rolled mobile UI components, in the making of the mobile app layout. In particular, we used the deck component for the nice transition effect between cards when the buttons are pressed. For more on using Brick, read Mozilla Brick: ready made UI components.

What's more relevant to this article is that we didn't want the Brick CSS and JavaScript files being applied to the markup unless we were looking at the mobile app view. To achieve this, we applied the Brick CSS to the page using a separate <link> element with a media attribute:

<link href="dist/brick.css" type="text/css" rel="stylesheet" media="all and (max-width: 480px)">

This says that the whole stylesheet will not be linked to the HTML unless the viewport width is 480px or less. Moving on to the JavaScript, <script> elements don't accept media attributes, so I had to do this a different way. Fortunately there is a JavaScript construct called window.matchMedia(), which can conditionally run JavaScript constructs depending on whether a media query returns true or not. We opened up the brick.js file and wrapped the whole lot in the following:

if (window.matchMedia("(max-width: 480px)").matches) {
  // The whole of brick.js goes here!
}

This causes nothing inside the brick.js file to be run unless the viewport width is 480px or less. Problem solved.

Really wide screens

One thing you might notice is that when the viewport gets very wide (such as on a cinema display), the layout stops getting wider, and just centers in the space available. This is pretty simple to achieve. You could use a min-width media query to fix the <body> width at a certain point:

@media all and (min-width: 1400px) {
  body {
    width: 1400px;
    margin: 0 auto;
  }
}

But it's actually easier to just set the following rule instead, and get rid of the media query altogether:

body {
  max-width: 1400px;
  margin: 0 auto;
}

Orientation fail

We also came across some problems with orientation: the mobile-app layout of our example app is designed for portrait orientation, and looks terrible when viewed on a device in landscape orientation. To fix this, we added in a media query that only applies its contents to the markup when device is viewed in landscape orientation:

@media all and (max-width: 480px) and (orientation: landscape) {
  nav {   
    width: auto;
    
    -webkit-flex-direction: column;
    -moz-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
  }
 
  nav button {
    font-size: 6.8vh;
  }
 
  nav button {
    border-left: 0;
  }
 
  x-card:nth-child(1) video, x-card:nth-child(2) img, x-card:nth-child(3) {
    margin-top: 0;
  }
 
  x-card:nth-child(1) button, x-card:nth-child(2) button {
    font-size: 2rem;
  }
}

This does the following:

  • Adjusts the nav buttons, changing the direction the flexbox is laid out in, and altering the font size and borders so they sit vertically instead of horizontally.
  • Removes the top margin from the x-card contents so you don't end up with an unsightly gap at the top of the screen in landscape mode.
  • Changes the sizing of the control buttons (e.g. Take Picture, Delete Photo) so they don't look too big and sit properly on the screen.

This results in the following layout:

Note: Another solution with respect to orientation might be to just lock the orientation of your app, to portrait or landscape. If you are working on a Firefox OS/installed app, you can easily do this with the orientation manifest field. If you want a solution that works across general web apps, you could use the Screen orientation API, and/or provide a message asking the user to rotate their screen if they are using the wrong orientation (for example, if window.innerWidth is larger than window.innerHeight, assume the
game is landscape mode and show a "please rotate" message.)

Viewport

One last problem to mention for our example app is concerned with mobile browsers and media queries. If we viewed my example in a mobile browser in its current state, we wouldn't see our nice mobile layout. Instead, we'd see the below image.

I'm sure you'll agree that this really isn't what we wanted — why is this happening? In short, mobile browsers lie. They don't render web pages at their true viewport width. Instead, they render pages at a higher assumed viewport width (something approaching a laptop screen), and then shrink the result down to fit inside the mobile screen. This is a sensible defensive mechanism — most old school sites that don't have media queries would look terrible when rendered at say, 320px or 480px wide. But this doesn't help us responsible web developers, who have written small screen layouts into our CSS using media queries and want mobile devices to display those!

There is a way to override this mobile rendering behavior — viewport, which is inserted into our HTML pages in the form of a <meta> tag. In my example, let's add the following into our HTML <head>:

<meta name="viewport" content="width=480">

This causes our browser to render our mobile app layout properly — width=480 tells the browser "render this markup at 480 pixels wide", hence the media queries kick in appropriately. There are many more options available in the viewport meta tag, which you can read about in Using the viewport meta tag to control layout on mobile browsers.

Note: There is a spec called device adaptation, which defines the same functionality but in CSS, using a @viewport at-rule. This is probably a more logical place to put such information, but the spec is not as well supported as the viewport meta tag, therefore you should stick with that for now.

Responsive images/video

Another problem that comes up more and more these days is making image/video weight (size in KB) responsive as well as the dimensions of the image on screen. Yes, you want the images to be contained inside the app UI whether you are using it on desktop or mobile, but you should also consider that mobile apps have much smaller viewport dimensions available than desktop apps, so you should try to give mobile devices a smaller image to download. Mobiles in general (more commonly in some parts of the world than others) are on lower bandwidth connections and have less memory available than desktop devices, so yes, those extra kilobytes really do count.

Another challenge is dealing with high resolution screens — raster graphics designed for low resolutions are in danger of appearing tiny when displayed on a high resolution screen, so devices often apply a default zoom factor to rendered pages to avoid this. The trouble with this, then, is that raster images are zoomed in and as a result can start to look pixellated.

CSS background images

For CSS background images this is a fairly easy problem to solve. If you use the mobile first methodology, you will be creating your mobile layout inside your default CSS, before any media queries have been applied. The media queries then supply CSS that is only applied to the markup when the viewport is above a certain width. Let's look at a quick example:

header {
  height: 300px;
  width: 100%;
  background: url(images/small-header.jpg) center;
}

@media all and (min-width: 480px) {
  header {
    background: url(images/large-header.jpg) center;
  }
}

This means that mobile browsers only download the mobile background image asset — not the desktop mobile assets — because they fail the media query tests and therefore ignore the media queries. You can also serve a larger graphic to a higher resolution device using a resolution media query, like so:

button {
  background: url(images/low-res-header.jpg) 1rem center ;
}

@media only screen and (-webkit-min-device-pixel-ratio: 2),
       only screen and ( min-resolution: 192dpi),
       only screen and ( min-resolution: 2dppx) { 
  button {
    background: url(images/high-res-header.jpg) 1rem center ;
  } 
}

This looks rather complicated, but really it's not — we are providing a number of media query options, as at this time different browsers support different resolution media query types and even units. Brett Jankord has a good explanation at Cross Browser Retina/High Resolution Media Queries.

<video>

HTML5 video is fairly well catered for in terms of responsive capabilities. If you wish, you can point to multiple video files via <source> attributes, each with their own source and MIME type:

<video controls>
  <source src="videos/720/crystal720.mp4" type="video/mp4">
  <source src="videos/720/crystal720.webm" type="video/webm">
</video>

But you can go one step further. You can include media attributes on the <source> element containing media queries — the video loaded in the browser will depend on both the format the browser supports, and the results of the media tests. So for example:

<video controls>
  <source src="videos/320/crystal320.mp4" type="video/mp4" media="all and (max-width: 480px)">
  <source src="videos/320/crystal320.webm" type="video/webm" media="all and (max-width: 480px)">
  <source src="videos/720/crystal720.mp4" type="video/mp4" media="all and (min-width: 481px)">
  <source src="videos/720/crystal720.webm" type="video/webm" media="all and (min-width: 481px)">
</video>

This allows your site to serve different video files based on the available space, in order to optimize the user's experience.

<img>

HTML images are a more difficult proposition. There is no mechanism inherent in HTML images for serving different image files dependent on viewport size, and, due to a number of irksome browser behavior realities, solutions are more difficult to hack together than you would imagine. There are currently some standards proposals in the works that would provide this — the W3C responsive images community group discussed this problem for ages and arrived at the <picture> element, which provides a similar markup structure to <video>, with <source> alternatives selectable via media query results. Another proposal, srcset, was put forward by Apple and takes a slightly different approach, instead providing a new srcset attribute for <img> inside which image references are placed along with "hints" that the browser can use to work out which image is most suitable to display given its viewport size, resolution, etc. These are not intended to be mutually exclusive.

This all sounds good. But those solutions are definitely not ready for production yet — both are in a very early stage of standardization, and have no support across browsers. Currently we have to rely on various polyfills and other solutions, none of which are perfect for all situations, so you need to decide which one is right for your particular situation. Some available solutions are as follows:

HiSRC
A jQuery plugin that allows you to create small, medium, and large versions of an image, and then serves the appropriate one according to the browser's resolution and available network speed.
Mobify.js capturing
A very clever technique from Mozilla that allows you to capture the source of the page before it's parsed. This way, you can swap out image src values with JavaScript depending on browser features, circumventing browser preloading issues. This is promising, but doesn't work very well across older browsers.
Picturefill
A JavaScript-based polyfill for <picture>, which works nicely, but it does require a lot of custom markup.
Adaptive images
A server-side solution, which records the viewport size in a cookie, then resizes images via a combination of PHP and .htaccess to a more appropriate size, if appropriate. This doesn't require markup or scripting, but has a number of limitations.

SVG and other vector graphics

For some image requirements (not photographs, but icons and user interface elements are a good fit), a good solution is to use vector graphics. Because vector images are calculated based on mathematical algorithms rather than containing separate data on every pixel in the image, they tend to be smaller in file size, and are infinitely scalable when zoomed or viewed on high resolution devices (at least, in theory). Some ideas follow, which also help to keep the number of HTTP requests down — another key factor in mobile app performance:

  • You should try to use CSS3 features to programmatically generate graphical effects where possible, rather than relying on image files. these include rounded corners, gradients, and drop shadows. These will scale as the resolution changes or the browser zooms, and although they are not supported very well on older browsers such as Internet Explorer 6-8, this is not too much of a concern when you are creating an interface aimed at modern devices such as Firefox OS, and they also tend to gracefully degrade.
  • You could also try using SVG to create interface elements. SVG produces vector graphics and is supported well across modern browsers, with polyfills available for older browser support.
  • Using Web fonts for displaying icons is an effective technique for keeping file size and HTTP requests down, and this is supported well across modern and older browsers.

See also

Etiquetas y colaboradores del documento

 Colaboradores en esta página: Pau_Ilargia, Stojan, stephaniehobson, maedca
 Última actualización por: Pau_Ilargia,