Introducción
Este tutorial explica paso a paso cómo diseñar un bloque de comparación de características para WordPress que muestre ticks (✔) y cruces (✖) únicamente con CSS. El objetivo es crear un bloque accesible, responsive y fácil de insertar vía shortcode o como bloque personalizado, con estilos limpios y altamente personalizables.
Concepto y accesibilidad
La idea es utilizar una estructura semántica (tabla para comparativas tabulares) y añadir clases (.yes / .no) en las celdas para que el CSS genere los iconos mediante pseudo-elementos (::before). Para lectores de pantalla se incluye texto oculto visualmente con una etiqueta (que actúa como texto accesible) y atributos aria-label. Esto asegura que el contenido sea legible para todos.
Estrategia:
- Estructura: Tabla con primera columna para la característica y columnas siguientes para planes/productos.
- Marcado: Celdas con clases .yes o .no y texto accesible dentro de un .
- Estilos: Pseudo-elementos para mostrar ✔ y ✖, variables CSS para colores y personalización.
- Responsive: Opciones para convertir la tabla en tarjetas en móviles o permitir desplazamiento horizontal.
HTML: marcado de ejemplo (tabla)
Ejemplo mínimo de la tabla que servirá como base:
| Característica | Plan A | Plan B |
|---|---|---|
| Soporte por email | Incluido | No incluido |
| Almacenamiento | No incluido | Incluido |
CSS: ticks y cruces con pseudo-elementos
A continuación, el CSS que crea los iconos, añade estilos base y la clase para ocultar visualmente el texto accesible. Se usan variables CSS para facilitar la personalización.
/ Variables globales (ajustables) /
:root {
--compare-border: #e6e6e6
--yes-color: #2ecc71
--no-color: #e74c3c
--cell-padding: 12px 16px
}
/ Estilos base de la tabla /
.compare-table {
width: 100%
border-collapse: collapse
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial
margin: 1rem 0
}
.compare-table th,
.compare-table td {
padding: var(--cell-padding)
border: 1px solid var(--compare-border)
text-align: center
vertical-align: middle
}
.compare-table th {
background: #fafafa
font-weight: 600
text-transform: none
}
.compare-table td:first-child,
.compare-table th:first-child {
text-align: left
}
/ Iconos generados por pseudo-elementos /
.compare-table td.yes::before,
.compare-table td.no::before {
display: inline-block
width: 1.1em
height: 1.1em
line-height: 1.1em
margin-right: 0.5em
font-weight: 700
font-size: 1em
vertical-align: middle
}
/ Tick (✔) /
.compare-table td.yes::before {
content: ✔
color: var(--yes-color)
}
/ Cross (✖) /
.compare-table td.no::before {
content: ✖
color: var(--no-color)
}
/ Texto accesible, visible solo para lectores de pantalla /
.sr-only {
position: absolute !important
width: 1px !important
height: 1px !important
padding: 0 !important
margin: -1px !important
overflow: hidden !important
clip: rect(0 0 0 0) !important
white-space: nowrap !important
border: 0 !important
}
Variantes de estilo
Si prefieres íconos SVG más consistentes o con mejor control visual, puedes reemplazar el content por un background-image con data URI SVG y usar mask/ background-color para colorear dinámicamente. Otra opción es usar fuentes de iconos (p. ej. Font Awesome) e insertar el carácter correspondiente en content.
Responsive: adaptar la comparativa para móviles
Dos enfoques comunes:
- Scroll horizontal: Dejar la tabla como está y permitir overflow-x en contenedor padre.
- Transformar en tarjetas: Convertir cada fila en un bloque apilado para pantallas estrechas (más legible en móviles).
CSS para scroll horizontal:
/ Contenedor que envuelve la tabla (en tu tema o bloque) /
.compare-table-wrapper {
overflow-x: auto
-webkit-overflow-scrolling: touch
}
CSS simplificado para convertir cada fila en tarjeta (técnica: display:block sobre filas y celdas en móvil):
@media (max-width: 720px) {
.compare-table,
.compare-table thead,
.compare-table tbody,
.compare-table th,
.compare-table td,
.compare-table tr {
display: block
}
.compare-table thead tr {
display: none / ocultar cabecera original /
}
.compare-table tr {
margin: 0 0 1rem 0
border: 1px solid var(--compare-border)
padding: 0.5rem
}
.compare-table td {
display: flex
justify-content: space-between
align-items: center
padding: 0.6rem 0.8rem
border: none
border-bottom: 1px solid var(--compare-border)
}
.compare-table td:first-child {
font-weight: 600
}
.compare-table td::before {
/ apagamos pseudo-content en este modo porque la estructura ya muestra el icono en posición natural /
content: none
}
}
Integración en WordPress
Se muestran dos vías sencillas y prácticas para integrar el bloque en WordPress: un shortcode en PHP (rápido) y la idea básica para un bloque de Gutenberg (JS). El ejemplo del shortcode encola un CSS con los estilos anteriores.
Shortcode en PHP
PHP para registrar un shortcode [compare] que recibe atributos y contenido con filas:
/ Encola el CSS desde el plugin o functions.php /
function cf_enqueue_styles() {
wp_enqueue_style(cf-compare-style, plugin_dir_url(__FILE__) . css/compare-features.css, array(), 1.0)
}
add_action(wp_enqueue_scripts, cf_enqueue_styles)
/ Shortcode [compare columns=Plan A,Plan B] con contenido:
Característicayes,no
Otrano,yes
/
function cf_compare_shortcode(atts, content = null) {
atts = shortcode_atts(array(columns => Plan A,Plan B), atts, compare)
cols = array_map(trim, explode(,, atts[columns]))
ob_start()
?>
Característica
. esc_html(parts[0]) .
values = isset(parts[1]) ? array_map(trim, explode(,, parts[1])) : array()
for (i = 0 i < count(cols) i ) {
val = isset(values[i]) ? strtolower(values[i]) :
isYes = in_array(val, array(yes, 1, true, si, sí))
class = isYes ? yes : no
label = isYes ? Incluido : No incluido
echo . esc_html(label) .
}
echo
}
}
?>
Bloque de Gutenberg (idea básica)
Para un bloque de Gutenberg se usaría registerBlockType con un editor que permita añadir filas y columnas dinámicamente. El bloque puede guardar HTML estático (save retorna la tabla) o usar render_callback en PHP para renderizado servidor. A continuación, la idea esencial de registro en JS (resumida):
/ Resumen: archivo block.js (requiere build con @wordpress/scripts) /
const { registerBlockType } = wp.blocks
const { RichText, InspectorControls } = wp.blockEditor
registerBlockType(cf/compare, {
title: Comparativa de características,
icon: editor-table,
category: widgets,
attributes: {
columns: { type: string, default: Plan A,Plan B },
rows: { type: string, default: } // contenido serializado: línea por línea Característicayes,no
},
edit({ attributes, setAttributes }) {
// Editor simplificado: un textarea para filas y uno para columnas.
// Implementar UI real con Repeatable fields es recomendable.
return (
wp.element.createElement(div, {},
wp.element.createElement(label, {}, Columnas (separadas por coma)),
wp.element.createElement(textarea, {
value: attributes.columns,
onChange: (e) => setAttributes({ columns: e.target.value })
}),
wp.element.createElement(label, {}, Filas (cada línea: Característicayes,no)),
wp.element.createElement(textarea, {
value: attributes.rows,
onChange: (e) => setAttributes({ rows: e.target.value })
})
)
)
},
save() {
return null // usar render_callback en PHP o serializar HTML aquí
}
})
Buenas prácticas y consejos
- Semántica: usar tabla para comparaciones tabulares. Evitar tablas para layout.
- Accesibilidad: añadir aria-label a celdas y texto oculto (.sr-only) que describa “Incluido” / “No incluido”.
- Colores: usar contraste suficiente entre color de icono y fondo para cumplir WCAG.
- Personalización: exponer variables CSS para colores y tamaños para que el tema pueda sobrescribirlas.
- Internationalización: si generas cadenas desde PHP, aplicar traducciones con __() / esc_html__().
Extensiones y mejoras avanzadas
Opciones para evolucionar el componente:
- Animaciones sutiles al cambiar valores (transiciones en color y scale del pseudo-elemento).
- Soporte para estados intermedios (por ejemplo, parcialmente incluido) usando otra clase (.partial) y un símbolo diferente o SVG).
- Incorporar iconos SVG para mejor control visual y retina crispness (usar data-uri o inline SVG en el markup si lo necesitas).
- Agregar filtros en el bloque de Gutenberg para ordenar columnas, destacar la más popular, etc.
Ejemplo completo del CSS consolidado
/ Consolidado - pegar en css/compare-features.css /
:root {
--compare-border: #e6e6e6
--yes-color: #2ecc71
--no-color: #e74c3c
--cell-padding: 12px 16px
}
.compare-table-wrapper { overflow-x: auto -webkit-overflow-scrolling: touch }
.compare-table { width:100% border-collapse:collapse font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial margin:1rem 0 }
.compare-table th, .compare-table td { padding: var(--cell-padding) border:1px solid var(--compare-border) text-align:center vertical-align:middle }
.compare-table th { background:#fafafa font-weight:600 }
.compare-table td:first-child, .compare-table th:first-child { text-align:left }
.compare-table td.yes::before, .compare-table td.no::before { display:inline-block width:1.1em height:1.1em line-height:1.1em margin-right:0.5em font-weight:700 font-size:1em vertical-align:middle }
.compare-table td.yes::before { content:✔ color:var(--yes-color) }
.compare-table td.no::before { content:✖ color:var(--no-color) }
.sr-only { position:absolute !important width:1px !important height:1px !important padding:0 !important margin:-1px !important overflow:hidden !important clip:rect(0 0 0 0) !important white-space:nowrap !important border:0 !important }
@media (max-width:720px) {
.compare-table, .compare-table thead, .compare-table tbody, .compare-table th, .compare-table td, .compare-table tr { display:block }
.compare-table thead tr { display:none }
.compare-table tr { margin:0 0 1rem 0 border:1px solid var(--compare-border) padding:0.5rem }
.compare-table td { display:flex justify-content:space-between align-items:center padding:0.6rem 0.8rem border:none border-bottom:1px solid var(--compare-border) }
.compare-table td:first-child { font-weight:600 }
.compare-table td::before { content:none }
}
Resumen
Con una estructura semántica, clases sencillas (.yes / .no) y pseudo-elementos CSS para los iconos, puedes crear una comparativa elegante, accesible y fácil de integrar en WordPress ya sea como shortcode o bloque. Manteniendo variables CSS y un CSS modular, el bloque será sencillo de personalizar desde cualquier tema.
Leave a Reply