Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove outdated prefixes? #283

Open
oliviertassinari opened this issue Jan 22, 2022 · 5 comments
Open

Remove outdated prefixes? #283

oliviertassinari opened this issue Jan 22, 2022 · 5 comments

Comments

@oliviertassinari
Copy link

oliviertassinari commented Jan 22, 2022

Stylis includes a prefixer module:

import { prefixer } from 'stylis';

This is very helpful as there are CSS properties that need vendor prefixes. For example, user-select: none; still requires it in browsers that have an important global usage rate.

However, I have noticed a couple of prefixes that I would argue are more harmful than beneficial. Mainly, the flexbox properties. The global need for the prefix seems to be 0.48% (0.01 + 0.14 + 0.05 + 0.01 + 0.02 + 0.03 + 0.01 + 0.1 + 0.11). Do we need to keep it, at this point?

By removing it, we would gain:

  1. A better DX when debugging CSS. When this module is used with emotion, you get this kind of output by default

Before

Screenshot 2022-01-22 at 19 31 18

After

Screenshot 2022-01-22 at 19 31 30

  1. A smaller bundle.

Actually, this might simply be the root cause of a different problem: What's the browser support target? Do we have something like this https://github.com/kripod/style-vendorizer#browser-support?


@oliviertassinari oliviertassinari changed the title Remove updated prefixes Remove outdated prefixes? Jan 22, 2022
@thysultan
Copy link
Owner

Moving this comment here where we can track the discussion.

In a way, this could be seen as a breaking change.

In a way you could avoid a breaking change by exporting a prefixer, that is a 1-1 clone of the current prefixer with the suggested amendments, i.e export prefixer_bleeding_age™ given that the current prefixer is not privileged and is as much a middleware as any other.

@Andarist
Copy link
Collaborator

Andarist commented Jan 22, 2022

Yep, it's only that with a different prefixer one would always bundle both as the prefixer is included in the default plugins. We've included that to make upgrading to Emotion 11 easier - but this is likely to change in Emotion 12 (no plans for it right now though)

cc @mitchellhamilton

@matthew-dean
Copy link

I'd also love to know how to disable vendor prefixing. We don't need any of it in our environments, so it's injecting a lot of un-needed CSS.

@Andarist
Copy link
Collaborator

If you are using Emotion then u can use CacheProvider and skip providing the prefixer plugin, u can roughly see how it could be done here: https://emotion.sh/docs/cache-provider

@kc980602
Copy link

kc980602 commented Aug 12, 2022

For those who would like to remove MS prefix

import {
  charat,
  combine,
  copy,
  DECLARATION,
  hash,
  indexof,
  KEYFRAMES,
  match,
  MOZ,
  replace,
  RULESET,
  serialize,
  strlen,
  WEBKIT
} from 'stylis'

/**
 * @param {string} value
 * @param {number} length
 * @param {object[]} children
 * @return {string}
 */
