Diseño responsivo
Diseño responsivo
El diseño responsivo permite que una aplicación web se adapte dinámicamente al tamaño del dispositivo desde el que se visualiza.Hoy en día una misma aplicación debe funcionar correctamente en:
- 📱 Móviles
- 📲 Tablets
- 💻 Portátiles
- 🖥️ Escritorio
La clave no es hacer varias webs, sino una única interfaz flexible.
Diferencias entre responsivo y adaptativo
🔹 Diseño Responsivo (Responsive Web Design)
- Usa CSS flexible.
- Se basa en media queries.
- El layout se adapta de forma fluida.
- No depende de dispositivos concretos.
- Es el enfoque moderno.
Cambia progresivamente según el ancho del viewport.
🔹 Diseño Adaptativo (Adaptive Design)
- Se crean varios layouts fijos.
- Cada layout está pensado para un rango de dispositivos.
- El servidor o el navegador decide cuál cargar.
- Es menos flexible.
- Mayor mantenimiento.
No es fluido, salta entre versiones predefinidas.
¿Qué es y en qué consiste el diseño responsivo?
El diseño responsivo se basa en tres pilares:
1️⃣ Layout flexible
Uso de porcentajes, flexbox o grid en lugar de medidas fijas.
2️⃣ Imágenes flexibles
Las imágenes deben escalar con el contenedor.
|
|
3️⃣ Media Queries
Permiten aplicar estilos según el ancho del dispositivo.
|
|
Tailwind y sistema mobile-first
Tailwind trabaja con enfoque mobile-first.
- Primero se diseñan estilos para móvil.
- Después se añaden variantes para pantallas mayores.
Ejemplo:
|
|
Explicación:
- text-base → móvil
- md:text-xl → desde 768px
- lg:text-3xl → desde 1024px
La clase sin prefijo siempre corresponde al tamaño más pequeño.
Puntos de ruptura (Breakpoints)
En Tailwind por defecto:
- sm → 640px
- md → 768px
- lg → 1024px
- xl → 1280px
- 2xl → 1536px
Ejemplo práctico:
|
|
En móvil:
- Se muestran en columna.
En escritorio:
- Se muestran en fila.
Ejemplo en nuestra aplicación
Caso típico en nuestro proyecto:
Header con logo + título + botones login/register.
En escritorio:
- Todo en horizontal.
En móvil:
- Se ocultan los botones.
- Aparece botón hamburguesa.
- Quitamos el título
- Lo ponemos en una columa
- Ejemplo simplificado:
Botón hamburguesa
El botón hamburguesa se utiliza para:
- Ahorrar espacio en móvil.
- Mostrar/ocultar navegación.
- Mantener la interfaz limpia.
Estructura básica:
|
|
Puede combinarse con:
- hidden / block
- flex / absolute
- peer / peer-checked
- Alpine o Vue para control dinámico
Importante: el diseño responsivo no es opcional. Es un requisito estructural en cualquier aplicación web moderna.
1. Proceso de creación: clase peer peer-checked mantener hermanos con el id
Permite que un input controle el estado visual de sus hermanos posteriores.
Código mínimo
|
|
Clases imprescindibles
peer→ convierte al input en referencia.peer-checked:*→ aplica estilos cuando el checkbox está marcado.sr-only→ oculta visualmente el input pero mantiene accesibilidad.
Regla técnica: el elemento afectado debe ser hermano posterior del peer.
—.
2. menu oculto y controlado visible con peer-checked
El menú existe en el DOM pero se muestra dinámicamente.
|
|
Clases clave
opacity-0→ estado inicial oculto.peer-checked:opacity-100→ visible cuando está activo.transition-opacity duration-300→ animación suave.
3. contenedor relative y menu absolute para colocar el menu
Permite posicionar el menú respecto a su botón.
|
|
relative→ referencia de posicionamiento.absolute→ saca el menú del flujo normal.left-full→ lo coloca a la derecha.top-0→ alineación vertical.
Sin relative, el menú se posiciona respecto al viewport.
4. Overlay para cerrar al hacer click fuera
Un segundo label con el mismo id permite cerrar el menú sin JavaScript.
|
|
fixed→ posición respecto al viewport.inset-0→ ocupa toda la pantalla.bg-black/40→ oscurece el fondo.pointer-events-none→ no bloquea cuando está oculto.peer-checked:pointer-events-auto→ activa interacción.
Al hacer click en el overlay, el checkbox se desmarca.
Resumen: Estructura final
peercontrola estado.peer-checkedmodifica hermanos.relative + absoluteposiciona el menú.- Overlay con
fixed inset-0permite cerrar sin JS. - Cada dropdown usa su propio checkbox.
5. Otro peer para logout sin javascript
Cada desplegable necesita su propio checkbox independiente para no interferir con el menú hamburguesa.
*Código:
|
|
peer→ controla el estado del dropdown.peer-checked:*→ activa visibilidad y animación.relative→ referencia para posicionamiento.absolute top-full→ menú aparece debajo.transition-all→ anima opacity y transform.peer-checked:rotate-180→ rota la flecha al abrir.
Importante:
Cada menú (burger y logout) debe tener un id distinto y su propio peer, ya que cada checkbox controla únicamente a sus hermanos posteriores.
Posible código final
<!--Para el buttron burguer, usaremos este checkbox-->
{{-- 3) Panel desplegable --}}
@guest
<div class="relative">
<input type="checkbox" class="peer sr-only" id="burguer_button">
<label for="burguer_button">
<img class="w-8 h-8 object-containt" src="{{asset("/images/burguer.png")}}" alt="">
</label>
<label for="burguer_button"
class="fixed inset-0 bg-black/40
opacity-0 pointer-events-none
peer-checked:opacity-100
peer-checked:pointer-events-auto
transition-opacity duration-300">
</label>
<div class="opacity-0
peer-checked:opacity-100
transition-all duration-300 ease-out
peer-checked:flex absolute bg-white p-2 flex-col left-9 top-4 transition rounded rounded-sm space-y-2">
<a class="flex-1" href="{{ route('login') }}">
<button class="btn btn-sm btn-primary w-full" type="button">
Login
</button>
</a>
<a class="flex-1" href="{{ route('register') }}">
<button class="btn btn-sm btn-primary w-full" type="button">
Register
</button>
</a>
</div>
</div>
@endguest
@auth
<div class="relative">
<input type="checkbox" class="peer sr-only" id="user_menu">
<label for="user_menu"
class="cursor-pointer text-green-800 text-xl font-semibold">
{{ auth()->user()->name }}
<!-- Flecha -->
<svg class="w-4 h-4 transition-transform duration-300
peer-checked:rotate-180"
fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
d="M19 9l-7 7-7-7" />
</svg>
</label>
<div class="absolute left-0 top-full mt-2
bg-white p-3 rounded shadow flex flex-col
opacity-0 scale-95
peer-checked:opacity-100
peer-checked:scale-100
transition-all duration-300 ease-out">
<form action="{{ route('logout') }}" method="POST">
@csrf
<button class="btn btn-primary w-full" type="submit">
Logout
</button>
</form>
</div>
</div>
@endauth