Cómo calcular con tamaños intrínsecos

Funciones web: calc-size() interpolate-size

calc-size() es una función de CSS para realizar operaciones matemáticas en palabras clave de tamaño intrínseco, como auto, min-content y fit-content. OBLIGATORIO: Usa calc-size() solo cuando necesites modificar un tamaño intrínseco con un cálculo o una restricción. Para animaciones simples basadas en palabras clave (p. ej., de 0 a auto), debes usar interpolate-size: allow-keywords.

Pasos de implementación

  1. Identifica la base intrínseca: Determina qué palabra clave intrínseca (auto, min-content, etc.) debe formar la base de tu cálculo.
  2. Define restricciones: Usa funciones matemáticas de CSS, como clamp(), min() o max(), dentro del segundo argumento para aplicar restricciones de diseño al tamaño intrínseco.
  3. OBLIGATORIO: Proporciona un resguardo: Declara siempre una palabra clave o longitud de tamaño estándar inmediatamente antes de la propiedad que usa calc-size() para garantizar que el diseño siga funcionando en los navegadores no compatibles.
  4. Aplica propiedades lógicas: Usa de forma predeterminada propiedades lógicas como inline-size o block-size para asegurarte de que los cálculos respeten el modo de escritura del documento.
  5. Opcional: Mejora progresiva: Une la lógica de diseño o las animaciones complejas en un bloque @supports (inline-size: calc-size(auto, size + 0px)) para ofrecer funciones avanzadas solo a los navegadores compatibles.

Sintaxis básica

/* calc-size(<calc-size-basis>, <calc-sum>) — mathematical operations on intrinsic sizing keywords */
.element {
  /* MANDATORY: Always provide a fallback for browsers that do not support calc-size() */
  inline-size: min-content;
  
  /* DO: Use calc-size to modify an intrinsic basis with a calculation or function */
  inline-size: calc-size(min-content, size + 2rem);
}

Argumentos de base válidos (<calc-size-basis>)

El primer argumento define el tamaño "base" para el cálculo.

Palabras clave estándar:

  • auto: Es el tamaño predeterminado del elemento.
  • min-content: Es el tamaño más pequeño que puede tener el elemento sin desbordarse.
  • max-content: Es el tamaño que ocupa el elemento para que todo el contenido quepa en una línea.
  • fit-content: Es equivalente a clamp(min-content, auto, max-content).
  • content: Solo es válido cuando se usa calc-size() dentro de la propiedad flex-basis.

Argumentos especiales:

  • any: Es una base genérica que se usa cuando se desconoce el tipo intrínseco específico o cuando se anidan cálculos.
  • calc-size() anidada: Permite realizar cálculos condicionales o de varios pasos.
  • <calc-sum>: Es una longitud, un porcentaje o una expresión matemática específicos (p.ej., 100px o 20%). Cuando se usa un valor fijo como base, la palabra clave size sigue estando disponible (pero solo dentro del segundo argumento) y representa el valor resuelto de esa base.

OBLIGATORIO: La palabra clave size no es válida dentro del primer argumento (<calc-size-basis>). Es una variable local que solo existe para hacer referencia a la base desde el segundo argumento (<calc-sum>).

Argumentos de cálculo válidos (<calc-sum>)

El segundo argumento es la expresión matemática.

  • Por lo general, usa la palabra clave size para hacer referencia al valor de la base.
  • Si bien la palabra clave size es técnicamente opcional, omitirla significa que el cálculo se resolverá en un valor fijo, ignorando la base por completo.
  • Puede incluir operadores matemáticos estándar (+, -, *, /).
  • Puede incluir funciones matemáticas de CSS, como clamp(), min(), max() y round().
  • OBLIGATORIO: calc-size() solo permite un único valor de tamaño intrínseco (la base) en cada cálculo. No puedes mezclar palabras clave de tamaño intrínseco en la misma llamada a calc-size().

Casos de uso

Cómo animar hacia y desde tamaños intrínsecos

De forma predeterminada, los navegadores no pueden interpolar entre una longitud (p.ej., 0px) y una palabra clave intrínseca (p.ej., auto). Unir la palabra clave en calc-size() la convierte en un valor interpolable.

Cómo elegir la herramienta adecuada para las animaciones

  • OBLIGATORIO: Usa interpolate-size: allow-keywords: Para animaciones simples hacia o desde tamaños intrínsecos (p.ej., de height: 0 a height: auto) sin modificaciones matemáticas. Este es el enfoque requerido para la interpolación simple de palabras clave y, idealmente, debería aplicarse de forma global a través de :root.

    :root {
      /* Best practice: Enable keyword interpolation globally */
      interpolate-size: allow-keywords;
    }
    
    .item {
      height: 0;
      transition: height 0.3s ease;
    }
    
    .item.open {
      /* Simple interpolation from 0 to auto now works without calc-size() */
      height: auto;
    }
    
  • Usa calc-size(): SOLO cuando necesites realizar cálculos matemáticos en un tamaño intrínseco durante una transición (p.ej., agregar padding o limitar el tamaño).

.accordion-content {
  display: block;
  overflow: hidden;
  /* MANDATORY: Fallback value for closed state */
  block-size: 0;
  transition: block-size 0.3s ease-out;
}

