As we all know, css is not the most straight-forward of the languages.
There are several dimensions of inheritance. There are different browsers to write for. There are hacks that defy logic. Etc.
Needless to say, css can get very messy and intangled. Not a surprize that it often treated like garbage, semi-intentionally swept under the couch.
Sometimes, it gets pushed into the most unpredictable places: html, js, php, java and sometimes even SQL. Good luck debugging this!
The purpose of this guideline is to introduce a set of clear and simple rules that, if followed, will:
1. Void most of the headache.
2. Bring beauty and structure to our CSS development cycle.
3. Minimize size of CSS load.
4. SIGNIFICANTLY ease the code maintenance.
1. Clear separation
Treat CSS like any other language - separate it into it's own tier, let it shine on it's own.
- The only place for CSS is in ".css" file.
- No inline CSS - the only part of CSS that should appear inside HTML tags are class names and ids.
- No CSS on server side - class names and ids are ok
- No CSS in JS - Javascript should NOT edit styles, but swap classes instead.
Example:[ CORRECT ]
The ONLY Exception:
myButton.onMouseOver = function() { myButton.addClass('my-button-over'); }
[ WRONG ]
myButton.onMouseOver = function() { myButton.setStyle('background-color','red'); }
Sometimes width, height, top, left and
display, etc. properties are changed internally by various animation
routines in JS. It is ok to define these
css properties inline, but only these. If the new routine is being
written - please try only using addClassName and removeClassName routines to swap css classes that are defined externally. - DO NOT use ids (#id) notations in CSS, reserve them for JavaScript identification. Instead use CSS classes (.myclass).
- If JS needs to use CSS classes, they must be prepended with "js-" notation, and NEVER be used to apply styles with CSS to
avoid introducing bugs in JavaScript when CSS selector is changed.
2. File system structure
- Take advantage of minimization - create separate CSS file for each specific purpose.
It is easier to read, debug and remove. Writing short, consise CSS files will help making the code self-explanatory. - Divide files into two groups:
a. Generic - Styles that are used to skin reusable widgets or modules. Styles that MAY be applied to a similar module elsewhere.
b. Specific - Styles responcible for particular page or a module. Styles that will NOT be used anywhere else but there.
Example:
Consider a dialog widget that is used in multiple places across the site.
Our generic skin css file will be called module.dialog.skin1.css.
This file will abstract the generic looks of the dialog widget regardless of the markup that goes inside it. The module.dialog.skin1.css does not,
and should not know about it's possible contents. This file is
similar to a base class in the inheritance paradigm of any programming
language.
For a specific dialog that will, say, display a user profile information, the specific css file will be called module.dialog.profilepopup.css.
This file will contain styling properties of the profile
displayed within the dialog. It may or may not override styles
inherited from module.dialog.skin1.css.
The module.dialog.profilepopup.css can be compared to an OOP subclass of module.dialog.skin1.css.
This
way, we will have only one file that defines the generic looks of the
dialog, and multiple specific files for any specific dialog. And no
extra CSS.
3. File naming conventions
- Use all-lowercase filenames.
- Use underscores (not dashes) in filenames
- Use periods "." to separate hierarchial namespaces within the filename:
<module_type>.<module_name>.<module_specific>.css
This will spare you firebugging, greping and searching your
<module_type> : [
common, // contains element styles common across ALL pages (reset, fonts, grids, forms, etc.)
page, // a single html page, including BODY tag
partial, // a single partial page loaded with ajax
module // a widget like dialog, button, pager, grid, custom form element, etc.
]
<module_name> : arbitrary // a name of a page, layout
or widget. Corresponds to js or php widget file name.
<module_specific> : arbitrary // a
specific instance of <module_name>. Corresponds to the page name of occurrence.
entire codebase for styles that correspond to your module or widget.
You will know EXACTLY the file you need.
4. CSS Selectors
- Use dashes instead of underscores in your selectors. This is just a widely accepted web standard.
- Add a CSS class to the outmost HTML tag of your module/widget/layout that has the SAME NAME as <module_name> or <module_name>-<module_specific> your CSS file
(replacing underscores with dashes, of course) - Use short but descriptive names for classes in any other inner tag. (Further referred to as "inner classes")
- ALWAYS define inner classes through the class of the outmost tag.
Example:
Inside of our module.dialog.skin1.css. file we need to skin a title bar and four corners:[ CORRECT ]
Prepending style selector with the widget/module/layout
.dialog-skin1 {
/* define css properties to inherit within the skin: font, background, etc */
background-color: #CCC;
}
.dialog-skin1 .title {
background-color: #666;
color: #FFF;
font-weight: bold;
}
.dialog-skin1 .corner-n {
width: 15px;
height: 15px;
background: url(images/dialog_corner_north.gif) no-repeat;
}
identifier will make sure that these styles will NEVER interfere with
any other style outside the module.[ WRONG ]
There is a great chance that ".title" or ".corner-n" may
.dialog-skin1 {
background-color: #CCC;
}
.title {
background-color: #666;
color: #FFF;
font-weight: bold;
}
.corner-n {
width: 15px;
height: 15px;
background: url(images/dialog_corner_north.gif) no-repeat;
}
be defined elsewhere in the application and you will end up overriding
it.
5. Indentation and grouping of styles
- Group styles inside the CSS file just the way they appear in HTML - Outer first, inner after
- [Optional] You may want to indent styles just as you would indent HTML tags they appear in - Outer less indented, inner more indented
Example:
selector1 {
}
selector1 selector2 {
}
selector1 selector2 selector3 {
}
selector1 selector4 {
}
selector1 selector5 {
}
This way you will ALWAYS know where in the file to look for a specific style.
You will clearly see the style inheritance structure.
You can at-a-glance identify how your CSS applies to HTML (vertical readability)
6. Grids
- Use grid classes to define positioning of your HTML elements. (Documentation coming soon)
7. Appendix. Crossbrowser CSS Hacks
Browser specific hacks (order is important):
.myClass {
width: 100px; /* Affects: FF, Safari, Opera, IE5, IE6, IE7, Targeting: FF, Safari, Opera */
.width: 102px; /* Affects: IE5, IE6, IE7, Targeting: IE7 */
_width: 101px; /* Affects: IE6, IE5, Targeting: IE6, IE5 */
}
IE8 Support
The best (google and facebook approved) solution is to make IE8 behave like IE7 by adding the following meta tag:
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
One less IE browser to code for :)