Skip to content

IS_NON_DIMENSIONAL has false positives and false negatives #2607

@kripod

Description

@kripod

Recently, I wrote some tests for a regular expression with functionality similar to IS_NON_DIMENSIONAL. Out of curiosity, I ran the same tests against Preact's implementation and found the following results:

False positives

When given a number, it should be postfixed with 'px' for the CSS properties below:

  • grid-auto-columns
  • grid-auto-rows
  • grid-template-columns
  • grid-template-rows

The properties above don't accept unitless values. However, IS_NON_DIMENSIONAL matches them, so they're not postfixed with 'px' when given a number.

False negatives

When given a number, it should not be postfixed with 'px' for the CSS properties below:

  • flex-grow
  • flex-shrink
  • font-size-adjust
  • font-weight
  • line-height
  • line-clamp
  • -webkit-line-clamp
  • animation
  • border-image
  • border-image-outset
  • border-image-slice
  • border-image-width
  • shape-image-threshold
  • scale
  • mask-border
  • mask-border-outset
  • mask-border-slice
  • mask-border-width
  • max-lines
  • tab-size
  • columns
  • column-count
  • initial-letter

The properties above accept unitless values. However, IS_NON_DIMENSIONAL doesn't match them, so they're mistakenly postfixed with 'px' when given a number.

Details of the test

