My goal here is to share my web work flow, from design to production, because things are fun again! I get that giddy feeling, the kind of giddy that stems from power, and not like super strength, I’m talking Sylar (Heroes) power, flick of your wrist power. Where when a designer makes a change request, you don’t cringe, you show off. ❤
I want to share how tools and technology have let me take designs, to prototypes, and into production, at a quality and reusability level that is making badass useable web experiences for me and my users. There’s going to be lots of buzzwords scattered throughout this next part, put on your nerd glasses.
Essentially what we’re after here, is given the scenario where designs need to become working accessible web applications, here’s how I’m doing it, how Sylar would build web apps. The end result is a universal, static optimized, deep link supporting, event driven cache, progressive web app. The concepts of which are tool independent, and exist to serve the user, who comes from many parts of the globe. Fast, efficient web sites. Where tools aren’t barriers, they’re making us Sylars. Where we leverage what the browser already offers, to provide the most optimal end user experience the browser is ready to deliver. Developer indians, not developer cowboys.
I will be mentioning my tools specifically, but thanks to the amazing open source web community, there are many variations one could use to follow the strategies and achieve the same end result. If a 20 minute read is too much for you, scroll to the bottom of this article for the bulleted list tl;dr summary. Or just skim the section titles.
The 12 Steps
// 1: Join Design Early
Lots of companies that operate a pipeline for web development, have a “hand off” between design and dev. Some call this throwing it over the fence. Do not do this. Participate early with the design team. If they aren’t asking you to join, ask them if you can join. Help them help you leverage the right tools and technology in the browser. Let them dream too, it will challenge you. But please, do not just accept some .jpeg’s or .psd’s from a designer and allow them to think what you’ll make will turn out exactly like what they gave you. The best web experiences are made collaboratively, and again, inject yourself as deep as the information architecture team, if you can.
# Start A Living Style Guide
This is a good time to start the foundation of a style guide. Brand colors are not likely going to change much, so I like to start setting CSS variables, and maybe even adding a living style guide tool to my CSS build tool chain. To me a living style guide is one where commented HTML is made inside a CSS file, with a description and varying state classes described, which the output is rendered into an interactive HTML page.
Easy style guide targets for this early:
- Typography hierarchy [H1…6], fonts, and weights
- Brand colors
- Links and buttons
- Gutters and grids
# Share It
At this point, you’ve gleaned everything you can from the designs and setup some nice scaffolding. Hopefully you’ve vocalized a few concerns and pro tips to the design team regarding certain choices they’ve made. Showing them the style guide should inspire some good design choices, may even be the catalyst to them thinking in a re-usable mentality.
// 2: Be Data Driven
I’ve heard of design teams that use plugins with Photoshop or Sketch to leverage JSON or API’s in their files. Data driven design! Yes! Here’s the article I remember reading, where I heard of this power first. So rad.
# Extract Data From Those Comps
I like to do this too! I extract names, dates, lists, images, etc from design comps, and loop over or utilize these values to populate my prototypes. This comes in so incredibly handy. I can change the fake username once, and it updates everywhere. I can change the nav menu items once, and populate them everywhere. This is the start of that Sylar power. When design says, we renamed all the nav items, you say “cool, no problem.” Flick your wrist, and boom, nav updates across every page. Nav change request becomes one YML entry change, save, auto refresh with BrowserSync, and you’re done.
# Static Site Templates and Modules
To accomplish this, I use Jade and YML. As part of my build system, I send converted YML (data I extracted in the above step) to my Jade as JSON locals for use in my templates. Jade is super powerful, that’s a whole other article, but ultimately the goal is to break the designs and layouts into re-usable modules. Each module will get some data, and you get to build a static site like you will eventually do when the data is real. Saves tons of time, and is one of the most fun parts of all these steps. There’s something fun about writing HTML that loops over data, your HTML files become really small and easy to manage. No changing a class 20 times in your data grid, just once on the grid item template. Managing 20 DOM nodes all of the same markup, with just different titles, is a pain. Make a loop and a module template!
# Mock Services
If you’re really lucky, the services team has been working on the data side of the project, and they have mock services for you to hit. This too can be built into your build system. Node build systems can fetch data and return it into a template system. How cool is that? Building a prototype or website against mock services, where you’re not writing any throw away code when you get to the client side rendering aspect of your site.
# One Template To Rule Them All
You should now have a templated static site. No cool word for this which sucks, because I think it’s really powerful. Isomorphic just sounds so cool right? Another cool thing about this setup, is you’re agnostic to client or server rendering. Jade can be used in the client and on the server, so if you make a data powered static site with Jade, then moving to server rendering and/or rendering partials in the client is a walk in the park. That’s one rad workflow no? One template can survive all phases of your code workflow, from prototype to production. Sylar power.
// 3: Be Modular
Components, a hot word right now, rightfully so. Breaking up an app into re-useable pieces is the only sane way of solving the problem. You gotta have pieces you can rely on, pieces your users can depend on and become familiar with. Consistency is a beautiful result of a good modular component setup. You want this beauty, trust me.
# Create A Project Standard Component Setup
My tools for components are Jade, Stylus and Coffeescript. I’ve found these are the most empowering and out of my way tools for my flavor of web work. Bang for my buck right out of the box. Just like any rad tool though, you can use them poorly, so using cool tools won’t make you a good component creator. You know Spiderman, “great power comes with great responsibility.”
I like my component organization to follow a pattern, a lot like one an Angular style guide would suggest. For my primary nav, the files may look as follows:
There’s an Adam component haha. Easy to find where the styles are, and easy to find where the events and markup code are. I like the separation of concerns, makes git merges easy, therefore easy team collaboration. Inside the stylus file, I’ll include a comment section for the living style guide. Boom, and that’s the modular component scaffolding I have. Names of files match all around the project, and the living style guide represents each of our modules. Share that with the team and see how pumped they are. Each component broken out, named and shown in a self updating interactive style guide. Power.
For the Sylar power finale here, you can now place that nav template and drop it anywhere in the site. Design decides to make a change of where the nav goes, or they want to repeat it in the footer? No problem, 10 seconds later, the change is reflected across the project. Thank you modules. If you’re using Jade, thank you mixins, includes and layouts.
# Re-usable SVG
I want to mention SVG as well as a module, since I’ve found it can be quite modular and re-usable in a site. As a quick example, if you were to inline twitter icon svg markup, you could use CSS to change it’s size and color, to fit your headers and footers per a design. One icon to rule all instances of a twitter icon! Furthermore, you can animate that element, make the icon interactive and not just an icon font character that can change color. Change borders, fills, scale, opacity, you name it! So much fun. There’s other ways to pull this off, but I like putting svg markup into a jade file, and including it in any components that needs it. That way it hides all the verbose junk that comes out of an svg file from Illustrator or Sketch, make it easy to manage. Remember to remove crufty code from your SVG too, neither Illustrator or Sketch export slim SVG, they put poo poo all throughout it.
// 4: Use Native Browser Features
The browser comes packed with a ton of native elements for you to use. I strive to keep them as unmarked with classes and attributes as possible. Let links be links, buttons be buttons, and so forth. I call this “scaffolding” in my CSS. I seek semantic HTML markup that’s followed with supporting CSS styles and consistency. I’ve found greater success with OOCSS than BEM, which I find doesn’t encourage CSS reuse and isn’t very readable in my markup. I try to add as little to the DOM as I can, and let component namespaces take care of any specific styles.
# Block Level Elements With Roles
For example, the <section> element, in my scaffolding I intend to use this to wrap content areas, it may be modified at times, but I try to always use it the same. It has a healthy amount of padding, so when I use a section, I know I’m really intending for a content block. Same goes for the <article> element, it wraps primary page messaging, and begins a namespace for treating child paragraphs and headers. The goal here is consistency, semantic usage, and predictability. Headers, articles, navs, lists, etc, the browser gives us descriptive containers, let’s leverage these and not recreate them.
As I go through the design comps and start to lay out components, I try to create a language with my block level elements. This enables me to be faster and stronger as I go through other pages of the designs. I now have solutions ready for new pages. I’ve had entire pages be created in minutes, simply because the designer stuck to some components and I had them all prepared from other pages.
# Flexbox Is Awesome
Flexbox is really helpful here too, since it’s a lovely parent child relationship. My <nav> element only need’s <a> children. Gone are these days `nav > ul > li > a`. Ew, that’s some heavy nesting for a ghetto old school grid system. Bring in a flexbox based grid system if you haven’t yet, some even have inline-block fallbacks (http://flexboxgrid.com/). The browser is now providing a very nice and flexible grid system for you, leverage it.
// 5: Mobile First CSS
Mobile first isn’t just a design philosophy, or a mental state during development. This literally means have your browser squished down to 400px or so, and dev the site in a single column context from the start. Your CSS should be treating mobile as a first class citizen. All styles are for mobile by default. Then, as you increase viewport size into tablet and desktop styles, add media queries that target browser sizes that are above your breakpoints. Make the desktop visitor, with their turbo powered machines, do all the work to adjust the layout, not a mobile device.
# Avoid (max-width) Media Queries
To be more specific, this means your media queries should primarily, or even exclusively use min-width. This helps you mentally insure the component or element styles are styling tiny screens first, and then you sprinkle in desktop styles and adjustments.
# Low Bandwidth First
These mobile first concepts, mentalities and applications should be at the forefront of your component and site architecture. At this point in the checklist, we’re still scaffolding and building our atomic component set, and being mobile first helps you ensure a pleasant visit from tiny brained mobile devices. Likely, these visitors will be a fair share of your traffic, and they’re usually visiting from limited bandwidth, simultaneously needing to accomplish tasks the fastest.
Let’s be empathetic to this right? I’m often in that scenario: 2g, want to read an article or need to change a setting in my profile. Don’t make me download a huge website (or your app) just to see the content. Even though we’re pretty used to sitting there for 20 seconds while a website loads 30 scripts, that doesn’t mean we have to be building sites that way. We’re developer indians, keeping the land beautiful and minimal. Trying to introduce the least amount of change while still delivering a unique message.
// 6: Leverage Native Browser Behavior
Every browser that get’s put on a device, more than likely has a bunch of built in behavior. These default browser behaviors are familiar for the users and the browser engineers have heavily optimized these standard features. I know it’s tempting to go out and use your own routing system, your own history management, your own scroll handlers, but by overwriting some default behavior, you’re missing out on all the optimizations that the browser engineers made for you.
# Leverage The Browser
Since we’re pretty much still in prototyping mode at this point in the 12 steps, you shouldn’t have included any overwrites yet. This is good. Our goal during the prototype stage is to make a static interactive version of the site, for us to user test and perfect with the design team. Static prototypes are super easy to update and modify, we want to feel fast and nimble at this stage.
# Avoid Browser Hijacking
Every time you pull in a library to do things like handle routes, hijack scroll, hijack links, etc, you bring in both page weight and the potential for broken behavior. If you really need to overwrite how the browser natively wants to handle things, be ready to maintain that choice.
# Pretty URLs Are Pretty
I’m a huge fan of pretty urls too. For me that’s something like http://mysite.com/profile/ or http://mysite.com/account/settings/. During the prototype stage, this is a good time to establish pretty urls and leverage this url for effective breadcrumbs. Users do read and look at urls, we know they share them too. Make them pretty, it’s not hard.
An often forgotten or not sold feature of a website is making it available for users coming from various screen reader technologies. The browser comes with super powers for making your content accessible to a wide variety of accessibility technology. Use it, you’ll make someone happy.
// 7: Iterate
It’s time to flex, show off those dev muscles you’ve been working out all day. Put this atomic prototype into the hands of users, sprinkle some JS in there for very basic spoofed functionality, and start refining your product.
# Feeling Powerful
All of your component work starts to shine here as users and designers ask for things to be moved, removed, append and prepended across your pages. You simply edit a few files, hit save, and watch the updates populate. Your modularity makes you a lego master, puppeting pieces and components around with ease. This is that giddy feeling. Where all our combined talent around the world has created an ecosystem where I’m so insanely effective at managing a website. This is where computers and building digital experiences start to spank the physical world, where we can shift bits with flicks of our wrist, instant delivery. Muahahahahaha.
# Keepin It Fresh Y’all
This is a good time to mention BrowserSync, which will auto reload HTML and JS changes, and hot reload CSS changes. You can look badass to someone if they’ve never seen this tool.
When I iterate with designers, I encourage them to open my localhost website on their machine and give it a test. Each change they ask for, I update my code, hit save, and their browser is immediately updated with the change. This is so powerful! You and a designer can eliminate hours of work by sitting down together and working through nit picks in real time. I love Jira and task management, but if you can cut the creation and fulfillment of a task right out of the pipeline, do it.
# User Testing Iteration
When I iterate with users, I may make auto refreshing updates, but usually I record the requests and follow up with them with my team. The user isn’t a professional, doesn’t know what they want, and shouldn’t be in a place of power. Under some circumstances though, the user will point out a very obvious thing you and your team missed, and you can make the update right away, unblocking the task you asked them to do.
# Iterate, Iterate, Iterate While Static
This step should be where you spend a lot of time. Your prototype can begin moving into a very design finalized state, spoofing all the primary interactions, while still being nimble and static. Once we move forward, we start to solidify things, create tighter dependencies, and therefore become less malleable in our solution. I suggest, that even if you think you’re done with your static prototype phase, iterate one or two more times. There are missed things, and trust me, you want to catch and fix those issues early instead of later.
// 8: Server Integration
If your team is big enough, and prepared enough, you’ve been building your prototypes against mock data from your services team this whole time. If you’ve been creating your mock data with local YML or JSON, then it’s time to connect some dots.
# Connect The Pipes
The prototype has been validated by clients, designers, developers, and users. Game on. Connecting these dots will depend on how you plan to execute your stack, any frameworks you’re using, etc. There’s so many ways to accomplish this data integration task, I don’t want to say too much about it. In the next few steps though, I will be suggesting methods to help the server load and perceived performance of your site to the user, but I’m intentionally leaving this step vague, since I bet you have your own way of fulfilling integration with the server.
The good news, is up until now, the amount of server dependency you have is super minimal, so you could do the UI work, and the services developers could do theirs. Integration gets sticky, you can find plenty of articles on how to make this task go smooth. You’re prepared though, you’ve been data driven since you saw design comps.
Regardless of how you choose to write your event driven application logic and manage state, I do want to mention a few cool techniques. These techniques are not for you, they’re for the user, who this whole thing we’ve been building is for anyway.
# Preventative Performance Monitoring
The first tip, one that oddly isn’t recommended more often, is open your dev tools to the timeline and/or the memory tools, and watch as you develop. Performance is too often an after thought. Why is this? Performance checking after you’re all done is the hardest time to debug the issues. If you watch your perf from day one, you’ll be able to identify problem areas right away. Preventative performance monitoring. Do this, way easier.
# Optimistic Interactions
Another great overarching technique for your JS is to build your interfaces with optimistic interactions. I first heard this from Instagram, in context with the like action. Ever noticed that when you like something on Instagram, the heart and count update immediately. No spinner, no errors or successes, just instant gratification. You told the UI what you want, and the engineering behind it promises to like that image for you, in the background. Trust it, it will try again if it fails. To the user though, they perceive it as instant and don’t have to waste brain power on monitoring the result of their choice, they scroll on. This is awesome, and can be applied to all types of UI interactions. Keep this in mind while building your interface, build it with optimistic interactions, your users will perceive your app as fast as they are. They will love you.
# Meaningful Animations
A sprinkling of meaningful animations is nice to mentioned here because it can impact your site’s perceived performance as well. If you have a task that runs long, disguise it with a clever animation. Pull to refresh is a good example. You can make 3 seconds feel way shorter with a clever animation. While animation is usually used to bring content into focus, use this disguise technique when want to change something from a boring wait to a delightful moment.
# Lazy Loading
// 10: Production & Compiling
Fast forward through all the debugging, task tickets, edge cases of your software’s business logic and onto the consideration of public deployment. Let’s talk about the series of events we want to happen when users hit your site. First time visit is ridiculously important. That’s why this compile section is all about minimizing requests from the client, in size and frequency. Users shouldn’t need to ask for a banana and get a gorilla holding a banana. Our visitors are at the forefront of our mindset, and we want to leverage some tech to optimize the visit for these folks. If your site loads slow on their first visit, every one second that goes by they increase in doubt and decrease faith in your service. We want a 0–3 second download experience.
Each page will have shared resources and unique resources. One page has a slider, the other doesn’t. One page has a filter grid mechanism, the other doesn’t. To be optimal, we want to deliver the smallest bundles of goodness we can to the user. You can make bundles with webpack and coffeescript, or async load modules with require. Regardless of the technology you choose, the goal is the same. Each page is devoid of fat. We’ve architected for slim delivery, and now we get to put a bow on it.
# Turbo Crunch
Hulk smash! Crunching takes those slim tight bundles we made earlier, and makes them even smaller! Take those big jpg’s and minify em’. Take that JS and obfuscate and minify it. Compress that CSS. Remove cruft from SVG’s. For an added bonus (with a little bit of incurred risk), you can tree shake your CSS and JS. Tree shaking has cut my files in half before, especially with CSS, where you pull in a grid and only end up using 20% of it. I believe code even runs faster minified and obfuscated. So it’s a win win here, users download less kb’s and the code is tighter and prepared for the browser’s compiler.
Trackers like user behavior analytics, marketing pixels, etc don’t usually fit into your compressed bundles, but they are specifically a production level inclusion. So while you’re putting the final touches on your production compression build system, this is a good time to think about analytics and when they get loaded. These unfortunately are usually fatty. Hopefully they load async and don’t take up too much of your precious memory. They often load more scripts, so careful the iceberg you’re dropping in, could be heavier then you think.
// 11: Cache
First visit has completed quickly due to our compilation step, users are now interacting with your content, we are victorious. Let’s make it even faster! We’ve delivered them a tiny resource, let’s ensure the next time they need it, boom, instant. Often if our cache and site paints fast enough, this fetch and load activity can be so fast the page doesn’t even flicker when painting. A static site can load pages so fast, it looks like a single page web application. This is that native indian effect we want, where we’ve worked with the land and not built around it. The browser begins to reward us heavily for giving it what it’s optimized for, and our users will notice. Mobile phones will scroll at 60fps, and change pages in instants.
# Local Storage
You can cache of bunch of cool stuff in local storage. Fonts, scripts, static data, etc. Various tools can help you do this, but it’s also really simple to do it yourself. Think to yourself, what data can I stash in local storage for a quick easy win? Local storage shouldn’t be your primary local data solution, so include it to compliment a strategy, not exclusively as a strategy.
# Cache Static Files
Check those server headers, make sure they’ve got all the best cache solutions implemented. Using a website that rides the cached static files wave are awesome. They practically run offline, but if files or data updates, there’s no wait.
# Content Delivery Network
A good way to optimize file delivery is to distribute the task among some super servers. CDN’s have servers around the globe with your file, and serve the file from the closest server to your visitor. Super cool. So your server can serve a few files, but you can share the task with an ultra prepared CDN. You’ll know the cache headers are set appropriate, there’s fallbacks, etc. This is especially important for media files, which can be very stressful on your server. Defer the streaming and serving of that stuff to a CDN.
# Be Mindful
This is just another user reminder, be mindful of their space, don’t go caching a gnarly video or something into their browser. Keep the client light, again we want thin solutions, just give them a banana, your gorilla is behind a curtain.
If you maintained a link based static site architecture, a cool tip for your nav and potentially other links, is to leverage page prefetching. A simple rel attribute can encourage the browser to do some work in it’s downtime. Just as it sounds, it will prefetch the contents behind the href, and if the link is clicked, it’s loaded instantly. Amazon leverages this hard, check out the code on their site, it’s all over the place.
# Target User Story
In a perfect world, a users first visit to your site is the following fun short story. User gets a link from a homie and taps it. They’re on 2g, but our site still loads in 1.2 seconds from the CDN. Helps when our CSS is 14kb and the home page JS bundle is 101kb. Users scrolls a bit, browser prefetches the primary nav links, lazy loaded images load conditionally as the user bring them into the viewport. User visits the about page, 0.4s page load, scrolling is 60fps right away. All subsequent interactions with the site continue to be speedy. User is pleased. We’ve efficiently sent documents back and forth with them, minimally magnificent.
// 12: Offline Support
Aw crap, your user is in a tunnel now or out in the boonies. That 2g or wifi they were visiting from is gone. Alone, in the dark, users may want to still access your content. Have no fear, the progressive web app strategy to the rescue, we’ve got techniques to make this possible! Viva la web. No app stores gating our content, web content is on demand and prepared for all scenarios. ❤
# Appcache Manifest
All those static files for your site that aren’t going to change, an appcache manifest is a quick and easy way to support offline mode for those assets. Just like it sounds, you create a file that says, see this list, download it and refer to it if there’s no internet. It’s dumb static, meaning you can’t cache anything dynamically with it, but it’s very simple to setup and can cover a huge chunk of your offline support required files. Tools exist to generate these automatically for you too, so it doesn’t need to be a manually managed file, it can be created at production compile time.
“Add to home screen” is a feature found in Windows 8+, iOS and Android. Users can take your website and put it in their app drawers like they would have from their respective app stores. Your website can now seamlessly integrate with their OS. With splash screen support, theme colors, full screen mode, and more, you can really blur the space between app and web app.
# Service Worker
There used to be data that were difficult to cache for offline use, things like users playlists, search results, etc. Dynamic data types, typically things the server keeps copies of and delivers down via XHR requests. Service worker, among many of it’s powers, can stash this dynamic data, and be smart about whether to make a new request or use what’s local. Bringing conditional logic to offline files and usage. Providing a robust foundation for optimal file delivery under any type of network status.
// querySelectorAll(“article h2”).conclusion()
Phew, I didn’t think my web dev strategy was going to take so long to explain. It’s really just a compilation of dev strategies that I’ve found stack and combine into a beautifully choreographed solution. I’m so proud when I share a url with a friend and I get to watch it load so fast. I’m also so happy when I’m on 2g and get to browse a website still.
Hopefully you feel the same about empathizing with our users on partial connections, and can adjust a bit during your architecting to optimize for these scenarios. Let’s keep the web an on demand content style ecosystem, gate-less and considerate to visitors from around the world.
I also manage my own Grunt based build system, that has many of the mentioned features built in and ready to go, called Bolt. It’s very fast and encourages a lot of good practices. It’s really helped our team build quick and release fast optimized sites.
- Join Design Early
- Setup a living style guide
- Initialize CSS variables
- Be Data Driven
- Leverage local or remote json
- Mock or actual
- Use Native Elements
- Block level
- Mobile First CSS
- Media queries
- Native Browser Behavior
- Pretty urls
- Back history
- User test
- Atomic architecture
- Sprinkle some js
- Server Integration
- Dynamic and static
- JS Time
- Optimistic UI
- JS go nuts
- Watch perf
- Production & Compiling
- Turbo crunch
- Local Storage
- Cache data
- Keep client light
- Service worker
- Appcache manifest