Saltar al contenido

enforce-shorthand ​

Regla de oxlint que une utilidades de Tailwind CSS con el mismo valor en cada lado en su shorthand, como mt-2 mr-2 mb-2 ml-2 → m-2 o w-4 h-4 → size-4.

De un vistazo ​

AutofixSugerencias en el editorDesign systemOpciones
SíNoOpcional — se usa si hay entryPointentryPoint

Qué hace esta regla ​

Combina utilities por-eje de Tailwind en sus equivalentes shorthand cuando todos los ejes llevan el mismo valor. El caso más común: mt-2 mr-2 mb-2 ml-2 colapsa a m-2. Familias cubiertas:

FamiliaColapsa
margin / paddingcuatro lados → m-*, ejes → my-*/mx-*, mx-*+my-* → m-*, y los lados lógicos: ms-*+me-* → mx-*, mbs-*+mbe-* → my-*, los cuatro → m-*
scroll-m*/scroll-p*las mismas formas
sizingw-*+h-* → size-*
radiosesquinas → bordes → rounded-*, incluidas las esquinas lógicas (rounded-ss-*+rounded-es-* → rounded-s-*)
borderslados → border-*, ejes → border-x-*/border-y-* — anchos y colores, lados lógicos (border-bs-*+border-be-* → border-y-*) incluidos
insettop/right/bottom/left → inset-*, ejes → inset-x-*/inset-y-*, start-*+end-* e inset-s-*+inset-e-* → inset-x-*, inset-bs-*+inset-be-* → inset-y-*
pares de una propiedadgap-x+gap-y, overflow-x+overflow-y, overscroll-x+overscroll-y, border-spacing-x+border-spacing-y, translate-x+translate-y

Un diagnóstico por grupo colapsable: los cuatro lados reportan m-2 una vez, no m-2 más las mitades my-2/mx-2.

scale-x-*+scale-y-* deliberadamente no es una familia. scale-110 además escribe --tw-scale-z, que scale-3d lee, así que fusionar cambiaría cómo renderiza scale-x-110 scale-y-110 scale-3d.

Con un entryPoint, la fusión se comprueba contra el CSS ​

Tailwind v4 tiene namespaces de tema por eje: w-* lee --width-* (y --container-*), h-* lee --height-*, size-* lee --size-*. Con este tema

css
@theme {
  --width-brand: 10rem;
  --height-brand: 20rem;
}

w-brand h-brand → size-brand es destructivo: size-brand no existe, y el elemento pierde el ancho y el alto. Si configuras settings.tailwindcss.entryPoint (o el entryPoint propio de la regla), la regla compara las declaraciones que Tailwind emite — las partes tienen que resolver al mismo valor y el reemplazo tiene que reproducirlo — así que esa fusión no se ofrece.

Los tokens de tema con nombre en la familia de sizing solo se fusionan cuando los valores son literalmente idénticos. w-card h-card se deja como está incluso si los tres namespaces definen card como 30rem, porque cada lado lee una variable distinta y un override en :root de una de ellas las separa — el mismo razonamiento que enforce-canonical aplica a rounded-[0.5rem] → rounded-lg.

Sin entry point la regla mantiene las fusiones que son seguras diga lo que diga el tema: números y fracciones (la escala de spacing compartida), valores arbitrarios (el mismo literal a los dos lados), las keywords del core (full, auto, min, max, fit, px y las unidades de viewport), y todas las familias que no son sizing — esas beben de un único namespace.

Opciones ​

entryPoint ​

string, opcional. Un entry point CSS solo para esta regla, que pisa settings.tailwindcss.entryPoint. Se usa únicamente para verificar las fusiones contra el CSS emitido; la regla funciona sin él.

Ejemplos ​

✗ Incorrecto ​

tsx
// Margen en los cuatro lados
<div className="mt-2 mr-2 mb-2 ml-2" />
//              ~~~~ ~~~~ ~~~~ ~~~~  → m-2

// Dos ejes (vertical, horizontal)
<div className="mt-2 mb-2" />  →  my-2
<div className="ml-2 mr-2" />  →  mx-2

// Width + height con el mismo valor
<div className="w-full h-full" />
//              ~~~~~~ ~~~~~~  → size-full

// Lados y ejes de cualquier familia cubierta
<div className="border-t-2 border-r-2 border-b-2 border-l-2" />  →  border-2
<div className="top-0 right-0 bottom-0 left-0" />                →  inset-0
<div className="rounded-tl-lg rounded-tr-lg" />                  →  rounded-t-lg
<div className="gap-x-4 gap-y-4" />                              →  gap-4

// Pares lógicos inline — `ms-*`+`me-*` ES `margin-inline`
<div className="ms-4 me-4" />  →  mx-4

// Lo mismo con important — los dos lados tienen que compartir el modificador
<div className="!mt-2 !mr-2 !mb-2 !ml-2" />
//              ~~~~~ ~~~~~ ~~~~~ ~~~~~  → !m-2

✓ Correcto ​

tsx
// Ya es shorthand
<div className="m-2 p-4" />

// Valores distintos por eje — no se puede colapsar
<div className="mt-2 mb-4" />

// w-screen es 100vw y h-screen es 100vh; size-screen no existe
<div className="w-screen h-screen" />

// Tokens de tema por eje: `size-brand` dejaría el elemento sin dimensiones
// (hace falta un entryPoint para detectarlo — ver arriba)
<div className="w-brand h-brand" />

// scale-110 además escribe --tw-scale-z, que scale-3d lee
<div className="scale-x-110 scale-y-110" />

// Cobertura parcial — necesita los cuatro lados para m-*
<div className="mt-2 mr-2" />

// Dos lados adyacentes no son un eje
<div className="top-0 right-0" />

// Variants distintas — la regla no fusiona cruzando cadenas de variants
<div className="hover:mt-2 focus:mb-2" />

Interacciones con otras reglas ​

  • enforce-sort-order: ejecuta shorthand primero así el shorthand participa del sort con su propia prioridad. Si no, el sort ubica mt-2 mr-2 mb-2 ml-2 en posiciones separadas y el fix del shorthand las colapsa después.
  • enforce-logical / enforce-physical: reescriben los mismos lados. mt-2 mb-2 es my-2 aquí y un par del eje block (mbs-2 mbe-2) para enforce-logical; esta regla también pliega los pares lógicos, y cae en utilities de eje (my-*, inset-x-*, border-y-*) que ninguna regla direccional convierte, así que aplique primero el fix que sea, el string termina igual. Nunca pliega inline-* + block-* en size-*: size-* es un ancho y un alto, y el sizing de enforce-logical lo volvería a separar.
  • enforce-consistent-important-position: el shorthand respeta la convención de posición del ! de las clases fusionadas. Si las cuatro usan prefijo, el shorthand queda con prefijo; lo mismo para sufijo.

Cuándo desactivarla ​

  • Quieres valores explícitos por eje para readability, sobre todo en libraries de componentes de design system donde los reviewers encuentran mt-2 mr-2 mb-2 ml-2 más claro que m-2.
  • Generación de código donde cada utility se emite a propósito y colapsarlas escondería la intención.

Released under the MIT License.