HTML5

HTML

Tutorial HTML: Compatibilidad con navegadores

Aprende a gestionar diferencias entre navegadores, implementar fallbacks y aplicar mejora progresiva para sitios web accesibles y robustos.

Aprende HTML y certifícate

Diferencias entre navegadores y motores de renderizado

Cuando desarrollamos sitios web, es fundamental entender que no todos los navegadores interpretan y muestran el código HTML de la misma manera. Estas diferencias pueden afectar significativamente la apariencia y funcionalidad de nuestras páginas web.

Un navegador web es un software completo que nos permite acceder a contenido en internet. Los navegadores más populares incluyen:

  • Chrome
  • Firefox
  • Safari
  • Edge
  • Opera

Cada navegador tiene sus propias características, interfaz de usuario y forma de procesar el código HTML. Sin embargo, el componente más importante que determina cómo se muestra realmente una página web es el motor de renderizado.

Motores de renderizado: el corazón de los navegadores

El motor de renderizado es el componente central que interpreta el código HTML, CSS y JavaScript para convertirlo en la página web que vemos en pantalla. Es como el "traductor" entre el código y la representación visual.

Los principales motores de renderizado son:

  • Blink: Utilizado por Chrome, Opera y Edge (desde 2020)
  • Gecko: Utilizado por Firefox
  • WebKit: Utilizado por Safari
  • Trident: Utilizado por Internet Explorer (obsoleto)
<!-- Este código puede verse diferente según el motor de renderizado -->
<div style="border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.2);">
  <h2>Ejemplo de contenido</h2>
  <p>Este elemento podría verse ligeramente diferente en distintos navegadores.</p>
</div>

Diferencias clave entre motores de renderizado

Las diferencias entre motores de renderizado pueden manifestarse en varios aspectos:

1. Interpretación de CSS

Cada motor puede implementar las propiedades CSS de manera ligeramente diferente:

<!-- Ejemplo de diferencias en CSS -->
<style>
  .gradient-box {
    background: linear-gradient(to right, blue, green);
    border-radius: 8px;
    padding: 20px;
  }
</style>

<div class="gradient-box">
  <p>Los degradados pueden verse diferentes entre navegadores</p>
</div>

En este ejemplo, el degradado podría verse con ligeras variaciones de color o suavizado entre WebKit (Safari) y Blink (Chrome).

2. Soporte de características HTML5

No todos los motores implementan las nuevas características de HTML al mismo tiempo:

<!-- La etiqueta details puede comportarse diferente -->
<details>
  <summary>Haz clic para expandir</summary>
  <p>Este contenido expandible puede tener diferente animación o estilo según el navegador.</p>
</details>

3. Rendimiento y velocidad

Los motores procesan el JavaScript y renderizan las páginas a diferentes velocidades:

  • Blink (Chrome): Generalmente ofrece un rendimiento rápido en JavaScript
  • Gecko (Firefox): Buen equilibrio entre rendimiento y consumo de memoria
  • WebKit (Safari): Optimizado para dispositivos Apple

4. Prefijos de proveedor

Históricamente, los navegadores han usado prefijos para implementar características experimentales:

/* Ejemplo de prefijos de proveedor */
.box {
  -webkit-transition: all 0.3s; /* Safari/Chrome */
  -moz-transition: all 0.3s;    /* Firefox */
  -ms-transition: all 0.3s;     /* Internet Explorer */
  -o-transition: all 0.3s;      /* Opera */
  transition: all 0.3s;         /* Estándar */
}

Aunque la tendencia actual es reducir el uso de prefijos, todavía existen algunas propiedades que los requieren.

Cómo identificar el motor de renderizado

Podemos detectar qué motor está utilizando un navegador mediante JavaScript:

// Código para detectar el motor de renderizado
function detectRenderingEngine() {
  const userAgent = navigator.userAgent;
  
  if (userAgent.indexOf("Gecko") > -1 && userAgent.indexOf("Firefox") > -1) {
    return "Gecko (Firefox)";
  } else if (userAgent.indexOf("AppleWebKit") > -1) {
    if (userAgent.indexOf("Chrome") > -1) {
      return "Blink (Chrome)";
    } else {
      return "WebKit (Safari)";
    }
  } else if (userAgent.indexOf("Trident") > -1) {
    return "Trident (Internet Explorer)";
  } else {
    return "Motor desconocido";
  }
}