✓ regexp matches unitless-valued 'flex' CSS property (1 ms)
✕ regexp matches unitless-valued 'flex-grow' CSS property (2 ms)
✕ regexp matches unitless-valued 'flex-shrink' CSS property
✕ regexp matches unitless-valued 'font-size-adjust' CSS property (1 ms)
✕ regexp matches unitless-valued 'font-weight' CSS property
✓ regexp matches unitless-valued 'grid-area' CSS property
✓ regexp matches unitless-valued 'grid-column' CSS property
✓ regexp matches unitless-valued 'grid-column-end' CSS property (1 ms)
✓ regexp matches unitless-valued 'grid-column-start' CSS property
✓ regexp matches unitless-valued 'grid-row' CSS property
✓ regexp matches unitless-valued 'grid-row-end' CSS property
✓ regexp matches unitless-valued 'grid-row-start' CSS property
✓ regexp matches unitless-valued 'z-index' CSS property
✓ regexp matches unitless-valued 'opacity' CSS property (1 ms)
✓ regexp matches unitless-valued 'order' CSS property
✓ regexp matches unitless-valued 'orphans' CSS property
✕ regexp matches unitless-valued 'line-height' CSS property
✕ regexp matches unitless-valued 'line-clamp' CSS property (1 ms)
✕ regexp matches unitless-valued '-webkit-line-clamp' CSS property
✕ regexp matches unitless-valued 'animation' CSS property
✓ regexp matches unitless-valued 'animation-iteration-count' CSS property
✕ regexp matches unitless-valued 'border-image' CSS property
✕ regexp matches unitless-valued 'border-image-outset' CSS property
✕ regexp matches unitless-valued 'border-image-slice' CSS property (1 ms)
✕ regexp matches unitless-valued 'border-image-width' CSS property
✕ regexp matches unitless-valued 'shape-image-threshold' CSS property
✕ regexp matches unitless-valued 'scale' CSS property (1 ms)
✕ regexp matches unitless-valued 'mask-border' CSS property
✕ regexp matches unitless-valued 'mask-border-outset' CSS property (4 ms)
✕ regexp matches unitless-valued 'mask-border-slice' CSS property
✕ regexp matches unitless-valued 'mask-border-width' CSS property (1 ms)
✕ regexp matches unitless-valued 'max-lines' CSS property
✕ regexp matches unitless-valued 'tab-size' CSS property
✕ regexp matches unitless-valued 'columns' CSS property
✕ regexp matches unitless-valued 'column-count' CSS property (1 ms)
✓ regexp matches unitless-valued 'widows' CSS property
✕ regexp matches unitless-valued 'initial-letter' CSS property
✓ regexp does not match non-unitless-valued 'background' CSS property
✓ regexp does not match non-unitless-valued 'background-position' CSS property
✓ regexp does not match non-unitless-valued 'background-position-x' CSS property
✓ regexp does not match non-unitless-valued 'background-position-y' CSS property
✓ regexp does not match non-unitless-valued 'background-size' CSS property
✓ regexp does not match non-unitless-valued 'block-size' CSS property
✓ regexp does not match non-unitless-valued 'border' CSS property
✓ regexp does not match non-unitless-valued 'border-block' CSS property
✓ regexp does not match non-unitless-valued 'border-block-width' CSS property
✓ regexp does not match non-unitless-valued 'border-block-end' CSS property
✓ regexp does not match non-unitless-valued 'border-block-end-width' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'border-block-start' CSS property
✓ regexp does not match non-unitless-valued 'border-block-start-width' CSS property
✓ regexp does not match non-unitless-valued 'border-bottom' CSS property
✓ regexp does not match non-unitless-valued 'border-bottom-left-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-bottom-right-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-bottom-width' CSS property
✓ regexp does not match non-unitless-valued 'border-end-end-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-end-start-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-inline' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'border-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'border-inline-width' CSS property
✓ regexp does not match non-unitless-valued 'border-inline-end-width' CSS property
✓ regexp does not match non-unitless-valued 'border-inline-start' CSS property
✓ regexp does not match non-unitless-valued 'border-inline-start-width' CSS property
✓ regexp does not match non-unitless-valued 'border-left' CSS property
✓ regexp does not match non-unitless-valued 'border-left-width' CSS property
✓ regexp does not match non-unitless-valued 'border-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-right' CSS property
✓ regexp does not match non-unitless-valued 'border-right-width' CSS property
✓ regexp does not match non-unitless-valued 'border-spacing' CSS property
✓ regexp does not match non-unitless-valued 'border-start-end-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-start-start-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-top' CSS property
✓ regexp does not match non-unitless-valued 'border-top-left-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-top-right-radius' CSS property
✓ regexp does not match non-unitless-valued 'border-top-width' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'border-width' CSS property
✓ regexp does not match non-unitless-valued 'bottom' CSS property
✓ regexp does not match non-unitless-valued 'column-gap' CSS property
✓ regexp does not match non-unitless-valued 'column-rule' CSS property
✓ regexp does not match non-unitless-valued 'column-rule-width' CSS property
✓ regexp does not match non-unitless-valued 'column-width' CSS property
✓ regexp does not match non-unitless-valued 'flex-basis' CSS property
✓ regexp does not match non-unitless-valued 'font-size' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'gap' CSS property
✕ regexp does not match non-unitless-valued 'grid-auto-columns' CSS property
✕ regexp does not match non-unitless-valued 'grid-auto-rows' CSS property
✕ regexp does not match non-unitless-valued 'grid-template-columns' CSS property (1 ms)
✕ regexp does not match non-unitless-valued 'grid-template-rows' CSS property
✓ regexp does not match non-unitless-valued 'height' CSS property
✓ regexp does not match non-unitless-valued 'inline-size' CSS property
✓ regexp does not match non-unitless-valued 'inset' CSS property
✓ regexp does not match non-unitless-valued 'inset-block' CSS property
✓ regexp does not match non-unitless-valued 'inset-block-end' CSS property
✓ regexp does not match non-unitless-valued 'inset-block-start' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'inset-inline' CSS property
✓ regexp does not match non-unitless-valued 'inset-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'inset-inline-start' CSS property
✓ regexp does not match non-unitless-valued 'left' CSS property
✓ regexp does not match non-unitless-valued 'letter-spacing' CSS property
✓ regexp does not match non-unitless-valued 'line-height-step' CSS property
✓ regexp does not match non-unitless-valued 'margin' CSS property
✓ regexp does not match non-unitless-valued 'margin-block' CSS property
✓ regexp does not match non-unitless-valued 'margin-block-end' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'margin-block-start' CSS property
✓ regexp does not match non-unitless-valued 'margin-bottom' CSS property
✓ regexp does not match non-unitless-valued 'margin-inline' CSS property
✓ regexp does not match non-unitless-valued 'margin-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'margin-inline-start' CSS property
✓ regexp does not match non-unitless-valued 'margin-left' CSS property
✓ regexp does not match non-unitless-valued 'margin-right' CSS property
✓ regexp does not match non-unitless-valued 'margin-top' CSS property
✓ regexp does not match non-unitless-valued 'mask' CSS property
✓ regexp does not match non-unitless-valued 'mask-position' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'mask-size' CSS property
✓ regexp does not match non-unitless-valued 'max-block-size' CSS property
✓ regexp does not match non-unitless-valued 'max-height' CSS property
✓ regexp does not match non-unitless-valued 'max-inline-size' CSS property
✓ regexp does not match non-unitless-valued 'max-width' CSS property
✓ regexp does not match non-unitless-valued 'min-block-size' CSS property
✓ regexp does not match non-unitless-valued 'min-height' CSS property
✓ regexp does not match non-unitless-valued 'min-inline-size' CSS property
✓ regexp does not match non-unitless-valued 'min-width' CSS property
✓ regexp does not match non-unitless-valued 'object-position' CSS property
✓ regexp does not match non-unitless-valued 'offset' CSS property
✓ regexp does not match non-unitless-valued 'offset-anchor' CSS property
✓ regexp does not match non-unitless-valued 'offset-distance' CSS property
✓ regexp does not match non-unitless-valued 'offset-position' CSS property
✓ regexp does not match non-unitless-valued 'outline' CSS property
✓ regexp does not match non-unitless-valued 'outline-offset' CSS property
✓ regexp does not match non-unitless-valued 'outline-width' CSS property
✓ regexp does not match non-unitless-valued 'padding' CSS property
✓ regexp does not match non-unitless-valued 'padding-block' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'padding-block-end' CSS property
✓ regexp does not match non-unitless-valued 'padding-block-start' CSS property
✓ regexp does not match non-unitless-valued 'padding-bottom' CSS property
✓ regexp does not match non-unitless-valued 'padding-inline' CSS property
✓ regexp does not match non-unitless-valued 'padding-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'padding-inline-start' CSS property
✓ regexp does not match non-unitless-valued 'padding-left' CSS property
✓ regexp does not match non-unitless-valued 'padding-right' CSS property
✓ regexp does not match non-unitless-valued 'padding-top' CSS property
✓ regexp does not match non-unitless-valued 'perspective' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'perspective-origin' CSS property
✓ regexp does not match non-unitless-valued 'right' CSS property
✓ regexp does not match non-unitless-valued 'row-gap' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-block' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-block-start' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-block-end' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-bottom' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-inline' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-inline-start' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'scroll-margin-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-left' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-right' CSS property
✓ regexp does not match non-unitless-valued 'scroll-margin-top' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-block' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-block-start' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-block-end' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-bottom' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-inline' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-inline-start' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-inline-end' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-left' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-right' CSS property
✓ regexp does not match non-unitless-valued 'scroll-padding-top' CSS property
✓ regexp does not match non-unitless-valued 'shape-margin' CSS property
✓ regexp does not match non-unitless-valued 'text-decoration' CSS property
✓ regexp does not match non-unitless-valued 'text-decoration-thickness' CSS property
✓ regexp does not match non-unitless-valued 'text-indent' CSS property
✓ regexp does not match non-unitless-valued 'text-underline-offset' CSS property
✓ regexp does not match non-unitless-valued 'top' CSS property (1 ms)
✓ regexp does not match non-unitless-valued 'transform-origin' CSS property
✓ regexp does not match non-unitless-valued 'translate' CSS property
✓ regexp does not match non-unitless-valued 'vertical-align' CSS property
✓ regexp does not match non-unitless-valued 'width' CSS property
✓ regexp does not match non-unitless-valued 'word-spacing' CSS property

A potential fix

The implementation of otion passes all the tests, while also checking strings in a more performant manner (matching only from the start instead of at any position):

// otion's variant (modified to work with non-hyphenated object syntax)
/^(-|f[lo].*[^se]$|g.{5,}[^ps]$|z|o[pr]|(W.{5})?[lL]i.*(t|mp)$|an|(bo|s).{4}Im|sca|m.{6}[ds]|ta|c.*[st]$|wido|ini)/

// Preact's variant
/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i

Unlike Preact's 67-byte solution, however, it weighs in at 115 bytes, adding 48 bytes to the bundle size.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions