CSS Frameworks are bloated! At least that is the argument. They can be is the truth. A standard Sass install with all components included of Foundation 5 is 111KB uncompressed 16 Kb compressed. They can also be as slim as you want. You can use only the parts you want when you use tools like Sass (scss) but that still may leave over unwanted styles. Grunt Uncss can fill in those gaps and shrink our file down even more.
Grunt Plugins | Foundation Templates |
---|---|
Foundation 5 Sass | Banded |
Grunt Uncss | Feed |
Grunt Cssmin | Grid |
Grunt Processhtml | Marketing |
Grunt Autoprefixer | Store |
Seeing that list of Grunt plugins, and their github pages might put a lot of people off. It looks hard. The great thing about grunt is: If you don't want to use a plugin dont. If it doesn't fit your workflow, don't use it. Its about your workflow and what works best for you.
Setup
We'll start off by creating a new Foundation 5 project. Mine will be in my htdocs directory of my xampp install. This project will be named uncss and will use libsass. Starting this project will give you a leg up by giving you a package.json and a gruntfile.js.
C:\xampp\htdocs>foundation new uncss --libsass
After you have completed the Foundation install you can then move on to setting up your gruntfile. Change directoies in your terminal/command prompt to your newly created project. You will install all of the above mentioned grunt plugins at once. Leave out any plugins you don't want to use. You may also elect to install the plugins one at a time.
npm install grunt-uncss grunt-contrib-cssmin grunt-processhtml grunt-autoprefixer --save-dev
This will download the plugins, save them locally to your project and update your package.json file. You can then move on to loading the tasks, enabling the tasks and actually creating the tasks you wish to run.
Enabling
At the bottom of your Gruntfile you will see the
grunt.loadNpmTasks('task here');
you will place your newly downloaded and installed tasks below the ones Foundation has installed for you.
// foundations tasks
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
// ones you wish to use
grunt.loadNpmTasks('grunt-uncss');
grunt.loadNpmTasks('grunt-processhtml');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-autoprefixer');
Uncss Task
Uncss will scan our HTML files for used selectors, remove the unused selectors and create a new, smaller css file. The files you want scanned will be on the right. The newly created css file is on the left. At this point the file and directory of this file don't exist. Once the uncss task has been ran it will create the file and/or directory specified on the left.
Underneath the "Watch" task in your gruntfile place the following
watch: {
grunt: { files: ['Gruntfile.js'] },
sass: {
files: 'scss/**/*.scss',
tasks: ['sass']
}
}, // <- notice the comma
uncss: {
dist: {
files: { // files scanned on the right. cleaned css on the left in a "cleaned" directory
'cleaned/css/app-cleaned.css': ['banded.html', 'feed.html', 'grid.html', 'marketing.html', 'store.html']
}
}
}, // <- notice the comma
To separate the cleaned css from the full css file I'll save the uncss task created css file into the "cleaned" directory.
Processhtml Task
This task is done in two parts. The first part is creating the task in our gruntfile. Proceeshtml will take the files on the right (our input) and scan those for a snippet we will place in each file then place those in the directory specified on the left.
processhtml: {
dist: {
files: {
'cleaned/banded.html' : ['banded.html'],
'cleaned/feed.html' : ['feed.html'],
'cleaned/grid.html' : ['grid.html'],
'cleaned/marketing.html': ['marketing.html'],
'cleaned/store.html' : ['store.html']
}
}
},
Here is the snippet we will place in each of the HTMl files on the right of the task
<!-- build:css css/app-cleaned.min.css -->
<link rel="stylesheet" href="css/app.css" />
<!-- /build -->
During the Processhtml task it will search your HTML files for this snippet. It will repleace our "app.css" with the css file with the .min.css extension located in the "cleaned/css" directory. The minified css will come from the cssmin task.
Autoprefixer Task
Autoprefixer will place needed vendor prefixes our css using data from Caniuse . We'll use the default values from the Autoprefixer github page and use the needed prefixes for the last 2 versions of all browser, Internet Explorer 8 and 9 and Android 2.3. The input is our cleaned CSS file from uncss task. We will save it in the same directory under the same name.
autoprefixer: {
options: {
browsers: ['last 2 versions', 'ie 8', 'ie 9', 'Android 2.3']
},
target: {
src: 'cleaned/css/app-cleaned.css',
dest: 'cleaned/css/app-cleaned.css'
}
},
Cssmin Task
Cssmin will take our file we have created from uncss and autoprefixer and minify it. Again the input file is on the right and our new file with the .min.css extension we will like to create is on the left.
cssmin: {
minify: {
files: {
'cleaned/css/app-cleaned.min.css': ['cleaned/css/app-cleaned.css']
}
}
}
Running a Task
You can now open up your terminal/command prompt in your project directory if you closed it and enter
grunt [task-name]
for each task you wish to run. That is time consuming if you have a large gruntfile and many plugins and kind of defeates the purpose of a task runner. To fix this we will register a task, call this task "clean". This task will build our css from scss the run uncss followed by autoprefixer, minify our prefixed-cleaned css then copy those files over to our "cleaned" directory.
At the bottom of your Gruntilfe in the
grunt.registerTask('task name')
section place this:
// default foundation grunt tasks
grunt.registerTask('build', ['sass']);
grunt.registerTask('default', ['build','watch']);
// our task we are registering
grunt.registerTask('clean', ['build', 'uncss', 'autoprefixer', 'cssmin', 'processhtml']);
Now we can run
grunt clean
from your terminal
Results
Before Photo | After Photo | |
---|---|---|
Css Size | 16KB | 4KB |
The results are great! We shrunk the complete css file from 16 KB compressed to 4. Your users on low bandwidth connections will love you. After all #PerfMatters .
The only issue we have now is some of the Foundation components no longer work. Things like the topbar will no longer open on small mobile menu screens. Example
Fixing Components
Fixing the broke components can be done at least two ways. The first way is to add an option parameter to uncss and have it ignore the selectors you place there or a regular expression.
uncss: {
dist: {
files: { // files scanned on the right. cleaned css on the left in a "cleaned" directory
'cleaned/css/app-cleaned.css': ['banded.html', 'feed.html', 'grid.html', 'marketing.html', 'store.html']
}
},
options: {
ignore: ['.top-bar .expanded', 'other selectors']
}
},
Doing this can fix the problem if you know all of the selectors generated by Javascript or are really handy with regex's.
The other longer more involved method would be to edit your 'app.scss' file in your scss folder. Comment out the main Foundation import in your app.scss file and then proceed to un comment all the components you wish to use. When you come across a component that was broke after running uncss leave it commented out. In this case its topbar.scss
@import "settings";
// @import "foundation";
// Or selectively include components
@import
"foundation/components/accordion",
"foundation/components/alert-boxes",
"foundation/components/block-grid",
/* rest of the components .... */
// "foundation/components/top-bar",
In your scss directory create a new scss file. This file will contain the scss/css files that were broken on the previous running of uncss. Copy over the imports from app.scss into this file and save.
@import "foundation/components/top-bar";
Fixing the Gruntfile
Open up your gruntfile and head to the sass task. We want it to compile a separate style sheet for our topbar scss file. Add this option.
sass: {
options: {
includePaths: ['bower_components/foundation/scss']
},
dist: {
options: {
outputStyle: 'compressed'
},
files: {
'css/app.css': 'scss/app.scss',
// our component file on the right
// file to save on the left
'css/top-bar.css' : 'scss/topbar.scss'
}
}
},
Once you have completed that part you'll have to edit the cssmin task. We want to combine the two css files generated by the sass build task into one file after uncss has ran then minify it.
cssmin: {
// the combine task
combine: {
files: {
'cleaned/css/app-cleaned.css': ['cleaned/css/app-cleaned.css', 'css/top-bar.css']
}
},
minify: {
files: {
'cleaned/css/app-cleaned.min.css': ['cleaned/css/app-cleaned.css']
}
}
}
We can now run grunt clean from our project directory and have a working topbar. Example .
Result Comparison
All components Photo | Separate components Photo | |
---|---|---|
Css Size | 4KB | 5KB |
Creating a standalone top-bar.css file will also include all of the grid css classes. You can see from the above example its not much of a size difference when using compression to serve your site (which is highly recommended). You can shrink the entire css file more once you are ready to put your site into production. After you have built your assets (by running
grunt build
) you'll have two css files. This instance we'll have app.css and top-bar.css. We can then take steps to shrink this file by running individual grunt tasks. In order to use this option we must remove the unnecessary css from our component css (top-bar.css). Open this file and remove the grid classes and the meta.mq classes and save the top-bar.css. You can then run the individual tasks or build a new task.
Individual
- Run Grunt uncss (will remove css from our app.css save it as app-cleaned)
- Run Grunt processhtml
- Run Grunt autoprefixer
- Run Grunt cssmin
Before Photo | After Photo | |
---|---|---|
Css Size | 5 KB (30 KB uncompressed) | 4 KB (18 KB uncompressed) |
Page Weight | 71 KB (246 KB uncompressed) | 70 KB (234 KB uncompressed) |
Run the clean task at the end of your build process and separate your cleaned css file from your development files in case anything breaks. You don't need to use another directory as I did with 'cleaned'. You could just give it a different name (ie tidy.css or cleaned.css). If something does break you don't have to worry about you writing over the one that worked and you can troubleshoot from there.
Css frameworks don't have to be "bloated" or heavy. With the increase of people accessing the internet with mobile devices it helps to send assets down to their device that aren't littered with unnecessary css.