console.log("Motor de renderizado: " + detectRenderingEngine());

Impacto en el desarrollo web

Estas diferencias entre motores tienen implicaciones prácticas para los desarrolladores:

  • Pruebas cruzadas: Es necesario probar nuestro sitio en múltiples navegadores
  • Hacks específicos: A veces necesitamos código específico para ciertos navegadores
  • Degradación elegante: Debemos planificar cómo se comportará nuestro sitio en navegadores con menos capacidades
<!-- Ejemplo de HTML con consideraciones de compatibilidad -->
<picture>
  <source srcset="imagen-moderna.webp" type="image/webp">
  <source srcset="imagen-fallback.jpg" type="image/jpeg"> 
  <img src="imagen-fallback.jpg" alt="Descripción de la imagen">
</picture>

En este ejemplo, los navegadores que soportan el formato WebP mostrarán la primera imagen, mientras que los demás utilizarán el formato JPG como alternativa.

Herramientas para desarrollo multiplataforma

Para facilitar el desarrollo con estas diferencias, podemos utilizar:

  • Frameworks CSS: Como Bootstrap o Tailwind CSS, que normalizan las diferencias
  • Autoprefixer: Herramienta que añade automáticamente los prefijos necesarios
  • Reset CSS: Hojas de estilo que normalizan el comportamiento base entre navegadores
<!-- Uso de normalize.css para estandarizar estilos base -->
<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
  <link rel="stylesheet" href="estilos-propios.css">
</head>

Evolución de los motores de renderizado

Es importante destacar que los motores de renderizado están en constante evolución. Con cada actualización, los navegadores implementan más estándares web y reducen sus diferencias. La tendencia actual es hacia una mayor estandarización y compatibilidad.

Por ejemplo, Edge abandonó su motor EdgeHTML para adoptar Blink (el mismo que usa Chrome), lo que redujo significativamente las diferencias entre estos navegadores.

Entender estas diferencias nos permite desarrollar sitios web más robustos que funcionen correctamente en diversos entornos, preparándonos para abordar las estrategias de fallback que veremos en la siguiente sección.

Estrategias de fallback para características no soportadas

Cuando desarrollamos sitios web, nos enfrentamos al desafío de que no todos los navegadores soportan las mismas características de HTML. Para crear experiencias web consistentes y funcionales en todos los navegadores, necesitamos implementar estrategias de fallback (alternativas de respaldo).

¿Qué son las estrategias de fallback?

Las estrategias de fallback son técnicas que permiten ofrecer una experiencia alternativa cuando un navegador no soporta una característica específica de HTML. En lugar de que nuestra página se rompa o muestre errores, proporcionamos una solución de respaldo que mantiene la funcionalidad básica.

Detección de soporte de características

Antes de implementar alternativas, necesitamos detectar si un navegador soporta una característica específica:

1. Detección mediante JavaScript

Podemos comprobar si una característica está disponible antes de usarla:

// Comprobar si el navegador soporta la API de geolocalización
if ("geolocation" in navigator) {
  // El navegador soporta geolocalización
  navigator.geolocation.getCurrentPosition(showPosition);
} else {
  // Fallback: mostrar un mapa estático o un mensaje
  showStaticLocationOption();
}

2. Detección mediante CSS

Para características CSS, podemos usar @supports para aplicar estilos alternativos:

/* Estilo principal usando grid */
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

/* Fallback para navegadores que no soportan grid */
@supports not (display: grid) {
  .container {
    display: flex;
    flex-wrap: wrap;
  }
  
  .container > div {
    width: 30%;
    margin: 1.5%;
  }
}

Estrategias de fallback para elementos HTML5

Elementos semánticos

Para navegadores antiguos que no reconocen elementos semánticos como <article>, <section> o <nav>:

<!-- Solución: definir los elementos como bloque en CSS -->
<style>
  article, section, nav, header, footer, aside, main {
    display: block;
  }
</style>

