In this presentation I share my best practices working with ZURB Foundation. Keep your projects clean and organized and make your code more maintainable and readable.
A mostly css framework
- jQuery + JS: required by some components
- Sass: CSS Preprocessor
- Everything On by Default
The Basics
JavaScript
- Individual Imports Per Component
- Import jQuery First
- Activate FastClick.js for better mobile ux
- Use DEFER Attribute
Use Sass
- Allows you to quickly “theme”
- Easily upgradeable via Bower
- Extend ZURB Components with @mixins
Presentational Classes
Presentational Classes
- always use .small-12 instead of .medium-12 or .large-12
- always start with the medium grid (unless mobile first)
- then refine small + large as needed
- if radically different use visibility classes
be consistent
.show-for-small-only vs. .hide-for-small-only
.hide-for-small-only vs. .show-for-medium-up
pick one – consistency is key – keep the order keep the form
word order
class=“ small-8 medium-9 large-10 columns small-centered ”
grid, columns, grid modifiers small to large offset, centered, push/pull
omit anything you can
small-centered medium-centered large-uncentered
small-centered medium-uncentered large-uncentered
small-12 medium-12 large-12
when classes go bad
small-8 columns medium-offset-2 small-centered medium-uncentered large-pull-4
maybe it’s time for a @mixin
source: xkcd.com/844
CSS
OOCSS BEM Something Else?
CSS
- Use OOCSS Principals when it makes sense
- Follow ZURB Foundation Naming Conventions (BEM is out)
- Great Reference: SMACSS Book
If you want to go full BEM – just use the sass mixins
Sass Workflow
- Grunt
- Libsass (no Sass 3.3-3.4 features)
- Sourcemaps or Inline Comments
- Autoprefixer (config for sourcemaps)
- Development vs. Production
Sass Organization – app.scss
1 2 3 4 5 6 7 8 |
1. Brand Variables 2. ZURB Foundation Overrides 3. Foundation Imports 4. Components 5. Modules (Views, Templates) 6. Sitewide 7. Etc. 8. Live Prototyping |
1 2 3 4 5 6 7 8 9 10 |
/********************************/ /* ~/scss/brand/_variables.scss */ /********************************/ // set common colors and calculations $brand-light-blue: lighten($brand-blue, 20%); $brand-dark-gray-text: #333333; // set any other globals $brand-spacing: rem-calc(20); |
1 2 3 4 5 6 7 8 |
/********************************/ /* ~/scss/brand/_settings.scss */ /********************************/ // copy and paste from foundation/_settings.scss $primary-color: $brand-light-blue; // refactor same values or colors into brand/vars |
_settings.scss
- not to be confused with the foundation/foundation/_settings.scss
- no dead sass vars
- these can change from time-to-time, easy upgrade
- can be thought of as the theme, skin, look of site
- be careful, changes everything sitewide
foundation imports
- just pull from bower_components/_foundation.scss
- turn on / off what you need for performance
- to leave @mixins set: $include-html-classes or include-html-n-classes
- in theory they all work
quicktip
for rapid prototyping leave // @import “foundation”; and or // $include-html-classes: true; at the top and commented out.
Then just uncomment when prototyping.
Recomment and adjust when done.
Components blocks of html + css used in more than one page Modules everything that is page sepcific Sitewide single elements / selectors on more than one page Shame/Drupalisms/etc. stuff that doesn’t fit appropriately named Prototype work fast in app.scss but find it a home fast
components WWZD?
1 2 3 4 5 6 7 8 9 |
<a class="button small secondary disabled"></a> <button class="small secondary disabled"></button> <ul class="button-group"> <li><a class="button">Lorem.</a></li> <li><a class="button">Quo.</a></li> <li><a class="button">Reiciendis.</a></li> </ul> |
say what it is
say it the ZURB way
KISS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$vars: true; @function magic-calc($some-value: true) { @return } @mixin my-component-base($some-value: true) { // css } ul.my-component { & li { & a.button { &.disabled { // ... } } } } |
nesting
sass is pretty smart
1 2 3 4 |
ul.my-component { } ul.my-component li { } ul.my-component li a.button { } ul.my-component li a.button.disabled { } |
makes refactoring class names fast and easy
1 2 3 4 |
my-component, another-component a { & small { } } |
becomes
1 2 |
my-component small { } another-component a small { } |
watch out for
1 2 3 |
my-component { & p, & a { /* each selector needs an & */ } } |
modules
- same structure, same process, only the scope is different
- based on project structure: views, templates, pages, etc.
1 2 3 4 5 6 7 8 |
/* component */ .everything-else ul.my-component>li>a .everything-else /* module, wrap entire page with a div */ .view-index-find> .everything-else |
naming conventions
- make it easy to find, have a direct 1-to-1 correlation
- keep the list alphabetical scss/view/index/_find.scss scss/view/partial/auth/_header.scss scss/page/about-us/_mission.scss scss/template/blog/_article.scss
example app.scss
1 2 3 4 5 6 |
@import "some-app/brand/defaults"; @import "some-app/brand/settings"; @import "settings"; // DO NOT MODIFY // For troubleshooting or prototyping, uncomment line below // @import "foundation"; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Performance: uncomment above and comment unused components so they don't generate CSS //@import "foundation/components/accordion"; @import "foundation/components/alert-boxes"; @import "foundation/components/block-grid"; @import "foundation/components/breadcrumbs"; @import "foundation/components/button-groups"; @import "foundation/components/buttons"; //@import "foundation/components/clearing"; //@import "foundation/components/dropdown"; //@import "foundation/components/dropdown-buttons"; //@import "foundation/components/flex-video"; @import "foundation/components/forms"; @import "foundation/components/grid"; @import "foundation/components/inline-lists"; //@import "foundation/components/joyride"; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//@import "foundation/components/keystrokes"; @import "foundation/components/labels"; // @import "foundation/components/magellan"; @import "foundation/components/orbit"; @import "foundation/components/pagination"; @import "foundation/components/panels"; //@import "foundation/components/pricing-tables"; @import "foundation/components/progress-bars"; @import "foundation/components/reveal"; //@import "foundation/components/side-nav"; //@import "foundation/components/split-buttons"; @import "foundation/components/sub-nav"; @import "foundation/components/switches"; //@import "foundation/components/tables"; @import "foundation/components/tabs"; @import "foundation/components/thumbs"; @import "foundation/components/tooltips"; @import "foundation/components/top-bar"; @import "foundation/components/type"; //@import "foundation/components/offcanvas"; @import "foundation/components/visibility"; |
1 2 3 4 5 6 7 8 9 10 11 |
// VIEWS @import "some-app/view/about-us"; @import "some-app/view/article"; @import "some-app/view/become-a-member"; @import "some-app/view/contact"; @import "some-app/view/create-account"; @import "some-app/view/footer"; @import "some-app/view/header"; @import "some-app/view/index"; @import "some-app/view/share"; @import "some-app/view/verify"; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// COMPONENTS @import "some-app/component/audio-player"; @import "some-app/component/card"; @import "some-app/component/datepicker"; @import "some-app/component/progress"; @import "some-app/component/rating"; @import "some-app/component/sidebar"; @import "some-app/component/slider"; @import "some-app/component/timeline"; @import "some-app/component/triangle"; @import "some-app/component/user-profile"; @import "some-app/component/visualization"; // SITEWIDE @import "some-app/drupalisms"; @import "some-app/sitewide"; |