├── LICENSE ├── README.md ├── bower.json ├── css ├── print.css └── style.css ├── fonts ├── Arvo-Bold.ttf └── Arvo-Regular.ttf ├── img ├── favicon.png ├── logo.png ├── logo.svg ├── noise.png └── raisedfist.png ├── index.html ├── index.js ├── minify ├── plugins ├── prefixfree.dynamic-dom.js ├── prefixfree.dynamic-dom.min.js ├── prefixfree.eventname.js ├── prefixfree.jquery.js ├── prefixfree.jsapi.js ├── prefixfree.vars.js └── prefixfree.viewport-units.js ├── prefixfree.js ├── prefixfree.min.js └── test └── jasmine ├── SpecRunner.html ├── lib └── jasmine-1.3.1 │ ├── MIT.LICENSE │ ├── jasmine-html.js │ ├── jasmine.css │ └── jasmine.js ├── onload.js ├── spec └── prefixfreeSpec.js └── test.css /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Lea Verou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [-prefix-**free**](https://leaverou.github.io/prefixfree/) 2 | ## Break free from CSS prefix hell! 3 | 4 | [Project homepage](https://leaverou.github.io/prefixfree/) 5 | 6 | A script that lets you use only unprefixed CSS properties everywhere. 7 | It works behind the scenes, adding the current browser’s prefix to any CSS code, only when it’s needed. 8 | 9 | ## API Documentation 10 | 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. 11 | 12 | -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. 13 | 14 | ## StyleFix API Documentation 15 | 16 | ### Properties 17 | StyleFix.fixers 18 | An array of the current callbacks. 19 | 20 | ### Functions 21 | StyleFix.register(callback) 22 | Adds `callback` to the queue of functions that will be called when fixing CSS code. `callback` will be called with the following parameters: 23 | 24 | * **css** (String): The CSS code that is being processed, 25 | * **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), 26 | * **element** (HTMLElement): The node that the CSS code came from (such as a `` element, a ` 16 | 17 | 18 | 19 | 20 |
21 |

-prefix-free

22 |

Break free from CSS prefix hell!

23 |
24 | 25 | Only 2KB gzipped 26 | Fork me on GitHub 27 | 28 |

29 | -prefix-free lets you use only unprefixed CSS properties everywhere. 30 | It works behind the scenes, adding the current browser’s prefix to any CSS code, only when it’s needed. 31 |

32 | 33 | 41 | 42 |
43 |

“[-prefix-free is] fantastic, top-notch work! Thank you for creating and sharing it.”

44 | — Eric Meyer 45 |
46 | 47 |
48 |
49 |

Features

50 | 56 |
57 |
58 |

Limitations

59 | 65 |
66 |
67 | 68 |
69 |
70 |

Demo?

71 |

Check this page’s stylesheet ;-)

72 |

You can also visit the Test Drive page, type in any code you want and check out how it would get prefixed for the current browser.

73 |
74 | 75 |
76 |

How to use

77 |

Just include prefixfree.js anywhere in your page. It is recommended to put it right after the stylesheets, to minimize FOUC 78 |

That’s it, you’re done!

79 |
80 |
81 | 82 |
83 |

Browser support

84 |

The target browser support is IE9+, Opera 10+, Firefox 3.5+, Safari 4+ and Chrome on desktop and Mobile Safari, Android browser, Chrome and Opera Mobile on mobile.

85 |

If it doesn’t work in any of those, it’s a bug so please report it. Just before you do, please make sure that it’s not because the browser doesn’t support a CSS3 feature at all, even with a prefix.

86 |

In older browsers like IE8, nothing will break, just properties won’t get prefixed. Which wouldn’t be useful anyway as IE8 doesn’t support much CSS3 ;)

87 |
88 | 89 |
90 |

Test drive

91 |

Test the prefixing that -prefix-free would do for this browser, by writing some CSS below:

92 | 121 | 122 |
123 | 124 | 125 |
126 |

FAQ

127 | 128 |
129 |

What if I actually want to target only a specific prefix?

130 |

Properties/values etc that already have a prefix won’t be altered. However, if you use the unprefixed property/value etc after the prefixed properties, you might run into issue #16. 131 | For those cases, -prefix-free adds a class on the root element (the <html> element in HTML) with the same name as the current prefix. So for example, to solve the problem presented in the above issue, you could do:

132 |
.myselector {
133 |     transform: rotate(15deg);
134 | }
135 | .-webkit- .myselector {
136 |     transform: rotate(15deg) rotateX(0);
137 | }
138 |

It’s not ideal, but it’s a solution, until a more intuitive way to deal with these cases is added in -prefix-free.

139 |

Please note that in unsupported browsers like IE8, no such class will be added.

140 |
141 | 142 | 143 |
144 |

How do I exclude specific files from being prefixed?

145 |

You can exclude a file from being prefixed by adding the data-noprefix attribute to the <link> or <style> element. For example:

146 |
<link href="//example.com/style.css" rel="stylesheet" type="text/css" data-noprefix>
147 |
148 | 149 |
150 |

How do I enable local testing?

151 |