<!-- O usar un script de polyfill como HTML5Shiv -->
<!--[if lt IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<![endif]-->

Elementos multimedia

Para el elemento <video>:

<video controls width="400">
  <source src="video.webm" type="video/webm">
  <source src="video.mp4" type="video/mp4">
  <!-- Fallback para navegadores sin soporte para video -->
  <a href="video.mp4">Descargar el video</a>
  <img src="poster.jpg" alt="Miniatura del video">
</video>

Para el elemento <audio>:

<audio controls>
  <source src="audio.ogg" type="audio/ogg">
  <source src="audio.mp3" type="audio/mpeg">
  <!-- Fallback para navegadores sin soporte para audio -->
  <a href="audio.mp3">Descargar el audio</a>
</audio>

Formatos de imagen modernos

Para imágenes en formatos nuevos como WebP:

<picture>
  <source srcset="imagen.webp" type="image/webp">
  <source srcset="imagen.jpg" type="image/jpeg">
  <img src="imagen.jpg" alt="Descripción de la imagen">
</picture>

Polyfills: rellenando los vacíos de compatibilidad

Los polyfills son scripts que implementan características modernas en navegadores antiguos:

<head>
  <!-- Polyfill para fetch API -->
  <script>
    if (!window.fetch) {
      document.write('<script src="https://cdn.jsdelivr.net/npm/whatwg-fetch@3.6.2/dist/fetch.umd.min.js"><\/script>');
    }
  </script>
</head>

Algunos polyfills populares:

  • Promises: Para navegadores que no soportan promesas nativas
  • Fetch: Para implementar la API Fetch en navegadores antiguos
  • ClassList: Para añadir soporte a la manipulación de clases CSS
<!-- Ejemplo de uso de polyfill para promesas -->
<script>
  if (typeof Promise === 'undefined') {
    document.write('<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"><\/script>');
  }
</script>

Fallbacks para CSS

Propiedades con prefijos de proveedor

Aunque cada vez menos necesarios, los prefijos siguen siendo útiles para algunas propiedades:

.box {
  -webkit-user-select: none;  /* Safari */
  -moz-user-select: none;     /* Firefox */
  -ms-user-select: none;      /* IE/Edge */
  user-select: none;          /* Estándar */
}

Múltiples declaraciones como fallback

Podemos proporcionar múltiples valores, donde los navegadores ignoran los que no entienden:

.container {
  /* Fallback para navegadores antiguos */
  background: #f0f0f0;
  /* Para navegadores modernos */
  background: linear-gradient(to right, #f0f0f0, #e0e0e0);
}

Variables CSS con valores de respaldo

.elemento {
  /* Fallback para navegadores que no soportan variables CSS */
  color: #0066cc;
  /* Versión con variables CSS */
  color: var(--color-primario, #0066cc);
}

Estrategias para JavaScript

Comprobación de existencia de APIs

// Verificar si existe la API de almacenamiento local
function saveData(key, data) {
  if (window.localStorage) {
    localStorage.setItem(key, JSON.stringify(data));
  } else {
    // Fallback: usar cookies
    document.cookie = key + "=" + JSON.stringify(data);
  }
}

Carga condicional de scripts

<script>
  // Cargar una librería alternativa si la API nativa no está disponible
  if (!window.IntersectionObserver) {
    const script = document.createElement('script');
    script.src = 'intersection-observer-polyfill.js';
    document.head.appendChild(script);
  }
</script>

Fallbacks para formularios HTML5

Los nuevos tipos de input como date, email o range se convierten automáticamente en inputs de texto en navegadores que no los soportan:

<form>
  <!-- Se convierte en input text en navegadores antiguos -->
  <input type="date" name="fecha">
  
  <!-- Podemos mejorar la experiencia con JavaScript -->
  <script>
    if (!Modernizr.inputtypes.date) {
      // Cargar un datepicker alternativo
      loadDatepickerFallback();
    }
  </script>
</form>

Herramientas para gestionar fallbacks

Existen herramientas que facilitan la implementación de fallbacks:

  • Modernizr: Biblioteca que detecta características del navegador
  • Autoprefixer: Añade automáticamente prefijos de proveedor a las propiedades CSS
  • Babel: Transpila JavaScript moderno a versiones compatibles con navegadores antiguos
<!-- Ejemplo de uso de Modernizr -->
<script src="modernizr.js"></script>
<script>
  if (Modernizr.webgl) {
    // Inicializar visualización 3D con WebGL
    initWebGL();
  } else {
    // Mostrar alternativa 2D
    showFallbackVisualization();
  }
</script>

Estrategia de fallback para fuentes web

/* Cascada de fuentes con alternativas seguras */
body {
  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 
               Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif;
}
<!-- Precargar fuentes con fallback para navegadores antiguos -->
<link rel="preload" href="fonts/roboto.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/roboto.woff" as="font" type="font/woff" crossorigin>

<style>
  @font-face {
    font-family: 'Roboto';
    src: url('fonts/roboto.woff2') format('woff2'),
         url('fonts/roboto.woff') format('woff'),
         url('fonts/roboto.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
  }
</style>

Consideraciones finales sobre fallbacks

Al implementar estrategias de fallback, es importante:

  • Probar en múltiples navegadores para verificar que las alternativas funcionan correctamente
  • Mantener el equilibrio entre soporte para navegadores antiguos y carga de código adicional
  • Priorizar la experiencia del usuario sobre la apariencia exacta en todos los navegadores
  • Documentar las decisiones sobre qué navegadores se soportan oficialmente

Implementar estas estrategias de fallback nos permite crear sitios web robustos que funcionan en una amplia gama de navegadores, asegurando que todos los usuarios puedan acceder al contenido y funcionalidad básica, independientemente del navegador que utilicen.

Herramientas para probar compatibilidad: Can I Use

Cuando desarrollamos sitios web, es fundamental saber qué características HTML son compatibles con los diferentes navegadores. Una de las herramientas más valiosas para los desarrolladores web es "Can I Use", un recurso que nos permite verificar rápidamente la compatibilidad de características web en distintos navegadores.

¿Qué es Can I Use?

Can I Use (caniuse.com) es una base de datos en línea que proporciona información actualizada sobre el soporte de características web en los principales navegadores. Esta herramienta nos permite:

  • Consultar la compatibilidad de características HTML, CSS y JavaScript
  • Ver estadísticas de uso global de navegadores
  • Identificar qué versiones de navegadores soportan determinadas funcionalidades
  • Tomar decisiones informadas sobre qué tecnologías implementar
<!-- Ejemplo: queremos usar la etiqueta <dialog> -->
<dialog open>
  <p>Este es un cuadro de diálogo nativo de HTML5</p>
  <button>Cerrar</button>
</dialog>

Antes de implementar este código, podríamos consultar Can I Use para verificar su compatibilidad.

Cómo utilizar Can I Use

Búsqueda de características

La forma más directa de usar Can I Use es a través de su barra de búsqueda:

  1. Visita caniuse.com
  2. Escribe el nombre de la característica que quieres verificar (por ejemplo, "flexbox", "webp" o "dialog")
  3. Revisa la tabla de compatibilidad que aparece

Interpretación de resultados

Can I Use muestra una tabla con códigos de colores que indican:

  • Verde: Soporte completo
  • Amarillo: Soporte parcial (puede requerir prefijos o tener limitaciones)
  • Rojo: Sin soporte
  • Gris: Característica en desarrollo o descontinuada

Además, proporciona información sobre:

  • Porcentaje de usuarios globales que pueden usar la característica
  • Notas específicas sobre implementaciones particulares
  • Problemas conocidos en ciertos navegadores

Filtrado de resultados

Puedes personalizar los resultados según tus necesidades:

  • Seleccionar regiones geográficas específicas
  • Mostrar solo navegadores de escritorio o móviles
  • Ajustar el rango de versiones de navegadores

Ejemplos prácticos de uso

Verificando soporte para formatos de imagen modernos

Supongamos que queremos usar imágenes WebP por su mejor compresión:

<img src="imagen.webp" alt="Descripción de la imagen">

Al consultar "webp" en Can I Use, podríamos descubrir que:

  • Chrome, Edge y Firefox tienen soporte completo
  • Safari añadió soporte en versiones recientes
  • Internet Explorer no lo soporta en absoluto

Con esta información, implementaríamos una solución con alternativas:

<picture>
  <source srcset="imagen.webp" type="image/webp">
  <img src="imagen.jpg" alt="Descripción de la imagen">
</picture>

Comprobando APIs de JavaScript modernas

Si queremos usar la API Intersection Observer para implementar lazy loading:

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach(img => {
  observer.observe(img);
});

Can I Use nos mostraría que esta API tiene buen soporte en navegadores modernos, pero necesitaríamos un polyfill para navegadores más antiguos.

Integración con herramientas de desarrollo

Can I Use se puede integrar en nuestro flujo de trabajo de varias maneras:

Extensiones para navegadores

Existen extensiones para Chrome y Firefox que permiten consultar Can I Use directamente desde las herramientas de desarrollo:

  • Can I Use for DevTools: Muestra información de compatibilidad al inspeccionar elementos
  • CanIUse Command Line: Permite consultas rápidas desde la consola

Integración con editores de código

Varios editores de código como VS Code tienen extensiones que muestran datos de Can I Use:

  • Can I Use Insights: Muestra información de compatibilidad al pasar el cursor sobre propiedades CSS
  • HTML Hints: Proporciona sugerencias basadas en datos de compatibilidad

Uso mediante npm

Para proyectos que utilizan herramientas de construcción modernas:

npm install caniuse-api --save-dev
// Ejemplo de uso en un script de construcción
const caniuse = require('caniuse-api');

if (!caniuse.isSupported('flexbox', 'ie 10')) {
  console.log('Flexbox no es compatible con IE10, añadiendo polyfill...');
  // Lógica para añadir polyfill
}

Alternativas y herramientas complementarias

Aunque Can I Use es la herramienta más popular, existen otras opciones:

  • MDN Browser Compatibility Data: La documentación de Mozilla incluye tablas de compatibilidad detalladas
  • Browserstack: Permite probar sitios web en navegadores reales
  • Browserslist: Define qué navegadores soportar en herramientas frontend
// Ejemplo de configuración de Browserslist en package.json
{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie <= 11"
  ]
}

Esta configuración se puede usar con herramientas como Autoprefixer para generar automáticamente código compatible.

Uso de Can I Use para tomar decisiones informadas

Can I Use nos ayuda a tomar decisiones basadas en datos sobre qué características implementar:

Análisis de audiencia

Si los datos de analítica muestran que el 95% de tus usuarios utilizan navegadores modernos, podrías implementar características avanzadas con fallbacks mínimos.

Soporte progresivo

Puedes implementar características avanzadas para navegadores modernos mientras mantienes una experiencia básica funcional para navegadores antiguos:

/* Ejemplo: diseño básico con fallback */
.container {
  /* Fallback para navegadores antiguos */
  overflow: hidden;
}

@supports (display: grid) {
  .container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 20px;
  }
}

Evaluación de riesgos

Can I Use te permite evaluar el riesgo de usar nuevas características:

  • Características estables: Alto soporte en navegadores (>95%)
  • Características emergentes: Soporte moderado (70-95%)
  • Características experimentales: Soporte limitado (<70%)

Limitaciones de Can I Use

Es importante entender que Can I Use tiene algunas limitaciones:

  • No muestra bugs específicos de implementación
  • No cubre todas las interacciones complejas entre características
  • La información puede no estar completamente actualizada para las versiones más recientes
  • No sustituye las pruebas reales en navegadores

Por ello, es recomendable complementar Can I Use con pruebas directas en los navegadores objetivo de tu proyecto.

Uso de datos de Can I Use en documentación

Una buena práctica es incluir información de compatibilidad en la documentación de tu proyecto:

<!-- 
  Feature: <dialog> element
  Compatibility: 
  - Chrome 37+
  - Firefox 98+
  - Safari 15.4+
  - Edge 79+
  - Not supported in IE
  
  See: https://caniuse.com/dialog
-->
<dialog id="myDialog">
  <h2>Título del diálogo</h2>
  <p>Contenido del diálogo...</p>
  <button id="closeDialog">Cerrar</button>
</dialog>

Esta documentación ayuda a otros desarrolladores a entender las limitaciones de compatibilidad del código.

Can I Use es una herramienta esencial que nos permite tomar decisiones informadas sobre qué características HTML implementar y cómo proporcionar alternativas adecuadas, complementando perfectamente las estrategias de fallback y el enfoque de mejora progresiva que veremos a continuación.

Enfoque "progressive enhancement"

El enfoque de mejora progresiva (progressive enhancement) es una filosofía de desarrollo web que prioriza la creación de experiencias digitales accesibles para todos los usuarios, independientemente del navegador o dispositivo que utilicen. Este método se basa en construir por capas, comenzando con un núcleo funcional básico y añadiendo mejoras graduales para navegadores más modernos.

Principios fundamentales de la mejora progresiva

La mejora progresiva se sustenta en tres capas principales que se construyen una sobre otra:

  • Contenido HTML: La base semántica y estructural accesible para todos
  • Presentación CSS: Mejoras visuales que se aplican cuando están disponibles
  • Comportamiento JavaScript: Funcionalidades avanzadas que enriquecen la experiencia
<!-- Ejemplo básico de mejora progresiva -->
<!-- 1. Capa de contenido: funciona en cualquier navegador -->
<div class="tarjeta-producto">
  <h2>Auriculares inalámbricos</h2>
  <p>Auriculares con cancelación de ruido y 20h de batería</p>
  <p class="precio">89,99€</p>
  <a href="/comprar/auriculares" class="boton-comprar">Comprar ahora</a>
</div>

A esta base HTML podemos añadir capas de mejora:

/* 2. Capa de presentación: mejoras visuales */
.tarjeta-producto {
  padding: 1rem;
  border: 1px solid #ddd;
}

/* Mejora para navegadores que soportan sombras */
@supports (box-shadow: 0 0 10px rgba(0,0,0,0.1)) {
  .tarjeta-producto {
    border: none;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
    border-radius: 8px;
  }
}
// 3. Capa de comportamiento: funcionalidades avanzadas
// Solo se ejecuta si el navegador soporta estas características
if ('IntersectionObserver' in window) {
  // Implementar animación de entrada cuando la tarjeta es visible
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.classList.add('visible');
        observer.unobserve(entry.target);
      }
    });
  });
  
  document.querySelectorAll('.tarjeta-producto').forEach(card => {
    observer.observe(card);
  });
}

