Skip to content

Instantly share code, notes, and snippets.

@fackux
Created October 9, 2025 20:00
Show Gist options
  • Select an option

  • Save fackux/44af76e74269e86e2630ab9d8c63c747 to your computer and use it in GitHub Desktop.

Select an option

Save fackux/44af76e74269e86e2630ab9d8c63c747 to your computer and use it in GitHub Desktop.
CLS en listado/re-ui-kit

🚨 Principales Causas del Aumento de CLS

1. Migración a TypeScript y Cambios en el Build

  • Cambio crítico: Se modificó el comando de build para incluir archivos .ts y .tsx
  • Impacto: Esto puede haber cambiado el orden de carga de los componentes y recursos
  • Efecto en CLS: Si los componentes ahora se cargan de manera diferente, pueden causar re-renders que desplazan el contenido

2. Actualización de React a v18.2.0

  • Cambio significativo: React 18 introdujo cambios importantes en el renderizado
  • Nuevo comportamiento: React 18 tiene un nuevo algoritmo de renderizado que puede causar cambios en el timing de la hidratación
  • Impacto en CLS: Los cambios en el ciclo de vida de los componentes pueden causar layout shifts durante la hidratación

3. Cambios en el Componente Button

  • Estilos dinámicos: El nuevo componente button.tsx usa estilos en línea que dependen de props
  • Renderizado condicional: El componente incluye lógica condicional para el contador (count)
  • Falta de dimensiones fijas: Los botones pueden cambiar de tamaño según el contenido

4. Nuevas Dependencias

  • @navent-re/utilities: Nueva dependencia que puede incluir estilos o componentes que se cargan asíncronamente
  • Storybook dependencies: Aunque son de desarrollo, pueden afectar el bundle si no están correctamente configuradas

🔍 Análisis Específico de Componentes

📊 Análisis Completo: Causas del Aumento de CLS

Basándome en el análisis detallado del PR, he identificado 5 causas principales que pueden haber causado el aumento del CLS en tu sitio web:

🚨 1. ESTILOS DINÁMICOS EN EL COMPONENTE BUTTON

Problema crítico: El nuevo componente Button usa estilos en línea que se aplican dinámicamente:

const inlineStyles: React.CSSProperties = {
    ...(fontSize ? { fontSize } : {}),
    ...(fontWeight ? { fontWeight } : {}),
    ...(borderRadius ? { borderRadius } : {}),
    ...(width ? { width } : {}),
    ...(height ? { height } : {}),
    // ... más estilos dinámicos
};

Impacto en CLS:

  • Los botones pueden cambiar de tamaño después del renderizado inicial
  • Si no se definen dimensiones fijas, causan layout shifts
  • Los estilos se aplican después de que el componente se monta

🚨 2. RENDERIZADO CONDICIONAL DEL CONTADOR

Problema: El componente incluye renderizado condicional que puede cambiar el layout:

{ count && <span className={countClasses()}>{ count }</span> }

Impacto en CLS:

  • El span del contador se añade/remueve dinámicamente
  • Puede cambiar el tamaño del botón después de la carga inicial
  • No hay espacio reservado para el contador

🚨 3. MIGRACIÓN A TYPESCRIPT Y CAMBIOS EN BUILD

Problema: El comando de build ahora incluye archivos .ts y .tsx:

"build": "lerna exec --parallel -- babel --root-mode upward src -d lib --extensions .js,.ts,.tsx"

Impacto en CLS:

  • Cambio en el orden de carga de componentes
  • Posible diferencia en el timing de renderizado
  • Los módulos TypeScript pueden cargar de manera diferente

🚨 4. ACTUALIZACIÓN A REACT 18.2.0

Problema: React 18 introdujo cambios importantes en el renderizado:

"react": "^18.2.0",
"react-dom": "^18.2.0"

Impacto en CLS:

  • Nuevo algoritmo de renderizado concurrente
  • Cambios en el timing de hidratación
  • Posibles re-renders durante la hidratación

🚨 5. NUEVA DEPENDENCIA @navent-re/utilities

Problema: Se añadió una nueva dependencia que puede incluir estilos o componentes:

"@navent-re/utilities": "^0.11.2"

Impacto en CLS:

  • Posible carga asíncrona de recursos
  • Estilos adicionales que se aplican después del renderizado inicial

🛠️ Soluciones Recomendadas

Inmediatas (Alta Prioridad)

  1. Definir dimensiones fijas para botones:
.styled-button {
    min-width: 120px; // Evitar cambios de tamaño
    min-height: 48px;  // Altura fija
}
  1. Reservar espacio para el contador:
// Siempre renderizar el span, pero ocultarlo si no hay count
<span className={countClasses()} style={{ display: count ? 'inline' : 'none' }}>
    {count || ''}
</span>
  1. Usar CSS en lugar de estilos en línea:
