El Desafío: Romper las Limitaciones del PDF Estático
Los currículums en PDF presentan una contradicción fundamental: son estáticos en un mundo profesional dinámico. No son indexables por buscadores, requieren descarga para visualización, y cada actualización implica redistribución manual. La solución moderna exige un CV web responsive que funcione como página interactiva y documento imprimible simultáneamente.
El desafío técnico consiste en crear una experiencia que mantenga perfección visual en A4 al imprimir, mientras ofrece navegación fluida en dispositivos móviles y escritorio. Esto requiere arquitectura dual: una para pantalla y otra para impresión.
Stack Técnico
La solución se construyó sobre tecnologías que priorizan performance y SEO:
- Astro 5.16: Framework con arquitectura Islands que genera HTML estático, logrando cero JavaScript en cliente por defecto
- Tailwind CSS 3.3: Sistema de utilidades para diseño responsive con configuración personalizada de colores y efectos glassmorphism
- Vercel Edge Functions: Deployment con CDN global para tiempos de carga <100ms
- Google Analytics 4: Tracking de interacciones sin comprometer performance
La ausencia deliberada de React/Vue reduce el bundle a <5KB de JS, maximizando Core Web Vitals.
Ingeniería de la Solución
Diseño Responsive vs. Print Perfect
El mayor desafío técnico fue garantizar que el diseño glassmorphism con degradados y efectos blur se tradujera correctamente a papel. La estrategia utiliza media queries print específicas:
/* Glassmorphism para pantalla */
.glass {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Conversión a bordes sólidos para impresión */
@media print {
.glass {
background: #ffffff;
backdrop-filter: none;
border: 1px solid #e5e7eb;
}
/* Forzar página A4 sin márgenes adicionales */
@page {
size: A4;
margin: 15mm;
}
/* Evitar ruptura de secciones críticas */
.no-break {
page-break-inside: avoid;
}
/* Ocultar elementos interactivos */
nav,
.cta-buttons,
footer {
display: none !important;
}
}
Este enfoque asegura que los degradados violeta-cian (#5706f3 → #24c1fb) se conviertan en bordes grises al imprimir, evitando desperdicio de tinta y mejorando legibilidad.
Arquitectura de Datos: Separación de Contenido
La arquitectura modular separa datos de presentación mediante componentes Astro reutilizables. El contenido se estructura en archivos .astro que actúan como fuente de verdad:
// src/data/experiencia.js
export const experienciaLaboral = [
{
puesto: "Asistente Contable",
empresa: "Estudio MGAM",
periodo: "2022 - Presente",
responsabilidades: [
"Conciliación bancaria y registro de operaciones diarias",
"Preparación de reportes mensuales para análisis gerencial",
"Gestión de facturación electrónica con AFIP",
],
tecnologias: ["Excel", "Tango Gestión", "AFIP"],
},
{
puesto: "Freelance - Marketing Digital",
empresa: "LeoMartinK Studios",
periodo: "2020 - Presente",
responsabilidades: [
"Desarrollo de sitios web con Astro y WordPress",
"Implementación de estrategias SEO y Google Analytics",
"Diseño de identidad visual y brand books",
],
tecnologias: ["Astro", "WordPress", "Tailwind CSS", "Google Ads"],
},
];
Los componentes Astro consumen estos datos mediante importación directa:
---
// src/components/sections/Experiencia.astro
import { experienciaLaboral } from '@/data/experiencia.js';
---
<section id="experiencia" class="py-20 bg-bg-secondary">
<div class="max-w-6xl mx-auto px-4">
<h2 class="text-4xl font-bold mb-12">Experiencia Laboral</h2>
{experienciaLaboral.map((trabajo) => (
<article class="glass p-6 rounded-lg mb-6 no-break">
<h3 class="text-2xl font-bold text-blue-400">{trabajo.puesto}</h3>
<p class="text-muted">{trabajo.empresa} | {trabajo.periodo}</p>
<ul class="mt-4 space-y-2">
{trabajo.responsabilidades.map((tarea) => (
<li class="text-muted">• {tarea}</li>
))}
</ul>
<div class="flex gap-2 mt-4">
{trabajo.tecnologias.map((tech) => (
<span class="px-3 py-1 rounded-full bg-blue-500/20 border border-blue-500/50 text-sm">
{tech}
</span>
))}
</div>
</article>
))}
</div>
</section>
Esta separación permite actualizar experiencias editando un solo archivo JavaScript sin tocar HTML, facilitando mantenimiento a largo plazo.
Accesibilidad: HTML Semántico y ARIA
El proyecto implementa WCAG 2.1 Level AA mediante estructura semántica:
<main role="main" aria-label="Curriculum Vitae de Leonardo Galeano">
<section aria-labelledby="hero-heading">
<h1 id="hero-heading">Leonardo Galeano</h1>
<p>Asistente Contable & Marketing Digital</p>
</section>
<nav aria-label="Navegación principal" class="fixed top-0 z-50">
<ul role="menubar">
<li role="none">
<a href="#experiencia" role="menuitem" aria-current="page">
Experiencia
</a>
</li>
</ul>
</nav>
<article class="glass" aria-label="Proyecto destacado">
<h3>Consultoría de Branding</h3>
<a href="/proyecto" aria-label="Ver caso de estudio completo">
Ver Caso de Estudio →
</a>
</article>
</main>
Los puntos clave incluyen:
- Landmarks ARIA (
role="main",aria-label) para navegación por lectores de pantalla - Contraste mínimo 4.5:1 entre texto y fondos (verificado con Lighthouse)
- Focus visible con anillos azules (
focus:ring-2 ring-blue-400) en elementos interactivos - Orden lógico de headings (h1 → h2 → h3) sin saltos
Conclusión: Performance y Escalabilidad
El resultado final alcanza Lighthouse Score 100/100 en las cuatro métricas:
- Performance: 100 (FCP <0.8s, LCP <1.2s)
- Accessibility: 100 (navegación por teclado, contraste óptimo)
- Best Practices: 100 (HTTPS, sin errores de consola)
- SEO: 100 (meta tags, sitemap.xml, robots.txt)
La arquitectura modular permite escalar agregando nuevas secciones sin refactorización. El patrón de separación contenido/presentación facilita traducciones futuras mediante archivos experiencia.es.js / experiencia.en.js.
El tiempo de build en Vercel es <30 segundos, con invalidación de caché automática ante commits. El CV impreso mantiene fidelidad visual 1:1 con la versión digital.
Repositorio Showcase: github.com/LeoMartinK/cv-engine-showcase
Demo en vivo: cv-leogaleano.vercel.app