Mejora progresiva vs. degradación elegante

Es importante distinguir entre estos dos enfoques complementarios:

  • Mejora progresiva: Comienza con lo básico y añade capas de mejora (de abajo hacia arriba)
  • Degradación elegante: Comienza con todas las características y proporciona alternativas cuando no están disponibles (de arriba hacia abajo)

La mejora progresiva suele considerarse un enfoque más robusto porque garantiza que el contenido básico siempre sea accesible, mientras que las mejoras se tratan como "extras" opcionales.

Implementación práctica de la mejora progresiva

Veamos cómo aplicar este enfoque en diferentes aspectos del desarrollo web:

Formularios con validación

<!-- Nivel básico: formulario funcional en cualquier navegador -->
<form action="/registro" method="post">
  <div>
    <label for="email">Email:</label>
    <input type="text" id="email" name="email" required>
  </div>
  <div>
    <label for="password">Contraseña:</label>
    <input type="password" id="password" name="password" required>
  </div>
  <button type="submit">Registrarse</button>
</form>

Mejora para navegadores modernos:

<!-- Mejora: usar tipos de input específicos y validación del lado del cliente -->
<form action="/registro" method="post" novalidate>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required 
           pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$">
    <span class="error" aria-live="polite"></span>
  </div>
  <!-- Resto del formulario... -->