function prefix(value, length, children) {
  switch (hash(value, length)) {
    // color-adjust
    case 5103:
      return WEBKIT + 'print-' + value + value
    // animation, animation-(delay|direction|duration|fill-mode|iteration-count|name|play-state|timing-function)
    case 5737:
    case 4201:
    case 3177:
    case 3433:
    case 1641:
    case 4457:
    case 2921:
    // text-decoration, filter, clip-path, backface-visibility, column, box-decoration-break
    case 5572:
    case 6356:
    case 5844:
    case 3191:
    case 6645:
    case 3005:
    // mask, mask-image, mask-(mode|clip|size), mask-(repeat|origin), mask-position, mask-composite,
    case 6391:
    case 5879:
    case 5623:
    case 6135:
    case 4599:
    case 4855:
    // background-clip, columns, column-(count|fill|gap|rule|rule-color|rule-style|rule-width|span|width)
    case 4215:
    case 6389:
    case 5109:
    case 5365:
    case 5621:
    case 3829:
      return WEBKIT + value + value
    // tab-size
    case 4789:
      return MOZ + value + value
    // appearance, user-select, transform, hyphens, text-size-adjust
    case 5349:
    case 4246:
    case 4810:
    case 6968:
    case 2756:
      return WEBKIT + value + MOZ + value + value
    // writing-mode
    case 5936:
      switch (charat(value, length + 11)) {
        // vertical-l(r)
        case 114:
          return WEBKIT + value + value
        // vertical-r(l)
        case 108:
          return WEBKIT + value + value
        // horizontal(-)tb
        case 45:
          return WEBKIT + value + value
        // default: fallthrough to below
      }

    // flex, flex-direction, scroll-snap-type, writing-mode
    case 6828:
    case 4268:
    case 2903:
      return WEBKIT + value + value
    // order
    case 6165:
      return WEBKIT + value + value
    // align-items
    case 5187:
      return (
        WEBKIT +
        value +
        replace(value, /(\w+).+(:[^]+)/, WEBKIT + 'box-$1$2') +
        value
      )
    // align-self
    case 5443:
      return WEBKIT + value + value
    // align-content
    case 4675:
      return WEBKIT + value + value
    // flex-shrink
    case 5548:
      return WEBKIT + value + value
    // flex-basis
    case 5292:
      return WEBKIT + value + value
    // flex-grow
    case 6060:
      return (
        WEBKIT + 'box-' + replace(value, '-grow', '') + WEBKIT + value + value
      )
    // transition
    case 4554:
      return (
        WEBKIT +
        replace(value, /([^-])(transform)/g, '$1' + WEBKIT + '$2') +
        value
      )
    // cursor
    case 6187:
      return (
        replace(
          replace(
            replace(value, /(zoom-|grab)/, WEBKIT + '$1'),
            /(image-set)/,
            WEBKIT + '$1'
          ),
          value,
          ''
        ) + value
      )
    // background, background-image
    case 5495:
    case 3959:
      return replace(value, /(image-set\([^]*)/, WEBKIT + '$1' + '$`$1')
    // justify-content
    case 4968:
      return (
        replace(
          replace(value, /(.+:)(flex-)?(.*)/, WEBKIT + 'box-pack:$3'),
          /s.+-b[^;]+/,
          'justify'
        ) +
        WEBKIT +
        value +
        value
      )
    // justify-self
    case 4200:
      if (!match(value, /flex-|baseline/)) return value

      break
    // grid-template-(columns|rows)
    case 2592:
    case 3360:
      return value
    // grid-(row|column)-start
    case 4384:
    case 3616:
      if (
        children &&
        children.some(function (element, index) {
          return (length = index), match(element.props, /grid-\w+-end/)
        })
      ) {
        return value
      }

      return value
    // grid-(row|column)-end
    case 4896:
    case 4128:
      return value
    // (margin|padding)-inline-(start|end)
    case 4095:
    case 3583:
    case 4068:
    case 2532:
      return replace(value, /(.+)-inline(.+)/, WEBKIT + '$1$2') + value
    // (min|max)?(width|height|inline-size|block-size)
    case 8116:
    case 7059:
    case 5753:
    case 5535:
    case 5445:
    case 5701:
    case 4933:
    case 4677:
    case 5533:
    case 5789:
    case 5021:
    case 4765:
      // stretch, max-content, min-content, fill-available
      if (strlen(value) - 1 - length > 6)
        switch (charat(value, length + 1)) {
          // (m)ax-content, (m)in-content
          case 109:
            // -
            if (charat(value, length + 4) !== 45) break
          // (f)ill-available, (f)it-content
          case 102:
            return (
              replace(
                value,
                /(.+:)(.+)-([^]+)/,
                '$1' +
                  WEBKIT +
                  '$2-$3' +
                  '$1' +
                  MOZ +
                  (charat(value, length + 3) == 108 ? '$3' : '$2-$3')
              ) + value
            )
          // (s)tretch
          case 115:
            return ~indexof(value, 'stretch')
              ? prefix(
                  replace(value, 'stretch', 'fill-available'),
                  length,
                  children
                ) + value
              : value
        }

      break
    // grid-(column|row)
    case 5152:
    case 5920:
      return replace(
        value,
        /(.+?):(\d+)(\s*\/\s*(span)?\s*(\d+))?(.*)/,
        function () {
          return value
        }
      )
    // position: sticky
    case 4949:
      // stick(y)?
      if (charat(value, length + 6) === 121)
        return replace(value, ':', ':' + WEBKIT) + value

      break
    // display: (flex|inline-flex|grid|inline-grid)
    case 6444:
      switch (charat(value, charat(value, 14) === 45 ? 18 : 11)) {
        // (inline-)?fle(x)
        case 120:
          return (
            replace(
              value,
              /(.+:)([^;\s!]+)(;|(\s+)?!.+)?/,
              '$1' +
                WEBKIT +
                (charat(value, 14) === 45 ? 'inline-' : '') +
                'box$3' +
                '$1' +
                WEBKIT +
                '$2$3'
            ) + value
          )
        // (inline-)?gri(d)
        case 100:
          return value
      }

      break
    // scroll-margin, scroll-margin-(top|right|bottom|left)
    case 5719:
    case 2647:
    case 2135:
    case 3927:
    case 2391:
      return replace(value, 'scroll-', 'scroll-snap-') + value
  }

  return value
}

function stylisCustomPrefixer(element, index, children, callback) {
  if (element.length > -1)
    if (!element.return)
      switch (element.type) {
        case DECLARATION:
          element.return = prefix(element.value, element.length, children)

          return
        case KEYFRAMES:
          return serialize(
            [
              copy(element, {
                value: replace(element.value, '@', '@' + WEBKIT)
              })
            ],
            callback
          )
        case RULESET:
          if (element.length)
            return combine(element.props, function (value) {
              switch (match(value, /(::plac\w+|:read-\w+)/)) {
                // :read-(only|write)
                case ':read-only':
                case ':read-write':
                  return serialize(
                    [
                      copy(element, {
                        props: [replace(value, /:(read-\w+)/, ':' + MOZ + '$1')]
                      })
                    ],
                    callback
                  )
                // :placeholder
                case '::placeholder':
                  return serialize(
                    [
                      copy(element, {
                        props: [
                          replace(
                            value,
                            /:(plac\w+)/,
                            ':' + WEBKIT + 'input-$1'
                          )
                        ]
                      }),
                      copy(element, {
                        props: [replace(value, /:(plac\w+)/, ':' + MOZ + '$1')]
                      })
                    ],
                    callback
                  )
              }

              return ''
            })
      }
}

module.exports = stylisCustomPrefixer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants