CSS Code Smells
Podcast: Play in new window | Download (52.9MB) | Embed
Subscribe: Apple Podcasts | Spotify | Email | RSS | More
Why CSS is painful to fix. Different mindset required to work with it. Cascading rules can make things hard to trace. It’s also hard to figure out where a particular style is being used. Things have changed a lot in the last 5-10 years, and developers are afraid to touch working css. Many developers don’t really want to learn how it works and you can bet they touched your codebase at some point. Lack of code reuse, if you aren’t using a preprocessor, makes a norm of copy/paste coding.
“We could have titled this 10 signs you’re not using a preprocessor.”
14:20 Not using a preprocessor.
CSS lacks many of the features that a developer would expect to use in order to have a clean codebase. Reusing chunks of vanilla CSS in multiple rules is harder than you probably would like. The layout of CSS files also doesn’t show the hierarchy of applied rules in a way that makes them easy to understand. Some things you have to specify are extremely verbose.
“Can the people I know that are slinging CSS maintain that?”
You can use CSS preprocessors such as Sass and Less to add features to CSS that make it easier to use. Sass, for instance, adds things like variables and nesting to help you create a better structure. Sass also allows partials, which are sets reusable rules that can be kept in a separate file and imported at preprocessing time. Sass also supports mixins for handling sets of verbose rules. Sass and less also support a lot of other constructs you might be interested in, like inheritance.
18:43 Using @Import in vanilla CSS.
This results in an extra HTTP call to your webserver and will slow down page rendering until it is cached. Essentially, all the rules that are required to render the page aren’t present until this other file is downloaded and the browser doesn’t know to download it until it has the file that references it. This pattern can also get worse, as the imported file might have imports in it as well.
This is better handled by using a CSS preprocessor like LESS or Sass and judiciously using partials and mixins. When you use a preprocessor, the contents of imports are inlined into the file that is being sent to the browser. This results in only a single download, rather than multiple ones.
21:10 Hardcoded numeric values, colors, etc. reused in numerous places in the code.
This happens a lot if non-design developers have been working on your CSS, especially under deadline pressure.
“If you’ve got a 95 pixel font, you’ve got a whole ‘nother thing going on with your site.”
Should you have to change any of these, you’ll have to search for the values in question, determine if they really apply, and fix them. Just because two elements are using the same hardcoded value (especially a color), doesn’t necessarily imply that they should both change if the color changes. This gets even more fun with things like sizing, because some of the hardcoded sizing that you run into is because of the sizing of a containing or contained element that does not use this hardcoded value. You end up fixing a lot of side effects.
“It was a good year lots of tables, lots of blink tags.”
Again, a preprocessor is a big help here, as it allows you to use variables, mixins, and arithmetic calculations for this sort of stuff. Instead of having to assume that two equivalent magic numbers mean that two elements are related, this approach allows you to indicate that via use of the same variables.
24:45 Insufficient attribute specificity.
Background, instead of background-color, when setting color, for instance. While it seems like a shorthand, what this approach actually does is reset other background attributes. You’ll see similar things for borders and the like as well.
This is another place where a preprocessor can help. If you do manage to use insufficiently specific attributes and are using mixins and the like, you only need to change them in one place. However, a preprocessor doesn’t get rid of the entire problem here. Instead, you probably need to use a code quality tool, like a CSS Linter, to find places where you are creating implicit CSS behavior rather than explicit behavior and clean up from there.
“So I read it as NOT Important because I don’t do much CSS outside of our stuff.”
!Important is used to override the styles applied to an element elsewhere. This is a way of overriding the CSS rules for an element.
This indicates not only poor or incorrect structure in your CSS code, but also indicates that you are trying to hack around the problem rather than solve it, which only makes problems bigger. CSS styles are applied based on importance and origin in a particular order, based on relevance and their appearance in the stylesheet. The more specific, the more weight they are given. !Important overrides this default approach and means that more specific rules will not be applied, which is really annoying to fix. If !Important is used on a shorthand property, it also applies on the sub-properties of that property.
There are cases where you should use this, but they are few. A preprocessor doesn’t necessarily help here, but you can often refactor to mixins and variables to achieve the same effect, without breaking the styling rules.
32:10 Overly large CSS files.
Overly long files generally indicate that you aren’t using cascading very well and tend to make people reluctant to work with the code. This combined with the fact that separate files end up being separate downloads is a good reason to use a preprocessor to combine the files for the end user, but keep them separate for the developer. Essentially this is the same kind of code smell you see when any other source file gets excessively long. It tends to indicate that the thing is doing too much.
34:20 Having a separate CSS file per page in the application.
“Really? People do this?”
This indicates that the designed didn’t understand what CSS actually does. CSS is meant for larger abstractions about how a site works, not for sniper-targeting every specific element in the site. It’s not an abstraction over inline styling, but is a way to understand and alter big-picture site structure.
This tends to result in a lot of repeated code and means that code that appears in many pages will have to be copied into many CSS files or @Imported. Neither of these is a particularly great way to handle it. This approach might be advantageous in some circumstances, however. If you do need this, consider using separate files for however you wish to lay it all out, and then using a preprocessor before serving it to the client. This will make it easier to combine files later if requirements change and will give you partials and mixins for code reuse.
40:00 Styling elements instead of classes and IDs
It’s very unlikely that every P tag, H1 tag, or LI tag in your entire website is going to look the same. Therefore, it’s not particularly wise to be applying styles to them. This rule doesn’t include situations where you have to have global CSS resets because you are targeting older, crappier browsers (have fun with the floats, though). Identify cross-cutting design decisions and refactor to using something like the BEM model (Block, Element, Modifier) or refactor to using classes instead. Overuse of IDs can also be a code smell, as it CAN indicate that you are dealing with HTML elements as elements and not as components of the system.
47:55 Inline styles
51:35 Serving unbundled/uncompressed CSS files without cache-busting.
In a development environment, running against localhost, it’s hard to see how excess HTTP requests make things slower. You also tend to avoid caching, because you are iterating on a design. In a real environment, that’s not true, and the excess web requests drastically slow down page rendering. In addition, failure to cache bust can mean that changes to your CSS aren’t seen by the users.
“I’ve seen some stuff with caching…”
Browsers often cache files by filename, which works well, unless you’ve changed something. While you can do a lot of things with cache headers, but sometimes the browsers ignore them. Again, preprocessing will help here, by allowing minification of the css files and allowing you to rename them for cache-busting purposes. If the filename rendered out for the user is different, the browser won’t cache it.
CleverPet provides a way for your dog to get some entertainment and activity while you are away at work or the bar. It has several different activities for your dog to progress through. One of the modes is a memory game very similar to “Simon” but for dogs. It even gives the dog a treat when it completes the challenge. You can follow your dog’s progress through a mobile app. It’s not available yet but will be soon.
Tricks of the Trade
Understand that you have four options to office conflict. You can bring it to a head, you can ignore it and hope it goes away, you can try to calm it down, or you can go somewhere else where the conflicts are different and unknown. Understanding that you are always making a choice between these options. The conflict is not being inflicted upon you without some degree of control on your part. If you catch yourself feeling helpless, pick a different choice.