</form>

<script>
  // Solo se ejecuta si el navegador soporta JavaScript
  const form = document.querySelector('form');
  
  if (form && 'validity' in document.createElement('input')) {
    form.addEventListener('submit', function(event) {
      const emailInput = document.getElementById('email');
      
      if (!emailInput.validity.valid) {
        event.preventDefault();
        // Mostrar mensaje de error personalizado
        document.querySelector('.error').textContent = 
          emailInput.validity.valueMissing ? 'Por favor, introduce un email' : 
          emailInput.validity.typeMismatch ? 'Por favor, introduce un email válido' : '';
      }
    });
  }
</script>

Diseño responsive con mejora progresiva

/* Base: diseño simple de una columna que funciona en cualquier navegador */
.contenedor {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.tarjetas {
  padding: 1rem;
}

.tarjeta {
  margin-bottom: 1rem;
  padding: 1rem;
  border: 1px solid #ddd;
}

/* Mejora: diseño de cuadrícula para navegadores modernos */
@supports (display: grid) {
  .tarjetas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
  }
  
  .tarjeta {
    margin-bottom: 0; /* Eliminar margen ya que grid usa gap */
  }
}

Imágenes responsivas

<!-- Base: imagen estándar que funciona en todos los navegadores -->
<img src="imagen-mediana.jpg" alt="Descripción de la imagen">

