Jonathan Snook's Blog, page 18
February 24, 2016
Reinvention
We humans like to categorize things and we make no exception with other humans. We typecast them, stereotype them, and place them into boxes. A Gemini, Type A personality, Alpha, INFP. As if any of these can accurately sum up the totality of a person.
You’re a designer or a developer or a researcher or a content strategist. Or maybe you’re a bit of everything.
How long have you known me? Do you consider me a CSS developer? Do you consider me a designer? Do you consider me a JavaScript developer? Maybe you know me as a PHP developer because of my work with CakePHP.
Many hats
My first job in the web industry, back in 1999, was as a technical architect at a digital agency. That meant I figured out how we should build the sites and applications for our clients. I also did a lot of technical writing, providing documentation for clients for said sites and applications.
Of course, working for a small agency meant wearing many hats. I did HTML production, some JavaScript, and a whole lot of whatever backend technology the client had. That meant learning MS SQL Server, Oracle, MySQL, ColdFusion, Java, Perl, ASP, and PHP.
When I moved into a larger agency, I was relegated to being a backend developer. That’s what people in the company saw me as and it was difficult to change that.
This was the catalyst to go freelance: an opportunity to break out of the box and explore new things. In those 5 years, I did a lot of JavaScript, CSS, Design, UX, MySQL, and PHP. Each project allowed me to explore different facets of web development, to stretch my skills in areas that hadn’t been stretched in awhile. I was a solid generalist with reasonably deep knowledge in a variety of areas.
After my freelance life, I’ve been a front-end developer, a designer, a product manager, and back to being a front-end developer.
Something old, something new
Every time I got known for something, I tried something new. I love the challenge of learning something new.
Don’t grow up to be a specialist. Diversity is your best defence against myopia.
— Jonathan Rosenberg, SVP of Products at Google
There’s the idea of being T-shaped. It is the idea of going deep in a particular skill but going broad to gain empathy. In this sense, I’ve aimed to be more U-shaped. I hope I’ve gained more empathy but going deep in a more extensive set of skills. (It was this extended skill set that I feel made me a better product manager.)
Our industry continues to grow and offers up even more opportunities to try new things. It may very well be time for me to try something new again.
February 21, 2016
You got your CSS in my JavaScript
Separation of concerns. You have your HTML over there, your CSS over there, and your JavaScript over there. Each should be as separated and independent as possible. Or so we’re told.
While CSS Zen Garden gave us a glimpse of a possible world where CSS could change and HTML never would, the reality—at least, in my experience—has been much different. Design changes often require both HTML and CSS to change. That’s because the fundamental structure of what we want to style also changes.
Likewise, for JavaScript. It interfaces with the document to allow for dynamic interactions for and from the user. For increasingly complex applications, JavaScript has needed to take on more and more work. JavaScript is used to load HTML partials (or entirely new views); it is used to manage application state; and it is used to manage data and decide whether it needs to generate new chunks of the page using a template system.
As you can see, with JavaScript doing so much, it should be unsurprising to see many frameworks move to using JavaScript as the crux of the application—to the point where the body may start empty until the application is loaded and can render the view.
The React community, with its large gravitational pull, is pulling everything into the land of JavaScript: HTML (in the form of JSX) and CSS (in the form of CSS Modules and inline CSS).
Some rail against this unified theory of application development on the purist grounds that each pillar of web development should remain completely autonomous.
Why declare CSS in JavaScript?
To answer that question, let’s consider the React approach. There’s a lot of talk about the virtual DOM but, to me, the big thing about React is its component-based approach to application development.
This component-based approach is very much in line with the SMACSS approach. They’re both trying to modularize an interface. Part of that modularization is the ability to isolate a component: to make it independent of the rest of the interface.
Making a component independent requires taking a chunk of HTML along with the CSS and JavaScript to make it work and hoping that other CSS and JavaScript don’t mess with what you built and that your component does not mess with other components.
At Yahoo!, we had a folder structure that looked similar to this:
/js/modules/modal.js
/css/modules/modal.css
/html/modules/modal.mu
React can essentially merge all of these into one file. For a given page, when you load only the components that you need, you load in only the JavaScript and CSS that you need as well. With these components now loaded, they can be used repeatedly without requiring any additional bandwidth. Again, this is very similar to how we did things at Yahoo! but we used YUI.
Whether you generate CSS classes or inline the CSS into the actual HTML won’t really matter for client-side-only applications. If you want to generate the initial view server-side then you might have some considerations about how to separate these pieces to allow caching, if that’s a concern. (Why wouldn’t it be a concern? Maybe you’re doing post-render client-side caching.)
http/2 and Web Components
Web Components are similar to React components in that they allow us to encapsulate HTML, CSS, and JavaScript into a single file. (Whether we choose to do that or not is another matter.) And http/2 allows us to ship these components individually without having to compile them into a large bundle like we’ve traditionally done.
What, me worry?
While some may rally against mixing CSS (and HTML) in with JavaScript, I’m not overly concerned. When using a component-based approach, bundling everything together doesn’t feel like a grand departure. Instead, it feels like a reasonable way to build a site.
Applying Product Management to Your Life
After having done product management for a time, I was asked whether the principles of product management could be applied to ones own life. It’s an interesting question and one I’m finally making some time to explore.
First, we have to define what a product manager does. In a company, they’re often wearing many hats as they work with various teams to get something shipped.
In the context of a company, a product manager could then be described as a shepherd. In the context of oneself, it’s, well—I guess it’s the same thing. You’re your own personal shepherd trying to keep yourself on a path to your goals.
Prioritization
It’s really easy to say yes to everything but it’s really hard to actually do everything. In a company, a product manager works with the team to decide on priorities and ensures the team has what they need to stay the course.
For myself, I know I’d love to work on the dozens of project ideas that I’ve thought of but ain’t nobody got time for that. Instead, I had to decide what my number one priority is and say no to everything else. (That’s exercise and writing.)
As much as I’d love to work on other projects, I want to reach my exercise and writing goals first and then I can work on setting new priorities.
Sometimes priorities shift and when they do, it’s important to reset expectations. For example, I have some travel coming up and I know that I am unlikely to maintain either of my goals during that time and that’s okay. I know what to expect and I can get back to those tasks when I get back.
Identify Opportunities
A product manager needs to evaluate new opportunities for growth. This doesn’t need to happen every day but it’s a great exercise to go through on a somewhat regular basis.
One of the ways I do this for myself is to create a mind map of my life. I have two main branches: Work and Personal. I’ve then identified areas from that. For work, I have things like personal brand, teaching, and revenue. For personal, I have things like my kids, fitness, and creativity.
Once I’ve identified core areas, I list off a number of things that can help me grow in those areas. In going through this exercise, I can sometimes see new opportunities or recognize where I haven’t been putting enough effort.
When an opportunity addresses multiple areas of my life, those become great opportunities to work towards. For example, writing a book can allow me to grow in areas of creativity, finance, and personal brand. (Hence why I’ve tried to refocus my writing this year.)
Champion
In a company, a product manager champions the product—internally within the team and company, and externally with existing and potential customers.
As a product manager for yourself, you have to be a personal champion. Sometimes I get in a rut and I start to get down on myself. With a bit of work, I become my own personal champion. Basically, I create confidence in myself and try to display that outwardly. (My modest Canadian sensibilities sometimes makes that difficult. I’m awesome! I’m sorry, that was a bit much.)
Time
Product Managers should be obsessed with optimizing a product to achieve the business goals while maximizing return on investment.
— Mind the Product
We human beings have a limited amount of time in this world and there are many ways to invest that time. I want to figure out how to reach my goals while maximizing my returns.
On the other hand, maybe we don’t have to be obsessed with milking every free moment in the pursuit of betterment.
February 10, 2016
How I Manage My Finances
Money is such a taboo topic but shouldn’t be. Money is, good or bad, a very important part of our daily lives. While I’ve had some rough times with money, through luck and hard work, I managed to get myself to a good place.
There are, in my opinion, some very basic tenets to how I manage my finances.
Increase Revenue
Decrease Expenses
Manage Cash Flow
Increase Revenue
There are a couple different ways I increase my revenue.
If you work full time, you can get a raise. Or switch to a new job that pays more. If you’re a freelancer or agency, you can charge more money for your services (assuming that you don’t increase beyond what people are willing to pay). If you have a product business, you can charge more for your products. Lastly, you can just pump out more work.
Nobody really likes doing that last one but if you charge by the hour, sometimes working 60 hours for awhile to build up the savings is okay. Be careful not to burn out!
For example, I often play around with pricing for the SMACSS book and workshop to see which results in more sales. Or, due to the declining Canadian dollar, I switched to charge in US dollars. Bam, I was suddenly making 40% more.
Another way to increase revenue is to diversify. Diversifying your revenue streams helps protect you if one stream begins to die down.
For example, I have my day job, ad revenue from my site, book revenue, along with conference and workshop revenue. My plan this year is to both increase revenue in one or more of these channels and possibly add more streams.
One concern with diversification is being able to manage multiple projects at the same time. For some things, like my site and the book, I’ve let them languish while I concentrate on other projects. I hope to be able to launch some new projects then come back to the ones that have stopped being as effective. Or in the case of SMACSS, freshen and expand the content in hopes that people will like the new content.
It can be hard to keep working on content that doesn’t have an obvious payout. Client work is guaranteed income. Hours for dollars. But in the land of content, some of the work is promotional, some of the work is just putting stuff out there in hopes that something will take off. Not everything will.
Decrease Expenses
Getting money is great but it’s important to keep your expenses in check. Like a project seems to fill the time we make available to it, so does our budget seem to match whatever we make.
What, you don’t have a budget? You gotta track money going in and out to know what’s going on!
I have a Google spreadsheet that I use that is pretty straightforward. It’s 3 columns:
Income and Expenses; take the difference and this is your free cash every month.
Cashflow. I detail what day of the month everything is going in and out for the next month or two.
Assets and Debts; take the difference and this is your net worth.
Once I know what’s going in and out and when, I can start to create a game plan for decreasing expenses. Can I eat out less? Do I need all the services I’m paying for? Can I cut back on the services I have?
When I was really broke, I stopped paying for garage parking in my apartment building and parked on the street. Unfortunately, if I forgot to move my car on a regular basis, I’d get a parking ticket. It became a game of trying to get less in parking tickets than I was paying for the garage spot.
The problem with being broke and in debt is dealing with the sometimes seemingly unsurmountable debt repayment. Consolidation loans from high interest to low interest can help reduce your costs. Focus on paying off higher interest debt before lower interest debt. Anytime you get a windfall, try to pay down that debt. Once you pay off debt, your cashflow opens up allowing you to pay down the rest of your debt faster.
I ended up cashing in my retirement savings (only about $10k at the time) to pay down my debt. When I got a bonus at Yahoo!, I used it to pay down my debt. When the book started to take off, I’d take lump sums and pay down my debt.
Friends and family also helped me through the time times in a pinch. Some people don’t like to borrow money from friends and family but a small interest free (or low interest) loan can be a blessing.
It took me 3 years to go from near bankruptcy ($60k in debt, no assets) to debt free, which was, admittedly, faster than expected.
I have a plan to continue decreasing my expenses over the next 3 years. My kids will slowly age out of after-school care. I’ll finish paying off my car. I’ll stop paying for a trainer at the gym.
Manage Cash Flow
I mentioned the cashflow thing a bit in the last section. To me, this is important because I want to avoid over-drafting my accounts, increasing expenses. I mentioned that spreadsheet that I use.
Here’s an example of what my spreadsheet looks like.