Firefox (and IE?) natively support local XHR, so -prefix-free will work fine locally with them.

152 |

To enable local XHR for Chrome, you need to run it with the flag --allow-file-access-from-files.

153 |

To enable local XHR for Opera, you have to go to opera:config#UserPrefs|AllowFileXMLHttpRequest, check that option and Save.

154 |
155 | 156 |
157 |

Something like this belongs to the server-side

158 |

A server side script would need to add all prefixes, making the size of the CSS file considerably larger. Also, it should maintain a list of features that need prefixes, or add them all and unnecessarily bloat the stylesheet. -prefix-free automatically detects what needs a prefix and what doesn’t.

159 |

Also, a common argument against doing this on the client side, is that it makes the design rely on JavaScript. However, that is completely false: If JS is disabled, only some of the CSS3 won’t show. But if your design relies on CSS3 to be functional, you have bigger problems bro.

160 |

You can read some more about this in my recent CSS Tricks interview

161 |

But every solution has its own pros and cons. If you would feel more comfortable with a server-side script, use that and don’t troll me please. Remember: nobody forced you to use -prefix-free. KTHXBAI ☺

162 |
163 |
164 | 165 |
166 |

Plugins

167 |

Extra code on top of -prefix-free that makes it more flexible, integrates it with different APIs etc

168 | 169 |
170 |

Dynamic DOM plugin

171 |

Originally a part of -prefix-free, it’s now a separate plugin. It makes -prefix-free take care of:

172 | 180 | Things to be aware of: 181 | 190 |

Get the Dynamic DOM plugin now:

191 | 195 |
196 | 197 |
198 |

jQuery plugin

199 |

A tiny plugin (I didn’t even bother minifying it as it’s so small) that lets you set/get unprefixed CSS properties through jQuery's .css method.

200 |

Get the jQuery plugin now:

201 | 204 |
205 | 206 |
207 |

Viewport-relative units

208 |

A static polyfill for the new vw, vh, vmin, vmax units.

209 | 213 | 216 |
217 | 218 |
219 |

CSS Variables

220 |

Enables rudimentary CSS variables support.

221 | 225 | Limitations: 226 | 230 | 233 |
234 |
235 | 236 | 241 | 242 | 243 | 244 | Tweet 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Scripts for the demo page of -prefix-free 2 | 3 | function $(id) { return document.getElementById(id) } 4 | 5 | (function(){ 6 | 7 | if(window.PrefixFree) { 8 | var source = $('source'), 9 | prefixed = $('prefixed'); 10 | 11 | (source.oninput = function() { 12 | prefixed.value = PrefixFree.prefixCSS(source.value, true); 13 | })(); 14 | 15 | source.onscroll = function() { 16 | prefixed.scrollTop = source.scrollTop; 17 | } 18 | } 19 | 20 | (window.onhashchange = function() { 21 | var target, page, previousPage; 22 | 23 | if(location.hash) { 24 | page = target = document.querySelector(location.hash); 25 | 26 | while(page && page.className != 'page') { 27 | page = page.parentNode; 28 | } 29 | } 30 | 31 | (previousPage = document.querySelector('.current.page')) && (previousPage.className = 'page'); 32 | 33 | if(page) { 34 | page.className = 'current page'; 35 | 36 | document.body.className = 'in-page'; 37 | } 38 | else { 39 | document.body.className = 'home'; 40 | } 41 | 42 | if(target) { 43 | target.scrollIntoView(true); 44 | } 45 | })(); 46 | 47 | })(); 48 | 49 | -------------------------------------------------------------------------------- /minify: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ( 3 | head -n 5 prefixfree.js 4 | curl --data-urlencode 'js_code@prefixfree.js' \ 5 | --data 'output_info=compiled_code' \ 6 | https://closure-compiler.appspot.com/compile 7 | ) > prefixfree.min.js 8 | -------------------------------------------------------------------------------- /plugins/prefixfree.dynamic-dom.js: -------------------------------------------------------------------------------- 1 | // StyleFix Dynamic DOM plugin 2 | (function(self){ 3 | 4 | if(!self) { 5 | return; 6 | } 7 | 8 | self.events = { 9 | DOMNodeInserted: function(evt) { 10 | var node = evt.target, tag = node.nodeName; 11 | 12 | if(node.nodeType != 1) { 13 | return; 14 | } 15 | 16 | if(/link/i.test(tag)) { 17 | self.link(node); 18 | } 19 | else if(/style/i.test(tag)) { 20 | self.styleElement(node); 21 | } 22 | else if (node.hasAttribute('style')) { 23 | self.styleAttribute(node); 24 | } 25 | }, 26 | 27 | DOMAttrModified: function(evt) { 28 | if(evt.attrName === 'style') { 29 | document.removeEventListener('DOMAttrModified', self.events.DOMAttrModified, false); 30 | self.styleAttribute(evt.target); 31 | document.addEventListener('DOMAttrModified', self.events.DOMAttrModified, false); 32 | } 33 | } 34 | }; 35 | 36 | document.addEventListener('DOMContentLoaded', function() { 37 | // Listen for new and