<!-- Mejora: imágenes responsivas con diferentes resoluciones -->
<picture>
  <!-- Formato WebP para navegadores que lo soportan -->
  <source 
    srcset="imagen-pequeña.webp 400w, 
            imagen-mediana.webp 800w, 
            imagen-grande.webp 1200w"
    sizes="(max-width: 600px) 400px, 
           (max-width: 1200px) 800px, 
           1200px"
    type="image/webp">
  
  <!-- Formato JPEG como fallback -->
  <source 
    srcset="imagen-pequeña.jpg 400w, 
            imagen-mediana.jpg 800w, 
            imagen-grande.jpg 1200w"
    sizes="(max-width: 600px) 400px, 
           (max-width: 1200px) 800px, 
           1200px">
  
  <!-- La imagen base que se mostrará si nada más funciona -->
  <img src="imagen-mediana.jpg" alt="Descripción de la imagen">
</picture>

Funcionalidades avanzadas con detección de características

// Ejemplo: implementación de un mapa interactivo con mejora progresiva

// 1. Versión básica: enlace a un mapa estático
const mapContainer = document.getElementById('mapa');
mapContainer.innerHTML = '<a href="https://maps.google.com/?q=Madrid,España">Ver ubicación en Google Maps</a>';

// 2. Mejora: mapa interactivo si el navegador lo soporta
if ('geolocation' in navigator && 'fetch' in window) {
  // Cargar la API de mapas dinámicamente
  const script = document.createElement('script');
  script.src = 'https://maps.example.com/api.js';
  script.onload = initMap;
  document.head.appendChild(script);
  
  function initMap() {
    // Inicializar mapa interactivo
    mapContainer.innerHTML = '';
    const map = new MapAPI.Map(mapContainer, {
      center: { lat: 40.416775, lng: -3.703790 },
      zoom: 12
    });
    // Añadir marcadores, controles, etc.
  }
}

