0Apoyar

Playground de if() en CSS

Elige valores de padding con condiciones style(), media() o supports(). Ajusta las ramas, observa el CSS nativo y comparte tu configuración. Incluye una guía con ejemplos y fallbacks.

Leer la guía

Preguntar a la IA

Playground de if() en CSS

Respuesta generada con openai/gpt-5.4-nano. La IA puede cometer errores. Revisa siempre el resultado.

El espacio entre el borde exterior y la caja interior es el padding que resuelve CSS.

CSS if()

Preview nativa: el navegador acepta esta sintaxis de if().

Fallback activo: padding fijo de 12px. Este navegador no acepta esta sintaxis de if().

if(
    style(--status: complete): 32px;
    style(--status: pending): 20px;
    else: 8px
  )
HTML
<article class="if-demo">
  <p>CSS if()</p>
</article>
CSS
.if-demo {
  --status: complete;
  box-sizing: border-box;
  inline-size: 100%;
  padding: 12px;
  border: 2px solid #1e40af;
  border-radius: 16px;
  corner-shape: squircle;
  color: #172554;
  background: #dbeafe;
  font: 600 1rem/1.5 system-ui, sans-serif;
  overflow-wrap: anywhere;
}

.if-demo p {
  margin: 0;
  padding: 0.5rem;
  border: 1px dashed #1e40af;
  background: #fff;
}

@supports (padding: if(
  style(--status: complete): 32px;
  style(--status: pending): 20px;
  else: 8px
)) {
  .if-demo {
    padding: if(
      style(--status: complete): 32px;
      style(--status: pending): 20px;
      else: 8px
    );
  }
}

@media (forced-colors: active) {
  .if-demo {
    color: CanvasText;
    background: Canvas;
    border-color: CanvasText;
  }

  .if-demo p {
    background: Canvas;
    border-color: CanvasText;
  }
}

Guía educativa de if()

Valores condicionales dentro de una declaración CSS

Decide qué valor recibe una propiedad con style(), media() y supports(). Aprende a ordenar las ramas, elegir un else y conservar una base legible cuando el navegador no entiende if().

Volver al playground

Modelo mental

Consulta → primera rama verdadera → valor de la propiedad.

  1. 1 · Comprobar la condición

    style(--status: complete) pregunta por una custom property del elemento.

  2. 2 · Elegir el primer true

    Su valor, 32px, se sustituye dentro de padding.

  3. 3 · Conservar una salida

    else: 8px se usa cuando ninguna condición anterior es verdadera.

Un recorrido de arriba abajoEsquema estático. Con --status: complete, la primera rama devuelve 32px; las siguientes no participan.

if(condición: valor; else: alternativa) ocupa el lugar de un valor CSS. No crea reglas ni ejecuta instrucciones JavaScript. Las ramas se separan con punto y coma; cada condición se separa de su valor con dos puntos. El último punto y coma es opcional.

style(): estado del propio elemento

El token puede estar definido en el elemento o llegar por herencia.

Aquí --status está en la misma tarjeta que recibe padding. A diferencia de @container style(), no hace falta consultar un antepasado ni definir container-type. Usa custom properties: consultar propiedades ordinarias como display no es una base interoperable para este ejemplo.

Tres estados, tres valores

Estado de la tarjeta

CSS if() · padding condicional

if() nativo activo.

Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.

Cambia el estado con los radios. complete elige 32px, pending elige 20px e idle llega a else: 8px. Sin soporte permanece la base de 12px.
Tres estados, tres valores
<div class="if-scene-style">
  <fieldset>
    <legend>Estado de la tarjeta</legend>
    <label><input type="radio" name="if-guide-state" value="complete" checked> complete</label>
    <label><input type="radio" name="if-guide-state" value="pending"> pending</label>
    <label><input type="radio" name="if-guide-state" value="idle"> idle → else</label>
  </fieldset>
  <article class="sample"><p>CSS if() · padding condicional</p></article>
  <p class="native">if() nativo activo.</p>
  <p class="fallback">Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.</p>
