Documentación completa del sistema de diseño, arquitectura CSS y componentes del sitio web Python CDMX
Esta guía documenta el sistema de diseño del sitio web de Python CDMX, construido con MkDocs Material siguiendo una arquitectura variables-first y principios de Material Design.
- Filosofía de Diseño
- Arquitectura CSS
- Sistema de Variables
- Componentes
- Sistema Unificado de Tarjetas
- Layout y Responsive
- Buenas Prácticas
- Troubleshooting
- Variables-First - Todo color, espaciado y transición debe usar variables CSS
- Mobile-First - Diseño responsive con breakpoint único en 768px
- Sistema Unificado - Componentes reutilizables con estructura consistente
- Zero
!important- Arquitectura CSS limpia con especificidad apropiada - Compatibilidad Automática - Modo claro/oscuro usando variables de MkDocs Material
"Vine por el código, me quedé por la comunidad"
Este lema es central y se destaca en todo el sitio usando el componente .community-motto.
El archivo docs/css/custom.css (~1466 líneas) está organizado en 13 secciones lógicas:
- Variables CSS personalizadas - 18+ variables centralizadas
- Sección Hero - Página principal y logos
- Sistema de botones - 4 variantes de botones
- Tarjetas y grillas - Componentes base
- Tarjetas de voluntarios - Sistema unificado
- Tarjetas de comunidades aliadas - Partners y alianzas
- Enlaces de comunidad - Redes sociales con colores de marca
- Lema de la comunidad - Componente destacado
- Navegación y secciones especiales - Navegación rápida
- Iconografía - FontAwesome 6.4.0
- Animaciones - Transiciones y efectos
- Media queries responsivas - Breakpoint único
- Utilidades y helpers - Clases auxiliares
# mkdocs.ymltheme:
palette:
- scheme: defaultprimary: greenaccent: green
- scheme: slateprimary: greenaccent: greenextra_css:
- css/custom.css:root {
/* Colores principales */--python-green:#4CAF50;
--python-green-dark:#45a049;
--python-white:#ffffff;
/* Radios y espaciado */--button-radius:3.125rem;
--card-radius:0.75rem;
/* Transiciones estándar */--transition-base: all 0.3s ease;
--transition-smooth: all 0.3scubic-bezier(0.4,0,0.2,1);
}:root {
--telegram-color:#0088cc;
--meetup-color:#ed1c40;
--youtube-color:#ff0000;
--github-color:#333333;
--instagram-color:#e4405f;
--linkedin-color:#0077b5;
}:root {
/* Colores de badges */--badge-ambassador:#2E7D32;
--badge-organizer:#1565C0;
--badge-production:#E65100;
--badge-host:#6A1B9A;
--badge-technical:#37474F;
--badge-support:#3E2723;
--badge-global:#AD1457;
--badge-strategic:#283593;
}:root {
/* Colores de años y especialización */--year-2024-color:#2196F3;
--year-2024-hover:#1976D2;
--year-2023-color:#FF9800;
--year-2023-hover:#F57C00;
}.nuevo-componente {
background:var(--python-green);
border-radius:var(--card-radius);
transition:var(--transition-base);
color:var(--python-white);
/* Usar variables de badges para roles */border-left:4px solid var(--badge-technical);
}
.nuevo-componente:hover {
background:var(--python-green-dark);
transform:translateY(-2px);
}.upcoming-btn,
.btn,
.btn-primary,
.participation-carda,
.year-carda {
background:var(--python-green);
color:var(--python-white);
padding:0.75rem1.5rem;
border-radius:var(--button-radius);
transition:var(--transition-base);
}Uso:
<ahref="/meetups/" class="btn-primary">Ver Todos los Meetups</a>.btn-nav {
background: transparent;
color:var(--md-default-fg-color--light);
border:1px solid var(--md-default-fg-color--lightest);
padding:0.5rem1rem;
border-radius:1.5rem;
min-width:140px;
}Uso:
<ahref="/meetups/2025/" class="btn-nav"><iclass="fas fa-calendar"></i> Meetups 2025
</a><divclass="community-links"><ahref="https://t.me/PythonCDMX" class="community-link telegram"><iclass="fab fa-telegram"></i> Telegram
</a><ahref="https://www.meetup.com/python-mexico" class="community-link meetup"><iclass="fas fa-calendar"></i> Meetup
</a><ahref="https://www.youtube.com/@PythonMexico" class="community-link youtube"><iclass="fab fa-youtube"></i> YouTube
</a></div>.community-links {
display: grid;
grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
gap:1rem;
margin:2rem0;
}
.community-link.telegram:hover {
background:var(--telegram-color);
color: white;
}
.community-link.meetup:hover {
background:var(--meetup-color);
color: white;
}<divclass="participation-grid"><divclass="participation-card participation-ponente"><h3><iclass="fas fa-microphone"></i> Ser Ponente</h3><p>Comparte tu conocimiento con la comunidad Python CDMX...</p><ahref="/comunidad/ponentes" class="btn-primary">Proponer Charla</a></div><divclass="participation-card participation-voluntario"><h3><iclass="fas fa-hands-helping"></i> Ser Voluntario</h3><p>Ayuda a organizar eventos y apoyar a la comunidad...</p><ahref="/comunidad/voluntarios/" class="btn-primary">Únete al Equipo</a></div></div>.participation-grid {
display: grid;
grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
gap:1.5rem;
margin:2rem0;
}
.participation-card {
padding:2rem;
min-height:200px;
text-align: center;
border-radius:var(--card-radius);
background:var(--md-default-bg-color);
border:1px solid var(--md-default-fg-color--lightest);
}
/* Especialización por tipo */
.participation-ponente {
border-left:4px solid var(--python-green);
}
.participation-voluntario {
border-left:4px solid var(--year-2024-color);
}.community-motto {
background:var(--md-default-bg-color);
border:1px solid var(--md-default-fg-color--lightest);
border-radius:var(--card-radius);
font-size:1.5rem;
font-style: italic;
font-weight:300;
margin:2rem auto;
max-width:600px;
padding:2rem;
position: relative;
text-align: center;
color:var(--md-primary-fg-color);
}
.community-motto::before,
.community-motto::after {
content:'"';
font-size:3rem;
color:var(--python-green);
position: absolute;
}
.community-motto::before {
top:-10px;
left:20px;
}
.community-motto::after {
bottom:-40px;
right:20px;
}<divclass="communities-grid"><divclass="community-card"><imgsrc="/images/comunidades/partner-logo.png" alt="Community Partner"><h4><iclass="fas fa-users"></i> Nombre de la Comunidad</h4><p>Descripción breve de la comunidad aliada</p></div></div>.communities-grid {
display: grid;
grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
gap:1.5rem;
margin:2rem0;
}
.community-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding:2rem1.5rem;
background:var(--md-default-bg-color);
border:2px solid var(--md-default-fg-color--lightest);
border-radius:var(--card-radius);
transition:var(--transition-smooth);
position: relative;
overflow: hidden;
}
.community-card::before {
content:'';
position: absolute;
top:0;
left:-100%;
width:100%;
height:100%;
background:linear-gradient(90deg, transparent,rgba(76,175,80,0.1), transparent);
transition:var(--transition-smooth);
}
.community-card:hover::before {
left:100%;
}
.community-cardimg {
width:120px;
height:120px;
border-radius:50%;
object-fit: cover;
margin-bottom:1rem;
border:3px solid var(--md-default-fg-color--lightest);
transition:var(--transition-base);
}
.community-card:hoverimg {
border-color:var(--python-green);
transform:scale(1.05);
}Voluntarios y ponentes usan la misma estructura.volunteer-card pero con contenido diferenciado:
- Voluntarios: Enfoque en contribuciones comunitarias y roles organizacionales
- Ponentes: Enfoque en especialidades técnicas y charlas recientes
### Nombre de la Persona {.volunteer-header}
<divclass="volunteer-card"><divclass="card-header"><divclass="card-info"><h3class="card-title">Nombre de la Persona</h3><pclass="card-subtitle">Rol/Empresa descripción</p><divclass="badges-container"><!-- Para Voluntarios --><spanclass="badge ambassador">Embajador</span><spanclass="badge organizer">Organizador</span><!-- Para Ponentes --><spanclass="badge technical">DevOps</span><spanclass="badge development">Desarrollo</span></div></div><divclass="avatar-section"><imgsrc="/images/ponentes/avatar.jpg" alt="Persona" class="volunteer-avatar"><divclass="social-icons"><ahref="#" class="social-icon linkedin"><iclass="fab fa-linkedin"></i></a><ahref="#" class="social-icon github"><iclass="fab fa-github"></i></a></div></div></div><divclass="card-content"><divclass="card-role"><spanclass="role-title">ESPECIALIDADES TÉCNICAS</span><spanclass="role-description">Lista de especialidades técnicas</span><strong>Charlas recientes:</strong><ul><li>Contenido item 1</li><li>Contenido item 2</li></ul></div></div></div>.volunteer-card {
background:var(--md-default-bg-color);
border:1px solid var(--md-default-fg-color--lightest);
border-radius:var(--card-radius);
padding:2rem;
margin-bottom:2rem;
transition:var(--transition-base);
}
.volunteer-card .card-header {
display: grid;
grid-template-columns:1fr auto;
gap:2rem;
align-items: start;
margin-bottom:1.5rem;
}
.volunteer-card .volunteer-avatar {
width:100px;
height:100px;
border-radius:50%;
object-fit: cover;
border:3px solid var(--md-primary-fg-color--light);
transition:var(--transition-base);
}.volunteer-card .badge {
padding:0.125rem0.5rem;
border-radius:0.75rem;
font-size:0.625rem;
font-weight:500;
text-transform: uppercase;
letter-spacing:0.03em;
}
.volunteer-card .badge.ambassador {
background:rgba(76,175,80,0.15);
color:var(--badge-ambassador);
border:1px solid rgba(76,175,80,0.3);
}
.volunteer-card .badge.technical {
background:rgba(96,125,139,0.15);
color:var(--badge-technical);
border:1px solid rgba(96,125,139,0.3);
}<spanclass="role-title">COMMUNITY ROLE TITLE</span><spanclass="role-description">Community role description</span><strong>Contribuciones principales:</strong><ul><li>Organización y planeación de meetups</li><li>Representación en otros espacios</li></ul><spanclass="role-title">ESPECIALIDADES TÉCNICAS</span><spanclass="role-description">DevOps, Docker, Kubernetes, CI/CD</span><strong>Charlas recientes:</strong><ul><li><ahref="/meetups/2025/202507-julio/">"Título de la charla" (Julio 2025)</a></li></ul>- Voluntarios:
/images/voluntarios/filename.jpg - Ponentes:
/images/ponentes/filename.jpg - Comunidades:
/images/comunidades/filename.png
.speaker-photoimg {
width:160px;
height:160px;
/* SIN border-radius - rectangulares */border:2px solid var(--md-default-fg-color--lightest);
}.volunteer-avatar {
width:100px;
height:100px;
border-radius:50%; /* Circulares */border:3px solid var(--md-primary-fg-color--light);
}Mobile: < 768pxDesktop: ≥ 768px
@media (max-width:768px) {
.participation-grid,
.year-cards {
grid-template-columns:1fr;
gap:1rem;
}
.community-links {
justify-content: center;
gap:0.75rem;
}
.volunteer-card .card-header {
grid-template-columns:1fr;
text-align: center;
gap:1.5rem;
}
.speaker-photoimg {
width:120px;
height:120px;
}
}grid-template-columns:repeat(auto-fit,minmax(280px,1fr));/* Participación */
.participation-grid {
grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
}
/* Enlaces de comunidad */
.community-links {
grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
}
/* Comunidades aliadas */
.communities-grid {
grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
}/* ✅ Correcto */
.nuevo-componente {
background:var(--python-green);
color:var(--badge-technical);
border-radius:var(--card-radius);
transition:var(--transition-base);
margin:var(--space-md);
}
/* ❌ Incorrecto */
.nuevo-componente {
background:#4CAF50;
color:#37474F;
border-radius:0.75rem;
transition: all 0.3s ease;
margin:1.5rem;
}/* ✅ Correcto - Usar clases existentes */
<div class="volunteer-card">
<div class="card-header">
<!-- estructura unificada -->
</div>
</div>/* ❌ Incorrecto - Crear nuevas estructuras */
<div class="speaker-profile-card">
<!-- estructura diferente -->
</div>/* ✅ Correcto - Base móvil, luego desktop */
.component {
font-size:1rem;
padding:1rem;
}
@media (min-width:768px) {
.component {
font-size:1.2rem;
padding:2rem;
}
}/* ✅ Correcto */
.volunteer-card/* Componente principal */
.volunteer-card .card-header/* Elemento del componente */
.volunteer-card .badge.technical/* Modificador *//* ❌ Incorrecto */
.volunteerCard
.card_header
.technicalBadge- Estilos inline - Usar siempre classes CSS
- Colores hardcoded - Usar variables CSS
!important- Usar especificidad apropiada- Múltiples breakpoints - Mantener único en 768px
- Componentes duplicados - Reutilizar sistema unificado
Verificar:
- ¿Está incluido
custom.cssenmkdocs.yml? - ¿La especificidad CSS es suficiente?
- ¿Hay conflictos con Material Design?
Solución:
/* Aumentar especificidad sin !important */
.md-content .volunteer-card {
/* estilos */
}/* ❌ Problemático */
.component {
color:#333;
background: white;
}
/* ✅ Correcto */
.component {
color:var(--md-default-fg-color);
background:var(--md-default-bg-color);
}/* ❌ Problemático */
.grid {
grid-template-columns:300px300px300px;
}
/* ✅ Correcto */
.grid {
grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
}Error común: Usar variables que no existen
/* ❌ Variable inexistente */color:var(--primary-blue);
/* ✅ Variable correcta */color:var(--year-2024-color);- ¿Usa variables CSS en lugar de valores hardcoded?
- ¿Es responsive con el breakpoint único (768px)?
- ¿Funciona en modo claro y oscuro?
- ¿Sigue las naming conventions establecidas?
- ¿Reutiliza el sistema unificado cuando es apropiado?
- ¿Tiene estados hover/focus con transiciones?
- ¿Es accesible y semánticamente correcto?
- ¿Está documentado en esta guía?
Última actualización: Esta guía se mantiene sincronizada con docs/css/custom.css (~1466 líneas)