That middle column is where the cashflow magic happens. As things are paid, I delete them from the middle column and update the current “IN BANK” amount in the top right. To know what the future looks like, I copy the items from the Expenses and Income column and add them to the bottom of the list.
(One annoyance: sometimes the calculations get thrown off due to copying and pasting cells. Google Spreadsheets get confused. You just have to reset the rightmost column of the Cash Flow, which I do by dragging the bottom right corner of the second cell and drag down. This copies the formula to the cells below and updates relative cell references.)
At this point, I can see where I might have to deal with issues like transferring money between accounts to ensure bills get paid.
My mom used to spend time balancing her chequebook. It was a way of knowing what money was coming out since a cheque comes out at some awkward future date and if you forget about it, you’re in for a world of hurt.
That’s what my cash flow does but, I think, does it better than what my mom had because I can see further into the future.
Conclusion
Getting out of debt can be daunting. I was always in debt up until 3 years ago. (And, well, if we consider I know have a house and car, I guess I’m still in debt! But I have a net worth above zero.)
I recognize that not every person’s situation is the same and this approach—while it works for me—may not work for you. In a lot of ways, I recognize that I’ve been very lucky along the way and not everybody will have the same opportunities that I have.
I do think that managing money well is important. It can be incredibly stressful. It’s also incredibly rewarding when a plan comes together.
February 7, 2016
Design Doubt
As a developer, rarely has my approach been put into question. If it works, it ships. The definition of “works” is usually well defined. Does it look like the design composition? When people click on the button, does it send the data where it needs to go?
As a designer, rarely has my approach not been questioned. I can’t even count how many times I’ve heard “have you tested this with users” as a way of shutting down any design direction I might want to take things.
In the beginning
I should give some background…
Early in my career, I was a backend developer. I worked in ASP, ColdFusion, PHP, and a handful of other technologies. I did front-end, too, but this was the late 90s/early 2000s. Front-end was HTML with a bit of JavaScript and CSS.
Many of the projects I worked on had a public-facing component (the site) and a client-facing component (the admin). Designers would design the site and I would build the site. I would design and build the admin to go along with it. Rarely did I receive any direction on what the admin should look like. I designed what I thought would work.
For 5 years, through 3 agencies, this was my job. I built content management systems that salespeople sold for thousands of dollars and clients used for years—nearly a decade at one particular organization. (I’m proud that I designed and built something that lasted that long.)
I leapt into freelance to have more freedom to do design. For 5 years, through dozens of client projects, I had the opportunity—and freedom—to design and develop. Being trusted for your expertise is a wonderful feeling.
Doubt
In the last couple years, however, doubt has crept in. Design after design has been rejected. Interactions have been questioned. And that phrase is thrown at me. Have you tested this with users? Build a prototype, put it in front of users, and prove that this is the way to do things.
In this way, I’m reminded of Doug Bowman’s experience at Google:
Reduce each decision to a simple logic problem. Remove all subjectivity and just look at the data. Data in your favour? Ok, launch it. Data shows negative effects? Back to the drawing board. And that data eventually becomes a crutch for every decision, paralyzing the company and preventing it from making any daring design decisions.
Thing is, it’s hard to argue with data. Why do I resist building prototypes and testing my ideas? Wouldn’t I want to know whether my ideas were any good?
<insert lengthy soul searching>
When I design, I create a solution for the problem at hand. I’ve gone through the work of understanding the use cases, done the work of prioritizing, and put out something that I believe solves the problem.
Of course, the way I solve that problem is going to be different than how someone else might solve it. There are a million ways to solve these problems. And often times, the issues of a design aren’t uncovered in a cursory review from co-workers or users.
A quick aside: I find most peer reviews focus on inane details rather than how the solution does or does not actually solve the use cases it’s designed to solve. Mostly because peers haven’t thought about the problem space and usually can’t provide meaningful input on the design. But I digress…
So what does it mean to test a design as a prototype? What quantifies it as a success? Am I building a prototype so you can understand things in a way that you couldn’t understand in a Sketch or Photoshop file?
If we look at the process of a design sprint, there are 5 major steps: Understand, Diverge, Converge, Prototype, and Test. The prototyping phase appears near the end once there has been a convergence of ideas and then those ideas are validated with users.
However, in those times I’ve been asked to build a prototype, we’ve still been working between the divergence and convergence phases. The prototyping and testing becomes a way to decide in which direction to converge. It’s like saying “I don’t believe you. Prove it.” It feels like a pissing match between designers.
Or maybe I just am not a good designer. Maybe I’m a difficult prima donna who doesn’t like to be questioned. Which, I guess, leads me back to doubt.
February 6, 2016
Spontaneity
I sometimes wonder if I’ve become too rigid with my time. Ask me if I want to go out some evening and chances are I’d have to say no. Between kids and travel, I didn’t really have the time to be spontaneous like that.
Now that I’m not travelling as much, I’ve added the gym, guitar practice, and writing to my regular schedule. Most often, when I try to be spontaneous with friends, they’re all busy. Everybody plans ahead.
Are there moments in my down time where I can be spontaneous? Drop everything and do something I didn’t have planned?
Thing is, state changes can be difficult. You’re in a moment of flow and someone interrupts you. Ugh. My kids don’t always respond well to state changes either. I sometimes get revolt when I pick them up from school ten minutes early. Setting expectations ends up being important.
Every now and then, I have my moments of spontaneity. Last minute plane trips to surprise a girlfriend. Surprise donut runs before school. I like surprises like this. Moments of delight.
Can spontaneity be used to my advantage? When schedules change due to sick days or people around the house, how do I manage the upheaval? I think this is where I really need to work on things. I’ve often used that upheaval as a reason to not get things done. A travel day? Not going to get work done. Kids at home? Not going to get work done. Somehow I’ve come to need the perfect conditions to be productive and yet those perfect conditions rarely happen and, thus, I’m rarely productive.
When it comes to my recent weight loss, I’ve motivated myself to do the hard, necessary work by saying to myself I need to do the work to get what I want. I can’t take shortcuts. I can’t wait for the perfect conditions to lose the weight. And the same needs to happen with everything else. If I want to write another book, I need to do the work, regardless of whatever the conditions might be.
Life is spontaneous, after all. I can’t plan every moment. I can live in the moment and deal with whatever life throws at me, all the while putting the work in to get to my goals.
January 16, 2016
SMACSS Rewrite Progress
I feel like it’s been more than a year since I mentioned how I wanted to rewrite SMACSS. It’s been slow going, that’s for sure. Mostly because I hadn’t been spending time on it. Apparently, you need to actually write for a book to get written.
As the ball dropped to kick off another new year, I decided to get serious about getting the book done. I’ve put together a more concrete outline and have slowly been working through all the pieces. Every day, I should be working on the book for at least a half an hour. I find little holes in my day and try to fill them with writing.
This edition is intended to be a bit less prescriptive in some areas and more descriptive in a lot of other areas. (A lot of which I cover in the workshop and wanted to get it back into the book.)
The book will continue to be focused on the core topic of CSS architecture but will also bleed more into other areas like design and documentation.
Here’s the new outline:
Introduction (done)
Modular Design (draft)
Categorization (draft)
Base (draft)
Layout (draft)
Modules (in progress)
States
Themes
Naming Convention
Decoupling CSS from HTML
Depth of Applicability
State-based Design
Preprocessors
Project Setup and Maintenance
Prototyping and Pattern Libraries
Performance
Converting an existing project to SMACSS
Appendix: Formatting Code (done)
As you can see, there’s more to cover and a long ways for me to go. I’m excited that I’ve got a plan and that progress is being made.
If you’ve been patiently waiting for the next edition, thanks for being patient!
January 13, 2016
Habit List
I don’t really do new year resolutions but sometimes I start up new things and one new thing that I decided to start doing is using the Habit List app to track and, more importantly, maintain certain habits.
Since my theme for this year is Movement, both in exercise and in writing, the items in my list are geared towards that goal.
Exercise, 5 days a week
Plank, every day
Stretch, every day
Meditate, every day
Write, every day
Blog, once a week
Guitar, every day
Okay, that last one is maybe a little out of left field. But I’ve always wanted to learn, my kids are learning, so I figured why not.
When you want something out of life, you also have to want the cost. This list is what it’s going to cost me to reach my goals of reaching my target weight, getting another book published, and being able to play a John Mayer song.
These things take time out of my day. I was asked how I fit all of this in and, honestly, I make the time. I have my day job, I have my kids, and I have the time I want to spend with friends. These are all things that I want and I’ll make the time for what I want.
(and with this, I just checked an item off my habit list today)
January 5, 2016
Simplest CSS Slideshow
In continuing my exercise of tackling a simple slideshow in different ways, this challenge attempts to make a slideshow without using any JavaScript.
Thankfully, I didn’t research this first and just went with it. Yes, this has been done before by other people. Whatevs. Enjoy…
To do so, I’ll attempt to do this with CSS animations. This was trickier than expected because, well, math is hard. I knew I was dealing with certain multiples but kept screwing up the timing.
The basic premise is to have an image fade in and then fade out. I use an animation-delay to offset the animations for each subsequent image in the slideshow.
This graph visualizes how the animation duration and animation delay work.

