
Website: http://www.snook.ca/
Jonathan's Blog: http://www.snook.ca/jonathan/
Interview with Jonathan Snook

My mind is on CSS quite a bit these days. At Shopify, I'm jumping into projects that already well under way. As a result, it's been a great way to look at what I wrote in SMACSS and see how applicable it is to yet another project. (As if Yahoo! wasn't already enough of a testing ground.)
With Yahoo!, I (and a team of people) were writing the CSS from scratch and creating our mental map of the project as we went along. Jumping into the middle of a project as I am at Shopify, I have to try and figure out why things are done the way they are.
Here's an example of something that I ran into in the CSS:
#loading-header .loading { background: url(spinner.gif) no-repeat 0 0; }
[...separated by a few pages of code...]
#content {
[...separated by more code...]
#loading-header { display:none; }
.row { display:block; }
&.loading {
#loading-header { display:block; }
.row { display:none; }
}
}
The loading class has a spinner. Got it. But wait, there's a loading class inside an element with an ID of loading-header and another loading class that gets added to the element with an ID of content. Are they the same somehow? Is there some inheritence that is taking place?
As it turns out, no. These two loading classes were named exactly the same thing but applied in two different contexts. They really had no relation at all except that the #loading-header (and thus, #loading-header .loading) is only visible with #content.loading. (The &.loading is part of SASS and adds #content in place of the ampersand.)
One class is a state. Because it's a state, I prefer to prepend all my states with "is-". In this case, it would be "is-loading". The question asked when I first mentioned this is, "isn't the 'is-' redundant?" But as you can see from the example, it isn't. The naming convention clarifies its intent.
In this case, I had to determine intent based on the CSS. Other times, you're looking at the HTML first.
<div id="content" class="loading">
<div id="loading-header">
<div class="loading">
Where do you begin to look in the CSS to find what you're looking for? You'd probably start with a search for ".loading". Now you're left trying to figure out which loading class applies to what element. The swaths of CSS that separated the relevant parts made it harder to see what was going on.
The simple answer to this, of course, is not to naming two different things with the same name. However, I believe a solid naming convention clarifies intent and makes the project easier to understand. We've long applied naming conventions to programmery things like JavaScript and PHP. The same should go for CSS.
Using CSS transitions can be quite fun. But what's not fun is when you want to transition something that needs to use display:none or visibility:hidden (or really, any non-transitionable property).
For example, let's say you have a dialog. When the user clicks on the close button, you want the dialog to fade out — a simple transition from opacity:1 to opacity:0. The problem is that the element is still there, even though you can't see it. There's the transitionEnd event that you can use in JavaScript to set display:none at that time but that doesn't help you for browsers that don't support transitions.
I put together a small little jQuery plug-in called prepareTransition to help out and is available on Github. Feedback is most welcome.
Let's say you had a dialog that you wanted to hide when someone clicks the close button.
.dialog {
position: absolute;
/* and other dialoggy styles */
}
.is-hidden {
display: none;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").addClass('is-hidden');
})
Now let's layer on some CSS transitions.
.dialog {
position: absolute;
/* and other dialoggy styles */
opacity: 1;
transition: opacity 1s; /* don't forget vendor prefixed */
}
.is-hidden {
display: none;
opacity: 0;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").addClass('is-hidden');
})
In browsers that don't support transitions, this will still work but for browsers that do support transitions, this doesn't work. Why is that? The display property ends up removing the element from flow before the animation even starts. Clearly less than ideal.
As mentioned at the beginning of this article, I could remove display: none from is-hidden and then use the transitionEnd event to add it back in but then I don't have something that works in browsers that don't support transitions.
The prepareTransition method forces display: block; until the end of the transition. It does this by applying an is-transitioning class to the element and then using the transitionEnd JavaScript event to remove the class from the element.
.dialog {
position: absolute;
/* and other dialoggy styles */
opacity: 1;
transition: opacity 1s;
}
.is-hidden {
display: none;
opacity: 0;
}
.is-transitioning {
display: block !important;
visibility: visible !important;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").prepareTransition().addClass('is-hidden');
})
Using prepareTransition is a handy way of allowing an easy fallback design for browsers that don't support transitions while making it easier to manage transitions for browsers that do support it.
This would be much easier if there was a transitionStart event, though. Then, a method wouldn't have to be run before applying the is-transitioning class.
Even better would be a pseudo-class that could be applied to an element.
:transition {
display: block !important;
}
Or maybe it's just assumed that any element in transition should be display: block (and visibility: visible). In any case, we clearly need a little more at the browser implementation level to simplify this use case.
It is once again that time of year where I reflect on the year that has passed and contemplate the year the come.
On a professional level, this has been a fantastic year but still not without its ups and downs. This year capped my second and final year with Yahoo!. Yahoo! has been a great experience for me and exposed me to an environment that I hadn't worked in before. I was able to work with large teams on a large scale across multiple products. To know that I had a big part to play in the success of those projects is very rewarding. It gave me the opportunity to work with talented people who are passionate about what they do and I was happy to have been given the opportunity to share what I learned both inside and outside the company.
It provided me a deeper foray into accessibility, getting to speak at CSUN and at the Ottawa Accessibility Unconference on the work we did with keyboard access on Yahoo! Mail.
My time at Yahoo! also led me to write Scalable and Modular Architecture for CSS (SMACSS), for which the outpouring of support from the community has blown me away. As a result of that success, I'm taking a big gamble in the new year: I'll be speaking only on SMACSS and CSS architecture in 2012. This is a departure from previous years where almost every talk I did was something new.
SMACSS has also been extremely fun to work on as it has thrown me into new things that I've never done before. I've had to learn about how to create e-books, had to learn about how to market the book and the workshops, and also thrown into a world of event planning. The last couple months have been quite rejuvenating!
I still haven't picked up the pace much around Snook.ca but I'm chalking it up to being extremely busy with everything else, especially all the writing for SMACSS. I did get the chance to write for 24ways again, which has become a bit of a tradition. And I got to write about another thing I learned from Yahoo!: bidi.
So now that my time at Yahoo! is done for, what will I be doing next? Yes, I have the book, and the workshops, and other speaking gigs, but I'll still be holding down a full-time job amidst it all. As of January 3rd, I'll be working for a local company doing great things: Shopify.
I'm quite excited to starting work at Shopify in the new year. I've had a chance to meet a bunch of the folks from there and they're all quite eager and passionate. My JavaScript skills weren't put to the test very often in the last two years, so I'm looking forward to exploring CoffeeScript and Batman.js.
It does mean my return to an office environment. Gone are the days of working in my underwear. Life is rough.
On a personal level, things have slowly stabilized. My divorce was finalized after two and a half years. It was looking like it was going to drag out for years and involve courts and all that icky stuff. Thankfully, that didn't materialize, for the most part.
Having things stabilize in my personal life has, I believe, given me a greater ability to focus on my professional life again.
Working for a company in the San Francisco Bay area was both wonderful and difficult. I had tried to maintain the balance between travelling for public speaking, travelling to the main Yahoo! campus in Sunnyvale, and spending time at home with my kids. The draw to move to the Bay area was strong at times but would've meant sacrificing my time with my kids. I have not succumbed to that temptation as of yet and instead, will be spending much more time in Ottawa now that I'm working for Shopify.
I will miss the friends I made in the Bay area and look forward to seeing them again at some point in the new year.
When 2012 comes, I'll be hitting the ground running as I finalize the remaining workshop venues for SMACSS and I'll be immersing myself in the world of Shopify as I try to get a handle on everything, all the while learning new names and new faces.
2011 definitely ended on a high note and I'm excited to what 2012 has in store.
