CSS Architecture
engineering.appfolio.com
engineering.appfolio.com
The way CSS is written amongst the web developers and designers depends on whether you have easy access to the HTML or not.
If I work on a Tumblr or WordPress theme, I can strip down my HTML structure to the minimal and work my way around with context selectors (for example having global styles for my .post-title, and add specific adjustments for #sidebar .post-title or #single .post-title).
But if I need to send HTML/CSS templates to a client's developers, I will need to turn my components into reusable and independent objects (like in a Bootstrap file), that will carry their style while being moved around to prevent them from being altered by the context in which they end up. I would also increase the density of my HTML to cover for all the possible cases, and give the developers some flexibility.
As a front-end developer only working on HTML and CSS, keeping content and style completely seperate is the goal I aim for everytime I start a new project. But maintaining such a division is hard when working with developers because they generally don't touch the CSS at all. So I need to provide styling directly into the HTML because that's what developers generate and have their hands on. I don't blame the working process for making me write a different kind of CSS. It's just how it has to be done. Neither type of CSS is better than the other: they are just suited for 2 different situations.
And that's why I don't believe there is a perfect way to write CSS. There are useful tricks and smart shortcuts but, although having been a dedicated front-ender for 4 years with no programming skills, I don't think CSS is meant to be discussed too thoroughly.
Obviously your CSS might be less important than core business logic, but just ignoring any sort of practices will make developing new features take longer and less efficiently. It will also come back to haunt you at some point.
A key metric of any company is how fast you can develop new features while keeping quality, consistency and reliability. Following good CSS practices will only help out that cause.
/* Bad */
.widget { }
#sidebar .widget { }
/* Good */
.widget { }
.widget-sidebar { }
In my opinion, it's best to use a "sidebar" class for the widget. .widget { }
.widget.sidebar { }
Now, you might be worried that the "sidebar" class affects the widget in unwanted ways. Well, it shouldn't. That class should have generic/basic styling that anything in the sidebar should have.Maybe you want to have special font styling for things in the sidebar. The ".widget.sidebar" is a special selector for a widget in the sidebar. You can also have the following
.separator
.separator.sidebar
.separator.footer
That makes elements easier to maintain and debug. Well, just my opinion.1) This approach is more error prone and less predictable. For a one-man job it's probably OK, but on a team it's harder to guarantee someone else isn't going to apply some styles to `.sidebar`, which will cause unwanted styles to be applied to your separator component. The namespaced approach is very intentional, so it's unlikely someone will add styles to that rule without knowing exactly what they're affecting.
2) chaining like this ups the specificity of the CSS rule, which means your other modifier/presenter classes might not work on the element anymore. In CSS specificity is everything, and keeping it nice and low is usually preferable.
It's also worth noting that this makes a lot of sense when you think about it, but from thought to application there is a big gap and it's not an easy one to cover. It takes a lot of time to incorporate it and it's really hard to get right.
OOCSS is most useful on massive websites.
CSSLint is useful, at least for me. The only problem is I find myself disabling a lot of rules.
There are certain rules that would be useful if you could easily specify their parameters. For example, there is a rule that says that you can only have 10 font-size declarations in your CSS sheet, which is completely and utterly arbitrary. What if I need 11? Or what if I ONLY want 3? It would be useful if I could specify that. In fact I should be able to do that for any property.
Developers need to be able to enforce standards in their JS, CSS and even HTML. The fact, however, is that certain standards aren't ubiquitous across every webpage, and need to be set by the developer.
I'd like to add another practice that has served me well over the years; Separate layout from style. Doing this will make your CSS much more modular and reusable.
Nicole Sullivan (OOCSS creator) refers to this principle as "separating content from container".
Am I reading this right? Or are templates an exception? I need to re-read the template/component thing a few times to figure out exactly what nomenclature he's using here. But in general, I'm not sure I see the advantage of `.modal__form__item` vs. `.modal .form .item` except that the first is exponentially more verbose in the html.
Essentially, you just have to treat your HTML class names as hooks into your CSS; that's their function. Your CSS rules should not be concerned with your HTML structure.
I hope that helps.
EDIT: This article, mentioned elsewhere in this thread, does a fine job explaining these concepts: http://nicolasgallagher.com/about-html-semantics-front-end-a...
There are so many things I do that are described in this article and I class myself as a seasoned CSS developer.
Every project I do I try to improve my layout and modularisation of my code. The one thing I find really difficult is naming, I always fall short on naming my elements.
I like to group stuff too so I know where it is but grouping is sometimes difficult, do I group buttons with buttons or inside the associated container it is in?
I've just done my second full responsive site and have learnt a lot about reusing code in this one due to the nature of responsive sites so on the next one I really want to come up with a routine.
[Edit]: And what then is the most optimal method to use instead of tables?
Tables are similar to a club (caveman-style), it performs best at a particular task, such as knocking-off dinos, but it was quite often used as a hammer, paper-weight, table-leg, etc. Once specific and readily available tools came about, the club's value as a club didn't diminish, just its extended usability did.
CSS provided programmers the ability to not use a club as a wrench, but there will always remain a value for tables until something more efficient and effective comes about for the task that they serve.
There are still scenarios when you need them though, so I wouldn't call them 'poor practice' so much as something that should only be used if it makes sense.
[Edit] Added to my original post.
But like I said, I don't think tables are 'bad'. I think the main stigma against tables was that back in the old days they were used to layout pages that had column layouts, but I didn't program back then so I don't really know.
Tables for tabular data are the only reason you should use the <table> element.
GMail uses a table for laying out emails, is that tabular? (Maybe it is, I don't know, which is why I'm asking.)
What if you have an element which has 5 children that are in a row and you want the one in the middle to take up all the remaining width while the rest just take the width they need? I'm actually curious because I haven't figured it out. (Besides using table cells that is)
A list of emails can be thought of as tabular data. In Gmail, you have columns (selection, star, important, participants, subject, and date) with one row per email. That's a table without explicit headers.
Yeah, with current css specs in browsers you need to resort to table-cell stylings like display:table-row and display:table-cell. But that can be done without using actual <table> elements.
I should have qualified that I rarely use the table tag and use display:table-cell.
I was thinking of them as effectively the same as using a table for layout.
In the example there is a 'regular' version of widget and a couple 'special cases'. I think if it was treated as .mainContent>.widget{...} vs .sideBar>.widget the granularity and expectations are the same, you can still have a more generic .widget that sets common values. In general I think this is more readable and concise than having a .mainContentWidget and .sideBarWidget separately.
2c. :-)
.mainContentWidget {
background-color: white;
font-size: 1.5em;
text-transform: uppercase;
}
.sideBarWidget {
background-color: red;
font-size: 1.5em;
text-transform: uppercase;
}
<div class="mainContentWidget"></div>
<div class="sideBarWidget"></div>
The article instead would suggest you do: .widget {
background-color: white;
font-size: 1.5em;
text-transform: uppercase;
}
.widget-sidebar {
background-color: red;
}
<div class="widget"></div>
<div class="widget widget-sidebar"></div>
To address the bit about common values vs. special modifications. The implication is, although you might have to change some names, it's not context dependent. So if you decide that you want to put apply that same style to a widget in your footer ...and the header ...and this special case on a certain page landing page ...etc, then you just add the extra class to your HTML rather than adding a bunch of context dependent rules in the CSS.I was thrown off at first by the ugly naming convention and "classitis" that the pattern produces, but the gains are worth it.
None of your examples break anything, thought they should be considered if writing something from the ground up, maintenance is another story. CSS semantics don't even make it into the bug tracker unless you have nothing to do, or your sole job is to write CSS. There is always more important things to do.
This is similar to how you can always spot a "new" web dev over how they obsess over WC3 validation. Sure it's important, but it's not that important.
This is my exact point, I have maintained large web apps that often have budgets and limited resources. I my experience they are always way more important pressing matters (aka actual bugs/features effecting revenue) then CSS semantics. There are companies out there that will of course deem this as important, but in my experience this has been a minority.
Getting bogged down into the semantics of html/css can also be limiting, unless you really enjoy doing it, personally I hate CSS, it's an ends to a means and a bad one at that.
Semantics weren't discussed at all. The focus was on making the best of working with a language that has a limited feature set, and learning to reexamine long held best practices.
I haven't had a lot of time lately but it's all Open Source - hoping the community will start working together on it.
1) I didn't write this while on the job at Appfolio. I wrote it at home, in my spare time, because I like sharing the things I've learned on the job with the rest of the Web community. Based on the upvotes and overwhelmingly positive responses I've received, I think it's worth my time.
2) My work on the CSS for Appfolio Property Manager has greatly helped the development team (mostly back-enders) and sped up the process. We can release features much faster because of it. I'm sorry they're not the features you want (that's not my call), but if/when we deliver those features they'll get to you quicker because of my work.
That's like saying the guy who developed the CSS for apple.com shouldn't share his CSS knowledge because because customers want a 5mm thick iPad and Apple hasn't given that to them.
It takes a certain kind of unique mindset to encounter excellent work somebody has done and use it as an opportunity to bash them because unrelated teams with unrelated skillsets are not churning out the features you want at the rate you want them. How in the world is doing his job the best he can do it somehow not the best use of his time?
What exactly is your argument here? Is it that appfolio should not hire such excellent front end developers because their backend is still lacking? Or is it that the front end developers should do worse work to mesh better with what you consider to be the failings of the back end? Even if the css author had anything to do with your complaints, your argument betrays the absolute worst mindset that one can find in software management: the idea that quality work is time-consuming rather than time-saving.
The house painter has single job; paint the house to the very best of his abilities.
If you have a problem with the design of the house, take it up with the home-owner. He may or may not decide to accommodate your needs, but in any case, whether or not he decides to do so is irrelevant to the painter. His job is to paint the house.