stylis
stylis copied to clipboard
Remove outdated prefixes?
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:
- 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](https://user-images.githubusercontent.com/3165635/150651112-6582252c-a9ff-4046-8829-0d71fecfd67d.png)
After
![Screenshot 2022-01-22 at 19 31 30](https://user-images.githubusercontent.com/3165635/150651111-ba9b139c-a582-402a-b2fb-1dedd7101d20.png)
- 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?
- A fun read https://css-tricks.com/is-vendor-prefixing-dead/#aa-prefixing-in-2021
- A related thread https://github.com/styled-components/styled-components/issues/285
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.
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
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.
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
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