Ventajas de la mejora progresiva

Este enfoque ofrece numerosos beneficios:

  • Accesibilidad universal: El contenido básico está disponible para todos los usuarios
  • Rendimiento optimizado: Las características avanzadas solo se cargan cuando son necesarias
  • Mantenimiento simplificado: La separación por capas facilita las actualizaciones
  • Compatibilidad a largo plazo: El sitio seguirá funcionando incluso en navegadores antiguos
  • SEO mejorado: Los motores de búsqueda pueden indexar el contenido base sin problemas

Implementación en proyectos reales

Para aplicar la mejora progresiva en proyectos reales, podemos seguir estas pautas:

1. Identificar funcionalidades críticas vs. mejoras

Antes de comenzar a desarrollar, clasifica las características de tu sitio:

  • Críticas: Contenido principal, navegación, formularios básicos
  • Mejoras: Animaciones, interacciones avanzadas, efectos visuales

2. Establecer una base HTML semántica

<!-- Estructura semántica básica -->
<header>
  <nav>
    <ul>
      <li><a href="/">Inicio</a></li>
      <li><a href="/productos">Productos</a></li>
      <li><a href="/contacto">Contacto</a></li>
    </ul>
  </nav>
</header>

<main>
  <section class="productos">
    <h1>Nuestros productos</h1>
    <!-- Contenido principal -->
  </section>
</main>

<footer>
  <p>&copy; 2023 Mi Empresa</p>
</footer>

3. Aplicar CSS con detección de características

/* Estilos base que funcionan en todos los navegadores */
.galeria-items {
  display: block;
}

.galeria-item {
  margin-bottom: 1rem;
}

/* Mejora: Flexbox para navegadores que lo soportan */
@supports (display: flex) {
  .galeria-items {
    display: flex;
    flex-wrap: wrap;
    margin: -0.5rem;
  }
  
  .galeria-item {
    flex: 0 0 calc(50% - 1rem);
    margin: 0.5rem;
  }
}

/* Mejora adicional: Grid para navegadores más modernos */
@supports (display: grid) {
  .galeria-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 1rem;
    margin: 0;
  }
  
  .galeria-item {
    margin: 0;
  }
}

