
🌐 También en: English · Deutsch · Français
☝️ Si estás leyendo esto en el móvil: hasta esta semana, la página de inicio te mostraba el mismo puñado de artículos cuatro veces seguidas (una cinta de noticias, un carrusel, una caja con pestañas, una lista de «tendencias», una cuadrícula de «destacados») antes de que empezara la lista de verdad. Ahora tienes los cinco artículos más recientes, uno detrás de otro, y ya está. En el ordenador no ha cambiado nada. Si no has notado nada: perfecto, ese era el plan. 📱
Todos los temas quedan geniales en su demo en un monitor de 27 pulgadas. El mío (MoreNews) tiene una portada recargada al estilo revista: una cinta de noticias, un carrusel «Main News», una caja con pestañas Latest / Popular / Update, una columna «Trending Now», «Featured Posts» y, al final del todo, «You may have missed». En el ordenador, estos bloques se colocan uno al lado del otro y parecen un periódico. En el móvil, el tema apila cada bloque debajo del siguiente. En un blog que publica unos pocos artículos por semana, eso significa una cosa: los mismos cinco artículos, una y otra vez, durante varias pantallas, antes de que empiece siquiera la lista de verdad.
El mismo reparto de siempre: yo decido, y mi coadministrador de IA (Claude) hizo las capturas de pantalla, escribió el CSS, hizo las mediciones y averiguó por qué la primera medición salió peor en lugar de mejor.

