What's wrong with YOUR website - Part 4, CSS

A good deal of this section will also be dealing with the HTML. This stems from something I've said for a long time, stylesheets are only as good as the markup they are applied to. Because of that a LOT of what's "wrong" with people's CSS is just an extension of mistakes made in the HTML.

4.1 Failure to grasp point of CSS

There are several reasons CSS exists and advantages to its use -- but the way a LOT of people out there use it runs 100% contrary to this; so lets go through the who/why/where of what it's for, and where people are using it wrong:

First up is "separation of presentation from content" - this means having your HTML say what things are, and your CSS say what things are going to look like for your various layoutS. Yes, layouts is plural as this is NOT just about re-skinning the website in the future without changing the markup, it's also about having dynamic layouts that adjust to screen size (like handheld) or device capabilities (like print, projection, etc). What's currently being called "responsive layout" is just the next evolutionary step in what CSS has been around to do since day one. Accessibility is the name of the game, and targeting specific devices by their capabilities is what CSS has been around for over a decade to do.

This is why you should have semantic markup, so non-CSS devices can best determine how to show the content based on what it IS. This is why you are supposed to have a MEDIA attribute on your LINK loading CSS files so you aren't sending screen specific information to all targets! That is a hefty part of why there is NO reason for the STYLE tag to even exist, and why if you need to use the STYLE attribute on more than one out of every five websites, you're not getting the point.

You will often see developers new to CSS - and some who should know better after almost a decade and a half - coming up with code like this:

<span style="color:red">

How does that fit into the above? It doesn't, which is why it shouldn't be done. IF you want it some other color on another skin or even the same skin but for handheld, whaddaya do? Do you REALLY want to send that to PRINT as that color?

The first response most then come up with is this:

<span class="red">

Ask the same questions, what are you going to do? Make .red not be red when you don't want it as such?

The question such developers fail to ask, or worse refuse to answer out of laziness and/or ignorance is "WHY IS IT RED?!?" -- what is it, what makes it so special? Are you emphasizing it (EM)? Are you giving it even more emphasis (STRONG)? Is it something like a "standout" or "callToAction"? Are you "highlight"ing it? If you can't answer that in two or three words to make a meaningful descriptive class or tag, guess what? It probably shouldn't be styled differently in the first place!

The main reason this is such a big deal though is you have to ask yourself, how are any of those any better or different from:

<font color="red">

The answer is they aren't! Zero improvement or change, to the point if you are going to write HTML and CSS that way, you might as well just go back to writing HTML 3.2 like it's 1997. Of course, that's actually what most people are STILL doing, hence the reason so many developers never pulled their heads out of 1997's arse and deployed as "transitional" -- now instead of slapping a tranny doctype on it they slap HTML 5's lip-service on there, while still practicing decade or more out of date building practices.

This type of nonsense reaches the pinnacle of stupidity with CSS frameworks or worse, the so called "Object Oriented CSS" (OOCSS). By their very nature they create presentational markup -- if you don't know what's wrong with code like this:

<div class="leftCol thirdwidth colorRed sectionHeight bigText">

Do the world a favor and go do something harmless like macramé.

The second reason for using CSS is even more important -- leveraging caching models. The laugh of this is that many of the recent "tools" to tell you how to make your site faster -- like "Google Page Speed" and "YSlow" -- will actually give you the opposite advice making your page slower, not faster.

So how does CSS effect caching and page speed? External CSS files are CACHED -- so anything you can say in the CSS instead of the markup that's used across multiple pages will already be downloaded and not have to be sent again. Smaller markup + cached CSS means faster page loads and less data transferred! It also means that if you have a site where people are visiting lots of different pages (basically if your visitor traffic outweighs your bounces) you can pre-cache the appearance of those sub-pages the first time they visit.

Right now there seems to be this noodle-doodle idea being circulated -- by Google, by Yahoo, and by developers who should just plain know better, that if you only use something on one page of a site you might be better off 'saving a handshake' by having one less external file and using the STYLE attribute or the STYLE tag.