4. Cargar JavaScript de forma condicional

<script>
  // Función para cargar scripts solo si se cumplen ciertas condiciones
  function cargarScriptSiSeSoporta(caracteristica, ruta) {
    if (caracteristica in window) {
      const script = document.createElement('script');
      script.src = ruta;
      document.head.appendChild(script);
      return true;
    }
    return false;
  }
  
  // Cargar características avanzadas solo si están disponibles
  if (!cargarScriptSiSeSoporta('IntersectionObserver', '/js/lazy-loading.js')) {
    // Fallback: cargar todas las imágenes inmediatamente
    document.querySelectorAll('img[data-src]').forEach(img => {
      img.src = img.dataset.src;
    });
  }
</script>

Herramientas para facilitar la mejora progresiva

Varias herramientas pueden ayudarnos a implementar este enfoque:

  • Modernizr: Biblioteca que detecta características del navegador y añade clases CSS
  • Feature-detect: Técnicas nativas para detectar soporte de características
  • PostCSS: Procesador CSS que puede añadir prefijos y fallbacks automáticamente
  • Babel: Transpilador que convierte JavaScript moderno en versiones compatibles
<!-- Ejemplo de uso de Modernizr -->
<script src="modernizr.js"></script>

<style>
  /* Estilos basados en capacidades detectadas */
  .mi-elemento {
    background: #f0f0f0;
  }
  
  .cssgradients .mi-elemento {
    background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);
  }
</style>

Mejora progresiva en la era de las SPA

Incluso en aplicaciones de página única (SPA), podemos aplicar mejora progresiva:

<!-- Base: versión sin JavaScript -->
<noscript>
  <p>Esta aplicación requiere JavaScript para funcionar correctamente. 
     Por favor, <a href="/version-estatica">accede a la versión estática</a>.</p>
</noscript>

<!-- Contenedor para la aplicación -->
<div id="app">
  <!-- Contenido inicial que se verá antes de que cargue JavaScript -->
  <header>
    <h1>Mi Aplicación</h1>
  </header>
  <main>
    <p>Cargando contenido...</p>
  </main>
</div>

<!-- Cargar la aplicación con detección de características -->
<script>
  // Verificar características mínimas necesarias
  if ('Promise' in window && 'fetch' in window && 'querySelector' in document) {
    // Cargar la aplicación moderna
    const script = document.createElement('script');
    script.src = '/js/app.modern.js';
    document.head.appendChild(script);
  } else {
    // Cargar versión simplificada con polyfills
    const script = document.createElement('script');
    script.src = '/js/app.legacy.js';
    document.head.appendChild(script);
  }
</script>

Equilibrio entre mejora progresiva y experiencia de usuario

Es importante encontrar un equilibrio entre la compatibilidad universal y la experiencia de usuario moderna:

  • No sacrifiques la experiencia principal por compatibilidad con navegadores extremadamente antiguos
  • Establece una línea base razonable de navegadores a soportar (por ejemplo, últimos 2 años)
  • Utiliza analíticas para entender qué navegadores usan realmente tus visitantes
  • Considera el contexto de tu proyecto (una aplicación interna corporativa vs. un sitio público)

La mejora progresiva no significa que todos los usuarios deban tener exactamente la misma experiencia, sino que todos deben poder acceder al contenido y funcionalidad esencial, mientras que aquellos con navegadores más modernos pueden disfrutar de una experiencia mejorada.

Al adoptar este enfoque, creamos sitios web más resilientes, accesibles y sostenibles a largo plazo, preparados para funcionar en el ecosistema diverso de dispositivos y navegadores que caracteriza la web actual.

Aprende HTML online

Otras lecciones de HTML

Accede a todas las lecciones de HTML y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a HTML y certifícate

Ejercicios de programación de HTML

Evalúa tus conocimientos de esta lección Compatibilidad con navegadores con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender las diferencias entre navegadores y motores de renderizado.
  • Aprender a implementar estrategias de fallback para características no soportadas.
  • Utilizar herramientas como Can I Use para verificar compatibilidad.
  • Aplicar el enfoque de mejora progresiva en el desarrollo web.
  • Identificar buenas prácticas para mantener la compatibilidad y accesibilidad en proyectos reales.