There are 3 sets of numbers that you need to determine:
The total animation-duration.
The animation-delay for each image.
The keyframe timings.
Animation Duration
To determine the animation duration, take the fade in time that you want plus the time you want the image to be visible before beginning to fade out. If you want the image to take 1 second to fade in and be visible for 1 second and you have 3 images then your animation duration is 6 seconds.
Math: (fade-in visible) × images = duration.
Animation Delay
The animation delay is pretty straightforward. The key thing is that you want to start the animation for the next image when the image before that is starting its fade-out. Therefore, you want the animation delay to be the fade-in time plus the visible time for the previous image. If it’s the second image and the animation should fade in for 1 second and be visible for 2 seconds before fading out then the animation delay should be 3 seconds. If it’s the third image, the delay is 6 seconds. If it’s the fourth image, the delay is 9 seconds, and so on.
Math: (fade-in visible) × (ordinal position − 1) = delay.
Keyframes
Keyframes can be a simple from or to but for more complicated animations, we have to use percentages. Therefore, the last piece of the puzzle is figuring out how to get the animation percentages correct. To do so, we need to break up 100% into the number of seconds of our animation. If the animation is 10 seconds long then each second is 10%. If the animation is 6 seconds then each second is 16.66%. The timing then becomes a multiple of that.
Math: 100 ÷ animation duration = percentage for 1 second.
All Together
Here’s how it all comes together. In this case, I’m doing a 1 second fade-in plus 2 seconds of visibility before fading out. First, I define the CSS keyframes for a fade animation.
@keyframes fade {
0% { opacity: 0; }
11.11% { opacity: 1; }
33.33% { opacity: 1; }
44.44% { opacity: 0; }
100% { opacity: 0; }
}
Next, I set the animation for all images.
.fadein img {
opacity:0;
animation-name: fade;
animation-duration: 9s;
animation-iteration-count: infinite;
position:absolute;
left:0;
right:0;
}
Lastly, I set the animation delay for each of the images.
.fadein img:nth-child(1) { animation-delay: 0s; }
.fadein img:nth-child(2) { animation-delay: 3s; }
.fadein img:nth-child(3) { animation-delay: 6s; }
And voila! We’re done!
The sucky thing about this is that any changes to the number of images you have require you to change the CSS to fix all three factors: duration, delay, and keyframes.
Of course, some crafty person could probably whip up a Sass function or mixin to handle this.
CSS-only Slideshows aren’t anything new and that’s okay. Check out Pure CSS3 Cycling Slideshow for an in-depth look at how to build a more complex CSS-only slideshow.
Sass Mixin
Okay, okay. Let’s do the Sass mixin!
We know that we need three things to determine all the values for the CSS animation:
The number of images.
The length of the fade.
The length of time it’s visible.
@mixin fade($num:1, $fade:1, $visible:2) { }
The mixin itself has three parts:
Define the keyframes
Set the animation properties
Create all the :nth-child definitions
@mixin fade($num:1, $fade:1, $visible:2) {
$a: 100 / (($fade $visible) * $num);
@keyframes fade {
0% { opacity: 0; }
#{$a * $fade}% { opacity: 1; }
#{$a * ($fade $visible)}% { opacity: 1; }
#{$a * ($fade $visible $fade)}% { opacity: 0; }
100% { opacity: 0; }
}
animation-name: fade;
animation-duration: (($fade $visible) * $num) s;
animation-iteration-count: infinite;
@for $i from 1 through $num {
&:nth-child(#{$i}) {
animation-delay: (#{($fade $visible) * ($i - 1)}) s;
}
}
}
Now, all we have to do is include the mixin on our images.
.fadein img {
position:absolute; left:0; right:0; opacity:0;
@include fade($num:3, $fade:5, $visible:0);
}
And like that, we’re done!
For more Snook.ca slideshows:
Simplest jQuery Slideshow
More Simple jQuery Slideshows
Simplest JavaScript Slideshow
January 4, 2016
Simplest JavaScript Slideshow
Years ago, I put together a tiny jQuery script for doing a simple slideshow. Due to chaining, it was only a handful of lines. It still needed jQuery, though, which was a 93KB dependency (33KB gzipped).
In the six years since then, browsers have improved their DOM APIs. What would it look like if I tried to write this script now without jQuery and used the DOM APIs along with some handy CSS?
The concept is still the same. First, I want to hide all the images except the first one.
var root = document.querySelector('.fadein');
var els = root.querySelectorAll(':not(:first-child)');
I grab the root element of the slideshow. This makes the assumption that there is only ever one slideshow, which is what the slideshow assumed, too. After that, I grab all the elements that are not the first child.
Since the NodeList is not an Array, I can’t use Array functions. Instead, I just use a simple for loop. Yes, I can convert the NodeList into an Array but since this is the only time I need to loop through the elements, I’d be wasting time to do so.
for (i=0; i < els.length; i++) {
els[i].classList.add('is-hidden');
}
In the original jQuery script, the fadeIn and fadeOut routines change the opacity by modifying inline styles. This time around, I used CSS transitions to handle this.
.fadein img { transition:opacity 1s; opacity:1; }
.fadein img.is-hidden { opacity:0; }
Since jQuery knew when the animation was over, it could easily move to the next part of the script. We’ll have to use the transitionEnd event to know this.
root.addEventListener('transitionend', function(){
root.insertBefore(root.querySelector(':first-child.is-hidden'), null);
});
The event is attached to the root and rely on event bubbling to respond to when the images are done transitioning. The problem is that the event is fired twice: once for the image fading out and another for the image fading in.
I qualified the image to move to the back to only grab the first child that is hidden. Once it’s moved to the back, the second event firing doesn’t have anything to do.
The last thing we need to do is set up the 3 second interval, just like we had before. Again, we use setInterval. All that happens in the interval, though, is the adding and removing of the is-hidden class.
setInterval(function(){
root.querySelector(':first-child').classList.add('is-hidden');
root.querySelector(':nth-child(2)').classList.remove('is-hidden');
}, 3000);
The entire demo page is 1KB.
The Full Script
The CSS:
.fadein { position:relative; height:332px; width:500px; outline: 1px solid blue; }
.fadein img { position:absolute; left:0; top:0; transition:opacity 1s; opacity:1; }
.fadein img.is-hidden { opacity:0; }
The Javascript:
var root = document.querySelector('.fadein');
var els = root.querySelectorAll(':not(:first-child)');
for (i=0; i < els.length; i++) {
els[i].classList.add('is-hidden');
}
root.addEventListener('transitionend', function(){
root.insertBefore(root.querySelector(':first-child.is-hidden'), null);
});
setInterval(function(){
root.querySelector(':first-child').classList.add('is-hidden');
root.querySelector(':nth-child(2)').classList.remove('is-hidden');
}, 3000)
For more slideshows:
Simple jQuery Slideshow
More Simple jQuery Slideshows
Jonathan Snook's Blog
- Jonathan Snook's profile
- 4 followers