</div>
:root {
  color-scheme: light dark;
}

.if-scene-style {
  display: grid;
  gap: 1rem;
  min-inline-size: 0;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font: 1rem/1.6 system-ui, sans-serif;
  overflow-wrap: anywhere;

  > p {
    margin: 0;
  }

  .sample {
    --status: complete;
    box-sizing: border-box;
    min-inline-size: 0;
    padding: 12px;
    border: 2px solid #1e40af;
    border-radius: 16px;
    corner-shape: squircle;
    color: #172554;
    background: #dbeafe;

    p {
      margin: 0;
      padding: 0.5rem;
      background: #fff;
      border: 1px dashed #1e40af;
    }
  }

  .native {
    display: none;
  }

  fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-inline-size: 0;
    padding: min(1rem, 5vi);
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  legend {
    padding-inline: 0.5rem;
  }

  label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    cursor: pointer;
  }

  input {
    accent-color: light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
  }

  input:focus-visible {
    outline: 2px solid light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
    outline-offset: 3px;
  }

  @supports (padding: if(
    style(--status: complete): 32px;
    style(--status: pending): 20px;
    else: 8px
  )) {
    .sample {
      padding: if(
        style(--status: complete): 32px;
        style(--status: pending): 20px;
        else: 8px
      );
    }

    .native {
      display: block;
    }

    .fallback {
      display: none;
    }
  }

  &:has(input[value="pending"]:checked) .sample {
    --status: pending;
  }

  &:has(input[value="idle"]:checked) .sample {
    --status: idle;
  }

  @media (forced-colors: active) {
    .sample {
      color: CanvasText;
      background: Canvas;
      border-color: CanvasText;
    }

    .sample p {
      background: Canvas;
      border-color: CanvasText;
    }
  }
}

Los valores pending y complete son tokens CSS sin comillas. "complete" y complete son valores distintos en una custom property sin registrar. Mantén la misma representación al asignar y consultar.

media(): el entorno de la página

Una consulta inline al viewport o a las preferencias.

media() usa las condiciones de una media query. El ejemplo cambia padding al alcanzar 800px de viewport. El ancho de esta tarjeta no decide la condición: if() no convierte una media query en una size container query.

Una tarjeta que sigue el viewport

CSS if() · padding condicional

if() nativo activo.

Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.

Con soporte, el padding es 32px desde 800px de viewport y 8px por debajo. Redimensiona la ventana; el fallback sigue siendo 12px.
Una tarjeta que sigue el viewport
<div class="if-scene-media">
  <article class="sample"><p>CSS if() · padding condicional</p></article>
  <p class="native">if() nativo activo.</p>
  <p class="fallback">Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.</p>
</div>
:root {
  color-scheme: light dark;
}

.if-scene-media {
  display: grid;
  gap: 1rem;
  min-inline-size: 0;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font: 1rem/1.6 system-ui, sans-serif;
  overflow-wrap: anywhere;

  > p {
    margin: 0;
  }

  .sample {
    --status: complete;
    box-sizing: border-box;
    min-inline-size: 0;
    padding: 12px;
    border: 2px solid #1e40af;
    border-radius: 16px;
    corner-shape: squircle;
    color: #172554;
    background: #dbeafe;

    p {
      margin: 0;
      padding: 0.5rem;
      background: #fff;
      border: 1px dashed #1e40af;
    }
  }

  .native {
    display: none;
  }

  fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-inline-size: 0;
    padding: min(1rem, 5vi);
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  legend {
    padding-inline: 0.5rem;
  }

  label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    cursor: pointer;
  }

  input {
    accent-color: light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
  }

  input:focus-visible {
    outline: 2px solid light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
    outline-offset: 3px;
  }

  @supports (padding: if(
    media((width >= 800px)): 32px;
    else: 8px
  )) {
    .sample {
      padding: if(
        media((width >= 800px)): 32px;
        else: 8px
      );
    }

    .native {
      display: block;
    }

    .fallback {
      display: none;
    }
  }

  @media (forced-colors: active) {
    .sample {
      color: CanvasText;
      background: Canvas;
      border-color: CanvasText;
    }

    .sample p {
      background: Canvas;
      border-color: CanvasText;
    }
  }
}