The major problem isn't so much with the idea itself as it is developers, particularly those making forums and CMS, misunderstanding what that means. When they say one page, they mean one STATIC page! If you have CSS that only applies to your "thread list" on a forums, do not inline it because that markup is sent how many times? Every time someone looks at the list of threads across all your different sub-boards. The entire point of leveraging caching is to reduce the amount of times you re-send the same information!

But even the concept itself doesn't really hold up well when exposed to sunlight and a little rational thought... this is because if you need more than 64K of CSS per media target for AN ENTIRE SITE, you are probably doing it all wrong. Over the past decade I've skinned forums, CMS, custom sites, and rarely if ever broken past 32k, the ONLY reason I'm saying 64K is my engineering background saying to Mr. Scott 'what I need'. Ach laddy, a good engineer is always a wee bit conservative on paper. If you have one or two custom pages that need more than 2k of Style apiece, you likely have a bad layout or usability issues due to inconsistencies. This is why I say dump each media type all in one stylesheet -- and if you break 64k of CSS, throw it out and start over!

The amount of CSS that's unique to subpages is IMHO not worth the hassles of separating out and sending as part of the markup or even as a separate file. There shouldn't be enough of it to significantly impact your first-load speed, if you make it a separate file that's the opposite of the reasoning that came up with the idea in the first place, and you're making the markup bigger, possibly for no good reason. This is why when 'analysis' tools bitch about 'unused CSS' in regards to pre-caching stuff for other pages, well... It doesn't do a lot for such tools legitimacy. Which is going to be an article unto itself!

4.2a Lack of resets and/or initialization of values

By definition there is no such thing as a pre-defined default appearance for HTML tags. That is left ENTIRELY at the discretion of the user-agent (aka browser). This is by design, since HTML -- AGAIN -- is for saying what things are so the user-agent can best determine how to convey those meanings within the capabilities of the device. That's the ENTIRE reason HTML was created!!!

This does lead to a problem where you can't rely on many elements having the same default margins, paddings or borders... so you either have to declare them on every element every time you use them, or hit them 'all at once' at the start with a 'reset'.

At the same time, some elements just do not style consistently cross browser to the point they don't even receive styling the same way. Form elements like INPUT for example are treated as 'special' by IE and FF receiving height differently from each-other, Opera treats them as inline-block, and don't even get me STARTED about what webkit does to form elements. This means that resets, or even just trying to set paddings on some elements can cause more harm than good. This is why the 'universal reset' of:

* { padding:0; margin:0; border:0; }

Often results in broken forms in certain browsers.

Declaring margins/paddings every time you have an element is just bloated code, so a reset is a good thing... They also mean you don't have to 'think' about it, and can concentrate on coding the page. The one I use:

/* null margins and padding to give good cross-browser baseline */
html,body,address,blockquote,div,
form,fieldset,caption,
h1,h2,h3,h4,h5,h6,
hr,ul,li,ol,ul,
table,tr,td,th,p,img {
	margin:0;
	padding:0;
}

img,fieldset {
	border:none;
}

Is less than a quarter of a K -- as such any complaints about it being 'bloat' are 100% grade A farm fresh rose fertilizer. It doesn't hit any elements where such values could cause problems.

There are those who seem to have a rabid hatred of resets, and this next section covers WHY:

4.2b Bloated framework masquerading as a reset

One of the best examples of this particular bit of garbage is Eric Meyer's "reset reloaded" -- I call it garbage because it is MORE than a reset, it goes through setting values you probably aren't even going to be using anyways. It's four times the size, sets values I've never seen be inconsistent cross-browser, can actually override user preferences (something of a no-no), and at four times the size of the above reset, you have to question what legitimate purpose it serves.

Even sadder, 'reset reloaded' is smaller than some of the resets I've seen in use... to the point they start to tread into being a framework; and as I said in section 4.1, frameworks by their very nature defeat the purpose of CSS due to their reliance on presentation in the markup.