// Mover estilos dinámicos a CSS classes
className={`${buttonClasses(...)} ${getDynamicClasses(props)}`}

Mediano Plazo

  1. Optimizar la carga de CSS Modules
  2. Implementar lazy loading para componentes pesados
  3. Revisar el timing de hidratación con React 18

Monitoreo

  1. Medir CLS antes y después de cada cambio
  2. Usar Chrome DevTools Performance para identificar elementos que causan shifts
  3. Implementar Core Web Vitals monitoring

🚨 SÍ, hay cambios específicos en el paquete cookies que pueden estar causando el aumento del CLS

He identificado 3 problemas críticos en el paquete de cookies que pueden estar contribuyendo significativamente al aumento del CLS:

1. 🚨 PROBLEMA CRÍTICO: Altura Dinámica del Banner

Problema: El banner de cookies tiene alturas diferentes según el dispositivo:

.cookiesContainer {
  height: 88px;  // Desktop
  
  @include breakpoints.mobile {
    height: auto;  // ⚠️ PROBLEMA: Altura automática
  }
  
  @include breakpoints.tablet {
    height: 170px;  // Tablet
  }
}

Impacto en CLS:

  • En móvil, la altura es auto, lo que significa que puede cambiar según el contenido
  • El banner está en position: fixed y bottom: 0, por lo que cambios en su altura afectan todo el layout
  • Si el contenido del banner cambia dinámicamente, puede causar shifts

2. 🚨 PROBLEMA CRÍTICO: Renderizado Condicional Complejo

Problema: El banner se renderiza condicionalmente basado en múltiples estados:

return !areCookiesAllowed ? (
  <div className={`${styles.cookiesContainer} ${hideBanner ? styles.hidden : ''}`}>
    // ... contenido del banner
  </div>
) : null;

Estados que pueden cambiar:

  • areCookiesAllowed - se inicializa como undefined y luego se actualiza
  • hideBanner - puede cambiar dinámicamente
  • collapsedText - cambia en móvil al hacer scroll

Impacto en CLS:

  • El banner puede aparecer/desaparecer después del renderizado inicial
  • Los cambios de estado causan re-renders que pueden desplazar contenido

3. 🚨 PROBLEMA CRÍTICO: Botones con Dimensiones Dinámicas

Problema: Los botones dentro del banner usan dimensiones dinámicas:

<Button
  width={!isMobile ? 'max-content' : '100%'}  // ⚠️ PROBLEMA
  tertiary
>
  {buttonConfigWordings}
</Button>

<Button
  width={!isMobile ? '100px' : '50%'}  // ⚠️ PROBLEMA
  primary
>
  {translates.textCTA}
</Button>

Impacto en CLS:

  • max-content puede cambiar según el contenido del botón
  • 50% en móvil puede causar cambios si el contenedor cambia de tamaño
  • Los botones pueden cambiar de tamaño después del renderizado inicial

4. 🚨 PROBLEMA ADICIONAL: Scroll Handler en Móvil

Problema: El componente tiene un handler de scroll que cambia el layout:

const handleNavigation = (e: Event) => {
  e.preventDefault();
  const windowTarget = e.currentTarget as Window;
  if (oldScrollY < windowTarget.scrollY && !collapsedText && isMobile) {
    setCollapsedText(true);  // ⚠️ Cambia el layout dinámicamente
  }
  if (isMobile) oldScrollY = windowTarget.scrollY;
};

Impacto en CLS:

  • Al hacer scroll hacia abajo en móvil, el texto se colapsa
  • Esto puede cambiar la altura del banner y causar layout shifts

🛠️ Soluciones Recomendadas para el Paquete Cookies

Inmediatas (Alta Prioridad)

  1. Definir altura fija para móvil:
.cookiesContainer {
  height: 88px;  // Desktop
  
  @include breakpoints.mobile {
    height: 120px;  // ✅ Altura fija en lugar de auto
    min-height: 120px;
  }
  
  @include breakpoints.tablet {
    height: 170px;
  }
}
  1. Usar dimensiones fijas para botones:
<Button
  width="120px"  // ✅ Ancho fijo
  tertiary
>
  {buttonConfigWordings}
</Button>

<Button
  width="100px"  // ✅ Ancho fijo
  primary
>
  {translates.textCTA}
</Button>
  1. Reservar espacio desde el inicio:
// En lugar de renderizado condicional, siempre reservar el espacio
return (
  <div className={`${styles.cookiesContainer} ${!areCookiesAllowed ? styles.visible : styles.hidden}`}>
    {/* contenido siempre presente */}
  </div>
);

Mediano Plazo

  1. Optimizar el scroll handler para evitar cambios de layout
  2. Implementar skeleton loading para el banner
  3. Usar CSS Grid/Flexbox con dimensiones fijas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment