Bringing CSS Grid to WordPress Layouts

December 6th, 2018 was a special date for WordPress: it marked the release of version 5.0 of the software that, to this day, powers more than one-third of the web. In the past, people working on the platform pointed out that there has never been any special meaning to version numbers used in WordPress releases; as such, WordPress 5.0 was simply the follower to WordPress 4.9. Yet, 5.0 brought possibly the biggest innovation since Custom Post Types were introduced in version 3.0 – that’s almost a decade, folks.

The Block Editor — codename “Gutenberg” — is now the new default writing tool in WordPress. Before its adoption in Core, our beloved CMS has relied on what we now call the Classic Editor. And, by the way, the Classic Editor isn’t really gone: you can bring it back by installing a plugin that restores the default editing experience you’ve known all these years.

So, why was the Classic Editor replaced? Essentially because it embodied an old concept of writing, a concept that was conceived when the only need of a text editor was to visually compose HTML code.

Not to create layouts. Not to embed dynamic content form heterogeneous sources. Not to offer a representation of what your post or page would look like when you pressed that “Publish” button, and go live with your piece of content.

In short, the Classic Editor delivered a very basic writing experience and, frankly, it always fell short at creating anything more than flowing text.

The Block Editor is based on the idea of content “blocks” in the sense that everything we can add to a page — a text paragraph, an image, an embed — is technically a block, that is, an atomic entity that’s defined by a certain series of properties. The combination of these properties determines the state of that particular block. Combine several blocks one after the other, and you’ll get the content of your page.

In this transition from unorganized text to rigorous content structure lies the biggest change introduced by the Block Editor.

Layouts pre-Block Editor

Before all of this bursted into existence, people who wanted to create a layout within WordPress had to choose between either of these options:

  1. Create a custom template from scratch, getting their hands dirty with code – a noble intent, yet not so appealing to the masses.
  2. Use a tool, better if a visual one, that helped them composing a page structure without having much code knowledge.

That’s how page builders were born: page builders are plugins that provide a visual way to compose a layout, ideally without touching a single line of code, and they were created out of necessity to fill a gap between visual mockups and the actual, finished website.

Page builders have always suffered from a bad reputation, for a variety of reasons:

  1. They tend to be slow and bulky.
  2. Some offer poor editing experiences.
  3. They end up locking users into a framework or ecosystem that’s tough to replace.

The first point is as obvious as it is unavoidable: if you’re a page builder author (and, hopefully, aspire to sell copies of your product), you have to make it as appealing as possible; physiologically, builders started to slowly become big code soups with everything in them, at the detriment of performance.

The second point may be subjective, at least to to some extent. The third point, however, is a fact. Sure, one could be perfectly fine using the same tool for every project, perfecting knowledge of the instrument as time goes by, but the more you stick to it, the harder it gets to potentially stop using it one day.

The Block Editor aims to surpass this deadlock: from the user’s point of view, it aims at offering a better, richer writing experience, while, from the developer’s perspective, providing a unified, shared API from which to build upon.

A brief history of CSS layouts

If you’re old enough, you’ll probably know the story already. If not, it might be fun for you to hear what life was like for a front-end developer back in the day.

The first version of the CSS specification dates back to 1996, and it allowed an embedded stylesheet to add font styling, pick colors for elements, change the alignments and spacing of objects in the page. The problem was that, in those days, the concept of semantic HTML wasn’t exactly widespread. In other words, there was no clear separation between content and form. The markup we’d write and the appearance we want were completely intertwined in the same document.

This led to HTML elements to be used more for presentation purposes, than conveying meaning to their presence in the page. For example, on the layout side of things, this also led to to table elements being used to create layouts instead of actual tabular data. To achieve even more complex layouts, tables began being nested into other tables, making the page become a nightmare from the semantic point of view, its size grow and grow, and resulting very hard to maintain over time. If you’ve ever coded an HTML email, then you have a good idea of what life was like. And, really, this still sort of happens in websites today, even if it’s for smaller elements rather than complete page layouts.

Then the Web Standards movement came along with the goal to raise awareness among developers that we could be doing things differently and better; that style and content should be separated, that we need to use HTML elements for their meaning, and reinforcing the concept that a lighter page (in terms of code weight) is a fundamentally better option than an unmanageable ocean of nested tables.

We then began (over)using div elements, and juxtaposed them using the float property. The presentation focus was shifted from the markup to the stylesheet. Floats became the most reliable layout tool available for years, yet they can be a bit problematic to handle, since they have to be cleared in order for the page to return to its standard flow. Also, in this age, page markups were still too redundant, even though using divs instead of tables helped make our content more accessible.

The turnaround moment came in 2012, with the publication of the Flexbox specification. Flexbox allowed developers to solve a whole series of long standing little layout problems, complete with an elegant syntax that requires a lot less markup to be implemented. Suddenly (well, not that suddenly, we still have to care about browser support, right?), reliably centering things on both axises wasn’t an issue anymore. It was refreshing. Finally, tweaking a layout could be reduced to altering just one property in our stylesheet.

As important as Flexbox is to this day, it is not the end of the story.

It’s 2019! Let’s use CSS Grid.

If you’ve come this far reading this piece, we think it’s safe to assume that two things are for sure:

  1. That we clearly aren’t in this industry to live peaceful, quiet professional lives.
  2. The things we use are going to change.

In 2017, the CSS Grid Layout Module specification was officially published, but, as it always happens with CSS specs, its draft and interim implementations had already been around for some time.

CSS Grid is a bold leap into what CSS can and should do. What if we stopped micromanaging our pages styles, and started thinking more holistically? What if we had a system to reliably position elements on the screen that doesn’t depend at all on the markup being used, nor the order of elements, and that is, at the same time, programmatically applicable on smaller screens?

No, this isn’t just a thought. This is more of a dream; one of those good ones you don’t want to wake up from. Except that, in 2019, this has become a reality.

The main difference between Grid and Flexbox is more nuanced, of course, but basically comes down to Grid operating in two dimensions, while Flexbox is limited to one. Knowing what elements are going to be placed within the limits of a container, we can choose exactly where those elements are going to end up, entirely from directives written in the stylesheet.

Do we want to tweak the layout down the road? Fine, that modification won’t affect the markup.

The basic idea behind Grid is that elements are laid out in, well, a grid. By definition, a grid is composed by a certain amount of columns and rows, and the boundaries between columns and rows form a series of cells that can be filled with content.

The savings of this approach in terms of quantity of code being used to achieve the desired result are extraordinary: we just need to identify a container element, apply the display: grid rule to it, and then pick elements within that container and tell CSS what column/row they begin/end in.