En el playground también puedes probar prefers-color-scheme y prefers-reduced-motion. Cambiar el tema local de la web no cambia necesariamente la preferencia del sistema que consulta media().

supports(): aceptar una sintaxis

Comprobar soporte y comprobar si una condición coincide son tareas distintas.

supports() devuelve una condición de soporte CSS. Aquí display: grid conduce a 32px cuando es aceptado. La opción negativa del playground pregunta por un valor deliberadamente inexistente para que puedas observar else sin falsear el navegador.

Elegir un valor según el soporte de Grid

CSS if() · padding condicional

if() nativo activo.

Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.

Solo si existe if() se evalúa supports(display: grid). Un navegador que acepta ambas sintaxis usa 32px; sin if() conserva 12px.
Elegir un valor según el soporte de Grid
<div class="if-scene-supports">
  <article class="sample"><p>CSS if() · padding condicional</p></article>
  <p class="native">if() nativo activo.</p>
  <p class="fallback">Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.</p>
</div>
:root {
  color-scheme: light dark;
}

.if-scene-supports {
  display: grid;
  gap: 1rem;
  min-inline-size: 0;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font: 1rem/1.6 system-ui, sans-serif;
  overflow-wrap: anywhere;

  > p {
    margin: 0;
  }

  .sample {
    --status: complete;
    box-sizing: border-box;
    min-inline-size: 0;
    padding: 12px;
    border: 2px solid #1e40af;
    border-radius: 16px;
    corner-shape: squircle;
    color: #172554;
    background: #dbeafe;

    p {
      margin: 0;
      padding: 0.5rem;
      background: #fff;
      border: 1px dashed #1e40af;
    }
  }

  .native {
    display: none;
  }

  fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-inline-size: 0;
    padding: min(1rem, 5vi);
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  legend {
    padding-inline: 0.5rem;
  }

  label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    cursor: pointer;
  }

  input {
    accent-color: light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
  }

  input:focus-visible {
    outline: 2px solid light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
    outline-offset: 3px;
  }

  @supports (padding: if(
    supports(display: grid): 32px;
    else: 8px
  )) {
    .sample {
      padding: if(
        supports(display: grid): 32px;
        else: 8px
      );
    }

    .native {
      display: block;
    }

    .fallback {
      display: none;
    }
  }

  @media (forced-colors: active) {
    .sample {
      color: CanvasText;
      background: Canvas;
      border-color: CanvasText;
    }

    .sample p {
      background: Canvas;
      border-color: CanvasText;
    }
  }
}

supports() dentro de if() necesita que if() exista primero. No protege una función desconocida para navegadores antiguos. Para esa protección se utiliza @supports alrededor de la declaración.

Orden de ramas y else

La primera coincidencia gana; la última no reemplaza a las anteriores.

Si dos condiciones son verdaderas, se devuelve el valor de la primera. No hay una cascada entre ramas. En estas tarjetas, --status: complete y media(width >= 0px) son verdaderos; invertir su orden cambia el padding de 32px a 8px.

Mismas condiciones, distinto orden

Primero style() → 32px

Primero media(width >= 0px) → 8px

if() nativo activo.

Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.

Con soporte, la primera tarjeta recibe 32px y la segunda 8px. La condición que aparece después ya no decide el valor. Ambas conservan 12px sin soporte.
Mismas condiciones, distinto orden
<div class="if-scene-order">
  <article class="sample"><p>Primero style() → 32px</p></article>
  <article class="sample media-first"><p>Primero media(width &gt;= 0px) → 8px</p></article>
  <p class="native">if() nativo activo.</p>
  <p class="fallback">Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.</p>
</div>
:root {
  color-scheme: light dark;
}

