1. Introducción
El framework b-Bulma-Alpine es una adaptación
de Bulma con prefijo b-, combinada con componentes
interactivos en Alpine.js. Está optimizado para:
- Rendimiento en móvil como prioridad.
- Código CSS mínimo y reutilizable.
- Uso intensivo de helpers de Bulma con prefijo
b-. - Scripts ligeros escritos como componentes Alpine.
Esta guía describe cómo usar el framework, cómo nombrar clases y cómo construir componentes como tarjetas de producto y carruseles parciales coherentes con el resto del tema.
2. Estructura de archivos
La implementación base asume el siguiente conjunto mínimo de archivos en tu tema o proyecto:
.
├── a-bulma-full.css # Bulma personalizado con prefijo b-
├── a-main-collection-plt.css # Estilos específicos para colecciones / cards
├── alpine-bundle.js # Bundle de Alpine.js + configuración común
├── alpine-product-card.js # Componente Alpine para tarjetas de producto
├── docs.js # Script de esta guía (ejemplo Alpine)
├── docs.css # Estilos adicionales para esta guía
└── index.html # Esta página de documentación
En un tema Shopify, estos archivos normalmente se referencian
desde theme.liquid o desde secciones específicas.
3. Convenciones CSS (b-Bulma)
Todas las clases de Bulma están prefijadas con
b-. Ejemplos:
b-containeren lugar decontainerb-columnsen lugar decolumnsb-button b-is-primaryen lugar debutton is-primary
Usa siempre las utilidades existentes antes de agregar CSS nuevo. Por ejemplo, para espaciados:
<section class="b-section b-py-5">
<div class="b-container">
<h2 class="b-title is-size-4">Título de sección</h2>
<p class="b-content">Contenido...</p>
</div>
</section>
Solo se agregan clases personalizadas cuando el layout lo exige (por ejemplo, para los carruseles y wrappers específicos de tarjeta).
4. Convenciones JS (Alpine.js)
Cada componente interactivo se define como un
Alpine.data() con un nombre claro. Por ejemplo,
el componente de tarjeta de producto:
document.addEventListener('alpine:init', () => {
Alpine.data('productCard', (props) => ({
loading: false,
errorMessage: null,
// ...
addToCart() {
// Lógica para agregar al carrito...
}
}));
});
En HTML, se usa con x-data="productCard({ ... })".
5. Componentes de tarjeta (cards)
Las tarjetas de producto siguen una estructura consistente:
<article
class="b-card b-is-shadowless b-has-border-light"
x-data="productCard({ productHandle: 'mi-producto' })"
>
<div class="b-card-image-wrapper">
<figure class="b-image is-square">
<img src="PRODUCT_IMAGE" alt="Nombre del producto">
</figure>
</div>
<div class="b-card-content-wrapper">
<h3 class="b-title is-size-6 b-mb-1">Nombre del producto</h3>
<p class="b-content is-size-7">Resumen breve del producto...</p>
<div class="b-level b-mt-3">
<div class="b-level-left">
<span class="b-tag b-is-primary b-is-light">$69.99</span>
</div>
<div class="b-level-right">
<button
class="b-button b-is-small b-is-primary"
@click="addToCart"
:disabled="loading"
>
<span x-show="!loading">Agregar</span>
<span x-show="loading">Agregando...</span>
</button>
</div>
</div>
</div>
</article>
Este patrón se reutiliza para colecciones, carruseles y secciones destacadas.
6. Carrusel parcial (scroll horizontal)
El carrusel parcial muestra varias tarjetas en scroll horizontal, dejando ver un avance de la siguiente tarjeta. Es mobile-first y no requiere JavaScript para funcionar.
6.1 Estructura HTML
<div class="b-carousel-wrapper">
<div class="b-carousel -partial">
<div class="b-carousel-item">
<!-- Card de producto o contenido -->
</div>
<div class="b-carousel-item">...</div>
<div class="b-carousel-item">...</div>
</div>
</div>
6.2 CSS base
Las clases clave se definen en tu hoja de estilos principal, siguiendo este patrón:
.b-carousel-wrapper {
position: relative;
}
.b-carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
gap: 1rem;
padding-bottom: 0.25rem;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
align-items: stretch;
}
.b-carousel::-webkit-scrollbar {
display: none;
}
.b-carousel > .b-carousel-item {
flex: 0 0 auto;
scroll-snap-align: start;
display: flex;
width: 75vw;
max-width: 320px;
}
@media screen and (min-width: 769px) {
.b-carousel > .b-carousel-item {
width: 40vw;
max-width: 380px;
}
}
6.3 Navegación con Alpine (opcional)
Para agregar botones de navegación, puedes usar un pequeño componente Alpine:
document.addEventListener('alpine:init', () => {
Alpine.data('carouselPartial', () => ({
el: null,
init() {
this.el = this.$root.querySelector('.b-carousel');
},
next() {
this.el.scrollBy({ left: this.el.clientWidth * 0.8, behavior: 'smooth' });
},
prev() {
this.el.scrollBy({ left: -this.el.clientWidth * 0.8, behavior: 'smooth' });
}
}));
});
Y en HTML:
<div x-data="carouselPartial" class="b-carousel-wrapper">
<button class="b-button b-is-light" @click="prev">‹</button>
<div class="b-carousel -partial">...</div>
<button class="b-button b-is-light" @click="next">›</button>
</div>
7. Uso en Shopify (Liquid)
En un tema Shopify, el framework se integra en
layout/theme.liquid o en una sección específica:
<!-- layout/theme.liquid -->
<head>
{{ 'a-bulma-full.css' | asset_url | stylesheet_tag }}
{{ 'a-main-collection-plt.css' | asset_url | stylesheet_tag }}
</head>
<body>
{{ content_for_layout }}
{{ 'alpine-bundle.js' | asset_url | script_tag }}
{{ 'alpine-product-card.js' | asset_url | script_tag }}
</body>
Las secciones y bloques Liquid solo deben preocuparse por la
estructura HTML y las clases de Bulma con prefijo
b-. El comportamiento se delega a Alpine y al
CSS que ya tienes definido.