🧹 La solución: una media query, seis selectores
Sin plugin, sin tema hijo, sin sobrescribir plantillas. Solo unas pocas líneas de CSS en el «CSS adicional» de WordPress, que se guarda en la base de datos y no en la carpeta del tema, así que una actualización del tema no puede borrarlo:
@media screen and (max-width: 1024px) {
body.home .banner-exclusive-posts-wrapper,
body.home .aft-main-banner-section,
body.home .af-main-banner-featured-posts,
body.home .above-footer-widget-section,
body.home #secondary .widget:has(.wp-block-latest-posts),
body.home #secondary .widget:has(.wp-block-archives-list) { display: none !important; }
}- ¿Por qué 1024 px? Es justo donde MoreNews pasa las columnas del banner a ancho completo y empieza a apilarlas. Por encima, las tabletas en horizontal reciben el diseño normal de escritorio, que ahí funciona bien.
- ¿Por qué
body.home? Solo afecta a la portada (y a sus páginas 2, 3, …). Los artículos individuales conservan su barra lateral y el bloque «You may have missed». - ¿Por qué
:has()para la barra lateral? Los identificadores de widget como#block-3cambian en cuanto alguien reordena la barra lateral. «El widget que contiene un bloque Latest Posts» no cambia. Todos los navegadores actuales admiten:has(). - Lo que queda en el móvil: los cinco artículos más recientes («Número máximo de entradas a mostrar en el sitio» está en 5 en WordPress), la paginación, la búsqueda y las categorías.
Y como este blog se gestiona con Ansible, el CSS no está solo en la base de datos: el playbook lo escribe en cada ejecución. Si alguien «ordena» el personalizador, la siguiente ejecución lo vuelve a poner.
📉 Giro de guion: la página se volvió más lenta
Menos cosas en la página, así que tiene que ser más rápida, ¿no? Lighthouse (móvil, tres pasadas cada vez) no estaba de acuerdo. La puntuación de rendimiento bajó de 93–95 a 91, y el tiempo hasta que se ve el elemento más grande (LCP) subió de 2,6 s a 3,4 s.
El motivo es una buena lección sobre cómo funciona el LCP. Antes, lo más grande en la pantalla del móvil era la imagen del carrusel, y un pequeño plugin «must-use» que había escrito dos días antes se encargaba de que esa imagen se cargara de inmediato y con prioridad alta. Ahora el carrusel está oculto, y el elemento más grande es la imagen del primer artículo de la lista. El tema marca todas las imágenes con loading="lazy" («cárgala más tarde, cuando esté a punto de aparecer»), también esa. Así que el navegador esperó 2,1 segundos antes de pedirla siquiera. Mientras tanto, mi plugin seguía priorizando con todo su empeño la imagen de un carrusel que nadie podía ver.
Corrección número uno: en la portada, el plugin ahora da «cargar ya, prioridad alta» a la primera imagen dentro de la lista principal de artículos (la función in_the_loop() de WordPress distingue la lista del banner, porque el banner se genera antes de que empiece el bucle). La primera imagen del banner solo recibe «cargar ya», sin el empujón de prioridad, para quienes la siguen viendo en el ordenador.
🕵️ El atributo que WordPress se tragó en silencio
Tras la corrección número uno, la imagen se cargaba de inmediato, pero el atributo fetchpriority="high" sencillamente no aparecía en el HTML. Al ejecutar el mismo código desde la línea de comandos, ahí estaba. En la página publicada, no.
El culpable: el tema muestra cada imagen de artículo a través de wp_kses_post(), el filtro HTML de WordPress. Su lista de atributos permitidos para <img> no incluye fetchpriority, así que el atributo se eliminaba sin hacer ruido. Ni un aviso, ni una entrada en el registro. Lo que también significa que la «optimización de rendimiento» de dos días antes solo había funcionado a medias. Un pequeño filtro que añade fetchpriority a los atributos permitidos, y por fin llega al navegador.
📊 Las cifras
| Lighthouse, móvil | Antes | Solo ocultando | Final |
|---|---|---|---|
| Puntuación de rendimiento | 93–95 | 91 | 95–96 |
| Largest Contentful Paint | 2,6 s | 3,4 s | 2,7 s |
| Total Blocking Time | 150–200 ms | 44 ms | 30–50 ms |
| Datos transferidos | 731 KB | 569 KB | 569 KB |
| Espera hasta que se pide la imagen LCP | – | 2,1 s | 0,7 s |
| Puntuación en escritorio | 100 | 100 | 100 |
Entonces, ¿cuánto más rápido es? Siendo sinceros: la imagen grande aparece más o menos igual de rápido que antes. Con la conexión de prueba deliberadamente lenta de Lighthouse, la mayor parte de esos 2,7 segundos es la respuesta del servidor (0,6 s) y la propia descarga de la imagen. Lo que sí ha cambiado: un 22 % menos de datos, porque los bloques ocultos nunca cargan sus imágenes, y unas cuatro veces menos tiempo de bloqueo de JavaScript, así que la página responde antes cuando tocas o te desplazas. Y lo principal: lees el artículo más reciente sin desplazarte, en lugar de tres pantallas más abajo.
🖼️ ¿Imágenes más pequeñas para el móvil? No merece la pena
La siguiente idea obvia: servir imágenes más pequeñas a los móviles. Lo comprobé y decidí que no.
- Ahora mismo, móviles y ordenadores reciben el mismo archivo: un AVIF de 768 px de ancho, normalmente de 30 a 70 KB. El optimizador de imágenes crea un solo tamaño para sus versiones AVIF; la versión WebP de reserva para navegadores antiguos ya existe en cuatro tamaños.
- Un móvil de 412 «píxeles CSS» de ancho tiene una densidad de unos 2,6, es decir, aproximadamente 1.070 píxeles reales. Para una imagen nítida a todo el ancho de la pantalla necesita al menos tantos píxeles como la columna en el ordenador. 768 px ya está algo por debajo, y solo se ve bien porque AVIF es muy eficiente.
- Solo saldrían ganando los móviles antiguos de baja densidad. En el mejor de los casos, quizá 20–30 KB por imagen, unos 100 KB en toda la portada. No compensa tener tamaños de imagen adicionales en disco y más piezas que mantener.
El verdadero cuello de botella nunca fue el tamaño de las imágenes. Fue que a la imagen más importante le habían dicho que esperara.
🤦 Extra: me bloqueé a mí mismo (otra vez)
Para la captura del «antes» generamos una copia guardada de la portada antigua. Esa copia todavía apuntaba a archivos CSS y JavaScript minificados que el plugin de optimización había tirado minutos antes, al vaciar su caché. Una carga de página, una ráfaga de «404 Not Found» en pocos segundos, y fail2ban hizo exactamente aquello para lo que existe: decidió que la IP de mi casa era un escáner y la bloqueó, tanto para la web como para SSH. Funciona como debe. Ligeramente bochornoso. Se aplicaron té y paciencia. ☕
🎨 ¿Qué tema uso, y qué pasa si algún día lo cambio?
Este blog usa MoreNews de AF themes, un tema clásico de tipo revista (no un tema de bloques). Eso importa, porque casi todo lo que he hecho arriba depende de él. Si algún día cambio de tema, esto es lo que se conserva y lo que no:
| Cambio | ¿Sobrevive a un cambio de tema? | Por qué |
|---|---|---|
| «5 entradas por página» | ✅ Sí | Un ajuste de WordPress (Ajustes → Lectura), no del tema. |
Permitir fetchpriority | ✅ Sí | Está en un plugin «must-use», al que el tema le da igual. Inofensivo si el tema nuevo no lo necesita. |
| «La primera imagen de la lista se carga primero» | ✅ En gran parte | Solo usa funciones estándar de WordPress (in_the_loop(), la clase estándar wp-post-image). Funciona con cualquier tema que muestre imágenes destacadas en la lista de artículos. |
| Precarga de fuentes | ❌ No | Apunta a los archivos de fuentes de la carpeta de MoreNews. Un tema nuevo tiene otras fuentes: hay que ajustar las rutas o quitarla. |
| Ocultar los bloques del banner | ❌ No | Los nombres de clase como .aft-main-banner-section solo existen en MoreNews. Un tema nuevo tiene sus propios bloques con sus propios nombres. |
| Ocultar Recent Posts / Archive | ⚠️ En parte | Las clases de bloque vienen del núcleo de WordPress y no cambian. #secondary como identificador de la barra lateral es habitual, pero no está garantizado. |
| El propio «CSS adicional» | ❌ No automáticamente | WordPress lo guarda por tema. Tras un cambio, el tema nuevo empieza con el campo vacío (el CSS antiguo se conserva para MoreNews). |
Así que la idea se traslada tal cual: decidir qué necesita de verdad quien visita desde el móvil, medir y hacer que la imagen más importante se cargue primero. Los selectores hay que reescribirlos. Eso lleva unos diez minutos con las herramientas de desarrollo del navegador: cambiar a la vista de móvil, clic derecho en el bloque que sobra y mirar su nombre de clase.
Y con un tema de bloques moderno ni siquiera haría falta CSS: en el editor del sitio basta con quitar esos bloques de la plantilla de la portada. Eso es incluso mejor que display: none, porque un bloque oculto sigue formando parte del HTML que descarga el navegador, mientras que uno eliminado ni siquiera se envía.
📂 Dónde está el código
Ambos cambios forman parte del rol de Ansible que gestiona este blog, en roles/blog_wordpress/tasks/main.yml: la tarea «Set custom CSS» para el diseño móvil, y «Deploy performance hints mu-plugin» para la prioridad de las imágenes y el permiso de fetchpriority.