.if-scene-order {
  display: grid;
  gap: 1rem;
  min-inline-size: 0;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font: 1rem/1.6 system-ui, sans-serif;
  overflow-wrap: anywhere;

  > p {
    margin: 0;
  }

  .sample {
    --status: complete;
    box-sizing: border-box;
    min-inline-size: 0;
    padding: 12px;
    border: 2px solid #1e40af;
    border-radius: 16px;
    corner-shape: squircle;
    color: #172554;
    background: #dbeafe;

    p {
      margin: 0;
      padding: 0.5rem;
      background: #fff;
      border: 1px dashed #1e40af;
    }
  }

  .native {
    display: none;
  }

  fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-inline-size: 0;
    padding: min(1rem, 5vi);
    border: 1px solid light-dark(oklch(0.84 0.01 95), oklch(0.36 0.024 260));
  }

  legend {
    padding-inline: 0.5rem;
  }

  label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    cursor: pointer;
  }

  input {
    accent-color: light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
  }

  input:focus-visible {
    outline: 2px solid light-dark(oklch(0.46 0.14 261), oklch(0.82 0.18 261));
    outline-offset: 3px;
  }

  @supports (padding: if(style(--status: complete): 32px; media(width >= 0px): 8px; else: 12px)) {
    .sample {
      padding: if(style(--status: complete): 32px; media(width >= 0px): 8px; else: 12px);
    }

    .native {
      display: block;
    }

    .fallback {
      display: none;
    }
  }

  @supports (padding: if(media(width >= 0px): 8px; style(--status: complete): 32px; else: 12px)) {
    .sample.media-first {
      padding: if(media(width >= 0px): 8px; style(--status: complete): 32px; else: 12px);
    }
  }

  @media (forced-colors: active) {
    .sample {
      color: CanvasText;
      background: Canvas;
      border-color: CanvasText;
    }

    .sample p {
      background: Canvas;
      border-color: CanvasText;
    }
  }
}

else es una condición siempre verdadera: colócala al final para no dejar ramas inalcanzables. Si no hay else y ninguna condición coincide, if() produce un valor garantizado inválido. No significa 0 ni recuperar automáticamente una declaración anterior.

Fallback y valores inválidos

Tres situaciones: falta if(), no coincide una rama o el valor no sirve para la propiedad.

La receta establece padding: 12px fuera de @supports y añade if() solo si el navegador acepta esa sintaxis para padding. El else de 8px actúa dentro de la función; el fallback de 12px protege a quien no puede usarla. Son niveles diferentes.

Una base antes de la mejora progresiva

CSS if()

if() nativo activo.

Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.

La tarjeta usa 32px si entiende if() y 12px si no lo entiende. El contenido y el borde siguen presentes en ambos casos.
Una base antes de la mejora progresiva
<div class="if-scene-fallback">
<article class="if-scene-fallback-card">
  <p>CSS if()</p>
</article>
  <p class="native">if() nativo activo.</p>
  <p class="fallback">Fallback activo: padding de 12px; este navegador no acepta la sintaxis de if() del ejemplo.</p>
</div>
:root {
  color-scheme: light dark;
}

.if-scene-fallback-card {
  --status: complete;
  box-sizing: border-box;
  inline-size: 100%;
  padding: 12px;
  border: 2px solid #1e40af;
  border-radius: 16px;
  corner-shape: squircle;
  color: #172554;
  background: #dbeafe;
  font: 600 1rem/1.5 system-ui, sans-serif;
  overflow-wrap: anywhere;
}

.if-scene-fallback-card p {
  margin: 0;
  padding: 0.5rem;
  border: 1px dashed #1e40af;
  background: #fff;
}

@supports (padding: if(
  style(--status: complete): 32px;
  style(--status: pending): 20px;
  else: 8px
)) {
  .if-scene-fallback-card {
    padding: if(
      style(--status: complete): 32px;
      style(--status: pending): 20px;
      else: 8px
    );
  }
}