.my-container { display: grid; grid-template-columns: repeat( 3, 1fr ); grid-template-rows: repeat( 2, 1fr );
} .element-1 { grid-column-start: 2; grid-column-end: 4; grid-row-start: 1; grid-row-end: 3;

The above example creates a 3×2 grid associated to the .my-container element; .element-1 is a 2×2 block that is inscribed in the grid, with its upper left vortex being positioned in the second column of the first row of the grid.

Sounds pretty neat, right?

The even neater thing about CSS Grid is the fact that you can create template areas, give those areas meaningful names (e.g. “header” or “main”), and then use those identifiers to programmatically position elements in those areas.

.item-a { grid-area: header;
.item-b { grid-area: main;
.item-c { grid-area: sidebar;
.item-d { grid-area: footer;
} .container { display: grid; grid-template-columns: 50px 50px 50px 50px; grid-template-rows: auto; grid-template-areas: "header header header header" "main main . sidebar" "footer footer footer footer";

For those who have begun working in this business in the tables era, the code above is nothing short of science fiction.

More good news, anyway: support for CSS Grid is pretty great, today.

Using CSS Grid in WordPress

So, this is great, and knowing that we can do so many more things today than we could compared to a few years ago probably makes you want to give Grid a try, at last.

If you are working on a WordPress project, you’re back facing the two options mentioned above: do we start from scratch and manually coding a template, or is there something that can give us a little help? Luckily, there is a plugin that might interest you, one that we have created with a dual goal in mind:

  1. Create a bridge between the Block Editor and CSS Grid.
  2. Create a plugin that could perhaps make people move past the initial skepticism of adopting the Block Editor.

It’s called Grids, and it’s a free download on the WordPress plugins repository.

Grids only takes care of the layout structure. It puts a 12×6 grid at your disposal (called Section), over which you can drag and draw the elements (Areas) that are going to be contained in that Section.

The system allows you to manually specify dimensions, backgrounds, responsive behavior, all using visual controls in the Block Editor, but by design, it doesn’t provide any content block. Sure, one could see this approach as a weak point, but we think it’s actually Grids’ biggest strength because it enables the plugin to integrate with the myriad content blocks that other developers all around the world are creating. More so, in a way Grids helps bringing those blocks, and WordPress as a platform, in touch with CSS Grid itself.

Yet, even if the plugin doesn’t strictly produce content, it’s inevitable to put it in the same phrase with successful page builders, in fact comparing its functionality to that offered by those. If you care about concepts like separation of form and content, page weight, ease of maintenance, Grids offers a cleaner solution to the problem of creating visually appealing layouts in WordPress.

The generated markup is minimal. In its most basic form, a Section (that is, the element with the display: grid property) is only composed by its own element — of course, an internal wrapper (that couldn’t be avoided and that’s used for spacing purposes), and then one element per Area belonging to the Section. This is a huge step forward in terms of avoiding using unnecessary markup.

For those of you who haven’t been afraid of getting your hands dirty with the development of blocks for the Block Editor, the rendering of the block is done server-side, which allows for custom classes to be added to Section and Area elements using filters.

This choice also directly determines what happens in the eventuality that you disable Grids in your install.
​​If you don’t re-save your page again, what’s left of Grids on the front end is actually exclusively the content you put inside the content Areas. Not any extra markup elements, not any weird-looking shortcode.
​​On the back-end side of things, the Block Editor has a system in place that warns you if you’re editing a page that is supposed to use a particular block type, but that block type isn’t currently available: in that case, you could easily turn Grids back on temporarily, move your content in another place, and then get rid of the Section altogether.

CSS generated to create the grid is also dynamically added to the page, as an inline style in the <head> portion of the document. We haven’t been exactly fans of styles written in the page directly, because ideally we’d like to delegate all of the styling to files that we could put under version control, yet this is a case where we found that approach to be very convenient.

Another viable option would have been to identify all the possible combinations of column/row starting/ending points, and programmatically map those with classes that could then be used to actually position elements within the grid. On a 12×6 grid, that would have lead to having a grand total of 36 class selectors, looking like this:

.grids-cs-1 { grid-column-start: 1;
} .grids-ce-2 { grid-column-end: 2;

What if we decide to offer more control over how a grid is composed and, say, give users access to options that determine how many columns or rows form the grid structure?

We’d have to manually map the classes that we don’t yet have in the stylesheet (and release an update to the plugin just for that), or, again, generate them inline, and then add those classes to the grid elements.

While perfectly fine, this approach kind of goes against the idea of having a leaner, more scannable markup, so we’ve decided not to follow this route, and pay the price of having style dynamically put in the head of the document, knowing that it could be easily cached.

Because of the experimental nature of the plugin, the backend UI that’s being used to actually compose the grid is created with CSS Grid, and a set of CSS variables through which we control the properties of content Areas. Using variables has immensely sped up our work behind the grid creator prototype — had we chosen a different path there, things wouldn’t just be much longer in terms of development times, but also more complex and less clear to maintain down the road.

Feedback wanted!

To further foster the adoption of CSS Grid, we need tools that automate the process of creating layouts with it.

While we have been seeing great examples of this technology out in the wild, it would be short-sighted to assume that every website that is published today has a team of front-end devs behind it, that can take care of the issue.

We need tools that produce good markup, that don’t hinder the maintenance of the website stylesheets, and, most importantly in the WordPress world, that can be easily integrated with the existing themes that people love to use.

We think Grids is a step forward in that direction, as it’s a tool that is built upon two standards — the Block Editor API, and CSS Grid — and, as such, suffers less risk of reinventing the proverbial wheel.

While we’ve been recording general interest in the plugin at the recent WordCamp Europe in Berlin – with Matt Mullenweg himself displaying a brief demo of the plugin during his keynote — we know that it still needs a lot of feedback that can only be obtained with real-life scenarios. So, if you want to take Grids for a spin, please use it, test it and, why not, suggest new features.

The post Bringing CSS Grid to WordPress Layouts appeared first on CSS-Tricks.

Simplify The Handoff From Sketch To Visual Studio Code With Indigo.Design

Simplify The Handoff From Sketch To Visual Studio Code With Indigo.Design

Simplify The Handoff From Sketch To Visual Studio Code With Indigo.Design

Suzanne Scacca

(This is a sponsored article.) If you think about it, software teams are a lot like sports teams. While each team member works towards the same exact goal, the role they play and the actions they take are vastly different from one another.

Which is why it’s crucial to have a seamless way of moving the ball from one team member to another.

Unfortunately, the handoff that takes place within software teams isn’t naturally as smooth as what you see on the sports field. And one of the primary reasons for this is the different systems and approaches used to build products.

Designers create pixel-perfect UIs in Sketch, only to have to translate them into a language that developers can use when they build apps in the Visual Studio Code IDE. Without a seamless way to move product designs through the pipeline, these inefficiencies lead to expensive reworks and debugging after an app has been shuttled from designer to developer.

Needless to say, a solution to the Sketch-to-IDE handoff problem has been a long time coming. It’s not that software teams don’t know how to collaborate or communicate well with one another. It’s just that their disparate systems and strategies make the transition from one team to another clunky, time-consuming and error-ridden.

Today, we’re going to look at why this happens and how your agency can fix the problem with two plugins and a prototyping cloud platform from Indigo.Design.

Where Does the Designer-Developer Handoff Go Wrong?

First, what we should really ask is:

Why is the designer-developer handoff such a problem?

Nick Babich recently wrote about how designers go to great lengths to create digital solutions that are perfectly measured and consistently crafted. But design systems don’t fluently translate to development systems.

The more the designer does to an interface, the more they have to actually communicate to a developer. So, it’s not enough to hand over a Sketch design file and leave the developer to run with it. Designers have to provide design specs that explain how all the moving pieces need to be laid out, spaced, styled, colored, engaged with and so on.

It’s been the only way to ensure that an app ends up pixel-perfect in the end. Even then, it still requires a lot of implementation on the part of the developer once they’re inside their IDE.

As you can imagine, this whole process takes a designer a lot of time to do. But without design specs, developers end up having to play a risky guessing game.

Not only that, developers aren’t typically in the habit of coding with HTML and CSS, which is tedious work and only represents the UI. There’s a lot more code behind the scenes that makes a web app work and not all developers are adept at or interested in learning to write the UI markup. When they’re forced into this position, the steep learning curve adds more time to projects and the resulting reworks and debugging sends costs spiraling out of control.

So, really, the designer-developer handoff has become a matter of whose time can we afford to waste?

Is it the designer who has to redline everything so the developer knows how to turn the design into reality?


Is it the developer who has to look at a design, manually measure everything on the screen and hope they get all the specifications right just by eyeballing it?

No one wins in either scenario. And you’re going to eat away at your profit margins in the process.

There may be some agencies who believe that forcing designers and developers to work in the same platform is the best solution. That way, there’s no need to do all of this translation or interpretation during the handoff from Sketch to Visual Studio Code. But that often results in stifled creativity on the part of the designer or a hampered ability to build effective software solutions on the part of the developer.

So, what’s the answer?

Improve The Designer-Developer Handoff With Indigo.Design

It’s not like Indigo.Design is the first platform to try to solve handoff issues for software teams. InVision and Zeplin have both offered up their own solutions.

Each of these platforms have made visual specifications more accessible for developers while consequently improving the efficiency of designer-developer teams. Specifically:

  • Designers don’t need to mark up the UI anymore as the platforms handle the redlines.
  • Developers can manually extract the design specs without the designers’ help.

That said, with platforms like InVision and Zeplin, developers still have to inspect each element and manually code it based on the extracted specs. These platforms also have yet to create a seamless bridge between Sketch and Visual Studio Code.

So, if designers and developers want to work as efficiently as possible with one another, Indigo.Design has developed an answer to their problem:

Step 1: Design in Sketch

There’s really only one thing about this phase that has to change for the designer. The app, pages and flow will still be designed as usual within Sketch, using components from the Indigo.Design UI Kit.

An app built in Sketch
An example of what your app might look like in Sketch. (Source: Sketch) (Large preview)

However, there’s no longer any need to compile redlines or specs for the app anymore. Indigo.Design takes care of it for you.

In order to leverage this, your designer has to ditch whatever prototyping system they were using before. With this new streamlined and error-free system, your designer can easily push their designs into the cloud using the Indigo.Design plugin.

This can be accessed under the Plugins menu > Indigo.Design > Publish Prototype:

Indigo.Design plugin
The Indigo.Design plugin simplifies the publication of prototypes. (Source: Sketch) (Large preview)

There’s no need for the designer to export files and upload into another system for clients to review or developers to work with. They get to stay right where they are to publish the prototype.

Indigo.Design cloud link
All it takes is one link to move clients, developers and others into the Indigo.Design cloud. (Source: Indigo.Design) (Large preview)

It takes only about a minute to complete the process, too. The designer is then given a link to the cloud which they can share with clients and others to review and comment on the prototype.

Step 2: Work in the Indigo.Design Cloud

To get others into the cloud is easy. The link provided will take them into the experience cloud where the design can be reviewed:

Indigo.Design app prototype
An example of how an app prototype looks in Indigo.Design. (Source: Indigo.Design) (Large preview)

It’s easy to leave comments on top of the design, too. All users have to do is open the Comments panel, drop a pin and attach their comment to it:

Indigo.Design prototype comments
How to leave comments on prototypes in Indigo.Design. (Source: Indigo.Design) (Large preview)

There’s more to this collaboration software than that though. The prototype can also be edited from the cloud.

To access this, the designer, developer and anyone else with group access will locate the project from the prototype library:

Indigo.Design prototype editor access
Access to the prototype editor in Indigo.Design. (Source: Indigo.Design) (Large preview)

Click “Edit Prototype” to enter the Indigo.Design editor:

Indigo.Design editor
An example of how prototypes appear in the Indigo.Design editor. (Source: Indigo.Design) (Large preview)

Once a screen is selected, the designer can add a hotspot to create a new interaction in the app.

Indigo.Design prototype editing
Adding a new interaction to a prototype in Indigo.Design. (Source: Indigo.Design) (Large preview)

You can also use the Indigo.Design editor to inspect the specifications of the app UI:

Indigo.Design relative spacing measurements
Measuring relative spacing of an app UI in Indigo.Design. (Source: Indigo.Design) (Large preview)

Hovering over an element reveals relative spacing specs. Clicking on an element reveals much more detail:

Indigo.Design design specs
Indigo.Design reveals all specs of the UI in its editor. (Source: Indigo.Design) (Large preview)

The developer can also edit or copy the cleanly written and outputted CSS from this panel, too. (Though they shouldn’t have to, as I’ll explain in the next step.)

See what I mean about saving designers time in generating specs? By simply pushing this design into the Indigo.Design cloud, the specs are automatically generated.

Step 3: Build in Visual Studio Code

Now, let’s say your design is good enough to go into development. The moving of an Indigo.Design prototype to Visual Studio Code is just as easy as the move from Sketch was.

Retrieve the original cloud link provided by the Indigo.Design plugin in Sketch. If you don’t have it anymore, that’s fine. You can retrieve it from the libraries screen in Indigo.Design:

Indigo.Design prototype link
Where to retrieve your Indigo.Design prototype link. (Source: Indigo.Design) (Large preview)

All the developer has to do now is install the Indigo.Design Code Generator extension. This is what enables Visual Studio Code to talk directly to Indigo.Design to retrieve the prototype.

Once the extension is set up, the developer will do the following:

Visual Studio Code extension
How to launch the Indigo.Design Code Generator in Visual Studio Code. (Source: Visual Studio Code) (Large preview)

Open the app shell that’s already been developed. Then, launch the Indigo.Design Code Generator. This is where you’ll enter the cloud link:

Indigo.Design Code Generator extension
Enter your prototype link into the Indigo.Design Code Generator extension. (Source: Visual Studio Code) (Large preview)

This will reveal a pop-up with the app designs that live in the cloud as well as the individual components they’re comprised of.

Indigo.Design generate code assets
Developers control which components they want to generate code assets for. (Source: Visual Studio Code) (Large preview)

The developer has the option to generate code for all components of the app or to go component-by-component, checking only the ones they need. This is especially helpful if an app is in progress and the developer only needs to import new components into VSC.

By clicking “Generate Code Assets”, the selected components will be added into Angular as readable and semantic HTML and CSS.

The developer now has less to worry about in terms of rebuilding styles or configuring other specs. Instead, they can spend their time building business functionality and really refining the product.

A Note About This Process

It’s important to point out that this Sketch – cloud – Visual Studio Code workflow doesn’t just work with the first iteration of a design. Developers can build while designers work through feedback with clients or usability studies with users — something Indigo.Design has accounted for.

So, let’s say the designer moved a login form UI through Indigo.Design and the developer generated the code to get things moving.

While working on the form, the developer implemented some authentication code in the TypeScript file.

In the meantime, though, the designer received a message from the client, letting them know that a new Universal Login with Google needed to be implemented. Which means the UX has to change.

When the update is ready and the prototype sync’ed to Indigo.Design, the designer messages the developer to let them know about the changes. So, the developer launches the Visual Studio Code Generator once more. However, when regenerating the login screen, they select “Do Not Override” on the TypeScript file. This way, they can preserve the code they wrote while simultaneously importing the new HTML and CSS.

The developer can then make any necessary adjustments based on the updated design.


Indigo.Design has effectively created an efficient and bug-free handoff for designers working in Sketch and developers working in Visual Studio Code.

Designers don’t waste time designing in one platform and prototyping in another, drawing up design specs or dealing with file exports. Developers don’t waste time trying to re-create the design intent from a static file.

As Jason Beres, the Senior VP of Product Development for Indigo.Design, said:

With Indigo.Design code generation, all of these bugs are 100% avoided. Not only is the spirit of the design maintained, but pixel-perfect HTML and CSS is created so the developer isn’t in the unfortunate position of having to manually match the design.

And by working out the technical kinks in the designer-developer workflows and handoff, your agency will greatly reduce the cost of reworks and debugging. You’ll also boost profits by providing your software team with a more efficient and quicker way to get apps through the process and in pixel-perfect condition.

Smashing Editorial (yk,ra)
Are Design Pitches Worthwhile?

For most designers – freelance or in-house – generating new business can be a dreaded part of the job. But it necessary to maintain and sustain growth and find new clients. When it comes to finding design work, is there a best way to find jobs? Do you pitch for new business or rely on other methods to find work?

Reasons to Pitch for New Business

There are so many places that freelance designers can pitch for new business, including job boards, and content or design networks, or marketplaces. Some designers may pitch on social media as well.

But is it worth your time to post in these places to generate business?

For some designers, the answer is, “Yes.”

Pitching requires you to think about the type of work and clients you want to take on. This can be a valuable exercise that helps you grow your business strategically and with the type of work you want to do. If you plan to pitch, create specific pitches that respond directly to postings, avoiding generic “I can do any type of design” pitches.

For freelancers with limited time, this can be an ideal situation

Pitching works for designers that want to know exactly where they stand with projects and don’t want to deal with the management of them. Most pitches you submit in response to a job board or marketplace post will detail a specific design need, timeline, and payment for that work. You know everything up front and don’t have to negotiate terms or deal with scope creep. For freelancers with limited time, this can be an ideal situation.

Pitching can help you find an “in” with new clients and turn into long-term work. There are plenty of designers that have found good projects through Behance, Dribbble, and Upwork.

Pitching might be the only way for a new designer to build a strong portfolio. Depending on the stage of your career, this type of work can help generate clients, relationships, and projects that can lead to more work later.

Whether responding to ads and sending pitches is the right choices depends on you and the stage you are at in your career. It’s not for everyone, but for some designers, pitching can be totally worthwhile, and work better than cold calling or trying to generate new business in other ways.

Reasons Not to Pitch

Some designers hate pitching and find that the time spent looking for new business doesn’t generate enough income to support itself. That’s the top reason not to pitch. If you aren’t bringing in work with pitches, it could actually be costing you money. Analyze pitches sent, responses received, and clients you are actually working with. How much time do you spend on pitching versus revenue generated from actual work from pitching?

If the math doesn’t work out to a sustainable hourly rate, pitching might not be the best option for you. It can be a lot of work, without a large return.

Are you charging less or doing work that you’d never put in your portfolio?

When it comes to responding and pitching for projects, there’s almost always a “middle” company or organization that gets a cut of the payment for the job. If you can generate new business own your own, why pay that fee?

Sometimes pitching can feel spammy or doesn’t help you build more business. Are you cutting your worth to respond to a pitch? Are you charging less or doing work that you’d never put in your portfolio? If the answer to either question is yes, then pitching is probably not for you.

Other Ways to Generate New Design Business

Building a reputation as a designer and taking new clients from word-of-mouth recommendations and referrals is the top way most designers seem to want to generate new business.

But you have to have a fairly established client base and good network for this model to be sustainable. For a lot of designers, this often means that seeking outside work starts with responding to pitch requests while building more of a network and portfolio and then moving to other (more profitable) methods of generating new business.

So how do you generate design business?

There’s a funnel for getting design work for freelancers. At the big end of the funnel is work that’s mostly unsolicited and projects are often granted via pitch (such as marketplaces or job boards). These jobs don’t typically include long-term contracts or big fees. At the small end of the funnel is referrals and repeat client work. These jobs come from relationship building, often pay more and result in longer-term business for more experienced designers.

And then there’s everything in the middle:

  • Cold pitches: Soliciting work from clients via cold call, email, or with a pitch letter;
  • Events: Using speaking engagements or conferences to network and make connections that result in design work;
  • Advertising: Using paid advertising, a website, or email/mail to connect with potential clients that might need design services;
  • Social media: Generating business through social media channels by showcasing work or expertise or offering services;
  • Networking and feeders: Connecting with businesses or design agencies that can subcontract overflow work to you.

The reality is that almost every type of connection requires some type of pitch. The colder the pitch (or less connected you are to the potential client) the more work it will probably take to land the job.


So, we are back to the question at hand: Are pitches worthwhile?

Depending on your career stage, the answer is yes. For early career, or new freelance designers, pitching through marketplaces or job boards can help you grow a business on your own or provide just a little extra income from a side hustle.

For designers that are more established and already have a strong network, cold pitching isn’t the go-to option. In the end, most of us have responded to pitches at some point and either loved the simplicity of pitch and respond work or hated the lower income ratio often associated with these jobs.

Personally, pitching was a great way to establish my position in the field. And with years of experience to show now, work comes via referral. So yes, pitches can be worthwhile. They were a building block in my career and I expect many others share a similar experience.


Featured image via DepositPhotos.

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Adventures In August (2019 Wallpapers Edition)

Adventures In August (2019 Wallpapers Edition)

Adventures In August (2019 Wallpapers Edition)

Cosima Mielke

Everybody loves a beautiful wallpaper to freshen up their desktops and home screens, right? So to cater for new and unique artworks on a regular basis, we embarked on our monthly wallpapers adventure nine years ago, and since then, artists and designers from all across the globe have accepted the challenge and submitted their designs to it. It wasn’t any different this time around, of course.

This post features wallpapers created for August 2019. Each of them comes in versions with and without a calendar and can be downloaded for free. A big thank-you to everyone who got their creative juices flowing and submitted their designs!

At the end of this month’s collection, you’ll also find some “oldies but goodies” that we rediscovered way down in our wallpapers archives and that are just too good to gather dust. So, which one is your favorite this month?

Please note that:

  • All images can be clicked on and lead to the preview of the wallpaper,
  • We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.

Submit your wallpaper

We are always looking for creative designers and artists to be featured in our wallpapers posts. So if you have an idea for a September wallpaper, please don’t hesitate to submit your design. We’d love to see what you’ll come up with. Join in! →

Colorful Summer

“‘Always keep mint on your windowsill in August, to ensure that the buzzing flies will stay outside where they belong. Don’t think summer is over, even when roses droop and turn brown and the stars shift position in the sky. Never presume August is a safe or reliable time of the year.’ (Alice Hoffman)” — Designed by Lívi from Hungary.

Colorful Summer

Smoky Mountain Bigfoot Conference

“Headed towards Smoky Mountain Bigfoot Conference this summer? Oh, they say it’s gonna be a big one! Get yourself out there well-prepared, armed with patience and ready to have loads of fun with fellow Bigfoot researchers. Looking forward to those campsite nights under the starry sky, with electrifying energy of expectations filling up the air? Lucky you!” — Designed by Pop Art Studio from Serbia.

Smoky Mountain Bigfoot Conference

Magic Forest

Designed by IQUADART from Belarus.

Magic Forest

Friends Are Forever

“Friends are forever! No matter what, when, where you are, they are with you. A day spent with friends is always a day well spent.” — Designed by Sweans Technologies from London.

Friends Are Forever!

El Pollo Pepe

“Summer is beach and swimming pool, but it means countryside, too. We enjoy those summer afternoons with our friend ‘El pollo Pepe’. Happy summer!” — Designed by Veronica Valenzuela from Spain.

El Pollo Pepe

Summertime Magic

“Inspired by the magic of summer nights.” — Designed by Bekah Richards from Washington, DC.

Summertime Magic

Praise The Bacon

“Seeing as August is the month in which both cats and bacon are internationally celebrated (8th and 31st), why not create an ode to these two joyous things?” — Designed by Michaël Van Lierde from Belgium.

Praise The Bacon

Life Is A Beach

“Life is like a beach, it is full of waves (read: ups and downs). But we got to learn to enjoy it the best we can!” — Designed by Emily van Hemert from the Netherlands.

Life Is A Beach

Crimson Sunset

“I was checking out a manga which centers around karuta, a game using cards with verses from a set of 100 Japanese Poems. One poem in the manga (which is not among those 100, ironically) caught my interest and since August instills some kind of autumn feel in it, I thought it suited this poem really well. By the way, I did this in HTML and CSS.” — Designed by Nguyen Tuong Van from Singapore.

Crimson Sunset

Oldies But Goodies

So many beautiful, unique, and inspiring wallpapers have emerged as a part of our wallpapers challenge in the past years. Deep in our archives we rediscovered some of these almost forgotten treasures. Here’s a small selection of August favorites. (Please note that these designs don’t come with a calendar.)

Purple Haze

“Meet Lucy: she lives in California, loves summer and sunbathing at the beach. This is our Jimi Hendrix Experience tribute. Have a lovely summer!” — Designed by PopArt Web Design from Serbia.

Purple Haze

Coffee Break Time

Designed by Ricardo Gimenes from Sweden.

Coffee Break Time

Chill Out

“Summer is in full swing and Chicago is feeling the heat! Take some time to chill out!” — Designed by Denise Johnson from Chicago.

Chill Out


“The warm, clear summer nights make me notice the stars more — that’s what inspired this space-themed design!” — Designed by James Mitchell from the United Kingdom.


I Love Summer

“I love the summer nights and the sounds of the sea, the crickets, the music of some nice party.” — Designed by Maria Karapaunova from Bulgaria.

I Love Summer

Melon Day

“Melon Day (second Sunday in August) is an annual national holiday in Turkmenistan devoted to festivities to celebrate the country’s muskmelon. Another reason for me to create this wallpaper is that melons are just awesome!” — Designed by Melissa Bogemans from Belgium.

Melon Day

Are You Ready For The Adventure?

Designed by UrbanUI from India.

Are You Ready For The Adventure?

Grow Where You Are Planted

“Every experience is a building block on your own life journey, so try to make the most of where you are in life and get the most out of each day.” — Designed by Tazi Design from Australia.

Grow Where You Are Planted

Elephant Time

“August is very notable for me. It is the month of two great events: World Elephant Day and the birthday of my son (both are on August 12th — what a coincidence!). So I want to share my double joy with you! Remember, elephants are great animals (in all meanings), but they still need your care.” — Designed by Anna K. from Minsk, Belarus.

Elephant Time

Shark Night

“I imagine that I am lying on the beach on a warm summer night looking up at the sky, just thinking and letting my imagination take me away.” — Designed by Maggie Green from the United States.

Shark Night

Camping Time

“I was inspired by the aesthetics of topography and chose to go with a camping theme for the month of August.” — Designed by Nicola Sznajder from Vancouver, B.C., Canada.

Camping Time

Dessert First

Designed by Elise Vanoorbeek from Belgium.

Dessert First


“For this piece, I was inspired by what the end of summer meant to me as a child. I remember running around barefoot in the warm grass and catching fireflies late into the night. I wanted this to be a little reminder to everyone of the simpler times.” — Designed by Rosemary Ivosevich from Philadelphia, PA.


Autumn Is Just Around the Corner

“August is the month that brings to mind the passage of summer season and the arrival of autumn. The entire landscape around us gets a new look, and each of us remains nostalgic due to the passage of summer.” — Designed by Tattoo Temptation from the United Kingdom.

Autumn is Just Around the Corner

Let It Bee

“In the summer, I always see a lot of buzzy animals, including bees. And because of the relaxing nature of summer, I thought ‘Let it bee!’” — Designed by Pieter Van der Elst from Belgium.

Let It Bee

Directional Colors

“I have created and recreated this image in my head many times over and finally decided to create an actual copy. The ‘arrows’ have been big lately as my life has shot off into the design field. And the colors, well, they’re just awesome.” — Designed by Tatyana Voronin from the United States.

Directional Colors

A Midnight Summer Dream

“It’s not Shakespeare, it’s Monk, staring at the stars in a warm summer midnight. Just relax…” — Designed by Monk Software from Italy.

A Midnight Summer Dream

Handwritten August

“I love typograhy handwritten style.” — Designed by Chalermkiat Oncharoen from Thailand.

Handwritten August

The Ocean Is Waiting

“In August, make sure you swim a lot. Be cautious though.” — Designed by Igor Izhik from Canada.

The Ocean Is Waiting


“Black and white landscape/waterscape photo.” — Designed by Jeremy Mullens from the United States.


No Drama Llama

“Llamas are showing up everywhere around us, so why not on our desktops too?” — Designed by Melissa Bogemans from Belgium.

No Drama Llama

Childhood Memories

Designed by Francesco Paratici from Australia.

Monthly Quality Desktop Wallpaper - August 2012

Join In Next Month!

Thank you to all designers for their participation. Join in next month!

Smashing Editorial (il)
Creating Dynamic Routes in a Nuxt Application

In this post, we’ll be using an ecommerce store demo I built and deployed to Netlify to show how we can make dynamic routes for incoming data. It’s a fairly common use-case: you get data from an API, and you either don’t know exactly what that data might be, there’s a lot of it, or it might change. Luckily for us, Nuxt makes the process of creating dynamic routing very seamless.

Let’s get started!

Creating the page

In this case, we’ve got some dummy data for the store that I created in mockaroo and am storing in the static folder. Typically you’ll use fetch or axios and an action in the Vuex store to gather that data. Either way, we store the data with Vuex in store/index.js, along with the UI state, and an empty array for the cart.

import data from '~/static/storedata.json' export const state = () => ({ cartUIStatus: 'idle', storedata: data, cart: []

It’s important to mention that in Nuxt, all we have to do to set up routing in the application is create a .vue file in the pages directory. So we have an index.vue page for our homepage, a cart.vue page for our cart, and so on. Nuxt automagically generates all the routing for these pages for us.

In order to create dynamic routing, we will make a directory to house those pages. In this case, I made a directory called /products, since that’s what the routes will be, a view of each individual product details.

In that directory, I’ll create a page with an underscore, and the unique indicator I want to use per page to create the routes. If we look at the data I have in my cart, it looks like this:

[ { "id": "9d436e98-1dc9-4f21-9587-76d4c0255e33", "color": "Goldenrod", "description": "Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.", "gender": "Male", "name": "Desi Ada", "review": "productize virtual markets", "starrating": 3, "price": 50.40, "img": "1.jpg" }, …

You can see that the ID for each entry is unique, so that’s a good candidate for something to use, we’ll call the page:


Now, we can store the id of the particular page in our data by using the route params:

data() { return { id: this.$, }

For the entry from above, our data if we looked in devtools would be:

id: "9d436e98-1dc9-4f21-9587-76d4c0255e33"

We can now use this to retrieve all of the other information for this entry from the store. I’ll use mapState:

import { mapState } from "vuex"; computed: { ...mapState(["storedata"]), product() { return this.storedata.find(el => ===; }

And we’re filtering the storedata to find the entry with our unique ID!

Let the Nuxt config know

If we were building an app using yarn build, we’d be done, but we’re using Nuxt to create a static site. When we use Nuxt to create a static site, we’ll use the yarn generate command. We have to let Nuxt know about the dynamic files with the generate command in nuxt.config.js.

This command will expect a function that will return a promise that resolves in an array that will look like this:

export default { generate: { routes: [ '/product/1', '/product/2', '/product/3' ] }

To create this, at the top of the file we’ll bring in the data from the static directory, and create the function:

import data from './static/storedata.json'
let dynamicRoutes = () => { return new Promise(resolve => { resolve( => `product/${}`)) })

We’ll then call the function within our config:

generate: { routes: dynamicRoutes

If you’re gathering your data from an API with axios instead (which is more common), it would look more like this:

import axios from 'axios'
let dynamicRoutes = () => { return axios.get('https://your-api-here/products').then(res => { return => `/product/${}`) })

And with that, we’re completely done with the dynamic routing! If you shut down and restart the server, you’ll see the dynamic routes per product in action!

For the last bit of this post, we’ll keep going, showing how the rest of the page was made and how we’re adding items to our cart, since that might be something you want to learn, too.

Populate the page

Now we can populate the page with whatever information we want to show, with whatever formatting we would like, as we have access to it all with the product computed property:

<main> <section class="img"> <img :src="`/products/${product.img}`" /> </section> <section class="product-info"> <h1>{{ }}</h1> <h4 class="price">{{ product.price | dollar }}</h4> <p>{{ product.description }}</p> </section> ...

In our case, we’ll also want to add items to the cart that’s in the store. We’ll add the ability to add and remove items (while not letting the decrease count dip below zero

<p class="quantity"> <button class="update-num" @click="quantity > 0 ? quantity-- : quantity = 0">-</button> <input type="number" v-model="quantity" /> <button class="update-num" @click="quantity++">+</button>
<button class="button purchase" @click="cartAdd">Add to Cart</button>

In our methods on that component, we’ll add the item plus a new field, the quantity, to an array that we’ll pass as the payload to mutation in the store.

methods: { cartAdd() { let item = this.product; item.quantity = this.quantity; this.tempcart.push(item); this.$store.commit("addToCart", item); }

In the Vuex store, we’ll check if the item already exists. If it does, we’ll just increase the quantity. If not, we’ll add the whole item with quantity to the cart array.

addToCart: (state, payload) => { let itemfound = false state.cart.forEach(el => { if ( === { el.quantity += payload.quantity itemfound = true } }) if (!itemfound) state.cart.push(payload)

We can now use a getter in the store to calculate the total, which is what we’ll eventually pass to our Stripe serverless function (the other post picks up from here). We’ll use a reduce for this as reduce is very good at retrieving one value from many. (I wrote up more details on how reduce works here).

cartTotal: state => { if (!state.cart.length) return 0 return state.cart.reduce((ac, next) => ac + next.quantity * next.price, 0)

And there you have it! We’ve set up individual product pages, and Nuxt generates all of our individual routes for us at build time. You’d be Nuxt not to try it yourself. 😬

The post Creating Dynamic Routes in a Nuxt Application appeared first on CSS-Tricks.

Designing And Building A Progressive Web Application Without A Framework (Part 3)

Designing And Building A Progressive Web Application Without A Framework (Part 3)

Designing And Building A Progressive Web Application Without A Framework (Part 3)

Ben Frain

Back in the first part of this series, we explained why this project came to be. Namely a desire to learn how a small web application could be made in vanilla JavaScript and to get a non-designing developer working his design chops a little.

In part two we took some basic initial designs and got things up and running with some tooling and technology choices. We covered how and why parts of the design changed and the ramifications of those changes.

In this final part, we will cover turning a basic web application into a Progressive Web Application (PWA) and ‘shipping’ the application before looking at the most valuable lessons learned by making the simple web application In/Out:

  • The enormous value of JavaScript array methods;
  • Debugging;
  • When you are the only developer, you are the other developer;
  • Design is development;
  • Ongoing maintenance and security issues;
  • Working on side projects without losing your mind, motivation or both;
  • Shipping some product beats shipping no product.

So, before looking at lessons learned, let’s look at how you turn a basic web application written in HTML, CSS, and JavaScript into a Progressive Web Application (PWA).

In terms of total time spent on making this little web-application, I’d guestimate it was likely around two to three weeks. However, as it was done in snatched 30-60 minute chunks in the evenings it actually took around a year from the first commit to when I uploaded what I consider the ‘1.0’ version in August 2018. As I’d got the app ‘feature complete’, or more simply speaking, at a stage I was happy with, I anticipated a large final push. You see, I had done nothing towards making the application into a Progressive Web Application. Turns out, this was actually the easiest part of the whole process.

Making A Progressive Web Application

The good news is that when it comes to turning a little JavaScript-powered app into a ‘Progressive Web App’ there are heaps of tools to make life easy. If you cast your mind back to part one of this series, you’ll remember that to be a Progressive Web App means meeting a set of criteria.

To get a handle on how your web-application measures up, your first stop should probably be the Lighthouse tools of Google Chrome. You can find the Progressive Web App audit under the ‘Audits’ tab.

This is what Lighthouse told me when I first ran In/Out through it.

The Chrome dev tools showing Progressive Web App results of 55/100
Initial scores for Progressive Web App weren’t great. (Large preview)

At the outset In/Out was only getting a score of 55100 for a Progressive Web App. However, I took it from there to 100100 in well under an hour!

The expediency in improving that score was little to do with my ability. It was simply because Lighthouse told me exactly what was needed to be done!

Some examples of requisite steps: include a manifest.json file (essentially a JSON file providing metadata about the app), add a whole slew of meta tags in the head, switch out images that were inlined in the CSS for standard URL referenced images, and add a bunch of home screen images.

Making a number of home screen images, creating a manifest file and adding a bunch of meta tags might seem like a lot to do in under an hour but there are wonderful web applications to help you build web applications. How nice is that! I used Feed it some data about your application and your logo, hit submit and it furnishes you with a zip file containing everything you need! From there on, it’s just copy-and-paste time.

Things I’d put off for some time due to lack of knowledge, like a Service Worker, were also added fairly easily thanks to numerous blog posts and sites dedicated to service workers like With a service worker in place it meant the app could work offline, a requisite feature of a Progressive Web Application.

Whilst not strictly related to making the application a PWA, the ‘coverage’ tab of the Chrome Dev Tools were also very useful. After so much sporadic iteration on the design and code over months, it was useful to get a clear indication of where there was redundant code. I found a few old functions littering the codebase that I’d simply forgotten about!

In short order, having worked through the Lighthouse audit recommendations I felt like the teacher’s pet:

Getting a 100/100 on Lighthouse Progressive Web App audit
Lighthouse makes it easy to get good scores by telling you exactly what to change. (Large preview)

The reality is that taking the application and making it a Progressive Web Application was actually incredibly straightforward.

With that final piece of development concluded I uploaded the little application to a sub-domain of my website and that was it.


Months have passed since parking up development my little web application.

I’ve used the application casually in the months since. The reality is much of the team sports organization I do still happens via text message. The application is, however, definitely easier than writing down who is in and out than finding a scrap of paper every game night.

So, the truth is that it’s hardly an indispensable service. Nor does it set any bars for development or design. I couldn’t tell you I’m 100% happy with it either. I just got to a point I was happy to abandon it.

But that was never the point of the exercise. I took a lot from the experience. What follows are what I consider the most important takeaways.

Design Is Development

At the outset, I didn’t value design enough. I started this project believing that my time spent sketching with a pad and pen or in the Sketch application, was time that could be better spent with coding. However, it turns that when I went straight to code, I was often just being a busy fool. Exploring concepts first at the lowest possible fidelity, saved far more time in the long run.

There were numerous occasions at the beginning where hours were spent getting something working in code only to realize that it was fundamentally flawed from a user experience point of view.

My opinion now is that paper and pencil are the finest planning, design and coding tools. Every significant problem faced was principally solved with paper and a pencil; the text editor merely a means of executing the solution. Without something making sense on paper, it stands no chance of working in code.

The next thing I learned to appreciate, and I don’t know why it took so long to figure out, is that design is iterative. I’d sub-consciously bought into the myth of a Designer with a capital “D”. Someone flouncing around, holding their mechanical pencil up at straight edges, waxing lyrical about typefaces and sipping on a flat white (with soya milk, obviously) before casually birthing fully formed visual perfection into the world.

This, not unlike the notion of the ‘genius’ programmer, is a myth. If you’re new to design but trying your hand, I’d suggest you don’t get hung up on the first idea that piques your excitement. It’s so cheap to try variations so embrace that possibility. None of the things I like about the design of In/Out were there in the first designs.

I believe it was the novelist, Michael Crichton, who coined the maxim, “Books are not written — they’re rewritten”. Accept that every creative process is essentially the same. Be aware that trusting the process lessens the anxiety and practice will refine your aesthetic understanding and judgment.

You Are The Other Dev On Your Project

I’m not sure if this is particular to projects that only get worked on sporadically but I made the following foolhardy assumption:

“I don’t need to document any of this because it’s just me, and obviously I will understand it because I wrote it.”

Nothing could be further from the truth!

There were evenings when, for the 30 minutes I had to work on the project, I did nothing more than try to understand a function I had written six months ago. The main reasons code re-orientation took so long was a lack of quality comments and poorly named variables and function arguments.

I’m very diligent in commenting code in my day job, always conscientious that someone else might need to make sense of what I’m writing. However, in this instance, I was that someone else. Do you really think you will remember how the block of code works you wrote in six months time? You won’t. Trust me on this, take some time out and comment that thing up!

I’ve since read a blog post entitled, Your syntax highlighter is wrong on the subject of the importance of comments. The basic premise being that syntax highlighters shouldn’t fade out the comments, they should be the most important thing. I’m inclined to agree and if I don’t find a code editor theme soon that scratches that itch I may have to adapt one to that end myself!


When you hit bugs and you have written all the code, it’s not unfair to suggest the error is likely originating between the keyboard and chair. However, before assuming that, I would suggest you test even your most basic assumptions. For example, I remember taking in excess of two hours to fix a problem I had assumed was due to my code; in iOS I just couldn’t get my input box to accept text entry. I don’t remember why it hadn’t stopped me before but I do remember my frustration with the issue.

Turns out it was due to a, still yet to be fixed, bug in Safari. Turns out that in Safari if you have:

* { user-select: none;

In your style sheet, input boxes won’t take any input. You can work around this with:

* { user-select: none;
} input || { user-select: text;

Which is the approach I take in my “App Reset” CSS reset. However, the really frustrating part of this was I had learned this already and subsequently forgotten it. When I finally got around to checking the WebKit bug tracking whilst troubleshooting the issue, I found I had written a workaround in the bug report thread more than a year ago complete with reduction!

Want To Build With Data? Learn JavaScript Array Methods

Perhaps the single biggest advance my JavaScript skills took by undergoing this app-building exercise was getting familiar with JavaScript Array methods. I now use them daily for all my iteration and data manipulation needs. I cannot emphasize enough how useful methods like map(), filter(), every(), findIndex(), find() and reduce() are. You can solve virtually any data problem with them. If you don’t already have them in your arsenal, bookmark now and dig in as soon as you are able. My own run-down of my favored array methods is documented here.

ES6 has introduced other time savers for manipulating arrays, such as Set, Rest and Spread. Indulge me while I share one example; there used to be a bunch of faff if you wanted to remove duplicates from even a simple flat array. Not anymore.

Consider this simple example of an Array with the duplicate entry, “Mr Pink”:

let myArray = [ "Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue", "Mr Pink"

To get rid of the duplicates with ES6 JavaScript you can now just do:

let deDuped = [ Set(myArray)]; // deDuped logs ["Mr Orange", "Mr Pink", "Mr Brown", "Mr White", "Mr Blue"]

Something that used to require hand-rolling a solution or reaching for a library is now baked into the language. Admittedly, on such as short Array that may not sound like such a big deal but imagine how much time that saves when looking at arrays with hundreds of entries and duplicates.

Maintenance And Security

Anything you build that makes any use of NPM, even if just for build tools, carries the possibility of being vulnerable to security issues. GitHub does a good job of keeping you aware of potential problems but there is still some burden of maintenance.

For something that is a mere side-project, this can be a bit of a pain in the months and years that follow active development.

The reality is that every time you update dependencies to fix a security issue, you introduce the possibility of breaking your build.

For months, my package.json looked like this:

{ "dependencies": { "gulp": "^3.9.1", "postcss": "^6.0.22", "postcss-assets": "^5.0.0" }, "name": "In Out", "version": "1.0.0", "description": "simple utility to see who’s in and who’s out", "main": "index.js", "author": "Ben Frain", "license": "MIT", "devDependencies": { "autoprefixer": "^8.5.1", "browser-sync": "^2.24.6", "cssnano": "^4.0.4", "del": "^3.0.0", "gulp-htmlmin": "^4.0.0", "gulp-postcss": "^7.0.1", "gulp-sourcemaps": "^2.6.4", "gulp-typescript": "^4.0.2", "gulp-uglify": "^3.0.1", "postcss-color-function": "^4.0.1", "postcss-import": "^11.1.0", "postcss-mixins": "^6.2.0", "postcss-nested": "^3.0.0", "postcss-simple-vars": "^4.1.0", "typescript": "^2.8.3" }

And by June 2019, I was getting these warnings from GitHub:

GitHub interface highlighting security issues with build tool dependencies
Keeping dependencies listed on GitHub means infrequent security warnings. (Large preview)

None were related to plugins I was using directly, they were all sub-dependencies of the build tools I had used. Such is the double-edged sword of JavaScript packages. In terms of the app itself, there was no problem with In/Out; that wasn’t using any of the project dependencies. But as the code was on GitHub, I felt duty-bound to try and fix things up.

It’s possible to update packages manually, with a few choice changes to the package.json. However, both Yarn and NPM have their own update commands. I opted to run yarn upgrade-interactive which gives you a simple means to update things from the terminal.

The CLI interface for upgrading packages with Yarn
Yarn makes upgrading project dependencies a little more predicatble. (Large preview)

Seems easy enough, there’s even a little colored key to tell you which updates are most important.

You can add the --latest flag to update to the very latest major version of the dependencies, rather than just the latest patched version. In for a penny…

Trouble is, things move fast in the JavaScript package world, so updating a few packages to the latest version and then attempting a build resulted in this:

Gulp build error
Gulp build error (Large preview)

As such, I rolled back my package.json file and tried again this time without the --latest flag. That solved my security issues. Not the most fun I’ve had on a Monday evening though I’ll be honest.

That touches on an important part of any side project. Being realistic with your expectations.

Side Projects

I don’t know if you are the same but I’ve found that a giddy optimism and excitement makes me start projects and if anything does, embarrassment and guilt makes me finish them.

It would be a lie to say the experience of making this tiny application in my spare time was fun-filled. There were occasions I wish I’d never opened my mouth about it to anyone. But now it is done I am 100% convinced it was worth the time invested.

That said, it’s possible to mitigate frustration with such a side project by being realistic about how long it will take to understand and solve the problems you face. Only have 30 mins a night, a few nights a week? You can still complete a side project; just don’t be disgruntled if your pace feels glacial. If things can’t enjoy your full attention be prepared for a slower and steadier pace than you are perhaps used to. That’s true, whether it’s coding, completing a course, learning to juggle or writing a series of articles of why it took so long to write a small web application!

Simple Goal Setting

You don’t need a fancy process for goal setting. But it might help to break things down into small/short tasks. Things as simple as ‘write CSS for drop-down menu’ are perfectly achievable in a limited space of time. Whereas ‘research and implement a design pattern for state management’ is probably not. Break things down. Then, just like Lego, the tiny pieces go together.

Thinking about this process as chipping away at the larger problem, I’m reminded of the famous Bill Gates quote:

“Most people overestimate what they can do in one year and underestimate what they can do in ten years.”

This from a man that’s helping to eradicate Polio. Bill knows his stuff. Listen to Bill y’all.

Shipping Something Is Better Than Shipping Nothing

Before ‘shipping’ this web application, I reviewed the code and was thoroughly disheartened.

Although I had set out on this journey from a point of complete naivety and inexperience, I had made some decent choices when it came to how I might architect (if you’ll forgive so grand a term) the code. I’d researched and implemented a design pattern and enjoyed everything that pattern had to offer. Sadly, as I got more desperate to conclude the project, I failed to maintain discipline. The code as it stands is a real hodge-bodge of approaches and rife with inefficiencies.

In the months since I’ve come to realize that those shortcomings don’t really matter. Not really.

I’m a fan of this quote from Helmuth von Moltke.

“No plan of operations extends with any certainty beyond the first contact with the main hostile force.”

That’s been paraphrased as:

“No plan survives first contact with the enemy”.

Perhaps we can boil it down further and simply go with “shit happens”?

I can surmise my coming to terms with what shipped via the following analogy.

If a friend announced they were going to try and run their first marathon, them getting over the finish line would be all that mattered — I wouldn’t be berating them on their finishing time.

I didn’t set out to write the best web application. The remit I set myself was simply to design and make one.

More specifically, from a development perspective, I wanted to learn the fundamentals of how a web application was constructed. From a design point of view, I wanted to try and work through some (albeit simple) design problems for myself. Making this little application met those challenges and then some. The JavaScript for the entire application was just 5KB (gzipped). A small file size I would struggle to get to with any framework. Except maybe Svelte.

If you are setting yourself a challenge of this nature, and expect at some point to ‘ship’ something, write down at the outset why you are doing it. Keep those reasons at the forefront of your mind and be guided by them. Everything is ultimately some sort of compromise. Don’t let lofty ideals paralyze you from finishing what you set out to do.


Overall, as it comes up to a year since I have worked on In/Out, my feelings fall broadly into three areas: things I regretted, things I would like to improve/fix and future possibilities.

Things I Regretted

As already alluded to, I was disappointed I hadn’t stuck to what I considered a more elegant method of changing state for the application and rendering it to the DOM. The observer pattern, as discussed in the second part of this series, which solved so many problems in a predictable manner was ultimately cast aside as ‘shipping’ the project became a priority.

I was embarrassed by my code at first but in the following months, I have grown more philosophical. If I hadn’t used more pedestrian techniques later on, there is a very real possibility the project would never have concluded. Getting something out into the world that needs improving still feels better than it never being birthed into the world at all.

Improving In/Out

Beyond choosing semantic markup, I’d made no affordances for accessibility. When I built In/Out I was confident with standard web page accessibility but not sufficiently knowledgeable to tackle an application. I’ve done far more work/research in that area now, so I’d enjoy taking the time to do a decent job of making this application more accessible.

The implementation of the revised design of ‘Add Person’ functionality was rushed. It’s not a disaster, just a bit rougher than I would like. It would be nice to make that slicker.

I also made no consideration for larger screens. It would be interesting to consider the design challenges of making it work at larger sizes, beyond simply making it a tube of content.


Using localStorage worked for my simplistic needs but it would be nice to have a ‘proper’ data store so it wasn’t necessary to worry about backing up the data. Adding log-in capability would also open up the possibility of sharing the game organization with another individual. Or maybe every player could just mark whether they were playing themselves? It’s amazing how many avenues to explore you can envisage from such simple and humble beginnings.

SwiftUI for iOS app development is also intriguing. For someone who has only ever worked with web languages, at first glance, SwiftUI looks like something I’m now emboldened to try. I’d likely try rebuilding In/Out with SwiftUI — just to have something specific to build and compare the development experience and results.

And so, it’s time to wrap things up and give you the TL;DR version of all this.

If you want to learn how something works on the web, I’d suggest skipping the abstractions. Ditch the frameworks, whether that’s CSS or JavaScript until you really understand what they are dong for you.

Design is iterative, embrace that process.

Solve problems in the lowest fidelity medium at your disposal. Don’t go to code if you can test the idea in Sketch. Don’t draw it in Sketch if you can use pen and paper. Write out logic first. Then write it in code.

Be realistic but never despondent. Developing a habit of chipping away at something for as little as 30 minutes a day can get results. That fact is true whatever form your quest takes.

Smashing Editorial (dm, il, ra)
Getting design system customization just right

I had a little rant in me a few months ago about design systems: “Who Are Design Systems For?” My main point was that there are so many public and open source ones out there that choosing one can feel like choosing new furniture for your house. You just measure up what you need and what you like and pick one. But it just isn’t that simple. Some are made for you, some makers want you to use them, and some just ain’t.

A more measured take from Koen Vendrik (consistently, the same Koen who just made a cool Jest browser tool):

… it’s important that you first define who a design system is for and what people should be able to do with it. When you have decided this, and start looking at the implementation for the level of flexibility you require, keep in mind that it’s okay to do something that’s different from what’s already out there. It’s easy to create a lot of flexibility or none at all, the trick is to get it just right.

The levels:

  • Zero customizability. Sometimes this is the point: enforcing consistency and making it easy to use (no config).
  • Build your own (BYO) theme. The other end of the spectrum: do whatever you want, fully cusomizable.
  • Guided theme building. This is baby bear. Like changing preprocessor values to change colors, but it can get fancier.

Direct Link to ArticlePermalink

The post Getting design system customization just right appeared first on CSS-Tricks.

I Used The Web For A Day On A 50 MB Budget

I Used The Web For A Day On A 50 MB Budget

I Used The Web For A Day On A 50 MB Budget

Chris Ashton

This article is part of a series in which I attempt to use the web under various constraints, representing a given demographic of user. I hope to raise the profile of difficulties faced by real people, which are avoidable if we design and develop in a way that is sympathetic to their needs.

Last time, I navigated the web for a day using Internet Explorer 8. This time, I browsed the web for a day on a 50 MB budget.

Why 50 MB?

Many of us are lucky enough to be on mobile plans which allow several gigabytes of data transfer per month. Failing that, we are usually able to connect to home or public WiFi networks that are on fast broadband connections and have effectively unlimited data.

But there are parts of the world where mobile data is prohibitively expensive, and where there is little or no broadband infrastructure.

People often buy data packages of just tens of megabytes at a time, making a gigabyte a relatively large and therefore expensive amount of data to buy.
— Dan Howdle, consumer telecoms analyst at

Just how expensive are we talking?

The Cost Of Mobile Data

A 2018 study by found that Zimbabwe was the most expensive country in the world for mobile data, where 1 GB cost an average of $75.20, ranging from $12.50 to $138.46. The enormous range in price is due to smaller amounts of data being very expensive, getting proportionally cheaper the bigger the data plan you commit to. You can read the study methodology for more information.

Zimbabwe is by no means a one-off. Equatorial Guinea, Saint Helena and the Falkland Islands are next in line, with 1 GB of data costing $65.83, $55.47 and $47.39 respectively. These countries generally have a combination of poor technical infrastructure and low adoption, meaning data is both costly to deliver and doesn’t have the economy of scale to drive costs down.

Data is expensive in parts of Europe too. A gigabyte of data in Greece will set you back $32.71; in Switzerland, $20.22. For comparison, the same amount of data costs $6.66 in the UK, or $12.37 in the USA. On the other end of the scale, India is the cheapest place in the world for data, at an average cost of $0.26. Kyrgyzstan, Kazakhstan and Ukraine follow at $0.27, $0.49 and $0.51 per GB respectively.

The speed of mobile networks, too, varies considerably between countries. Perhaps surprisingly, users experience faster speeds over a mobile network than WiFi in at least 30 countries worldwide, including Australia and France. South Korea has the fastest mobile download speed, averaging 52.4 Mbps, but Iraq has the slowest, averaging 1.6 Mbps download and 0.7 Mbps upload. The USA ranks 40th in the world for mobile download speeds, at around 34 Mbps, and is at risk of falling further behind as the world moves towards 5G.

As for mobile network connection type, 84.7% of user connections in the UK are on 4G, compared to 93% in the USA, and 97.5% in South Korea. This compares with less than 50% in Uzbekistan and less than 60% in Algeria, Ecuador, Nepal and Iraq.

The Cost Of Broadband Data

Meanwhile, a study of the cost of broadband in 2018 shows that a broadband connection in Niger costs $263 ‘per megabit per month’. This metric is a little difficult to comprehend, so here’s an example: if the average cost of broadband packages in a country is $22, and the average download speed offered by the packages is 10 Mbps, then the cost ‘per megabit per month’  would be $2.20.

It’s an interesting metric, and one that acknowledges that broadband speed is as important a factor as the data cap. A cost of $263 suggests a combination of extremely slow and extremely expensive broadband. For reference, the metric is $1.19 in the UK and $1.26 in the USA.

What’s perhaps easier to comprehend is the average cost of a broadband package. Note that this study was looking for the cheapest broadband packages on offer, ignoring whether or not these packages had a data cap, so provides a useful ballpark figure rather than the cost of data per se.

On package cost alone, Mauritania has the most expensive broadband in the world, at an average of $768.16 (a range of $307.26 to $1,368.72). This enormous cost includes building physical lines to the property, since few already exist in Mauritania. At 0.7 Mbps, Mauritania also has one of the slowest broadband networks in the world.

Taiwan has the fastest broadband in the world, at a mean speed of 85 Mbps. Yemen has the slowest, at 0.38 Mbps. But even countries with good established broadband infrastructure have so-called ‘not-spots’. The United Kingdom is ranked 34th out of 207 countries for broadband speed, but in July 2019 there was still a school in the UK without broadband.

The average cost of a broadband package in the UK is $39.58, and in the USA is $67.69. The cheapest average in the world is Ukraine’s, at just $5, although the cheapest broadband deal of them all was found in Kyrgystan ($1.27 — against the country average of $108.22).

Zimbabwe was the most costly country for mobile data, and the statistics aren’t much better for its broadband, with an average cost of $128.71 and a ‘per megabit per month’ cost of $6.89.

Absolute Cost vs Cost In Real Terms

All of the costs outlined so far are the absolute costs in USD, based on the exchange rates at the time of the study. These costs have not been accounted for cost of living, meaning that for many countries the cost is actually far higher in real terms.

I’m going to limit my browsing today to 50 MB, which in Zimbabwe would cost around $3.67 on a mobile data tariff. That may not sound like much, but teachers in Zimbabwe were striking this year because their salaries had fallen to just $2.50 a day.

For comparison, $3.67 is around half the $7.25 minimum wage in the USA. As a Zimbabwean, I’d have to work for around a day and a half to earn the money to buy this 50MB data, compared to just half an hour in the USA. It’s not easy to compare cost of living between countries, but on wages alone the $3.67 cost of 50 MB of data in Zimbabwe would feel like $52 to an American on minimum wage.

Setting Up The Experiment

I launched Chrome and opened the dev tools, where I throttled the network to a slow 3G connection. I wanted to simulate a slow connection like those experienced by users in Uzbekistan, to see what kind of experience websites would give me. I also throttled my CPU to simulate being on a lower end device.

I opted to throttle my network to Slow 3G and my CPU to 6x slowdown. (Large preview)

I installed ModHeader and set the ‘Save-Data’ header to let websites know I want to minimise my data usage. This is also the header set by Chrome for Android’s ‘Lite mode’, which I’ll cover in more detail later.

I downloaded TripMode; an application for Mac which gives you control over which apps on your Mac can access the internet. Any other application’s internet access is automatically blocked.

Screenshot of Tripmode settings; Chrome is enabled, Mail is disabled
You can enable/disable individual apps from connecting to the internet with TripMode. I enabled Chrome. (Large preview)

How far do I predict my 50 MB budget will take me? With the average weight of a web page being almost 1.7 MB, that suggests I’ve got around 29 pages in my budget, although probably a few more than that if I’m able to stay on the same sites and leverage browser caching.

Throughout the experiment I will suggest performance tips to speed up the first contentful paint and perceived loading time of the page. Some of these tips may not affect the amount of data transferred directly, but do generally involve deferring the download of less important resources, which on slow connections may mean the resources are never downloaded and data is saved.

The Experiment

Without any further ado, I loaded, using 402 KB of my budget and spending $0.03 (around 1% of my Zimbabwe budget).

402 KB transferred, 1.1 MB resources, 24 requests
402 KB transferred, 1.1 MB resources, 24 requests. (Large preview)

All in all, not a bad page size, but I wondered where those 24 network requests were coming from and whether or not the page could be made any lighter.

Google Homepage — DOM

Chrome devtools screenshot of the DOM, where I’ve expanded one inline style tag. (Large preview)

Looking at the page markup, there are no external stylesheets — all of the CSS is inline.

Performance Tip #1: Inline Critical CSS

This is good for performance as it saves the browser having to make an additional network request in order to fetch an external stylesheet, so the styles can be parsed and applied immediately for the first contentful paint. There’s a trade-off to be made here, as external stylesheets can be cached but inline ones cannot (unless you get clever with JavaScript).

The general advice is for your critical styles (anything above-the-fold) to be inline, and for the rest of your styling to be external and loaded asynchronously. Asynchronous loading of CSS can be achieved in one remarkably clever line of HTML:

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="'all'">

The devtools show a prettified version of the DOM. If you want to see what was actually downloaded to the browser, switch to the Sources tab and find the document.

A wall of minified code.
Switching to Sources and finding the index shows the ‘raw’ HTML that was delivered to the browser. What a mess! (Large preview)

You can see there is a LOT of inline JavaScript here. It’s worth noting that it has been uglified rather than merely minified.

Performance Tip #2: Minify And Uglify Your Assets

Minification removes unnecessary spaces and characters, but uglification actually ‘mangles’ the code to be shorter. The tell-tale sign is that the code contains short, machine-generated variable names rather than untouched source code. This is good as it means the script is smaller and quicker to download.

Even so, inline scripts look to be roughly 120 KB of the 210 KB page resource (about half the 60 KB gzipped size). In addition, there are five external JavaScript files amounting to 291 KB of the 402 KB downloaded:

Network tab of DevTools showing the external javascript files
Five external JavaScript files in the Network tab of the devtools. (Large preview)

This means that JavaScript accounts for about 80 percent of the overall page weight.

This isn’t useless JavaScript; Google has to have some in order to display suggestions as you type. But I suspect a lot of it is tracking code and advertising setup.

For comparison, I disabled JavaScript and reloaded the page:

DevTools showing only 5 network requests
The disabled JS version of Google search was only 102 KB and had just 5 network requests. (Large preview)

The JS-disabled version of Google search is just 102 KB, as opposed to 402 KB. Although Google can’t provide autosuggestions under these conditions, the site is still functional, and I’ve just cut my data usage down to a quarter of what it was. If I really did have to limit my data usage in the long term, one of the first things I’d do is disable JavaScript. It’s not as bad as it sounds.

Performance Tip #3: Less Is More

Inlining, uglifying and minifying assets is all well and good, but the best performance comes from not sending down the assets in the first place.

  • Before adding any new features, do you have a performance budget in place?
  • Before adding JavaScript to your site, can your feature be accomplished using plain HTML? (For example, HTML5 form validation).
  • Before pulling a large JavaScript or CSS library into your application, use something like to measure how big it is. Is the convenience worth the weight? Can you accomplish the same thing using vanilla code at a much smaller data size?

Analysing The Resource Info

There’s a lot to unpack here, so let’s get cracking. I’ve only got 50 MB to play with, so I’m going to milk every bit of this page load. Settle in for a short Chrome Devtools tutorial.

402 KB transferred, but 1.1 MB of resources: what does that actually mean?

It means 402 KB of content was actually downloaded, but in its compressed form (using a compression algorithm such as gzip or brotli). The browser then had to do some work to unpack it into something meaningful. The total size of the unpacked data is 1.1 MB.

This unpacking isn’t free — there are a few milliseconds of overhead in decompressing the resources. But that’s a negligible overhead compared to sending 1.1MB down the wire.

Performance Tip #4: Compress Text-based Assets

As a general rule, always compress your assets, using something like gzip. But don’t use compression on your images and other binary files — you should optimize these in advance at source. Compression could actually end up making them bigger.

And, if you can, avoid compressing files that are 1500 bytes or smaller. The smallest TCP packet size is 1500 bytes, so by compressing to, say, 800 bytes, you save nothing, as it’s still transmitted in the same byte packet. Again, the cost is negligible, but wastes some compression CPU time on the server and decompression CPU time on the client.

Now back to the Network tab in Chrome: let’s dig into those priorities. Notice that resources have priority “Highest” to “Lowest” — these are the browser’s best guess as to what are the more important resources to download. The higher the priority, the sooner the browser will try to download the asset.

Performance Tip #5: Give Resource Hints To The Browser

The browser will guess at what the highest priority assets are, but you can provide a resource hint using the <link rel="preload"> tag, instructing the browser to download the asset as soon as possible. It’s a good idea to preload fonts, logos and anything else that appears above the fold.

Let’s talk about caching. I’m going to hold ALT and right-click to change my column headers to unlock some more juicy information. We’re going to check out Cache-Control.

Screenshot showing how to display cache-control information
There are lots of interesting fields tucked away behind ALT. (Large preview)

Cache-Control denotes whether or not a resource can be cached, how long it can be cached for, and what rules it should follow around revalidating. Setting proper cache values is crucial to keeping the data cost of repeat visits down.

Performance Tip #6: Set cache-control Headers On All Cacheable Assets

Note that the cache-control value begins with a directive of public or private, followed by an expiration value (e.g. max-age=31536000). What does the directive mean, and why the oddly specific max-age value?

Screenshot of Google network tab with cache-control column visible
A mixture of max-age values and public/private. (Large preview)

The value 31536000 is the number of seconds there are in a year, and is the theoretical maximum value allowed by the cache-control specification. It is common to see this value applied to all static assets and effectively means “this resource isn’t going to change”. In practice, no browser is going to cache for an entire year, but it will cache the asset for as long as makes sense.

To explain the public/private directive, we must explain the two main caches that exist off the server. First, there is the traditional browser cache, where the resource is stored on the user’s machine (the ‘client’). And then there is the CDN cache, which sits between the client and the server; resources are cached at the CDN level to prevent the CDN from requesting the resource from the origin server over and over again.

Diagram showing how caches interact with the server
Source. (Large preview)

A Cache-Control directive of public allows the resource to be cached in both the client and the CDN. A value of private means only the client can cache it; the CDN is not supposed to. This latter value is typically used for pages or assets that exist behind authentication, where it is fine to be cached on the client but we wouldn’t want to leak private information by caching it in the CDN and delivering it to other users.

Screenshot of Google logo cache-control setting: private, max-age=31536000
A mixture of max-age values and public/private. (Large preview)

One thing that got my attention was that the Google logo has a cache control of “private”. Other images on the page do have a public cache, and I don’t know why the logo would be treated any differently. If you have any ideas, let me know in the comments!

I refreshed the page and most of the resources were served from cache, apart from the page itself, which as you’ve seen already is private, max-age=0, meaning it cannot be cached. This is normal for dynamic web pages where it is important that the user always gets the very latest page when they refresh.

It was at this point I accidentally clicked on an ‘Explanation’ URL in the devtools, which took me to the network analysis reference, costing me about 5 MB of my budget. Oops.

Google Dev Docs

4.2 MB of this new 5 MB page was down to images; specifically SVGs. The weightiest of these was 186 KB, which isn’t particularly big — there were just so many of them, and they all downloaded at once.

Gif scrolling down the very long dev docs page
This is a loooong page. All the images downloaded on page load. (Large preview)

That 5 MB page load was 10% of my budget for today. So far I’ve used 5.5 MB, including the no-JavaScript reload of the Google homepage, and spent $0.40. I didn’t even mean to open this page.

What would have been a better user experience here?

Performance Tip #7: Lazy-load Your Images

Ordinarily, if I accidentally clicked on a link, I would hit the back button in my browser. I’d have received no benefit whatsoever from downloading those images — what a waste of 4.2 MB!

Apart from video, where you generally know what you’re getting yourself into, images are by far the biggest culprit to data usage on the web. A study of the world’s top 500 websites found that images take up to 53% of the average page weight. “This means they have a big impact on page-loading times and subsequently overall performance”.

Instead of downloading all of the images on page load, it is good practice to lazy-load the images so that only users who are engaged with the page pay the cost of downloading them. Users who choose not to scroll below the fold therefore don’t waste any unnecessary bandwidth downloading images they’ll never see.

There’s a great guide to rolling out lazy-loading for images which offers a good balance between those on good connections, those on poor connections, and those with JavaScript disabled.

If this page had implemented lazy loading as per the guide above, each of the 38 SVGs would have been represented by a 1 KB placeholder image by default, and only loaded into view on scroll.

Performance Tip #8: Use The Right Format For Your Images

I thought that Google had missed a trick by not using WebP, which is an image format that is 26% smaller in size compared to PNGs (with no loss in quality) and 25-34% smaller in size compared to JPEGs (and of a comparable quality). I thought I’d have a go at converting SVG to WebP.

Converting to WebP did bring one of the SVGs down from 186 KB to just 65 KB, but actually, looking at the images side by side, the WebP came out grainy:

Comparison of the two images
The SVG (left) is noticeably crisper than the WebP (right). (Large preview)

I then tried converting one of the PNGs to WebP, which is supposed to be lossless and should come out smaller. However, the WebP output was *heavier* (127 KB, from 109 KB)!

Comparison of the two images
The PNG (left) is a similar quality to the WebP (right) but is smaller at 109 KB compared to 127 KB. (Large preview)

This surprised me. WebP isn’t necessarily the silver bullet we think it is, and even Google have neglected to use it on this page.

So my advice would be: where possible, experiment with different image formats on a per-image basis. The format that keeps the best quality for the smallest size may not be the one you expect.

Now back to the DOM. I came across this:

Screenshot of code
(Large preview)

Notice the async keyword on the Google analytics script?

Screenshot of performance analysis output of devtools
Google analytics has ‘low’ priority. (Large preview)

Despite being one of the first things in the head of the document, this was given a low priority, as we’ve explicitly opted out of being a blocking request by using the async keyword.

A blocking request is one that stops the rendering of the page. A <script> call is blocking by default, stopping the parsing of the HTML until the script has downloaded, compiled and executed. This is why we traditionally put <script> calls at the end of the document.

Performance Tip #9: Avoid Writing Blocking Script Calls

By adding the async attribute to our <script> tag, we’re telling the browser not to stop rendering the page but to download the script in the background. If the HTML is still being parsed by the time the script is downloaded, the parsing is paused while the script is executed, and then resumed. This is significantly better than blocking the rendering as soon as <script> is encountered.

There is also a defer attribute, which is subtly different. <script defer> tells the browser to render the page while the script loads in the background, and even if the HTML is still being parsed by the time the script is downloaded, the script must wait until the page is rendered before it can be executed. This makes the script completely non-blocking. Read “Efficiently load JavaScript with defer and async” for more information.

Anyway, enough Google dissecting. It’s time to try out another site. I’ve still got almost 45 MB of my budget left!


screenshot of Amazon homepage
(Large preview)

The Amazon homepage loaded with a total weight of about 6 MB. One of these was a 587 KB image that I couldn’t even find on the page. This was a PNG, presumably to have crisp text, but on a photographic background — a classic combination that’s terrible for performance.

image of spanners with overlaid text: Hands-on time. Discover our tool selection for your car
This grainy image used over 1% of my budget. (Large preview)

In fact, there were a few several-hundred-kilobyte images in my network tab that I couldn’t actually see on the page. I suspect a misconfiguration somewhere on Amazon, but these invisible images combined chewed through at least 1 MB of my data.

How about the hero image? It’s the main image on the page, and it’s only 94 KB transferred — but it could be reduced in size by about 15% if it were cropped directly around the text and footballers. We could then apply the same background color in CSS as is in the image. This has the additional advantage of being resizable down to smaller screens whilst retaining legibility of text.

Screenshot says: Premier league football - Live on Prime video
(Large preview)

I’ve said it once, and I’ll say it again: optimising and lazy-loading your images is the single biggest benefit you can make to the page weight of your site.

Optimizing images provided, by far, the most significant data reduction. You can make the case JavaScript is a bigger deal for overall performance, but not data reduction. Optimizing or removing images is the safest way of ensuring a much lighter experience and that’s the primary optimization Data Saver relies on.
— Tim Kadlec, Making Sense of Chrome Lite Pages

To be fair to Amazon, if I resize the browser to a mobile size and refresh the page, the site is optimized for mobile and the total page weight is only 2.1 MB.

101 requests, 2.1 MB transferred
101 requests, 2.1 MB transferred. (Large preview)

But this brings me onto my next point…

Performance Tip #10: Don’t Make Assumptions About Data Connections

It’s difficult to detect if someone on a desktop is on a broadband connection or is tethering through a data-limited dongle or mobile. Many people work on the train like that, or live in an area where broadband infrastructure is poor but mobile signal is strong. In Amazon’s case, there is room to make some big data savings on the desktop site and we shouldn’t get complacent just because the screen size suggests I’m not on a mobile device.

Yes, we should expect a larger page load if our viewport is ‘desktop sized’ as the images will be larger and better optimized for the screen than a grainier mobile one. But the page shouldn’t be orders of magnitude bigger.

Moreover, I was sending the Save-Data header with my request. This header explicitly indicates a preference for reduced data usage, and I hope more websites start to take notice of it in the future.

The initial ‘desktop’ load may have been 6 MB, but after sitting and watching it for a minute it had climbed to 8.6 MB as the lower-priority resources and event tracking kicked into action. This page weight includes almost 1.7 MB of minified JavaScript. I don’t even want to begin to look at that.

Performance Tip #11: Use Web Workers For Your JavaScript

Which would be worse — 1.7 MB of JavaScript or 1.7 MB of images? The answer is JavaScript: the two assets are not equivalent when it comes to performance.

A JPEG image needs to be decoded, rasterized, and painted on the screen. A JavaScript bundle needs to be downloaded and then parsed, compiled, executed —and there are a number of other steps that an engine needs to complete. Be aware that these costs are not quite equivalent.
— Addy Osmani, The Cost of JavaScript in 2018

If you must ship this much JavaScript, try putting it in a web worker. This keeps the bulk of JavaScript off the main thread, which is now freed up for repainting the UI, helping your web page to stay responsive on low-powered devices.

I’m now about 15.5 MB into my budget, and have spent $1.14 of my Zimbabwe data budget. I’d have had to have worked for half a day as a teacher to earn the money to get this far.


I’ve heard good things about Pinterest’s performance, so I decided to put it to the test.

A staggering 327 requests, making 6.1 MB of data.
A staggering 327 requests, making 6.1 MB of data. (Large preview)

Perhaps this isn’t the fairest of tests; I was taken to the sign-in page, upon which an asynchronous process found I was logged into Facebook and logged me in automatically. The page loaded relatively quickly, but the requests crept up as more and more content was preloaded.

However, I saw that on subsequent page loads, the service worker surfaced much of the content — saving about half of the page weight:

8.2 / 15.6 MB resources, and 39 / 180 requests handled by the service worker cache.
8.2 / 15.6 MB resources, and 39 / 180 requests handled by the service worker cache. (Large preview)

The Pinterest site is a progressive web app; it installed a service worker to manually handle caching of CSS and JS. I could now turn off my WiFi and continue to use the site (albeit not very usefully):

Loading spinner and message saying: you're not connected to the internet
You can’t do much when you’re offline. (Large preview)
Performance Tip #12: Use Service Workers To Provide Offline Support

Wouldn’t it be great if I only had to load a website once over network, and now get all the information I need even if I’m offline?

A great example would be a website that shows the weather forecast for the week. I should only need to download that page once. If I turn off my mobile data and subsequently go back to the page at some point, it should be able to serve the last known content to me. If I connect to the internet again and load the page, I would get a more up to date forecast, but static assets such as CSS and images should still be served locally from the service worker.

This is possible by setting up a service worker with a good caching strategy so that cached pages can be re-accessed offline. The lodash documentation website is a nice example of a service worker in the wild:

Screenshot of devtools showing 'ServiceWorker' next to each request
The Lodash docs work offline. (Large preview)

Content that rarely updates and is likely to be used quite regularly is a perfect candidate for service worker treatment. Dynamic sites with ever-changing news feeds aren’t quite so well suited for offline experiences, but can still benefit.

Screenshot of Chris Ashton profile on Pinterest
The second Pinterest page load was 443 KB. (Large preview)

Service workers can truly save the day when you’re on a tight data budget. I’m not convinced the Pinterest experience was the most optimal in terms of data usage – subsequent pages were around the 0.5 MB mark even on pages with few images — but letting your JavaScript handle page requests for you and keeping the same navigational elements in place can be very performant. The BBC manages a transfer size of just 3.1 KB for return-visits to articles that are renderable via the single page application.

So far, Pinterest alone has chewed through 14 MB, which means I’ve blown around 30 MB of my budget, or $2.20 (almost a day’s wages) of my Zimbabwe budget.

I’d better be careful with my final 20 MB… but where’s the fun in that?


I picked this one because it felt noticeably sluggish on my mobile in the past and I wanted to dig into the reasons why. Sure enough, loading the homepage consumes 8.5 MB of data.

Screenshot of devtools alongside homepage
The Gamespot homepage trickled up to 8.5 MB, and a whopping 347 requests. (Large preview)

6.5 MB of this was down to an autoplaying video halfway down the page, which — to be fair — didn’t appear to download until I began scrolling. Nevertheless…

Gif screenshot of the video within my viewport
The video is clipped off-screen. (Large preview)

I could only see half the video in my viewport — the right hand side was clipped. It was also 30 seconds long, and I would wager that most people won’t sit and watch the whole thing. This single asset more than tripled the size of the page.

Performance Tip #13: Don’t Preload Video

As a rule, unless your site’s primary mode of communication is video, don’t preload it.

If you’re YouTube or Netflix, it’s reasonable to assume that someone coming to your page will want the video to auto-load and auto-play. There is an expectation that the video will chew through some data, but that it’s a fair exchange for the content. But if you’re a site whose primary medium is text and image — and you just happen to offer additional video content — then don’t preload the video.

Think of news articles with embedded videos. Many users only want to skim the article headline before moving on to their next thing. Others will read the article but ignore any embeds. And others will diligently click and watch each embedded video. We shouldn’t hog the bandwidth of every user on the assumption that they’re going to want to watch these videos.

To reiterate: users don’t like autoplaying video. As developers we only do it because our managers tell us to, and they only tell us to do it because all the coolest apps are doing it, and the coolest apps are only doing it because video ads generate 20 to 50 times more revenue than traditional ads. Google Chrome has started blocking autoplay videos for some sites, based on personal preferences, so even if you develop your site to autoplay video, there’s no guarantee that’s the experience your users are getting.

If we agree that it’s a good idea to make video an opt-in experience (click to play), we can take it a step further and make it click to load too. That means mocking a video placeholder image with a play button over it, and only downloading the video when you click the play button. People on fast connections should notice no difference in buffer speed, and people on slow connections will appreciate how fast the rest of your site loaded because it didn’t have to preload a large video file.

Anyway, back to Gamespot, where I was indeed forced to preload a large video file I ended up not watching. I then clicked through to a game review page that weighed another 8.5 MB, this time with 5.4 MB of video, before I even started scrolling down the page.

What was really galling was when I looked at what the video actually was. It was an advert for a Samsung TV! This advert cost me $0.40 of my Zimbabwe wages. Not only was it pre-loaded, but it also didn’t end up playing anywhere as far as I’m aware, so I never actually saw it.

Screenshot of the offending request
This advert wasted 5.4 MB of my precious data. (Large preview)

The ‘real’ video — the gameplay footage (in other words, the content) — wasn’t actually loaded until I clicked on it. And that ploughed through my remaining data in seconds.

That’s it. That’s my 50 MB gone. I’ll need to work another 1.5 days as a Zimbabwean schoolteacher to repeat the experience.

Performance Tip #14: Optimize For First Page Load

What’s striking is that I used 50 MB of data and in most cases, I only visited one or two pages on any given site. If you think about it, this is true of most user journeys today.

Think about the last time you Googled something. You no doubt clicked on the first search result. If you got your answer, you closed the tab, or else you hit the back button and moved onto the next search result.

With the exception of a few so-called ‘destination sites’ such as Facebook or YouTube, where users habitually go as a starting point for other activities, the majority of user journeys are ephemeral. We stumble across random sites to get the answers to our questions, never to return to those sites again.

Web development practices are heavily skewed towards optimising for repeat visitors. “Cache these assets — they’ll come in handy later”. “Pre-load this onward journey, in case the user clicks to read more”. “Subscribe to our mailing list”.

Instead, I believe we should optimize heavily for one-off visitors. Call it a controversial opinion, but maybe caching isn’t really all that important. How important can a cached resource that never gets surfaced again be? And perhaps users aren’t actually going to subscribe to your mailing list after reading just the one article, so downloading the JavaScript and CSS for the mail subscription modal is both a waste of data and an annoying user experience.

The Decline Of Proxy Browsers

I had hoped to try out Opera Mini as part of this experiment. Opera Mini is a mobile web browser which proxies web pages through Opera’s compression servers. It accounts for 1.42% of global traffic as of June 2019, according to

Opera Mini claims to save up to 90% of data by doing some pretty intensive transcoding. HTML is parsed, images are compressed, styling is applied, and a certain amount of JavaScript is executed on Opera’s servers. The server doesn’t respond with HTML as you might expect — it actually transcodes the data into Opera Binary Markup Language (OBML), which is progressively loaded by Opera Mini on the device. It renders what is essentially an interactive ‘snapshot’ of the web page — think of it as a PDF with hyperlinks inside it. Read Tiffany Brown’s excellent article, “Opera Mini and JavaScript” for a technical deep-dive.

It would have been a perfect way to eek my 50 MB budget as far as possible. Unfortunately, Opera Mini is no longer available on iOS in the UK. Attempting to visit it in the app store throws an error:

The item you've requested is not currently available in the UK Store.
(Large preview)

It’s still available “in some markets” but reading between the lines, Opera will be phasing out Opera Mini for its new app — Opera Touch — which doesn’t have any data-saving functionality apart from the ability to natively block ads.

Opera desktop used to have a ‘Turbo mode’, acting as a traditional proxy server (returning a HTML document instead of OBML), applying data-saving techniques but less intensively than Opera Mini. According to Opera, JavaScript continues to work and “you get all the videos, photos and text that you normally would, but you eat up less data and load pages faster”. However, Opera quietly removed Turbo mode in v60 earlier this year, and Opera Touch doesn’t have a Turbo mode either. Turbo mode is currently only available on Opera for Android.

Android is where all the action is in terms of data-saving technology. Chrome offers a ‘Lite mode’ on its mobile browser for Android, which is not available for iPhones or iPads because of “platform constraints“. Outside of mobile, Google used to provide a ‘Data Saver’ extension for Chrome desktop, but this was canned in April.

Lite mode for Chrome Android can be forcibly enabled, or automatically kicks in when the network’s effective connection type is 2G or worse, or when Chrome estimates the page will take more than 5 seconds to reach first contentful paint. Under these conditions, Chrome will request the lite version of the HTTPS URL as cached by Google’s servers, and display this stripped-down version inside the user’s browser, alongside a “Lite” marker in the address bar.

Screenshot showing button in toolbar denoting 'Lite' mode
‘Lite mode’ on Chrome for Android. Image: Google. (Large preview)

I’d love to try it out — apparently it disables scripts, replaces images with placeholders, prevents loading of non-critical resources and shows offline copies of pages if one is available on the device. This saves up to 60% of data. However, it isn’t available in private (Incognito) mode, which hints at some of the privacy concerns surrounding proxy browsers.

Lite mode shares the HTTPS URL with Google, therefore it makes sense that this mode isn’t available in Incognito. However other information such as cookies, login information, and personalised page content is not shared with Google — according to — and “never breaks secure connections between Chrome and a website”. One wonders why seemingly none of these data-saving services are allowed on iOS (and there is no news as to whether Lite mode will ever become available on iOS).

Data saver proxies require a great deal of trust; your browsing activity, cookies and other sensitive information are entrusted to some server, often in another country. Many proxies simply won’t work anymore because a lot of sites have moved to HTTPS, meaning initiatives such as Turbo mode have become a largely “useless feature“. HTTPS prevents this kind of man-in-the-middle behaviour, which is a good thing, although it has meant the demise of some of these proxy services and has made sites less accessible to those on poor connections.

I was unable to find any OSX or iOS compatible data-saving tool except for Bandwidth Hero for Firefox (which requires setting up your own data compression service — far beyond the technical capabilities of most users!) and skyZIP Proxy (which, last updated in 2017 and riddled with typos, I just couldn’t bring myself to trust).


Reducing the data footprint of your website goes hand in hand with improving frontend performance. It is the single most reliable thing you can do to speed up your site.

In addition to the cost of data, there are lots of good reasons to focus on performance, as described in a GOV.UK blog post on the subject:

  • 53% of users will abandon a mobile site if it takes more than 3 seconds to load.
  • People have to concentrate 50% more when trying to complete a simple task on a website using a slow connection.
  • More performant web pages are better for the battery life of the user’s device, and typically require less power on the server to deliver. A performant site is good for the environment.

We don’t have the power to change the global cost of data inequality. But we do have the power to lessen its impact, improving the experience for everyone in the process.

Smashing Editorial (yk,ra)
3 Essential Design Trends, August 2019

Each of the design trends we are spotting this month have to deal with over-the-top techniques. It’s interesting because these big effects don’t always pop on the radar of what’s trending, but these concepts almost begged to be featured with a large number of projects showcasing these design elements.

This type of trend is interested because designers either love them or hate them. Take a look and see if these are concepts you’ll use. Here’s what’s trending in design this month.

Exaggerated White Space

So much white space.

These websites feature exaggerated amounts of whitespace and strong minimal themes with very little color or design ornamentation. And if you are like me, you can’t stop looking at them.

How does a design with so little visual information work?

The design trick here is disruption. If you see one of these designs, they are vastly different than almost any other site you are visiting. That makes you stop, and look, and think about what you are seeing. With the right content it can be quite effective.

While each of the designs here use exaggerated amounts of white space and practically no color, they don’t all look the same and use complementary effects to get a message across.

VS+Company uses a subtle animation with text blocks that appear next to the oversized “POST” and “MGMT” lines. The text provides additional content and information about the website and uses a black color that makes it easy to read.

Lundqvist & Dallyn asks a question to pique user interest. The image on the home screen and throughout the scroll feature hover animations that encourage clicks.

Jillian Hobbs uses white space to help users hone in on the words – in this case project names – to interact with. It’s a risky concept for a design portfolio, but it did encourage clicking through to pages with the same visual pattern, but featuring images and color.

Sharp Edges and Lines

While brutalism has never fully taken off as a widespread design trend, it is influencing designers. Sharp edges and lines are one way that we’re seeing it manifest.

Most recently, projects have had a softer feel with gradient coloring, real images or illustrations, and softer shapes. The projects below feature more hard edges, thick lines and square shapes. These shapes can be paired with different elements to establish a feel. The result is a design trend that’s a little harder, stronger, and harsh. It almost demands that you look at it.

Future London Academy uses bold yellow and black to create the most brutalist feel of the collection. Even the typography has an edge to it.

Purple Rock Scissors has an animated twitch to the hard lines on its homepage, which creates a feeling of unease for users. Why is everything twitching and moving in this way? It almost forces you to scroll. All of the video clips on the site use the same effect, which feels a lot like what we are seeing with the TikTok social network.

The Unshift portfolio focuses on shapes and animation with almost no color to draw users in. The moving cube is intriguing and enough to generate interest.

Screen-Centered Headlines

Hero headlines aren’t a new trend at all. But have you noticed a shift in the placements of the big text on homepages?

It’s vertically and horizontally centered.

The placement makes sense when you think about it. The eye will go right to the middle of the screen and then spread out to other elements. But do you love the super symmetrical feel?

The other benefit to this design technique is for the mobile versions of websites. It fits just a nicely on a mobile screen as desktop. Conversely if the text is positioned strong to the left or right, it often has to be moved when you shift from a more horizontal to vertical screen orientation.

This is one of those neat trends that’s heavily influenced by technology and how we use and interact with devices online.

The only thing to be aware of with a trend like this is that while perfect symmetry is harmonious and visually appealing it might not work with all backgrounds or imagery. It can also start to seem somewhat boring if everyone does it.

Finally, think about the length of words and messaging. With too many characters this style can feel heavy and overwhelming and works best with short blocks of text, such as each of the featured examples below.


When it comes to over-the-top design ideas, what works for you, do you prefer color, space, or typography? While you can see some influences of these trends on each other, what makes them work is that the focus is on one strong design element.

Love these ideas or hate them, each project above has a design style that encourages users to take a second look and consider engaging with the design.

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Privacy Settings
We use cookies to enhance your experience while using our website. If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. We also use content and scripts from third parties that may use tracking technologies. You can selectively provide your consent below to allow such third party embeds. For complete information about the cookies we use, data we collect and how we process them, please check our Privacy Policy
Consent to display content from Youtube
Consent to display content from Vimeo
Google Maps
Consent to display content from Google