Saltar al contenido

📑 Tercera tanda de ejercicios‑plantilla (nivel medio) – Código incluido


1 · Banner “cookies” accesible y persistente

Objetivo: dialog, atributos ARIA y localStorage.

cookies.html

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Banner de cookies</title>
<style>
  body{font-family:system-ui;margin:0}
  dialog{position:fixed;inset:0 auto 0 0;width:100
  dialog[open]{animation:slide .4s}
  @keyframes slide{from{transform:translateY(100
  button{margin-left:1rem;padding:.4rem 1rem;border:none;border-radius:4px;cursor:pointer}
</style>
</head>
<body>
  <header><h1>Mi Web</h1></header>

  <dialog id="banner" aria-label="Aviso de cookies">
    <span>Usamos cookies para mejorar la experiencia.</span>
    <div>
      <button id="ok">Aceptar</button>
      <button id="no">Rechazar</button>
    </div>
  </dialog>

<script>
  const banner = document.getElementById('banner');
  if(localStorage.getItem('cookies')===null) banner.show();
  document.getElementById('ok').onclick = ()=>{localStorage.setItem('cookies','yes');banner.close()};
  document.getElementById('no').onclick = ()=>{localStorage.setItem('cookies','no');banner.close()};
</script>
</body>
</html>

2 · Tabla filtrable con la pseudoclase :is()

Objetivo: selectores modernos y estilo condicional sin JS.

tabla‑filtrable.html

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Filtra por estado</title>
<style>
  body{font-family:system-ui;margin:2rem}
  label{margin-right:.8rem}
  table{border-collapse:collapse;margin-top:1rem;width:320px}
  th,td{border:1px solid #999;padding:.3rem;text-align:left}
  /* Oculta filas cuyo data-state ≠ radio marcado */
  tbody tr{display:table-row}
  input[name=estado]:checked ~ table tbody tr:not([data-state="todos"])  {display:none}
  input[name=estado="activos"]:checked ~ table tbody tr[data-state="activo"]{display:table-row}
  input[name=estado="pendientes"]:checked ~ table tbody tr[data-state="pendiente"]{display:table-row}
</style>
</head>
<body>
  <!-- Controles -->
  <label><input type="radio" name="estado" value="todos" checked>Todos</label>
  <label><input type="radio" name="estado" value="activos">Activos</label>
  <label><input type="radio" name="estado" value="pendientes">Pendientes</label>

  <!-- Datos -->
  <table>
    <thead><tr><th>Tarea</th><th>Estado</th></tr></thead>
    <tbody>
      <tr data-state="activo"><td>Diseñar logo</td><td>Activo</td></tr>
      <tr data-state="pendiente"><td>Prototipo móvil</td><td>Pendiente</td></tr>
      <tr data-state="activo"><td>Reunión cliente</td><td>Activo</td></tr>
    </tbody>
  </table>
</body>
</html>

3 · Ventana modal centrada solo con CSS

Objetivo: práctica de :target, Flexbox y propiedades backdrop-filter.

modal.html

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Modal CSS puro</title>
<style>
  body{font-family:system-ui;margin:0}
  /* Capa semitransparente */
  .overlay{position:fixed;inset:0;background:#0008;backdrop-filter:blur(2px);display:none;justify-content:center;align-items:center}
  .overlay:target{display:flex}
  .box{background:#fff;border-radius:8px;padding:2rem;max-width:300px;text-align:center}
  a.btn{display:inline-block;margin:1rem 0;padding:.4rem 1rem;background:#4f46e5;color:#fff;border-radius:4px;text-decoration:none}
</style>
</head>
<body>
  <a href="#modal" class="btn">Abrir modal</a>

  <div id="modal" class="overlay" role="dialog" aria-modal="true">
    <div class="box">
      <h2>¡Hola!</h2>
      <p>Este modal se cierra sin JS.</p>
      <a href="#" class="btn">Cerrar</a>
    </div>
  </div>
</body>
</html>

4 · Calendario mini con CSS Grid

Objetivo: practicar grid-template-areas y variables personalizables.

calendario.html

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Calendario mayo 2025</title>
<style>
  :root{--h:#4f46e5;--w:120px}
  body{font-family:system-ui;display:flex;justify-content:center}
  .cal{display:grid;grid-template-columns:repeat(7,var(--w));grid-auto-rows:80px;border:2px solid var(--h)}
  .cal > *{display:flex;align-items:center;justify-content:center;border:1px solid #ddd}
  .head{background:var(--h);color:#fff;font-weight:700}
</style>
</head>
<body>
  <div class="cal">
    <!-- Encabezados -->
    <div class="head">Lun</div><div class="head">Mar</div><div class="head">Mié</div>
    <div class="head">Jue</div><div class="head">Vie</div><div class="head">Sáb</div><div class="head">Dom</div>

    <!-- Días mayo 2025 empieza jueves -->
    <div></div><div></div><div></div> <!-- espacio Lun‑Mié -->
    <!-- 1 → 31 -->
    <!-- Fila 1 -->
    <div>1</div><div>2</div><div>3</div><div>4</div>
    <!-- Fila 2 -->
    <div>5</div><div>6</div><div>7</div><div>8</div><div>9</div><div>10</div><div>11</div>
    <!-- Fila 3 -->
    <div>12</div><div>13</div><div>14</div><div>15</div><div>16</div><div>17</div><div>18</div>
    <!-- Fila 4 -->
    <div>19</div><div>20</div><div>21</div><div>22</div><div>23</div><div>24</div><div>25</div>
    <!-- Fila 5 -->
    <div>26</div><div>27</div><div>28</div><div>29</div><div>30</div><div>31</div><div></div>
  </div>
</body>
</html>

5 · Comparador de imágenes “antes/después”

Objetivo: usar <input type="range"> y clip-path para crear un “slider” visual sin librerías externas.

comparador.html

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Comparador imagen</title>
<style>
  body{font-family:system-ui;display:flex;flex-direction:column;align-items:center;margin:2rem}
  .wrap{position:relative;width:480px;height:320px;overflow:hidden}
  .wrap img{position:absolute;inset:0;width:100
  .after{clip-path:inset(0 50
  input[type=range]{width:480px;margin-top:1rem}
</style>
</head>
<body>
  <h1>Antes / Después</h1>
  <div class="wrap">
    <img src="after.jpg" alt="Después" class="after">
    <img src="before.jpg" alt="Antes">
  </div>
  <input type="range" min="0" max="100" value="50" aria-label="Deslizador comparación">

<script>
  const range=document.querySelector('input[type=range]');
  const after=document.querySelector('.after');
  range.addEventListener('input',e=>{
    const v=100-e.target.value;                 // invertido para clip‑path
    after.style.clipPath=`inset(0 ${v}
  });
</script>
</body>
</html>

🔍 Cómo practicar con esta ronda

  1. Comprende qué técnica nueva usa cada ejemplo (dialog‑&‑localStorage, filtros con atributos, :target, Grid, clip‑path…).
  2. Adapta: cambia colores, añade más filas, ajusta la transición; observa qué rompe y cómo lo arreglas.
  3. Valida y perfila la accesibilidad revisando tabindex, etiquetas ARIA y contraste.
  4. Versiona: súbelos a un repositorio aparte (“ejercicios‑3”) y crea ramas para cada modificación.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Información básica sobre protección de datos Ver más

  • Responsable: Tomas Gonzalez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento:  No se ceden o comunican datos a terceros para prestar este servicio.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

¿Atascado con tu proyecto? Presupuesto GRATIS

X
error: Content is protected !!
Este sitio web utiliza cookies, si necesitas más información puedes visitar nuestra política de privacidad    Ver
Privacidad