@media (forced-colors: active) {
  .if-scene-fallback-card {
    color: CanvasText;
    background: Canvas;
    border-color: CanvasText;
  }

  .if-scene-fallback-card p {
    background: Canvas;
    border-color: CanvasText;
  }
}

.if-scene-fallback {
  display: grid;
  gap: 1rem;
  color: light-dark(oklch(0.22 0.01 95), oklch(0.95 0.01 95));
  font: 1rem/1.6 system-ui, sans-serif;
  overflow-wrap: anywhere;

  > p {
    margin: 0;
  }

  .native {
    display: none;
  }

  @supports (padding: if(
    style(--status: complete): 32px;
    style(--status: pending): 20px;
    else: 8px
  )) {
    .native {
      display: block;
    }

    .fallback {
      display: none;
    }
  }
}

Una custom property puede almacenar tokens que luego no sean válidos para padding. CSS.supports("--token", "if(...)") no detecta la función. Comprueba una propiedad real y una expresión concreta. Incluso con soporte, el valor que termina en padding debe tener el tipo adecuado; usa else y evita referencias cíclicas.

Sin coincidencia: usar el fallback de var()

En este caso --status vale idle y la única rama consulta complete. --space queda garantizado inválido y var(--space, 8px) puede aportar la alternativa. Esto no convierte cualquier valor de tipo incorrecto en un fallback de var().

Sin coincidencia: usar el fallback de var()
<div class="if-no-match">CSS if()</div>
.if-no-match {
  padding: 12px;

  @supports (padding: if(style(--status: complete): 32px; else: 8px)) {
    --status: idle;
    --space: if(style(--status: complete): 32px);
    padding: var(--space, 8px);
  }
}

Errores frecuentes

Diagnosticar el nivel correcto evita confundir una condición falsa con falta de soporte.

La función no se interpreta

Resultado esperado
La propiedad cambia según una condición.
Causa
Se usan comas entre ramas, falta un colon o hay espacio entre if y el paréntesis.
Solución
Usa if(condición: valor; else: alternativa), sin espacio en if(.

La segunda condición no gana

Resultado esperado
Una rama más abajo reemplaza el resultado anterior.
Causa
La primera rama ya era verdadera, o un else anterior detuvo la búsqueda.
Solución
Ordena de más específica a más general y deja else al final.

else no rescata un navegador antiguo

Resultado esperado
El navegador usa el valor de else al no conocer if().
Causa
No puede evaluar ninguna parte de una función que no implementa.
Solución
Declara una base fuera y protege if() con @supports sobre una propiedad real.

La tarjeta estrecha no activa media()

Resultado esperado
La condición cambia cuando se estrecha el panel.
Causa
media(width ...) consulta el viewport de la página, no la caja del componente.
Solución
Redimensiona el viewport; usa @container para condiciones de tamaño del contenedor.

Comparativas

Elige la herramienta por lo que necesitas cambiar.

if() elige un valor en una declaración; @media y @supports permiten aplicar conjuntos de declaraciones. @container consulta un contenedor y puede aplicar reglas a sus descendientes; style() dentro de if() consulta el elemento al que se aplica el valor. @function define una función CSS personalizada; if() ya viene definida por la plataforma.

Para un tema que solo alterna colores según color-scheme, light-dark() puede expresar mejor la intención. Para variantes completas de un componente, una clase o una regla condicional puede ser más clara que repetir if() en muchas propiedades.

Soporte y compatibilidad

Estado del catálogo, detección de sintaxis y comportamiento real.

Consulta del 15 de octubre de 2026: Web Platform DX y MDN sitúan if() en disponibilidad limitada. BCD registra Chrome/Edge desde 137, sin soporte estable en Firefox ni Safari. La tarjeta Baseline puede actualizarse independientemente de este texto.

@supports verifica aceptación de la sintaxis consultada; no certifica todas las ramas ni todos los motores. La preview deja que CSS resuelva la condición. En un navegador sin soporte conserva la base y su aviso, sin simular if() mediante JavaScript.