The ability to inject newly-modified CSS on every file change (without reloading the page) is the type of workflow-enhancement that you never truly appreciate… until you lose it.
This is exactly what happened to me recently.
For at least the last 12 months I had been using Grunt and the LiveReload browser extension to inject CSS when my files changed. It felt like a really nice workflow until I had to work on a project that required IE7 & 8 support. The LiveReload plugin I was using simply didn’t support older versions of IE. For the first time in over a year I had to resort to manual page-refreshes every time I made a change to my CSS. It was painful. It’s also why I built Browser-Sync
Introducing Browser-Sync
Browser-sync is a tool that gives you cross-browser CSS injecting. It will watch over your files and the moment you make a change, it will inform all connected browsers to reload (inject) the new CSS. This all happens without reloading the page. Most importantly, it works in every browser I’ve been able to test it on.

How Browser-Sync came to be
I knew from the outset that simply inserting new CSS into browsers is easy enough to do. The issue I had to solve was how to communicate a file-system change back to the browsers. The Grunt + LiveReload combination I was using previously relied on Web Sockets. This is why there was no support for old IE.
Say hello to Socket.io
I had my lightbulb moment when using Karma for running unit-tests. Karma allows you to run tests in multiple browsers. While testing in IE8 one day, I realized that Karma was automatically re-running the tests on each file save.
Bingo. I had found something that was able to watch the file system for changes and inform browsers all about it. I started to dig into the Karma source code. Eventually I discovered they were using Socket.io to achieve this.
Starting to come together
Everything was in place. With the pain endured from manual page refreshing as my driving force and the discovery of Socket.io as my inspiration, I was well set-up to build a tool that I would use myself on a daily basis.
Getting set up
This guide assumes you already have Grunt installed inside a project and know how to use it. If you don’t, then you can learn about it on the Grunt site.
Browser-sync can be installed as a stand-alone command-line tool, or as a Grunt plugin. Because of the current popularity of Grunt I’ll focus here on how to set it up as as Grunt Task. If you would prefer the command-line only approach, please checkout these instructions.
From the same file directory as your Gruntfile.js:
npm install grunt-browser-sync
This will install Browser-sync locally into your project. Now you can make sure it’s loaded by Grunt by placing this near the end of your Gruntfile.js:
grunt.loadNpmTasks('grunt-browser-sync');
Finally, like all Grunt plugins, you’ll need to provide some configuration. At a minimum, you’ll need the following:
// Inside the Gruntfile.js config object
browser_sync: {
files: {
src : 'assets/css/style.css'
}
}
I got a bit confused when I tried to follow along the steps in the article. It simply did not work – So I went to the official website and read. Seems the steps have changed a bit and instead of naming the task “browser_sync” it should say “browserSync” otherwise grunt won’t run the task.
With your config set up, you can run the plugin with this command:
grunt browser_sync
Now you should receive an HTML snippet that you can paste into the footer of your website. Place that there. Now whenever you change that CSS file (or it’s changed by another build process), it will be automatically injected into all browsers.
Note: there are ways to specify multiple files and you can use wildcards (*) too. Please see the Readme on Github for more information.
A more automated approach
The example above is great for those situations where you already have a server. Building a site with WordPress or Rails, for example. But the downside is that you have that manual step of copying & pasting a snippet into a file. If you’re working with static files (HTML, CSS, & JS) then you can use the built-in server instead. The built-in server will automatically insert any HTML snippets needed so you don’t have to.
To use the built-in server, just set your config like this.
// Inside the Gruntfile.js config object
browser_sync: {
files: {
src : 'app/css/style.css'
},
options: {
server: {
baseDir: "app"
}
}
}
Files will now be served from the app
directory and all the magic needed to inject CSS will be done for you.
Going even further
If you use the server option above, did you notice the IP address and port that is used? Normally something like 192.168.0.8:3001
? Browser-sync tries to figure out a good external IP address to use for the server. That means you should be able to connect to it from any device/computer on the same WiFi network. The cool thing here is that the CSS injecting will work across all mobile devices and tablets too. When you see this type of automation in action, you’re going to find it hard to live without it.
If it doesn’t work for you
In my tests, I’ve found that on typical WiFi networks, Browser-sync does a fantastic job of getting the correct IP address. However, in a large office setup, you may find that it chooses an IP that is not accessible to other devices/computers. If this is the case, and you know what the correct one is, just provide it as an option like this:
// Inside the Gruntfile.js config object
browser_sync: {
files: {
src : 'app/css/style.css'
},
options: {
server: {
host: "192.168.1.1",
baseDir: "app"
}
}
}
Beyond CSS injecting
Being a guest post on CSS-Tricks, I’ve focused mostly on setting up the CSS-injecting part of my tool. But Browser-sync does a lot more than that! It has something awesome called Ghost-mode.
Ghost mode will keep track of all connected browsers and keep the following in sync:
- Scroll Position – extremely helpful when developing with multi-monitor
- Form Fields – fill out a form in one browser and all others will be populated with that data.
- Links – Reviewing a few pages of a newly built site? Have it open on all your devices and when you navigate from page to page, all the browsers with follow you around!
Conclusion
I hope this all sounds pretty cool to you. I loved building Browser-sync. I welcome feedback and issue reporting so that we can improve it as a community.
Remember Browser-sync can be used two ways:
- Stand Alone – installed globally, use anywhere
- Grunt Plugin – installed locally, configure as grunt task
Great work Shane!
Thank you! Thats insanely helpful!
Whoa!! That’s a very cool tool!! I’m definitely gonna start using this!!!
This is a feature of the latest Visual Studio that I have definitely fallen in love with! Having the page reload my styles every time I save is such a small thing that makes my day so much better :)
This is incredible cheers.
As a front end dev I’ve known about Grunt.js before and after reading this article I’m now at their website reading how to make it work.
Truth be told, as much as I want to make this work and try it out, I can’t help to feel the pain of doing so just like I felt when I tried to set up Sass, and FYI I am not intimidated by the CMD at all. Some things are just not front end devs-friendly.
With this being said, here’s a totally dumb and n00b question(s) in the name of PC front end devs: Are these instructions for Mac only? Or do they apply for PC as well? Or are these questions too dumb? (Don’t answer this last one :p, your comment(s) will make it clear :]). Tnx!
I feel your pain re: setting up grunt.
It’s one of those things that is frustrating at first, but if you stick with it and get these tools working – you won’t look back I promise.
I work at WeAreJH in my day-job and we recently put aside some time for a grunt workshop that really helped our front-end devs/designers understand some of the the common mistakes/problems you can encounter. Now they are completely sold on it.
Have a look at this config here & see if you can get it working.
Gruntfile.js example
To answer your question about PC/Mac: using Browser-sync is identical across Windows & Mac. I’ve tested (and even changed some code) to ensure that you get the same tool on either platform. (I do confess to not having tested on any linux-based machine, however).
Hey Ricardo,
Get yourself setup with a boilerplate of some sort… it will help in getting setup with a grunt.js / node and maybe give you a few of those “aha!” moments.
Checkout something like ngBoilerplate. It has a project in a box that will prob help you out a bit with node and grunt. (However its in AngularJS, so you may need to find a substitute if you’re not comfortable with AngularJS).
No its not MAC only. SASS has compass which is on Mac, hence why you hear that frequently.
It wasn’t completely clear to me that Browser Sync could be run without Grunt, until I read your comment below: “…(and without grunt too)”. I ran it via the Command Prompt and it worked*.
Not sure if other front end devs that have no idea about using Grunt are getting discouraged by thinking that this can only be used with Grunt because although you mention that it can run as a “…stand-alone command-line tool”, this part doesn’t seem to be clear enough.
Aaaanyway, *I was able to make it watch a test
/css
folder and a testindex.html
file, however, I’m unable to make my browser “see” the HTML file. So I have some questions.Where can I submit questions about my case, in the Issues tracker of the repo in Github? Here? Where else?
Thanks in advance.
Unreal, I was able to make it work!
Thing is that what I did is not described here nor in the README.md instructions on the repo.
I’ll try to think of something to put that information out there for others.
—
After unsuccessfully trying so many other ‘live injection’ tooIs out there, I finally have a way to see my changes happen live without having to refresh and without the need to use some complex framework or library.
A million Thanks Mr. Shane.
Thanks so much :)
This tool is really amazing. I’ve used it a number of times and can say that I love it.
Are there any plans for making this tool into something similar like GhostLab where there’s an interface that’ll plug all this in without the Grunt config step? Not that I’m complaining – I find Grunt easy to use and don’t mind the setup but I’m thinking about those who don’t feel as comfortable.
Anyways – keep up the epic work here Shane I love the tool and can’t wait to see where it goes :)
Yeah I have plans for small interface stuff (like notifications, the ability to disconnect individual browsers, or to enable/disable ghost-mode without having to resort back to the command line etc).
I also want to integrate debugging tools like weinre that will enable remote debugging of mobile devices through your main browser. (so image running browser-sync with all the features it already has + you’ll get a webpage that lists all of the connected browsers – you could choose one & start debugging it with chrome dev-tools!).
The infrastructure is in place to build some really awesome features like that.
Glad you like it, & thanks for helping drive it’s development in the early days at @wearejh :p
Great tool no doubt. However after I have fallen in love with livejs.com it’s hard to resist such an easy setup. Its just a single js file that you include in your pages and it automaticaly inserts updated css files, js files and even refreshes page after html changes (configurable). It’s so simple to use. But it doesn’t have all the great features of this setup. But as long as I’m a coding designer it’s just enough.
This is just another weapon in our arsenal. No need to apologise because you like something else already! :)
I love any/all tools that help automate our workflow.
Probably worth mentioning though, if you are working with html, css & js, then browser-sync can be used with a single command (and without grunt too). Check the docs
Wow, great stuff.
Could you explain how to set this up with Mamp?
Thanks,
Flo
This tool can be used with Mamp no problem. Just run it as described in the docs & you’ll get a HTML snippet that you can paste into the footer of your website.
To get the full benefit though, you need to be connecting to your Mamp server through an IP address (you can configure this through Mamps server settings).
If you need further help finding the correct IP to use, it just so happens that I’ve built a little tool to help you :p
dev-ip – Find a suitable IP host to view local websites on
Thanks so much! I have been waiting for a great LiveReload alternative for the longest time, oh, oh, oh, for the longest time… I’m so happy, I’m singing!
Looks good, but I think livereload also handles html & javascript changes.
Browser-sync can handle as many files as you want & will reload/inject where possible.
Example Grunt Config:
Or if you are using it stand-alone, you can pass a config file as explained in the docs
Uhm, why didn’t you just submit a PR for livereload to have a fallback when it doesn’t support websockets?
Browser-sync ended up having enough extra features to warrant it being it’s own project.
Never had a really good reason to use grunt but this is amazing, not to mention extremely useful. I am also tired of the same old refresh across multiple browsers. Definitely an install for me. Nice work though.
Don’t forget it can be used without Grunt if needed.
stand-alone browser-sync
Thanks for great tool!
Is there a solution for the opposite ? Saving dev. tools changes into dev. server files ?
Now that would be a cool feature!
I think Emmet already has this feature though.
http://emmet.io/
It was easy to setup with the command line. It says watching 1 file (my style.css)…But. I keep geting in the browser:
Cannot GET /add-member.php
can you shed any light as to why this is occuring? my address bar has: http://192.168.1.65:3001/add-member.php
my config file is:
module.exports = {
files: “*.css”,
debugInfo: true,
host: “192.168.1.65”,
ghostMode: {
links: true,
forms: true,
scroll: true
},
server: {
baseDir: “/mvyc/”
},
open: true
};
thanks
@Vahagn
There is livestyle which is new http://livestyle.emmet.io/ and there was DevTools Autosave not sure how active that is and it only worked in Chrome https://github.com/NV/chrome-devtools-autosave
This is great, love it! One thing I noticed is that it doesn’t work when using this “trick” for getting around IE’s limitations on # of stylesheets while in development:
Interesting!
Can you file this as an issue/feature request on GitHub with a few more details?
Thanks
Hey Shane,
I. Love. Browser-Sync!
Thanks a lot for developing this and just to inform you:
It works perfectly on both my Linux setups (Linux Mint 15 & Ubuntu 13.04)
That’s good to know as I haven’t had chance to test on any Linux distros (apart from the CI server builds)
Thanks, glad you like it :)
Hello Shane,
Can we use it in custom javaEE projects (non-node.js project)? If yes, any extra config. needed?
Thanks
Shane thank you very much! This is freaking awesome and will same me a lot of time. It refreshes the browser instantly after I save my editor file.
Blessings
Norman
Hi !
i’m new too grunt so i’ve set up a simple grunt in a new folder. I install Browser-sync as described here, with minimal settings :
browser_sync: {
files: {
src : ‘css/style.css’
}
}.
No server or nothing is installed, only grunt and browser-sync.
When i hit grunt browser_sync, all i got is “Browser Sync could not find any files to watch”.
Did i missed something, is there any issue Windows related ?
ps : the command-line version finds 4 .css files on my path, plugins just doesn’t want to find my css files :).
How can I use this plugin at the same time as the watch plugin? As I’m using LESS and the watch plugin to process it, this plugin is kind of useless if I can’t use both. Running
grunt browser_sync
runs the plugin, but just runninggrunt
runs watch only.Grunt noob here, sorry!
I’m not sure if this is the best way, but I’m now using grunt-shell and
grunt watch & grunt browser-sync
to run both of them at the same time.Thanks for the awesome plugin, this is great!
Managed to get it working with chrome devtoools. I used chrome workspace [which is available in devtools] to map my css file to the actual source file and did a setup on browser-sync to watch over the css file and this automatically injects the css to all the connected devices, reflecting any changes I make in devtools to all the connected devices. Sweet!!
However I did have to put a change in ‘browser-sync-client.js’ to make it work, because when browser-sync injects the css file it timestamps the newly injected css file. So I changed the following line elem[attr] = currentValue + “?rel=” + timeStamp; to elem[attr] = currentValue; in ‘browser-sync-client.js’. Without the change the css injection will only work for the first time using chrome devtools.
Hi Chris,
Thanks great article on the grunt… which made my day on workflow.
Now i am getting error on browser_sync.
Warning: Cannot find module ‘optimist’ Use –force to continue.
Regards,
Jesudas