.accordion-content.open {
  /* MANDATORY: Fallback value for open state */
  block-size: auto;

  /* 
    DO: Use calc-size(auto, ...) to enable animation from 0 to the element's 
    intrinsic size while doing a calculation (in this case, adding a space of 2rem).
  */
  block-size: calc-size(auto, size + 2rem);
}

OBLIGATORIO: No es posible realizar la interpolación entre dos palabras clave de tamaño intrínseco de forma directa. Un extremo de la transición debe ser una longitud o un porcentaje.

Cómo respetar las preferencias de movimiento del usuario

Las animaciones que cambian el tamaño de las áreas de diseño grandes pueden ser particularmente disruptivas para los usuarios con trastornos vestibulares. OBLIGATORIO: Respeta siempre las preferencias de movimiento del usuario con la consulta de medios prefers-reduced-motion para simplificar o minimizar las animaciones no esenciales. Entre las estrategias comunes, se incluyen inhabilitar el movimiento por completo, reducir la duración o reemplazar los cambios de diseño por transiciones de opacidad sutiles.

.accordion-content {
  opacity: 0;
  transition: block-size 0.3s ease, opacity 0.3s ease;
}

.accordion-content.open {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .accordion-content {
    /* 
       EXAMPLE: Replacing disruptive layout animations with a subtle fade-in.
       Setting the block-size instantly and transitioning opacity 
       provides a clear state change without large-scale motion.
    */
    transition: opacity 1.5s ease;
  }

  .accordion-content.open {
    /* Jump the size instantly */
    block-size: auto;
  }
}

Cómo aplicar restricciones a los tamaños intrínsecos

Puedes usar calc-size() con cualquier función matemática de CSS, como min(), max(), clamp() o round(), para garantizar que el tamaño intrínseco de un elemento permanezca dentro de los límites del diseño.

.dynamic-container {
  /* MANDATORY: Always provide a fallback for browsers that do not support calc-size() */
  inline-size: fit-content;

  /* 
    DO: Establish a dynamic size based on content, while:
    1. Enforcing boundaries using CSS math functions (min, clamp, etc.)
    2. Modifying the intrinsic size with fixed or relative offsets
  */
  inline-size: calc-size(fit-content, min(size + var(--extra-space), var(--max-allowed)));
}

Consideraciones más importantes

  • Errores comunes con los porcentajes: Los porcentajes dentro de <calc-sum> se resuelven en función del tamaño del contenedor, no de la palabra clave size. Por ejemplo, calc-size(auto, size + 10%) agrega el 10% del ancho del elemento superior al ancho de auto del elemento, lo que puede generar resultados inesperados o desbordamientos.
  • Requisito de cálculos: OBLIGATORIO: Usa interpolate-size: allow-keywords en lugar de calc-size() para animaciones simples (p.ej., de 0 a auto). calc-size() solo se debe usar cuando el diseño requiera ajustes matemáticos dinámicos en la base intrínseca.
  • Nota de rendimiento: Animar las propiedades del modelo de caja, como inline-size o block-size, activa nuevos cálculos de diseño, lo que puede ser costoso. Usa animaciones de calc-size() principalmente para elementos críticos del diseño en los que las alternativas que no son de diseño no sean suficientes.

Estrategias de resguardo

calc-size() y interpolate-size son mejoras progresivas. En los navegadores que no las admiten, se ignorarán las propiedades y el diseño seguirá funcionando, aunque las animaciones de las palabras clave intrínsecas saltarán en lugar de realizar la transición. Proporciona siempre una palabra clave o una longitud estándar como resguardo.

.element {
  /* Fallback for browsers that don't support calc-size() */
  inline-size: fit-content; 
  /* Modern browsers will override the fallback */
  inline-size: calc-size(fit-content, size + 2rem);
}

Resguardos de animación y transición

En los navegadores que no admiten calc-size() ni interpolate-size, las transiciones que involucran palabras clave de tamaño intrínseco no se interpolarán.

  • Degradación elegante: El resguardo predeterminado es un "salto instantáneo" entre estados (p.ej., de 0 a auto). Esto suele ser aceptable, ya que el diseño sigue siendo funcional.
  • Experiencia mejorada: Usa @supports para aplicar una lógica de diseño compleja o un estilo adicional que solo tenga sentido cuando se puedan realizar animaciones intrínsecas fluidas.
  • Evita las mediciones basadas en JS: Si bien puedes usar JavaScript para medir elementos y animar sus dimensiones de forma manual, esto suele ser innecesario y puede provocar un desorden en el diseño. Confiar en el "salto instantáneo" nativo es el resguardo recomendado para las aplicaciones web modernas.

En el caso de las animaciones, la experiencia de resguardo será un salto instantáneo al tamaño final. Para detectar la compatibilidad en CSS o JavaScript, haz lo siguiente:

/* CSS Feature Detection */
@supports (inline-size: calc-size(auto, size + 0px)) {
  .element {
    /* Apply advanced logic only when supported */
  }
}
/* JavaScript Feature Detection */
if (CSS.supports('inline-size', 'calc-size(auto, size + 0px)')) {
  // Apply advanced sizing or animations
}