Break free from CSS prefix hell!

  • By Lea Verou
  • Last update: Dec 19, 2022
  • Comments: 16


Break free from CSS prefix hell!

Project homepage

A script that lets you use only unprefixed CSS properties everywhere. It works behind the scenes, adding the current browserโ€™s prefix to any CSS code, only when itโ€™s needed.

API Documentation

Note: To use -prefix-free you don't need to write any JS code, just to include prefixfree.js in your page. The following is meant mostly for plugin authors.

-prefix-free creates 2 global variables: StyleFix and PrefixFree. StyleFix is a framework for building various CSS fixers and -prefix-free depends on it. Currently, StyleFix is bundled with -prefix-free and only available this way, but it might eventually get split to a separate project, with separate documentation.

StyleFix API Documentation



An array of the current callbacks.



Adds callback to the queue of functions that will be called when fixing CSS code. callback will be called with the following parameters:

  • css (String): The CSS code that is being processed,
  • raw (Boolean): Whether the CSS code can contain rules etc or it's just a bunch of declarations (such as the ones found in the style attribute),
  • element (HTMLElement): The node that the CSS code came from (such as a <link> element, a <style> element or any element with a style attribute)

and it should return the fixed CSS code.

Processes a <link rel="stylesheet"> element and converts it to a <style> element with fixed code. Relative URLs will be converted.


Fixes code inside a <style> element.


Fixes code inside the style attribute of an element. Will not work in IE and Firefox < 3.6 due to a bug those have with getAttribute('style'): In IE invalid values of valid properties will be dropped, and in Firefox < 3.6 anything invalid will be dropped.


Utility methods that convert a string to camelCase and back.

-prefix-free API Documentation



The detected prefix of the current browser (like '-moz-' or '-webkit-')


The detected prefix of the current browser in camelCase format (like 'Moz' or 'Webkit')

Properties/functions/keywords/etc that are only available with a prefix in the current browser.


PrefixFree.prefixCSS(code [, raw])

Prefixes the properties and values in the code passed with the prefix of the current browser, only when needed. If the second parameter is truthy, it also prefixes selectors and @-rules. This is the most useful method in -prefix-free.


Prefixes the passed selector or property. The property is prefixed even when it's supported prefix-less. These are more internal methods and I assume they won't be too useful in general.



  • 1

    box-shadow gets prefixed even when it shouldn't

    IE10 version tested: 10.0.8102.0 When prefixing the box-shadow propertie (like -prefix-free do it on IE10), this propertie doesn't work. Example that doesn't work for IE10: -ms-box-shadow(#6D6D6D 2px 2px 4px) This works for IE10: box-shadow(#6D6D6D 2px 2px 4px)

    You can see this issue on that page:

    Thanks for your great work

  • 2

    Broken when stylesheet URL contains RegExp chars like +

    Behavior RegExp is broken:

    SyntaxError: Invalid regular expression /bla/: Nothing to repeat

    Base URL needs to be escaped before being used in a RegExp.

  • 3

    -prefix-free disables media query in IE9

    In IE9 with a linked stylesheet using the media query "only screen and (min-width: 500px)", -prefix-free disables that stylesheet when it loads. Resizing the browser causes the stylesheet to be re-applied.

    Test case:

  • 4

    box-sizing not getting prefixed in FireFox v27

    Hi! I don't know if it's a bug of FF, because, strangely, in your example page box-sizing gets prefixed. Instead, in my page it doesn't get replaced:

    * {
        box-sizing: border-box;

    gets me

    * {
  • 5

    stopped working on Chrome 26.0.1410.43

    I was working on my Mac, with Chrome, and everything was OK. Then I turned on my PC and fired my site, also on Chrome. Immediately I noticed linear-gradients stopped working. After further investigation I realized that the CSS files were being parsed but no property was actually being prefixed.

    Then I checked both browser (on Mac and on PC) versions. Chrome on Mac was outdated (24) and on PC it was up to date (26).

    Simply updated my Chrome on my Mac and the same error (no prefixes) occurred.

    I assume Prefixfree is not working under Chrome 26.

  • 6

    Properties under a "transition" aren't prefixed

    For example, transition: transform 0.25s ease-in-out; becomes -moz-transition: transform 0.25s ease-in-out;.

    I expected -moz-transition: -moz-transform 0.25s ease-in-out;

  • 7

    Add a few new keywords and selectors, fix some of the test suite.

    This adds support for:

    • cursor: grab, cursor: grabbing, width: contains-float
    • ::backdrop, :fullscreen and ::placeholder.

    The tests have improved, but they are still broken...

  • 8

    Relative URLs do not work

    Tried out this script today and as soon as I refreshed the page I was working on all of the css background images disappeared as soon as the script loaded. I tried the script first at bottom of page, where I normally put js like this, tried it in the as well.

    I'm on a mac and this bug happened in Chrome 14 and the latest Firefox version 7.0.

    I typically write my css on one line and write background properties like this: background: url(../img/hero-bg.png) no-repeat;

    Would love to use the script but unfortunately won't be able to with this bug.


  • 9

    Add support for input-placeholder

    Any chance you can add support for styling the input placeholder? AFAIK, following works:

    :-ms-input-placeholder for IE 10+ :-moz-placeholder for Firefox 4+ ::-webkit-input-placeholder for Chrome and Safari

  • 10

    IE9: Fallback to XDomainRequest if available.

    On IE9, XMLHttpRequest does not allow to do a crossdomain request. An exception is triggered on open() in this case. We intercept this exception and use XDomainRequest if available.

    This should close #60.

  • 11

    Adding support for grab & grabbing cursors

    I needed support for these values in a prototype I'm building and noticed they were omitted. See:

    WebKit & Mozilla both implement these values with prefixes.

  • 12

    Update prefixfree.min.js

    There have been PRs merged to update prefixfree.js, but the prefixfree.min.js file hasn't been updated for 4 years. Would be good to have this updated to the latest.

  • 13

    grid-column-gap and grid-row-gap support

    Can you add support for "column-gap" and "row-gap"?

    // does not work in iOS Safari 11.1
    column-gap: 10px
    row-gap: 10px

    For example iOS Safari 11.1 doesn't understand column-gap and row-gap.

    The prefixed version would be:

    // does work in iOS Safari 11.1
    grid-column-gap: 10px
    grid-row-gap: 10px
  • 14

    disable grid?

    Thanks for this awesome library!

    I am having IE issues with grid. Is it possible to tell prefix-free not to handle any grid styles?


    By the way, I am including prefixfree.min.js in my project.

  • 15

    Caution: StyleFix breaks BrowserSync stream reloading

    StyleFix converts <link ... /> into <style ... /> , and this breaks BrowserSync automatic style refresh. As a result, BrowserSync stylesheet reloading doesn't work, one needs to fully reload the page. This is probably a wont-fix, but still good to know for some people.

  • 16

    Document.currentScript is null when executed in a module or with eval

    Document.currentScript is null when executed in a module or with eval. This results in an exception on line 14 in prefixfree.js. I understand that the limitations state, "Prefixing code in @import-ed files is not supported." However, I am not sure if that refers to the CSS or the -prefixfree source. Applications run in environments like StackBlitz are bundled or executed with eval where Document.currentScript is always null. This reproduction using -prefixfree and conic-gradients performs a null check.

    var currentScript = document.currentScript;
    var self = window.StyleFix = {
    	optIn: currentScript && currentScript.hasAttribute("data-prefix"),