Massive bloated resets that spend time setting values that don't need to be set generally do more harm than good, and are what gives resets as a whole a bad name.

4.3a Redundancies

One of the key features of CSS is that something applied to a element effects all its children and its psuedo-types. A great example of someone failing to grasp this is in styling an anchor.

a:link { text-decoration:none; font-size:14px; color:#0F0; }
a:visited { text-decoration:none; font-size:14px; color:#0F0; }
a:focus { text-decoration:none; font-size:14px; color:#880; }
a:hover { text-decoration:none; font-size:14px; color:#880; }

Laughably bad since it redeclares the same things over and over... the following is functionally identical:

a { text-decoration:none; font-size:14px; color:#0F0; }
a:focus, a:hover { color:#880; }

Setting in on 'a' sets the same values on ALL of its psudo-states.

Font settings in particular people go nuts declaring on everything... when really you should only ever declare CSS for when things are DIFFERENT. If you declare the most commonly used font on BODY, it applies EVERYWHERE -- then you only need to redeclare your font values when they are DIFFERENT.

... and that's true of most everything in CSS.

That said, there ARE cases for using the full condensed declaration on things like fonts -- since you can't trust line-heights to inherit it's often expedient to just use the full line of "normal 125%/150% arial,helvetica,sans-serif" since it's nearly as many characters as "font-size:125%; line-height:150%;" anyways, and you can clearly see what's being declared for everything.

4.3b Wasting time declaring default values

Some examples of this would be:

div { display:block; }
span { display:inline; }

DIV are block level elements, they are display:block by default. Span are inline-level, they're display:inline by default. Even though above we said you can't rely on defaults, if you are targeting screen you'll never find a user-agent that handles it otherwise.

There are more... intricate defaults that ARE defined by the CSS specification -- an example would be floats or position:absolute elements. They not only automatically switch to display:block's behavior, nothing you set can override that! This is why one of the fixes for the 'margin doubling floats' bug in IE is to set display:inline on a float. In EVERY browser that display:inline is ignored and the element retains display:block's behavior for setting sizes -- it just happens to for some weird reason fix the margin bug in IE as well.

So try to be aware that while some defaults like margins and padding can't be relied upon, there ARE defaults defined by the CSS specification you don't need to waste time redeclaring.

4.4 'Single Line' formatting

Stuffing everything on one line in CSS, even per element ( for examples of how not to format, see all the examples above Big Grin ) - is just bad practice, and it can often lead to accidentally declaring the same values over and over because even if you THINK you can read your code that way -- guess what?

Seriously, what's easier to digest?

ul a { position: relative; float: left; padding: 8px 0 8px 16px; margin: 0 -13px 0 16px; text-decoration: none; color: #444; background: #FAA; font: bold 14px/16px arial,helvetica,sans-serif; }

or

ul a {
	position:relative;
	float:left;
	padding:8px 0 8px 16px;
	margin:0 -13px 0 16px;
	text-decoration:none;
	color:#444;
	background:#FAA;
	font:bold 14px/16px arial,helvetica,sans-serif;
}

Hand in hand with this is the practice of white-space stripping to 'save' bandwidth. I'm a nut when it comes to saving bandwidth, I go to some real extremes to do so -- and to me, whitespace stripping is just a sleazy shortcut used to sweep bad code under the rug. If the handful of bytes shaved off by stripping out spaces, carriage returns and tabs actually provides you with a meaningful overall savings, then much like a lot of other 'common practices' it likely means there's something wrong with how you built the site in the first place.

4.5 IE Conditionals for CSS

There is NO legitimate reason for this apart from inept coding or non-viable or outdated layout methods. I say this because I can make pages that work all the way back to IE 5.5 without ever once resorting to them. IMHO if you have to use a conditional comment to load CSS for specific versions of IE, there is probably something horrifically wrong with how you built your layout! Most likely 'not viable for web deployment' layout concepts, failure to grasp inheritance, failure to realize not all elements accept padding the same way, or simply a failure to understand easier and smaller code-fixes like haslayout triggers.

Likewise there's this lovely bit of idiocy circulating right now created by one "Paul Irish" that wraps the HTML tag in endless nested IE conditionals for each and every version of the past decade and a half. If you REALLY need to do that, you probably have ZERO BUSINESS WRITING HTML OR CSS in the first place. The only legitimate reason for it might be for javascript detection of IE versions, but there are many MANY ways, including IE conditionals you put in the scripting itself for handling that. In terms of CSS targeting, there is literally no legitimate excuse for it apart from ineptitude on the part of the developers using it... Which of course is why it's made its way into idiocy like the "HTML 5 Blueprint" framework...

At the best of times IE conditionals for CSS are a crutch for people who don't know what they are doing. At the worst of times they are pointless bloat used to cover up ineptitude, ignorance or just plain wishful thinking.

4.6 Failure to set line-heights properly

Remember up above where I said many things do NOT have a consistent default value? Line-height is one of them. The MOST the specification suggests is somewhere between 110% and 130%... The majority of browsers, IE, Opera, Safari and Chrome use 120% -- dead center of that, but Firefox being the sweetly retarded cousin to Nyetscape 4 that it is, due to its rather unique practices for rounding off and/or tracking fractions seems to run the full gamut between those suggestions.

Worse, line-height inherits across values... funny. Quite often if you set dynamic font sizes (aka % and/or EM, which you should be doing as much as possible anyways) the line-height won't change from the parent element. There is a 'trick' some people advocate using where you don't state a metric (metric is the type of measurement -- like px, pt, em, etc) on the size, and it will behave as a multiplier. This too is broken/unreliable no matter how much its advocates claim otherwise.

That last part is a personal pet peeve because no matter how many times you show them sites with broken screencaps built using that technique, the apologists just say "Is not" and stick their heads in the sand like a bunch of ostrich.

My rule of thumb is, you change the font-size you should EXPLICITLY declare a line-height at the same time. It avoids ALL of the potential headaches. A lot of people then reply with "but isn't that a lot of code?"

Only if you change font sizes fifty times like some sort of indecisive weirdo. As a general rule of thumb, you should never really have to change font size more than around 8 to ten times, and that's me being generous. MOST sites I've written use maybe 5 at most. Once on BODY to declare 90% of what's on the site, once for image replacement on the H1, once for the menu, and then any various headings. If five to ten 'line-height' declarations is 'a lot of code', well...

It also helps to redeclare the ENTIRE condensed font property -- 1) so you know exactly what's set, and 2) it's really not a significant amount more or less code.

Seriously:

font-size:85%; line-height:140%;

vs.

font:normal 85%/140% arial,helvetica,sans-serif;

So close in size as to make no never mind.

You'll notice I say that a lot, hence this final section:

4.7 Minimalism vs. Byte obsession

This applies to more than just CSS, but rarely do you see quite as much nonsense as you do with CSS -- Clean, clear minimalist code is one thing, going nuts obsessing over every last byte does nothing but make the code harder to work with and more work for yourself. There's a fine line between the two. I like small, compact minimalist code -- but don't ever sacrifice usability or ease of maintenance/design in the process!

Which is far, FAR too easy to do with CSS. At the same time, CSS has things like condensed properties that to be frank, are often CLEARER than declaring the values separately as at least they're all in one place and you can see EXACTLY what they are.

Projects

  • elementals.js
    A lightweight JavaScript library focusing on cross browser support, ECMAScript polyfills, and DOM manipulation.
  • eFlipper.js
    An image carousel script using elementals.js
  • eProgress.js
    A JavaScript controllable progress bar using elementals.js. Based on the nProgress project that relies on the much heavier jQuery library.

/for_others

Browse code samples of people I've helped on various forums. These code snippets, images, and full rewrites of websites date back a decade or more, and are organized by the forum username of who I was helping. You'll find all sorts of oddball bits and pieces in here. You find any of it useful, go ahead, pick up the ball, and run with it.