<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adam McKenna</title>
    <description>The latest articles on DEV Community by Adam McKenna (@adammckenna).</description>
    <link>https://dev.to/adammckenna</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F15088%2F18e78464-0bfb-4d3b-977e-3889faf7e00c.jpg</url>
      <title>DEV Community: Adam McKenna</title>
      <link>https://dev.to/adammckenna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adammckenna"/>
    <language>en</language>
    <item>
      <title>Why developers need to challenge product and design</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Tue, 11 Jan 2022 10:57:52 +0000</pubDate>
      <link>https://dev.to/adammckenna/why-developers-need-to-challenge-product-and-design-34j0</link>
      <guid>https://dev.to/adammckenna/why-developers-need-to-challenge-product-and-design-34j0</guid>
      <description>&lt;p&gt;Rare is the developer who hasn’t had to “throw away” their code. For many, discarding months of hard work has been a common, recurring theme of their career. &lt;/p&gt;

&lt;p&gt;This is how it happens: someone in management thinks they’ve identified a problem. They rally a bunch of people together — product owners and maybe a few designers — and collaboratively hash out a solution to the apparent problem.&lt;/p&gt;

&lt;p&gt;Once all the decisions are made, and the solution is ready, a development team is assembled and they’re handed the product requirements. “Build this,” they’re told. &lt;/p&gt;

&lt;p&gt;This is where the two different types of developers reveal themselves. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consider the first type of developer: the complacent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When presented with a set of requirements, the complacent developer gets straight to work without any fuss. They’ll ask questions to fully understand the requirements and debate the best technical architecture to implement them. But once that’s worked out, they’ll knuckle down for a while, emerging only once they’ve completed a system that not only matches the given requirements, but does so with clean, fully-tested and robust code.&lt;/p&gt;

&lt;p&gt;Sounds perfect, right? There’s just one problem. Those requirements that they’ve meticulously implemented often fail to actually match the user’s needs. &lt;/p&gt;

&lt;p&gt;Though the implementation may have been executed with the utmost proficiency, the developer may as well have been writing code for eskimos. That is to say, it won’t see the light of day because the fundamental requirements failed to cater to the actual user needs.&lt;/p&gt;

&lt;p&gt;Thus, we begin to see the value of &lt;strong&gt;the second type of developer: the challenger.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Like the former, the challenger asks questions to come to an understanding of the requirements. But their line of inquiry doesn’t stop there. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Once they understand what’s being asked of them, they challenge it&lt;/strong&gt;: Why are we doing this? How does this benefit the user? Where did this decision come from?&lt;/p&gt;

&lt;p&gt;The challenger refuses to take on work that they know doesn’t fit the user needs, and they’ll more often than not take it upon themselves to propose alternative solutions. Even if they don’t propose a solution, the simple act of challenging a decision can spur the product team to think about aspects of their solution that they hadn’t previously considered. &lt;/p&gt;

&lt;p&gt;In other words, the challenger doesn’t need to be a “designer” in order to improve the design. As with recovering from addiction, an awareness of a design flaw is the first step in creating a product that works for the user. More often than not, these flaws are easily rectified. But, a design flaw can’t be resolved if the designer doesn’t realise it exists.&lt;/p&gt;

&lt;p&gt;It’s also not always the case that the “complacent” developer isn’t aware of the potential flaws in the solution they’re building. Often, they are. But, for whatever reason, they refuse to speak up, and may even moan among fellow developers about the oh-so-obvious flaws in the product that they’re building.&lt;/p&gt;

&lt;p&gt;This is often because the design and product teams have historically refused to give the development team a platform to propose feedback or changes. Routinely ignoring a developer’s suggestions is possibly the most expedient route to converting a keen challenger into a complacent developer.&lt;/p&gt;

&lt;p&gt;So, while to an extent it is up to the developer as to whether they challenge a solution or fall complacent, the rest of the team need to make sure that the developer has a platform to speak, and will have their voices heard if they utilise that platform. &lt;/p&gt;

&lt;p&gt;As Donald A. Norman, director of The Design Lab at University of California, explains: “all things artificial are designed.” In that sense, anyone involved in building anything is a designer to some extent. Design isn’t just about building user interfaces or crafting interactions, it’s about creating an experience. It’s about understanding that the user is a human, and understanding all the nuances about being a human.  &lt;/p&gt;

&lt;p&gt;In that vein, anyone with a shred of empathy or even a vague understanding of human emotions will have something valuable to contribute to the design of any product. &lt;/p&gt;

&lt;p&gt;By adhering strictly to job titles and shoe-horning people into silos — in other words, artificially prohibiting a developer from design — you only serve to cut your team off from valuable insight and resource. &lt;/p&gt;

&lt;p&gt;Everyone wants to build something good. Nobody wants to finish the day at work acutely aware that all their efforts have contributed to a product that ultimately won’t see the light of day. But, no-one (well, most people, at least) wants to sit all day without anything to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That raises another thing to consider&lt;/strong&gt;: wasted resource. It’s a simple fact of software development that there isn’t always development work to do. Sometimes, the team need to take a step back from development and reconsider the design, do more research, or consider the next steps on the roadmap.&lt;/p&gt;

&lt;p&gt;But, in these hiatuses, how should developers utilise their time? &lt;/p&gt;

&lt;p&gt;In my experience, developers are doled out busy-work or told to develop future features that haven’t yet been fully tested with users — that is to say, the requirements will change. When those requirements do invariably change, the development work is then re-done. &lt;/p&gt;

&lt;p&gt;Yes, this approach keeps developers busy. But, is that really the best use of their time? I don’t think so. This problem is especially prevalent in government, when that time is paid for by the tax-payer. &lt;/p&gt;

&lt;p&gt;A better approach? Recognise that even though their job title may read “Software Engineer,” “Frontend Developer” or “Dev Ops Engineer,” they have value as designers. &lt;/p&gt;

&lt;p&gt;If you’re involved in product, include the development team in design. If you’re a developer, make sure your voice is heard. If there’s a flaw in your product’s design, let the team know. It doesn’t matter what your job title is.&lt;/p&gt;

&lt;p&gt;A final word of advice to the “challengers” out there: while I advocate challenging the work of designers and product owners on your team, you must also respect that, just like your users, your colleagues are human. They also want to do the best work they can. &lt;/p&gt;

&lt;p&gt;“When we are wrong, we may admit it to ourselves,” explains Dale Carnegie, author of &lt;em&gt;How to Win Friends and Influence People&lt;/em&gt;. “And if we are handled gently and tactfully, we may admit it to others and even take pride in our frankness and broadmindedness. But not if someone else is trying to ram the unpalatable fact down our oesophagus.” &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fast as a Veyron: Achieving 100/100 on Google PageSpeed Insights and beyond</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Sun, 23 Sep 2018 16:27:05 +0000</pubDate>
      <link>https://dev.to/adammckenna/fast-as-a-veyron-achieving-100100-on-google-pagespeed-insights-and-beyond-5ada</link>
      <guid>https://dev.to/adammckenna/fast-as-a-veyron-achieving-100100-on-google-pagespeed-insights-and-beyond-5ada</guid>
      <description>&lt;p&gt;Article originally posted &lt;a href="https://adammckenna.co.uk/articles/fast-as-a-veyron-achieving-100-100-on-google-pagespeed-insights-and-beyond" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During the years in my role as a web developer, I have built a variety of different websites and web applications, taking performance into consideration more and more with each project. I have built a number of supposedly super-fast applications, only to discover that Google didn't share my perceived optimism.&lt;/p&gt;

&lt;p&gt;Upon typing the website domain address into the &lt;a href="https://developers.google.com/speed/pagespeed/insights/" rel="noopener noreferrer"&gt;Google PageSpeed Insights&lt;/a&gt; (GPI) search bar, I would begin to bite my nails as Google began the heart wrenching analysis of said web application. Fear would turn to disappointment as I read the 'Needs Work' amber performance ratings of the desktop platform. Often, the disappointment worsened upon the discovery of the unspeakable 'Poor'red performance ratings that the mobile platform was receiving. Why were these seemingly fast websites performing so poorly in Google's eyes?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FcLYAE4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FcLYAE4h.png" title="Example of Google PageSpeed Insights rating" alt="Example of Google PageSpeed Insights rating" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reasons why I was unable to achieve 'Good' green ratings varied from project-to-project. Common examples include a lack of control over server-side performance; lack of time or budget to make the (seemingly) sizable performance improvements required or, in the early days of my career, simply a lack of understanding or inability to digest the sometimes-confusing GPI documentation advising how to configure and build a website to align with the tool's metrics.&lt;/p&gt;

&lt;p&gt;Over time, I simply accepted that my websites would never be good enough for Google. "Anyway, the tool isn't a valid measurement of a website's performance," I concluded.&lt;/p&gt;

&lt;p&gt;While my latter conclusion may hold some truth – there are certainly other web performance considerations outside the scope of PageSpeed Insights; for example, the tool fails measure website loading time (&lt;a href="https://wp-rocket.me/blog/the-truth-about-google-pagespeed-insights/" rel="noopener noreferrer"&gt;as demonstrated by Lucy Beer&lt;/a&gt;) and is even less accurate if you begin to consider user experience as a performance metric (but, this is a discussion for another time!) – I was wrong on the former conclusion.&lt;/p&gt;

&lt;p&gt;Having delved deeper and deeper into web performance, attempting to ensure that every website I build is faster than the last, and embracing a variety of web performance techniques – both new and old – it was time to show Google PageSpeed Insights that my websites &lt;em&gt;could&lt;/em&gt; be good enough. The opportunity arose in the form of a long-overdue redesign and rebuild of &lt;a href="https://adammckenna.co.uk/" rel="noopener noreferrer"&gt;personal website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With no constraints – i.e. in terms of budget, time or technology – I was able to embrace everything I have learnt and put performance at the heart of the rebuild. And, as the story goes, I was finally able to attain the dream: 100/100 score on PageSpeed Insights (and 'A' scores via &lt;a href="http://www.webpagetest.org/" rel="noopener noreferrer"&gt;WebPagetest&lt;/a&gt;, an arguably more comprehensive tool for measuring website performance and optimisation – which also measures loading time).&lt;/p&gt;

&lt;p&gt;In this article, I will discuss my experiences in the pursuit and attainment of high website performance, discussing the abstract concepts and design decisions that helped improve the performance of my website, as well as walking through the various metrics that the Google PageSpeed Insights test is comprised of with practical examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts and Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Simple UI design
&lt;/h3&gt;

&lt;p&gt;Though I have dabbled, I am certainly not a user interface designer. Yet, it seems almost common sense: the more content that is displayed on a website, the more content the browser is required to render and load. More content = higher load times.&lt;/p&gt;

&lt;p&gt;In my experience, I have found a lot of web pages – particularly website home pages – to be cluttered with any amounts of seemingly arbitrary content, trying to cram in as much as the display dimensions will allow in an effort to promote every nuance of their service.&lt;/p&gt;

&lt;p&gt;I have no doubt that some websites and web applications simply &lt;em&gt;need&lt;/em&gt; to be complex, but does not mean that my laptop screen needs to be overflowing with a sea of hero banners, videos, animations and so on? I'm not so sure. As the saying goes, less is more.&lt;/p&gt;

&lt;p&gt;So, I asked myself "what is the purpose of my website?" I had one objective: I wanted a website to post and display my articles. It was decided, then, that the website will serve to that end and no other.&lt;/p&gt;

&lt;p&gt;I adopted a &lt;a href="https://www.uxpin.com/studio/blog/a-hands-on-guide-to-mobile-first-design/" rel="noopener noreferrer"&gt;mobile-first design approach&lt;/a&gt; to design (and build) the website; starting with a simple navigation (a text-based logo and a handful of links); a very simple footer that promotes my social media accounts and, between the header and footer elements, a grid layout of articles. Nothing more. (Though I was feeling a tad rebellious and added images to the articles within the grid layout).&lt;/p&gt;

&lt;p&gt;I knew – and intended that – my design would not require any videos, heavy-duty hero banner images or complex JavaScript or CSS animations. Just good old HTML, a few thumbnail images and a sprinkle of CSS and JavaScript. It's amazing what you can achieve with very little code these days.&lt;/p&gt;

&lt;h3&gt;
  
  
  Progressive Web App
&lt;/h3&gt;

&lt;p&gt;I knew from the offset that I wanted to build the website as &lt;a href="https://developers.google.com/web/fundamentals/primers/service-workers/" rel="noopener noreferrer"&gt;Progressive Web App&lt;/a&gt; (PWA). If you're unfamiliar with the concept of a PWA, I implore you to watch &lt;a href="https://www.youtube.com/watch?v=2NZc4C7uNcU" rel="noopener noreferrer"&gt;Nicole Saidy's talk: Designing Great Progressive Web Apps&lt;/a&gt; from &lt;em&gt;.concat() 2018&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Long story short, though, a PWA is a regular website that has the added benefit of native mobile app-like interactions, including push notifications and offline support. Among the ever-growing list of reasons to build my website as a PWA was the significant web performance increases, achieved through the implementation of caching via a &lt;a href="https://developers.google.com/web/fundamentals/primers/service-workers/" rel="noopener noreferrer"&gt;JavaScript Service Worker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The nitty-gritty implementation details are out-of-the-scope of this article, but if you intend on building your website as a Progressive Web App, Google offer great documentation on the implementation of &lt;a href="https://developers.google.com/web/fundamentals/codelabs/offline/" rel="noopener noreferrer"&gt;offline support and caching via a Service Worker&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Application Shell Model
&lt;/h3&gt;

&lt;p&gt;There are a number of ways in which a Progressive Web App can be implemented and its functionality leveraged to provide a great user experience and high web performance. The architectural approach that I found most appealing was the &lt;a href="https://developers.google.com/web/fundamentals/architecture/app-shell" rel="noopener noreferrer"&gt;Application Shell Model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevelopers.google.com%2Fweb%2Ffundamentals%2Farchitecture%2Fimages%2Fappshell.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevelopers.google.com%2Fweb%2Ffundamentals%2Farchitecture%2Fimages%2Fappshell.png" alt="app-shell-model" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The approach entails delivering a cacheable "shell" of the website user interface to the user – i.e. the website layout without content – and subsequently loading the content as it becomes available (we'll touch on some of the implementation details soon).&lt;/p&gt;

&lt;h2&gt;
  
  
  The PageSpeed Insight Metrics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Avoid landing page redirects
&lt;/h3&gt;

&lt;p&gt;The first metric on the list is one of the easiest to avoid: landing page redirects. A landing page redirect is the process of a webpage redirecting the user to an alternative URL when they attempt to navigate to a given webpage URL. For example, if the user attempts to navigate to &lt;code&gt;example.com&lt;/code&gt;, but is then redirected to &lt;code&gt;m.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is a reason this metric is still evaluated as part of the GPI. The implementation of landing page redirects has a handful of common and practical use cases.&lt;/p&gt;

&lt;p&gt;The most common use of landing page redirects is the redirection of users who navigate to a URL prefaced with '&lt;a href="http://www.'" rel="noopener noreferrer"&gt;www.&amp;amp;#39&lt;/a&gt;; to the 'non-www' version of the website, or vice versa. For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;adammckenna.co.uk&lt;/code&gt; redirected to &lt;code&gt;www.adammckenna.co.uk&lt;/code&gt;&lt;br&gt;
&lt;code&gt;www.adammckenna.co.uk&lt;/code&gt; redirected to &lt;code&gt;adammckenna.co.uk&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this is a nice touch – and supposedly has &lt;a href="https://moz.com/blog/301-redirection-rules-for-seo" rel="noopener noreferrer"&gt;positive connotations for SEO&lt;/a&gt; – it will slightly impede the website performance for those unfortunate enough to browse to the version of the website that is being redirected from. But, while I personally avoided this redirect in my website, there is certainly a valid use case for it – especially if SEO is a major concern.&lt;/p&gt;

&lt;p&gt;Another common use of redirects is the (now-medieval) practise of redirecting mobile users to an entirely separate website built for mobile users, which is typically hosted on an 'm' subdomain. For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;adammckenna.co.uk&lt;/code&gt; redirected to &lt;code&gt;m.adammckenna.co.uk&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before the mainstream adoption of &lt;a href="https://www.smashingmagazine.com/2011/01/guidelines-for-responsive-web-design/" rel="noopener noreferrer"&gt;responsive web design&lt;/a&gt;, the practise of redirecting mobile users to a separate website was commonplace. Nowadays, though, it is frowned upon by the entire web community and everyone unfortunate enough to have experienced a redirect.&lt;/p&gt;

&lt;p&gt;Not only does this practise cause performance issues in terms of redirects, it has a &lt;a href="https://alistapart.com/article/responsive-web-design" rel="noopener noreferrer"&gt;plethora of negative implications&lt;/a&gt; (&lt;a href="https://www.smashingmagazine.com/2012/04/why-we-shouldnt-make-separate-mobile-websites/" rel="noopener noreferrer"&gt;see also&lt;/a&gt;). The verdict is clear: the 'm' subdomain is a relic of the past.&lt;/p&gt;

&lt;p&gt;As such, I built my personal website as a responsive website, following the principles – well, the ones that are still relevant – established in Ethan Marcotte's ground-breaking book, &lt;a href="https://abookapart.com/products/responsive-web-design" rel="noopener noreferrer"&gt;Responsive Web Design&lt;/a&gt;. No 'm' subdomain redirect.&lt;/p&gt;

&lt;p&gt;There are a number of other use-cases for redirects – for example, you simply cannot avoid a redirect if the website has several domain addresses for the same website or if the website is available in multiple languages – but, unless absolutely unavoidable, I would suggest leaving the redirects on the top-level shelf.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eliminate render-blocking JavaScript and CSS in above-the-fold content
&lt;/h3&gt;

&lt;p&gt;When a browser requests a webpage, it begins to build up a DOM tree. Before the page can be rendered, the DOM tree must be fully built. Seems simple enough.&lt;/p&gt;

&lt;p&gt;However, as part of the DOM building process, when the browser parser encounters an external &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; or stylesheet resource, it halts parsing the page until the relevant resource has been executed.&lt;/p&gt;

&lt;p&gt;Further still, many websites rely on external resources hosted elsewhere – e.g. 3rd party JavaScript packages, Google Fonts or content delivery network (CDN) resources – and when the parser encounters these external resources, it must also wait for the file to download before it can be executed.&lt;/p&gt;

&lt;p&gt;Often, scripts and stylesheets grow to become &lt;em&gt;huge&lt;/em&gt; documents, leading to notable bottlenecks during the page rendering process. Combined with a lax use of Google Fonts and other external resources, render-blocking can start to take a large toll on website performance.&lt;/p&gt;

&lt;p&gt;In my case, I was requesting a large stylesheet and moderately-sized scripts file – albeit both were minified (a process we will touch on soon) – alongside an external Google Font with four weights and an external Google Analytics script. Though my website's use of resources was light in contrast to many popular websites, even these resources caused substantial loading latency.&lt;/p&gt;

&lt;p&gt;I needed a solution. I needed to load my resources asynchronously with the page rendering – but how?&lt;/p&gt;

&lt;p&gt;Back yonder, this may have been a monumental task. Thankfully, though, we live in a decade wherein the HTML spec is being developer faster than ever. With each new release comes easier, more efficient ways to achieve complex functionality.&lt;/p&gt;

&lt;p&gt;One such addition to the HTML spec is the new ability to preload content via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content" rel="noopener noreferrer"&gt;'preload' value for the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element's &lt;code&gt;rel&lt;/code&gt; attribute&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The new preload value has a &lt;a href="https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/" rel="noopener noreferrer"&gt;number of benefits over its precursors&lt;/a&gt;, but ultimately it lets the browser load resources – those pesky stylesheets, scripts and external files – without blocking the rendering the web page's DOM tree. We can now &lt;em&gt;natively&lt;/em&gt; load our resources asynchronously. What a time to be alive!&lt;/p&gt;

&lt;p&gt;The syntax is amazingly simple, too (the following is an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content" rel="noopener noreferrer"&gt;example from MDN&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  &amp;lt;meta charset="utf-8"&amp;gt;
  &amp;lt;title&amp;gt;JS and CSS preload example&amp;lt;/title&amp;gt;

  &amp;lt;link rel="preload" href="style.css" as="style"&amp;gt;
  &amp;lt;link rel="preload" href="main.js" as="script"&amp;gt;

  &amp;lt;link rel="stylesheet" href="style.css"&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;bouncing balls&amp;lt;/h1&amp;gt;
  &amp;lt;canvas&amp;gt;&amp;lt;/canvas&amp;gt;

  &amp;lt;script src="main.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;link rel="stylesheet"&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags are included as standard. But, before that, some &lt;code&gt;&amp;lt;link rel="preload' as="x" href="y"&amp;gt;&lt;/code&gt; tags are also included for each resource that is being included. In the above example, we're loading in a &lt;code&gt;style.css&lt;/code&gt; stylesheet and a &lt;code&gt;main.js&lt;/code&gt; script, so we need a separate &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; for each resource.&lt;/p&gt;

&lt;p&gt;If you're thinking this seems too good to be true then, well… you'd be &lt;em&gt;a little bit&lt;/em&gt; right. There is one teeny, tiny problem: browser support.&lt;/p&gt;

&lt;p&gt;As the time of writing, the new preload value is only fully supported in Chrome, Safari and a handful of mobile browsers. That means no Firefox or Internet Explorer (surprise, surprise) support, and even MS Edge only offers partial support.&lt;/p&gt;

&lt;p&gt;Of course, since we have the regular references to the style and script resources, as well as the new &lt;code&gt;rel="preload"&lt;/code&gt; meta tags, the resources will load regardless. We just won't see the benefit of preload – and this just isn't great news.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://github.com/filamentgroup/loadCSS" rel="noopener noreferrer"&gt;loadCSS&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;loadCSS is a polyfill for browsers that do not yet support &lt;code&gt;rel=preload&lt;/code&gt;, and can be implemented with relative ease.&lt;/p&gt;

&lt;p&gt;Firstly, to use loadCSS, we need to include the &lt;a href="https://github.com/filamentgroup/loadCSS/blob/master/src/cssrelpreload.js" rel="noopener noreferrer"&gt;loadCSS preload polyfill script&lt;/a&gt; somewhere in website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to include a slightly amended &lt;code&gt;&amp;lt;link rel=”…”&amp;gt;&lt;/code&gt; tag. When leveraging loadCSS, it is recommended that a single &lt;code&gt;&amp;lt;link rel=”preload”&amp;gt;&lt;/code&gt; tag is used, instead of using both &lt;code&gt;rel=”preload”&lt;/code&gt; and &lt;code&gt;rel=”style”&lt;/code&gt; tags as per our previous example, because otherwise the browser will  only &lt;strong&gt;fetch&lt;/strong&gt; the stylesheet and will not &lt;strong&gt;apply&lt;/strong&gt; it to the page.&lt;/p&gt;

&lt;p&gt;We can convert the &lt;code&gt;rel=preload&lt;/code&gt; value to &lt;code&gt;rel=stylesheet&lt;/code&gt; once the resource has loaded by leveraging the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element's native &lt;code&gt;onload&lt;/code&gt; event. This also has the added benefit of reducing the amount of markup we actually need to write.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-— our local stylesheet. --&amp;gt;
&amp;lt;link rel="preload" href="path/to/style.css" as="style" onload=" this.rel='stylesheet'"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also recommended that the value of the &lt;code&gt;onload&lt;/code&gt; attribute is changed to &lt;code&gt;null&lt;/code&gt; within the &lt;code&gt;onload&lt;/code&gt; handler (onload-ception) because some browsers will re-call the handler when the &lt;code&gt;rel&lt;/code&gt; attribute's value is switched from &lt;code&gt;preload&lt;/code&gt; to &lt;code&gt;style&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!—- our local stylesheet. --&amp;gt;
&amp;lt;link rel="preload" href="path/to/style.css" as="style" onload="this.onload=null; this.rel='stylesheet'"&amp;gt;

&amp;lt;!—- we can also apply the same logic to external stylesheets, such as Google Fonts --&amp;gt;
&amp;lt;link rel="preload" href="https://fonts.googleapis.com/css?family=Muli:300,300i,400,400i,600" as="style" onload="this.onload=null; this.rel='stylesheet'"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, we also need to think about those users who do not have JavaScript enabled and, since the &lt;code&gt;onload&lt;/code&gt; handler requires JavaScript, we need a fallback. We can easily provide such a fallback via the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-— for users with JavaScript disabled --&amp;gt;
&amp;lt;noscript&amp;gt;
    &amp;lt;link rel="stylesheet" href="path/to/style.css"&amp;gt;
    &amp;lt;link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Muli:300,400,400i,600"&amp;gt;
&amp;lt;/noscript&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, loadCSS is ready to do what it does best: load our CSS. Here's our complete code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="preload" href="path/to/style.css" as="style" onload="this.onload=null; this.rel='stylesheet'"&amp;gt;
&amp;lt;link rel="preload" href="https://fonts.googleapis.com/css?family=Muli:300,300i,400,400i,600" as="style" onload="this.onload=null; this.rel='stylesheet'"&amp;gt;

&amp;lt;noscript&amp;gt;
    &amp;lt;link rel="stylesheet" href="path/to/style.css"&amp;gt;
    &amp;lt;link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Muli:300,400,400i,600"&amp;gt;
&amp;lt;/noscript&amp;gt; 

&amp;lt;script&amp;gt;
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our small snippet of code, we are able to asynchronously load our CSS across a plethora of browsers, regardless of whether the browser supports &lt;code&gt;rel="preload"&lt;/code&gt;, and we can still deliver our resources to users who do not have JavaScript enabled.&lt;/p&gt;

&lt;p&gt;Though confident that the stylesheets and scripts were no longer causing any trouble blocking the page rendering, I was not quite done with the above-the-fold issue.&lt;/p&gt;

&lt;p&gt;My stylesheet was still a behemoth of a file, and there was no priority given to the styles that pertained to the above-the-fold elements of my webpage. For that, another solution was necessary. It's time to explore the Application Shell Model Architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prioritise visible content (via the Application Shell Model Architecture)
&lt;/h3&gt;

&lt;p&gt;Instead of loading all of the website styles in a single request – potentially wasting valuable loading time rendering CSS that isn't even visible to the user initially, e.g. the footer, content from other pages, etc. – we can prioritise the styles for &lt;a href="http://www.webvanta.com/post/2014-07-06/responsive-design-above-the-fold" rel="noopener noreferrer"&gt;above-the-fold&lt;/a&gt; elements – i.e. any elements that will be visible as the website initially loads. In my case, my above-the-fold elements consisted of the website header, navigation and the 'article grid'.&lt;/p&gt;

&lt;p&gt;This is where the Application Shell Model comes in. The Application Shell Model is one of several solutions to ensure that the delivery of visible content is prioritised to the user. As outlined earlier in the Application Shell Model section, the approach focuses on the serving the layout styles to the user first, then loading in the content styles secondarily.&lt;/p&gt;

&lt;p&gt;We can take this a step further by ensuring that not only the layout styles are included in the prioritised styles, but we can focus on only delivering the styles for the layout that is above-the-fold. Doing so will ensure our prioritised styles are as minimal as possible, delivering the shell of the website to the user as fast as possible.&lt;/p&gt;

&lt;p&gt;Enough theory. How do we actually implement our Application Shell Model?&lt;/p&gt;

&lt;p&gt;The implementation was easier than you might expect. I simply needed to separate the styles that pertained to the above-the-fold elements, by removing them from the website's main stylesheet and embedding them into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the website. Those prioritised styles will be rendered straight away, while any styles retained in the main stylesheet, relating to content and elements below-the-fold, can afford to be rendered later.&lt;/p&gt;

&lt;p&gt;It all seemed simple enough in theory. Then I remembered that I was using &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;; &lt;a href="https://github.com/Shopify/liquid" rel="noopener noreferrer"&gt;Liquid&lt;/a&gt; (a templating engine); build tools and task runners. Things got messy rather quickly.&lt;/p&gt;

&lt;p&gt;I needed to embed specific styles from my Sass which, at this point, was being compiled into a single stylesheet. Thankfully, though, I had structured the website Sass in alignment with the &lt;a href="https://blog.alexdevero.com/atomic-design-scalable-modular-css-sass/" rel="noopener noreferrer"&gt;Atomic Design methodology&lt;/a&gt;, which ensured that my styles were finely de-coupled.&lt;/p&gt;

&lt;p&gt;To implement the separation of prioritised and non-prioritised styles, I needed to compile two stylesheets – one that would provide the CSS that would be embed in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the website, and another with the content and below-the-fold styles that would be loaded in afterwards via &lt;code&gt;&amp;lt;link rel="stylesheet"&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, simply enough, a second Sass file was created – creatively called 'inline.scss', alongside the pre-existing 'style.scss' master stylesheet. The file imports from the &lt;code&gt;style.scss&lt;/code&gt; that pertained to the above-the-fold elements were moved to the 'inline' stylesheet to be embedded in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A small problem: I had a handful of Sass 'settings' files that consisted of variables (for colours, breakpoints, etc.) and mixins. I quickly realised that both of the stylesheets would still require access to all of these 'settings' files, or else I would have to start hardcoding values.&lt;/p&gt;

&lt;p&gt;Therefore, a third file was required – which I named 'master.scss' – which imports the Sass resources that were mutually required between the 'inline' and 'style' Sass files – i.e. the settings files – and subsequently imported the 'master' Sass resource into both stylesheets.&lt;/p&gt;

&lt;p&gt;Great. Now that the styles were separated, I needed to figure out how I could serve from the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the website.&lt;/p&gt;

&lt;p&gt;The first obvious klaxon-horn-inducing solution I thought of was to just manually copy the styles into the head of the website. &lt;em&gt;How elegant&lt;/em&gt;. While yes, it would functionally achieve the desired outcome, it would come with a myriad of implications.&lt;/p&gt;

&lt;p&gt;This approach would be a nightmare to maintain since any changes in the relevant Sass files would have to be manually coped into the head. Hypothetically, even if it wasn't a maintainability nightmare, duplicate code would have to be commit to the Git repo, since the styles that would be embedded in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; would already exist in the respective Sass files. This solution would never be feasible.&lt;/p&gt;

&lt;p&gt;The second solution devised was to leverage the project's task runner – which, in this case, was &lt;a href="https://gulpjs.com/" rel="noopener noreferrer"&gt;Gulp&lt;/a&gt; (though &lt;a href="https://gruntjs.com/" rel="noopener noreferrer"&gt;Grunt&lt;/a&gt; would have been ample for the task too) – to inject the content of the complied inline CSS file into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; during the build process. This seemed more realistic, and the implementation was pretty straight forward.&lt;/p&gt;

&lt;p&gt;First, in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the website I included an arbitrary &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag that is replaced with the embedded styles during the Gulp build process:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;link href="inline.css"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I then created a Gulp task to replace the arbitrary &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag with the styles. The Gulp task leverages the &lt;a href="https://www.npmjs.com/package/file-system" rel="noopener noreferrer"&gt;file-system&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/gulp-replace" rel="noopener noreferrer"&gt;gulp-replace&lt;/a&gt; npm packages. Gulp, and the relevant packages, can be installed via the CLI with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i gulp gulp-replace fs --save-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's have a look at the task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// instantiate the relevant packages
const gulp = require('gulp')
const fs = require('fs')
const replace = require('gulp-replace')

// The Gulp task “generates” the header of the website; in my case it finds the 
// “src” header file (located in "_includes/header.html”), subsequently finds the
// “&amp;lt;link href="inline.css"&amp;gt;” tag and replaces it with the contents of the 
// inline.css stylesheet. The generated header is then stored 
// in the "_includes/build" directory
gulp.task('generate-header', () =&amp;gt; {
    return gulp.src("_includes/header.html")
        .pipe(replace(/&amp;lt;link href="inline.css"[^&amp;gt;]*&amp;gt;/, (s) =&amp;gt; {
            let style = fs.readFileSync("build/css/inline.css", 'utf8')
            return '&amp;lt;style&amp;gt;\n' + style + '\n&amp;lt;/style&amp;gt;'
        }))
        .pipe(gulp.dest("_includes/build"))
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CSS file to which the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag &lt;code&gt;href&lt;/code&gt; attribute refers to does not exist; the decision to use this tag was arbitrary. Any tag could have been used. For example, I could have instead included:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;meta id="embedded-styles"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then in the Gulp task, the syntax &lt;code&gt;replace(/&amp;lt;meta id="embedded-styles"[^&amp;gt;]\*&amp;gt;/ …&lt;/code&gt; could have been used instead of &lt;code&gt;replace(/&amp;lt;link href="inline.css"[^&amp;gt;]\*&amp;gt;/ …&lt;/code&gt;. The outcome would have been the same: the tag being replaced with the content of my &lt;code&gt;inline&lt;/code&gt; stylesheet.&lt;/p&gt;

&lt;p&gt;And that's it! With that, the website's above-the-fold styles were embedded in the head, I included the generated &lt;code&gt;header.html&lt;/code&gt; file in my &lt;code&gt;.gitignore&lt;/code&gt; so there was no duplication in the Git repo and the entire process was automated. The remainder of my styles were retained in a separate style sheet that was being served asynchronously and no longer blocked the page from rendering.&lt;/p&gt;

&lt;p&gt;In my experience, addressing the issues of render-blocking and above-the-fold prioritisation were certainly the most time-consuming and difficult aspects of the website performance optimisation process, but were certainly the most fruitful. If there is only one thing you take away from this article, make it these sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable compression
&lt;/h3&gt;

&lt;p&gt;Okay! Now we have got the big guns out of the way, let's focus on some quick and easy wins, starting with compression.&lt;/p&gt;

&lt;p&gt;In the context of PageSpeed Insights, compression refers to a nifty package called &lt;a href="https://www.gzip.org/" rel="noopener noreferrer"&gt;gzip&lt;/a&gt; which, despite the fact its website and logo look straight out of the 90s, is a very popular and commonly used package to increase website performance.&lt;/p&gt;

&lt;p&gt;Gzip works on the server side, compressing website resources into a zipped format and serving them to the browser. In turn, the browser unzips the resources and presents them to the end user. These zipped resources typically have dramatically smaller file sizes, vastly reducing server download time.&lt;/p&gt;

&lt;p&gt;For more information on gzip's technical details, and the interaction between the server and client browser, check out both &lt;a href="https://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; and &lt;a href="http://blog.servergrove.com/2014/04/14/gzip-compression-works/" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, surely there are no doubts about the incredible benefit of gzip. All that remains is the lingering question: how the hell do I get it working with my website?&lt;/p&gt;

&lt;p&gt;Since gzip is a server-side technology, the implementation actually depends on what software your web server is running. Chances are, you're working with Apache, ngnix or IIS, so here's some guidance for each platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knackforge.com/blog/karalmax/how-enable-gzip-compression-apache" rel="noopener noreferrer"&gt;Apache – How to enable gzip compression in Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://easyengine.io/tutorials/nginx/enable-gzip/" rel="noopener noreferrer"&gt;Ngnix – Enable gzip compression on ngnix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://help.accusoft.com/PCC/v10.4/HTML/How%20to%20Enable%20Gzip%20Compression%20in%20IIS%20on%20Windows.html" rel="noopener noreferrer"&gt;IIS – Enabling Gzip Compression in IIS on Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Leverage browser caching
&lt;/h3&gt;

&lt;p&gt;Let's move onto browser caching.&lt;/p&gt;

&lt;p&gt;Every resource – whether a stylesheet, script, image or something other resource – that is requested from a web server by the browser when loading a web page delays the processing and rendering of the webpage, as well as consuming more and more of the user's data allowance. The latter can be particularly devastating to mobile users with limited data or expensive data usage rates – remember: data costs are often much higher outside of Europe, the United States and other 'western' nations.&lt;/p&gt;

&lt;p&gt;When you consider that many of the resources used throughout a website are shared across multiple web pages throughout the website, the idea of re-requesting each resource every time a new page is loaded is a waste of time (in terms of processing and rendering) and data (let's help our users save some money!).&lt;/p&gt;

&lt;p&gt;Instead, wouldn't it be easier if the resources that have already been loaded, whether in the user's current session, or in a previous interaction with the website, could be simply just &lt;em&gt;re-used&lt;/em&gt;? That's exactly what browser caching allows.&lt;/p&gt;

&lt;p&gt;To enable browser caching, a caching policy needs to be defined to identify how long a given resource should be cached for. You can tell the browser, for example: "I want .jpg, .png and .svg images to be cached for one year; HTML and CSS resources to be cached for one month…" and so on. You could even set a caching policy for an individual resource, if necessary.&lt;/p&gt;

&lt;p&gt;Just like compression, the browser caching policy is operated server-side, meaning the implementation is dependent upon the software your web server is running. Here's some guidance for the big three platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://varvy.com/pagespeed/leverage-browser-caching.html" rel="noopener noreferrer"&gt;Apache – Leverage Browser Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scotch.io/@leaderinternet/how-to-quickly-leverage-browser-caching-on-nginx" rel="noopener noreferrer"&gt;Nginx – How To Quickly Leverage Browser Caching on Nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.janjonas.net/2011-08-21/microsoft-iis-7-enable-client-side-browser-caching-static-content-web-config" rel="noopener noreferrer"&gt;IIS - Enable Client Side Browser Caching for static Content in Web.config&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, we're not done there. Though the above steps will accommodate for 99.9% of your website's resources, there is one caveat: third-party resources. The browser caching policy for resources loaded from external servers is handled by the server that provides the resource. Often, this isn't a problem, as most CDN providers recognise the benefit of caching policy.&lt;/p&gt;

&lt;p&gt;There is one organisation that, in the most ironic of fashions, seems to not recognise the benefit of a good caching policy. One organisation that offer a package that is enormously popular on the web. That organisation is Google.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://analytics.google.com/analytics/web/#/report-home/a108634322w162315639p163326671" rel="noopener noreferrer"&gt;Google Analytics&lt;/a&gt;, the widely popular web analytics platform, is served by an external JavaScript resource that, when validated via the Google PageSpeed Insights, will prompt an error for a rubbish caching policy. Google are invalidating the use of their own resource.&lt;/p&gt;

&lt;p&gt;While this may seem counterintuitive, there is method in the madness. The caching policy for this particular resource is so lax because Google want to ensure that users are always using the latest version of their script, even if the script has just been updated. They do not want an outdated version of analytics to be cached in a user's browser for, say, three months, especially if the outdated script no longer tracks the user due to breaking changes.&lt;/p&gt;

&lt;p&gt;Even with that in mind, there is a solution: a package called &lt;a href="https://github.com/jehna/ga-lite" rel="noopener noreferrer"&gt;ga-lite&lt;/a&gt;. The package serves the Google Analytics script via the &lt;a href="https://www.jsdelivr.com/" rel="noopener noreferrer"&gt;jsdelivr.net CDN&lt;/a&gt; with a more "performance-friendly" caching policy. So, instead of including the Google Analytics script in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your website, you include the ga-lite script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
(function(e,t,n,i,s,a,c){e[n]=e[n]||function(){(e[n].q=e[n].q||[]).push(arguments)}
;a=t.createElement(i);c=t.getElementsByTagName(i)[0];a.async=true;a.src=s
;c.parentNode.insertBefore(a,c)
})(window,document,"galite","script","https://cdn.jsdelivr.net/npm/ga-lite@2/dist/ga-lite.min.js");

// Replace UA-XXXXXXXX-X' with your own Analytics tracking code
galite('create', 'UA-XXXXXXXX-X', 'auto');
galite('send', 'pageview');
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy! Now, in complete honesty, you won't find any notable performance increases from the use of this package, but if you &lt;em&gt;really&lt;/em&gt; want to achieve a 100/100 score via PageSpeed Insights and you also want to use Google Analytics, then this may be your best bet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce server response time
&lt;/h3&gt;

&lt;p&gt;In the past, server response time was a consideration that was completely out of my control: the stakeholder for whom the website was being developed often dictated the server wherein the website would be hosted. More often than not, the clients would opt for cost-effective shared hosting solutions provided by the likes of &lt;a href="https://www.123-reg.co.uk/" rel="noopener noreferrer"&gt;123 Reg&lt;/a&gt;, &lt;a href="https://godaddy.com/" rel="noopener noreferrer"&gt;GoDaddy&lt;/a&gt; and &lt;a href="https://www.1and1.com/" rel="noopener noreferrer"&gt;1&amp;amp;1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These solutions are great for many people and certainly have a wide target audience: they offer cost-effective hosting solutions and require absolutely no server configuration. But, for people looking to get the absolute maximum out of their web server, they are limited: these organisations typically provide very few server customisation or configuration options and offer average-at-best performance.&lt;/p&gt;

&lt;p&gt;I recently went down an alternative route: cloud hosting via &lt;a href="https://www.linode.com/" rel="noopener noreferrer"&gt;Linode&lt;/a&gt;. Linode, much like the service's main competitor &lt;a href="https://www.digitalocean.com/" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt;, offer a vastly different experience to the aforementioned services. They strip away the customer-friendly pre-configured web servers and provide users with access to a web server (there are varying specifications available depending on requirements) wherein the user is required to install and configure everything: the OS, the web hosting stack (in my case, &lt;a href="https://www.debian.org/releases/jessie/" rel="noopener noreferrer"&gt;Debian 8&lt;/a&gt; with a classic &lt;a href="https://www.liquidweb.com/kb/what-is-a-lamp-stack/" rel="noopener noreferrer"&gt;LAMP stack&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Though this alternative route is certainly more work than the former options, there is one crucial contextual benefit: a significantly increased server response time. Even the most basic package that Linode offers has a significantly reduced response time when compared to the average GoDaddy or 1&amp;amp;1 hosting packages; a reduced server response time means that the browser can receive resources from the web server faster and will spend less time waiting for an opportunity to begin rendering the web page.&lt;/p&gt;

&lt;p&gt;Opting for Linode over the likes of GoDaddy or 1&amp;amp;1 was a major contributor towards achieving the 100/100 source via PageSpeed Insights. (And no, unfortunately I am not being paid by Linode to promote their service – it's just a great service).&lt;/p&gt;

&lt;h3&gt;
  
  
  Minify HTML, CSS and JavaScript
&lt;/h3&gt;

&lt;p&gt;Right – no more server stuff, I promise. Let's get back to some trusty HTML, CSS and JavaScript. In the eliminating render-blocking and prioritising visible content sections of this article, we already explored how we can write and structure our client-side code to optimise performance, but there is a much quicker way we can take that optimisation even further – &lt;a href="https://developers.google.com/speed/docs/insights/MinifyResources" rel="noopener noreferrer"&gt;minification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Minification is the process of reducing and compressing the contents of a resource (typically HTML, CSS and JavaScript) as much as possible, while still ensuring the resource still functions as originally intended.&lt;/p&gt;

&lt;p&gt;The process parses the resource and removes code comments, spaces, formatting, unused code and reduces the length of variable names, among other things. The result is a resource left in an almost unreadable state. But, while a human cannot (easily) read a minified resource, the browser has absolutely no trouble reading the resource – in fact, it reads it much faster.&lt;/p&gt;

&lt;p&gt;After all, those comments, spaces, formatting and descriptive variable names are only there for the sake of code readability. Once removed, the file size is dramatically reduced, meaning the time required to request the resource from the server is reduced, reducing the time necessary to render the relevant webpage.&lt;/p&gt;

&lt;p&gt;How can we actually minify our HTML, CSS and JavaScript, though? I remember, when I first discovered minification, I had stored two separate files: the source file and the minified version of the source file. Every time I made a change to a resource, I would need to manually copy and paste my styles and scripts from the source file into an online minification tool, such as &lt;a href="https://csscompressor.com/" rel="noopener noreferrer"&gt;CSS Compressor&lt;/a&gt; or JSCompress then copy the minified results into the minified file… and what a chore it was.&lt;/p&gt;

&lt;p&gt;In more recent years, I have been using Gulp to automatically generate a minified version of my stylesheets and scripts every time a change is made. Sure, I still have two files, but instead of having to do anything manually, I simply run Gulp, edit my styles and scripts, and let Gulp do the hard work. My HTML pages are, of course, always requesting the generated minified versions of the files, while I continue to work on the source versions.&lt;/p&gt;

&lt;p&gt;Let's have a look at my Gulp task for minifying my CSS. Alongside Gulp, I am leveraging &lt;a href="https://www.npmjs.com/package/gulp-shorthand" rel="noopener noreferrer"&gt;gulp-shorthand&lt;/a&gt;, which merges and reduces the length of certain CSS declarations, and &lt;a href="https://www.npmjs.com/package/gulp-cssnano" rel="noopener noreferrer"&gt;gulp-cssnano&lt;/a&gt;, which minifies the file. Gulp, and the relevant packages, can be installed via the CLI with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i gulp gulp-shorthand gulp-cssnano --save-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's have a look at the task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp')
const shorthand = require('gulp-shorthand')
const cssnano = require('gulp-cssnano')

gulp.task('css', () =&amp;gt; {
    return gulp.src('src/css/**/*.css')
        .pipe(shorthand())
        .pipe(cssnano())
        .pipe(gulp.dest('build/css'))
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gulp works great for minification (along with a million other things) but there is an even simpler way to achieve site-wide minification of your HTML, CSS and JavaScript – and it doesn't even require a single line of code.&lt;/p&gt;

&lt;p&gt;Answer: &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cloudflare is a free service (with premium options) that offers so much that I won't get into the details of their entire service. But, among their many functions, Cloudflare serves as a powerful &lt;a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/" rel="noopener noreferrer"&gt;content delivery network (CDN)&lt;/a&gt; that serves as a middleman between the web server and the browser.&lt;/p&gt;

&lt;p&gt;A CDN is a collection of geographically distributed servers working in conjunction to deliver content to users faster. Unlike a typical web server, the CDN can deliver resources from a server in their vast network that is most geographically close to the end user, significantly reducing request times for users that may be far away from the website's web server.&lt;/p&gt;

&lt;p&gt;In addition to serving as a CDN, Cloudflare also offers several general options to increase the 'speed' of the website it is serving. Though most of these options are only available to premium users, free users get access to 'Auto Minify' features – Cloudflare will automatically minify your HTML, CSS and JavaScript with the click of a checkbox. No manual work; no code and no build tools. It doesn't get better than that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNUcvsCO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FNUcvsCO.png" alt="cloudflare" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, Cloudflare is free and lets users serve as many websites as desired. It also offers a plethora of other useful features, including SSL, security and caching. In other words, it is a no-brainer. (And again, no, unfortunately I am not being paid by Cloudflare to promote their services – it's just a great service).&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimize images
&lt;/h3&gt;

&lt;p&gt;Phew. Almost there. While I may not have saved best till last – I've certainly saved easiest till last: image optimisation. Broadly, this recommendation is simple: ensure that the images used throughout a website have the smallest file sizes possible.&lt;/p&gt;

&lt;p&gt;There are a number of ways wherein this can be achieved, and the steps different depending on whether the image is a &lt;a href="https://vector-conversions.com/vectorizing/raster_vs_vector.html" rel="noopener noreferrer"&gt;bitmap (.jpg, .png or .gif) or a vector (.svg)&lt;/a&gt; image.&lt;/p&gt;

&lt;p&gt;I have already discussed &lt;a href="https://dev.to/adammcquiff/how-and-why-to-clean-svg-markup-49i"&gt;the optimisation of .svg images&lt;/a&gt; in a separate article, so I will not go into too much detail here.&lt;/p&gt;

&lt;p&gt;Let's explore some recommendations for bitmap image optimisation.&lt;/p&gt;

&lt;p&gt;The first step to ensure a reduced file size is ensuring appropriate image dimensions. For example, if an image is going to be used as the background for a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element that has a width of 800px, there is absolutely no reason for that image to have a width of 1920px. Surely an image width of 800px would suffice?&lt;/p&gt;

&lt;p&gt;There are caveats to this logic, of course. The responsive web is known for being, well… &lt;em&gt;responsive&lt;/em&gt;. It is often the case that the container that the image is a background of has no pre-defined width, and can range from a width of 0px to a width of 4000px (okay, that might be a tad extreme, but you get the idea). With that in mind, I advocate the approach generally and advise that it is applied as appropriate.&lt;/p&gt;

&lt;p&gt;Once the bitmap has appropriate dimensions (or doesn't, whatever), there are a number of routes we can take to optimise it even further.&lt;/p&gt;

&lt;p&gt;The first approach is manual optimisation via compression tools. There are a number of desktop applications available for both Windows (&lt;a href="https://nikkhokkho.sourceforge.io/static.php?page=FileOptimizer" rel="noopener noreferrer"&gt;FileOptimizer&lt;/a&gt;, for example) and MacOS (such as the very popular &lt;a href="https://imageoptim.com/mac" rel="noopener noreferrer"&gt;ImageOptim&lt;/a&gt;), as well as a plethora of online compression tools (popular examples include &lt;a href="https://imagecompressor.com/" rel="noopener noreferrer"&gt;ImageCompressor&lt;/a&gt; for .jpg and .png images; &lt;a href="https://jakearchibald.github.io/svgomg/" rel="noopener noreferrer"&gt;SVGGOM&lt;/a&gt; for .svg images).&lt;/p&gt;

&lt;p&gt;Assuming that your project has only a handful of images, the manual approach should be manageable. But, what happens when you're working with a project that contains thousands of images, or maybe even tens of thousands? Unless you're planning on losing a few weeks of your life, you're probably going to be looking for an automated solution.&lt;/p&gt;

&lt;p&gt;Once again, our trusty task-running friend Gulp comes to save the day.&lt;/p&gt;

&lt;p&gt;In my project, I was able to create two Gulp tasks – one for bitmaps, one for vectors – that would routinely inspect the project directory and, when an image of the respective format was added to the project, would automatically run the relevant task, compress the image and save it to a 'build' directory.&lt;/p&gt;

&lt;p&gt;One last time, let's explore the Gulp task. The task uses two packages: &lt;a href="https://www.npmjs.com/package/gulp-imagemin" rel="noopener noreferrer"&gt;gulp-imagemin&lt;/a&gt; for bitmap minification and &lt;a href="https://www.npmjs.com/package/gulp-svgmin" rel="noopener noreferrer"&gt;gulp-svgmin&lt;/a&gt; for vector minification. Gulp, and the relevant packages, can be installed via the CLI with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i gulp gulp-imagemin gulp-svgmin --save-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's look at the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gulp = require('gulp')
const imagemin = require('gulp-imagemin')
const svgmin = require('gulp-svgmin')

gulp.task('bitmap', () =&amp;gt; {
    return gulp.src('src/img/**/*.{png,jpg,gif}')
        .pipe(imagemin({
            progressive: true
        }))
        .pipe(gulp.dest('build/img'))
}) 

gulp.task('vector', () =&amp;gt; {
    return gulp.src('src/img/**/*.svg')
        .pipe(svgmin())
        .pipe(gulp.dest('build/img'))
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beautify. Now, instead of having to manually minify all of those tens of thousands of images, you can sit back, grab a coffee and let Gulp do the legwork. What a great friend Gulp is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So – there you have it. I have explored a ton of stuff that Google's PageSpeed Insights evaluates when rating a website's performance, providing examples from my own experience in achieving the precious 100/100 score.&lt;/p&gt;

&lt;p&gt;If you have made it this far, you can breathe a sigh of relief – I hope you managed to learn something valuable and practical about web performance. If you have any questions regarding my experience or approaches, feel free to leave a comment, &lt;a href="https://twitter.com/AdamMcQuiff" rel="noopener noreferrer"&gt;Tweet me&lt;/a&gt; or throw a brick through my window – whichever approach feels right.&lt;/p&gt;

&lt;p&gt;If you want to explore my personal website (the basis for these examples) in more detail, check out the complete &lt;a href="https://github.com/AdamMcquiff/personal-site" rel="noopener noreferrer"&gt;source code on GitHub&lt;/a&gt; and, most importantly, thank you for reading!&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>perf</category>
      <category>optimisation</category>
      <category>minification</category>
    </item>
    <item>
      <title>What on earth is User Experience?</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Sun, 03 Jun 2018 22:36:03 +0000</pubDate>
      <link>https://dev.to/adammckenna/what-is-user-experience-anyway-248g</link>
      <guid>https://dev.to/adammckenna/what-is-user-experience-anyway-248g</guid>
      <description>&lt;p&gt;Article originally posted &lt;a href="https://adammckenna.co.uk/articles/what-is-user-experience-anyway/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Unless you've been living your life as a member of the &lt;em&gt;Uncontacted Indians of Brazil&lt;/em&gt;, deep within the Amazon rainforest, then it's likely you've heard the term "&lt;strong&gt;User Experience&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;In fact, you've probably heard the term thrown around more than you would like. It seems as though everyone in the digital sector, and their hip dogs, are experts in this emerging field. &lt;/p&gt;

&lt;p&gt;Go to any digital consultancy's website and you'll be barraged with promises that they can convert your old, clunky web application into a "seamless," or "forward-thinking app" with an "unparalleled" user experience.&lt;/p&gt;

&lt;p&gt;What on earth are they talking about? Moreover, what on earth am &lt;em&gt;I&lt;/em&gt; talking about? Putting the "&lt;a href="https://www.urbandictionary.com/define.php?term=bullshit%20bingo" rel="noopener noreferrer"&gt;bullshit bingo&lt;/a&gt;" aside, what does "user experience" actually refer to? Has the term become so overused that it has lost all meaning? Well, no, because it never had a clear definition to begin with.&lt;/p&gt;

&lt;p&gt;Let's address the elephant in the room. &lt;strong&gt;What on earth is User Experience?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Definitions of User Experience (and the problem)
&lt;/h2&gt;

&lt;p&gt;Here's the crux of the matter: &lt;strong&gt;a plethora of definitions do exist, but professionals, researchers, and experts in the field have been unable to agree upon a single definition.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For instance, in 2007 a collective of human-computer interaction (HCI) professors, including Effie Lai-Chong Law and Arnold P.O.S. Vermeere, convened in an attempt to establish a so-called "&lt;a href="https://dl.acm.org/citation.cfm?id=1531468" rel="noopener noreferrer"&gt;user experience manifesto&lt;/a&gt;." &lt;/p&gt;

&lt;p&gt;Alas, the document was never complete, and even now, over ten years later, the digital sector is rife with disagreement, squabbles, and good old fashion quick-draw matches*.&lt;/p&gt;

&lt;p&gt;At this point, I can almost hear the readers thoughts: "Well, &lt;em&gt;I&lt;/em&gt; &lt;em&gt;definitely&lt;/em&gt; know what user experience is! I'm a bloody three-time award winning web interaction designer!" Or, something along those lines. And, to be fair, they wouldn't be wrong. There &lt;em&gt;are&lt;/em&gt; definitions floating around.&lt;/p&gt;

&lt;p&gt;For example, the &lt;a href="https://www.iso.org/obp/ui/#iso:std:iso:9241:-210:ed-1:v1:en" rel="noopener noreferrer"&gt;ISO 9241-210&lt;/a&gt; standard, has a very clear, commonly-used definition of user experience:&lt;/p&gt;

&lt;blockquote&gt;
[a] person's perceptions and responses resulting from the use and/or anticipated use of a product, system or service.
&lt;/blockquote&gt;

&lt;p&gt;The problem, however, isn't finding a definition -- it's finding a definition that everyone can agree upon.&lt;/p&gt;

&lt;p&gt;Well, why can't professionals just agree on a single definition, like the ISO standard?&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring the metrics
&lt;/h2&gt;

&lt;p&gt;Well, although there are numerous factors, the main cause of frustration in the debate is the question of whether usability is a metric of user experience or not. After all, user experience is a subjective concept, whereas usability is, for the most part, objective.&lt;/p&gt;

&lt;p&gt;ISO 9241-210 also have a definition for usability:&lt;/p&gt;

&lt;blockquote&gt;
The effectiveness, efficiency and satisfaction with which specified users achieve specified goals in particular environments.
&lt;/blockquote&gt;

&lt;p&gt;In the context of digital artefacts, such as websites, mobile apps, etc., usability encapsulates scads of factors: accessibility, performance, user interface considerations, and task completion time are just a few examples.&lt;/p&gt;

&lt;p&gt;But, despite the objective nature of usability, could it still be considered a metric of user experience? After all, it's hard to deny that these factors contribute to the overall &lt;em&gt;experience&lt;/em&gt; and feelings that a user has when using an application. &lt;/p&gt;

&lt;p&gt;Take the following definition of the relationship between user experience and usability:&lt;/p&gt;

&lt;blockquote&gt;
Usability, when interpreted from the perspective of the users' personal goals, can include the kind of perceptual and emotional aspects typically associated with user experience. 
Usability criteria can be used to assess aspects of user experience.
&lt;/blockquote&gt;

&lt;p&gt;This definition, also sourced from (you guessed it) the ISO standards, argues that usability is not only related to objective metrics, such as performance and accessibility, but also includes more abstract metrics, such as the user's awareness, emotions, and feelings towards a given system.&lt;/p&gt;

&lt;p&gt;With that definition in mind, usability and user experience require co-existence. The user experience of an application depends on an application's usability in order to elicit a positive emotional response from the user. &lt;/p&gt;

&lt;p&gt;Can you think of many instances when an application has be &lt;em&gt;unusable&lt;/em&gt; and you have felt positively towards it? Sure, these instances do occur, but they are few and far between.&lt;/p&gt;

&lt;p&gt;In the same vein, can you think of examples when you have responded with positive emotion to an application because of how &lt;em&gt;usable&lt;/em&gt; it was? I know I can. &lt;/p&gt;

&lt;p&gt;The reliance that the two metrics have upon one-another is not all-encompassing, but it is certainly substantial.&lt;/p&gt;

&lt;p&gt;Yet, if these metrics are so dependant upon one-another, why spend so much energy debating their differences?&lt;/p&gt;

&lt;p&gt;The critical difference lies in the nature of each metric. &lt;/p&gt;

&lt;p&gt;As stated, usability is, for the most part, objective. &lt;/p&gt;

&lt;p&gt;If a task cannot be complete, you would know what the task was and why it could not be complete. &lt;/p&gt;

&lt;p&gt;If an application has poor speed, you can perform a benchmark test and meticulously assess the performance of each line of code. &lt;/p&gt;

&lt;p&gt;If a user with accessibility requirements cannot access a button with their keyboard, you would know what the button was and what would need to done to ensure that the user could use it. &lt;/p&gt;

&lt;p&gt;Though not always the case, most usability issues convert directly into tangible tasks.&lt;/p&gt;

&lt;p&gt;User experience, based upon the aforementioned ISO definition, is on the other hand heavily subjective. What metric could be more subjective than a person's emotions and subconscious feelings? If a user responses with negative emotions to a system that is otherwise usable during a user experience evaluation, the chances are that it will be difficult for both the evaluator &lt;em&gt;and&lt;/em&gt; the user to quantify the perceived "issue."&lt;/p&gt;

&lt;p&gt;A person's emotions cannot be quantified with a benchmark test. We cannot discover the 'line of code' pertaining to a user's emotion. If a user dislikes a system, that can be due to a negative association in that person's mind, or because the system does not cater to (or fails to consider) some aspect of the user's culture. Or, it can be a completely unrelated factor. &lt;/p&gt;

&lt;p&gt;Of course, although user experience professionals have techniques to drill deeper and create solutions to the user experience issues that they discover, they face a different challenge to the team responsible for identifying and resolving usability issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Satisfaction
&lt;/h2&gt;

&lt;p&gt;It is hard to deny that user experience and usability have different natures. One is subjective and the other is objective. But, it is also difficult to deny that they depend upon, and are relative to, one-another. &lt;/p&gt;

&lt;p&gt;A system with poor usability is likely to deliver a poor user experience. So, perhaps it is prudent to look beyond the definitions of both metrics and instead discuss the overarching issue: let's talk about the &lt;em&gt;outcome&lt;/em&gt;. Let's talk about &lt;strong&gt;user satisfaction&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Because ultimately, if a system is usable, but a user has a negative experience - for whatever hard-to-quantify reason - then the user may decide to use an alternative application, even if their goals &lt;strong&gt;are&lt;/strong&gt; achieved within your system. In this situation, the user has low user satisfaction.&lt;/p&gt;

&lt;p&gt;Similarly, if the system manages to emotionally resonate with the user - again, for whatever hard-to-quantify reason - but the user cannot complete their goals, then their overall user satisfaction will be low, and they will seek an alternative application to solve their goals.&lt;/p&gt;

&lt;p&gt;When discussing the user experience of an application, usability (and all the metrics that define it) cannot be neglected. The ultimate goal of delivering a great user experience is user satisfaction - and a user cannot be satisfied unless their goals are achievable with your system.&lt;/p&gt;

&lt;p&gt;Applications exist to solve problems. But, without usability, a user cannot use your system to solve their problem. And, if the user's problem is not being solved, a poor user experience has been delivered, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are many of us that work in the digital sector and have our own interpretations of what user experience is, and that's fine. The problem is the neglect of the aspects of an application that contribute to the overall user satisfaction.&lt;/p&gt;

&lt;p&gt;As long as the user is ultimately satisfied with your product, you can rest easy knowing a great user experience has been delivered.&lt;/p&gt;

&lt;p&gt;To do so, however, it is necessary to look at the bigger picture and, whether user experience professionals wish to accept it or not, usability is a vital piece of the puzzle.&lt;/p&gt;

&lt;p&gt;So, instead of shunning away usability metrics during our user experience discussions, let's instead embrace them with open arms and consider the overall user satisfaction.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Abeysiri, L. and Weerawarna, N. T. (2017) Usability and user experience towards an experience economy. &lt;em&gt;Technology and Management (NCTM), National Conference on&lt;/em&gt; (pp. 81-86). IEEE.&lt;/p&gt;

&lt;p&gt;Davis, F. D. (1989) Perceived Usefulness, Perceived Ease of Use, and User Acceptance of Information Technology. &lt;em&gt;The Management Information Systems Quarterly&lt;/em&gt;, Vol 13 (3), pp. 319-340.&lt;/p&gt;

&lt;p&gt;Glanznig, M. (2012) User experience research: Modelling and describing the subjective. &lt;em&gt;Interdisciplinary Description of Complex Systems: INDECS&lt;/em&gt;, 10(3), 235-247.&lt;/p&gt;

&lt;p&gt;Kaye, J. J., Boehner, K., Laaksolahti, J. and Ståhl, A. (2007) Evaluating experience-focused HCI. &lt;em&gt;Proceedings of the CHI 2007 Conference, Extended Abstracts&lt;/em&gt;, ACM Press, San Jose, CA&lt;/p&gt;

&lt;p&gt;Law, E. L. C., Vermeeren, A. P., Hassenzahl, M. and Blythe, M. (2007) Towards a UX manifesto. &lt;em&gt;In Proceedings of the 21st British HCI Group Annual Conference on People and Computers: HCI... but not as we know it-Volume 2&lt;/em&gt; (pp. 205-206). British Computer Society.&lt;/p&gt;

&lt;p&gt;Vermeeren, A. P., Law, E. L-C., Roto, V., Obrist, M., Hoonhout, J. and Väänänen-Vainio-Mattila, K. (2010) User Experience Evaluation Methods: Current State and Development Needs. &lt;em&gt;6th Nordic Conference on HumanComputer Interaction&lt;/em&gt;. ACM, New York, pp. 521-530.&lt;/p&gt;

&lt;p&gt;Vermeeren, A. P., Roto, V. and Väänänen, K. (2016) Design-inclusive UX research: design as a part of doing user experience research. &lt;em&gt;Behaviour &amp;amp; Information Technology&lt;/em&gt;, 35(1), 21-37.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>usability</category>
      <category>hci</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Three Things I Learnt at .concat() 2018 (and other reasons to visit Salzburg)</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Mon, 05 Mar 2018 11:37:23 +0000</pubDate>
      <link>https://dev.to/adammcquiff/three-things-i-learnt-at-concat-2018-and-other-reasons-to-visit-salzburg--3amj</link>
      <guid>https://dev.to/adammcquiff/three-things-i-learnt-at-concat-2018-and-other-reasons-to-visit-salzburg--3amj</guid>
      <description>&lt;p&gt;This year, I was fortunate enough to attend &lt;a href="https://2018.conc.at/" rel="noopener noreferrer"&gt;.concat() 2018&lt;/a&gt;, a user experience and web development conference hosted in Salzburg, Austria - the home of Mozart and setting of &lt;em&gt;The Sound of Music&lt;/em&gt; - at FH Salzburg, the University of Applied Science. The &lt;a href="https://www.sunderland.ac.uk/" rel="noopener noreferrer"&gt;University of Sunderland&lt;/a&gt; sponsored my attendance as part of my studies.&lt;/p&gt;

&lt;p&gt;The conference ran two tracks which, unfortunately, meant that all of the talks clashed, and I was unable to attend a handful of presentations that had caught my attention, including those by &lt;a href="https://twitter.com/ursulasarracini" rel="noopener noreferrer"&gt;Ursula Sarracini&lt;/a&gt;, &lt;a href="https://twitter.com/rasmus" rel="noopener noreferrer"&gt;Rasmus Lerdorf&lt;/a&gt;, and &lt;a href="https://twitter.com/estellevw" rel="noopener noreferrer"&gt;Estelle Weyl&lt;/a&gt;, among others exploring concepts such as accessibility, PHP, and maintaining legacy codebases.&lt;/p&gt;

&lt;p&gt;The day began with a delicious, vegan-friendly breakfast, followed by an endless stream of 30-minute presentations, all kicked off with a keynote presentation by Google engineer &lt;a href="https://twitter.com/expatdanno" rel="noopener noreferrer"&gt;Danno Clifford&lt;/a&gt;: &lt;em&gt;When Fast is Faster Than Fastest&lt;/em&gt;, wherein he discussed optimising the Chrome V8 JavaScript engine.&lt;/p&gt;

&lt;p&gt;Interweaved between the talks was evermore food (authentic Austrian food, this time), an endless supply of freebies, barista coffee, and beers. The day was rounded off nicely with a keynote presentation by the renowned &lt;a href="https://www.sarasoueidan.com/" rel="noopener noreferrer"&gt;Sara Soueidan&lt;/a&gt;, discussing a host of applications for SVGs in her talk:  &lt;em&gt;the &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; of .svg&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I had a great time at the conference, and I learned a great deal, too. I'd like to share some of what I learnt with you in this article. So, here are three things I learnt at &lt;em&gt;concat() 2018&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  No. 1: Practical tips for designing Progressive Web Apps.
&lt;/h2&gt;

&lt;p&gt;Before attending the conference, I had some experience of the technical aspects of  Progressive Web App (PWA) development. I'd implemented service workers for caching and offline support, theming, etc. But, I was not as well versed in the user experience and interface design aspects of PWA development.&lt;/p&gt;

&lt;p&gt;Thankfully, &lt;a href="https://twitter.com/nicolesaidy" rel="noopener noreferrer"&gt;Nicole Saidy&lt;/a&gt; stepped in to fill in the gaps in my knowledge. In her fast-paced talk: &lt;em&gt;Designing Great Progressive Web Apps&lt;/em&gt;, Nicole talked through a checklist of tricks to ensure your progressive web app offers a great user experience.&lt;/p&gt;

&lt;p&gt;Nicole rattled through some of the basic steps: app icons generated via &lt;a href="https://realfavicongenerator.net/" rel="noopener noreferrer"&gt;Real Favicon Generator&lt;/a&gt;, and theming via &lt;code&gt;manifest.json&lt;/code&gt; and &lt;code&gt;meta&lt;/code&gt; tags. &lt;/p&gt;

&lt;p&gt;She then moved onto the more complex aspects.&lt;/p&gt;

&lt;p&gt;One of the main attractions of a PWA, she explained, is the ability to operate offline. To leverage this, Nicole proposed an "offline-first" strategy. This can be achieved with a number of steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inform the user about the change in internet connectivity.&lt;/li&gt;
&lt;li&gt;When the connection is restored, provide a means to retrieve new content.&lt;/li&gt;
&lt;li&gt;If the PWA is data-heavy, provide a 'data-saver' mode.&lt;/li&gt;
&lt;li&gt;If the PWA offers content, provide the ability to download the content. Inform the user of file sizes if a download option is provided.&lt;/li&gt;
&lt;li&gt;Simple but effective: add an 'offline-mode' colour to the app. (To accommodate  users with visual impairment, ensure other means to determine the offline state have been provided to the user - a label, for example).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another interesting topic that Nicole touched on was &lt;em&gt;Progressive Loading&lt;/em&gt; with an &lt;a href="https://developers.google.com/web/fundamentals/architecture/app-shell" rel="noopener noreferrer"&gt;Application Shell Architecture&lt;/a&gt; - the concept of loading particular elements before the entire page loads.&lt;/p&gt;

&lt;p&gt;With a 'traditional' website, everything is rendered immediately when the stylesheets, and other resources, have been loaded. Whereas, when leveraging the Application Shell Architecture, specific elements can be loaded earlier in the rendering process to create an impression of a faster loading website, even though the website hasn't &lt;em&gt;actually&lt;/em&gt; loaded faster.&lt;/p&gt;

&lt;p&gt;The best part of this effect, in my opinion, is the simplicity of its implementation. All you need to do is serve the applicable CSS via a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag at the top of the page. The rest of the website styles can continue to be served via a stylesheet. The browser will automatically prioritise the styles served at the top of the page, rendering them while the stylesheet loads.&lt;/p&gt;

&lt;p&gt;You can see this effect used across multiple Google products, including YouTube and the Google search engine.&lt;/p&gt;

&lt;p&gt;Nicole covered plenty more in her talk, including 'PWA audits', iOS-specific considerations, 'micro-interactions', and a detailed PWA checklist that you can use.&lt;/p&gt;

&lt;p&gt;You can watch Nicole's full talk on YouTube via the link below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=2NZc4C7uNcU" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2F2NZc4C7uNcU%2F0.jpg" alt="Nicole Saidy - Designing Great Progressive Web Apps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  No. 2: You can use CSS Custom Properties today.
&lt;/h2&gt;

&lt;p&gt;Though I had heard of CSS Custom Properties before the conference, I had &lt;strong&gt;no experience at all&lt;/strong&gt; with them. At the pace that the HTML, CSS, and JavaScript specs grow - not even mentioning third-party technologies - I find it difficult to keep up-to-date with every feature.&lt;/p&gt;

&lt;p&gt;That being said, the CSS Custom Properties spec looks a promising addition to the CSS language. Even better, it is fully supported in all modern browsers - you can start using it &lt;em&gt;today&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If, like I was, you're wondering how on earth you can, then &lt;a href="https://twitter.com/mikeriethmuller" rel="noopener noreferrer"&gt;Mike Riethmuller&lt;/a&gt; has you covered. In his talk &lt;em&gt;The Strategy Guide to CSS Custom Properties&lt;/em&gt;, Mike explored a host of ways in which you can use custom properties in your projects to improve the maintainability of your CSS.&lt;/p&gt;

&lt;p&gt;At first, I feared that the new feature was an attempt to replace the variable functionality of pre-processors, such as &lt;em&gt;SASS&lt;/em&gt; and &lt;em&gt;LESS&lt;/em&gt;, but this is not the case. In fact, Mike explores how, and why, we can, and should, use both.&lt;/p&gt;

&lt;p&gt;Concisely put, Mike argues that you should use pre-processor variables for theming, and CSS Custom Properties for values that will change within your media queries. &lt;/p&gt;

&lt;p&gt;To learn the nitty-gritty of Mike's strategy, check out his full talk on YouTube below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Zg8f0fNekp4" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2FZg8f0fNekp4%2F0.jpg" alt="Mike Riethmuller - The strategy guide to CSS Custom Properties"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  No. 3: Address your bias
&lt;/h2&gt;

&lt;p&gt;It's a fact: we all have biases. As software developers, UX designers, and the like, this inevitably effects the applications that we build. However, this fact is not ample justification to let our applications reflect our biases: we need to address them.&lt;/p&gt;

&lt;p&gt;Nobody understands that more, it would seem, than &lt;a href="https://twitter.com/ivanamcconnell" rel="noopener noreferrer"&gt;Ivana McConnell&lt;/a&gt;. In her much-warranted, antagonistic talk, &lt;em&gt;Your Algorithm is Not Neutral&lt;/em&gt;, Ivana explored the concept of exclusion in our applications. Ivana called out a host of companies who failed to address their biases, and who had in turn released applications into the wild that negatively affected the lives of their users.&lt;/p&gt;

&lt;p&gt;From a &lt;a href="https://www.mirror.co.uk/news/uk-news/doctor-locked-out-womens-changing-5358594" rel="noopener noreferrer"&gt;Pure Gym application that assumed all users with the title 'Dr' were male, subsequently disallowing a female into the changing rooms&lt;/a&gt;, to apps like &lt;a href="https://www.npr.org/2017/03/02/518087610/new-research-looks-at-ways-to-help-stop-airbnb-racial-discrimination" rel="noopener noreferrer"&gt;AirBnb&lt;/a&gt; and &lt;a href="https://www.wired.com/2017/02/for-nextdoor-eliminating-racism-is-no-quick-fix/" rel="noopener noreferrer"&gt;Nextdoor&lt;/a&gt; that allowed racial discrimination, and &lt;a href="http://www.bbc.co.uk/news/world-asia-37042475" rel="noopener noreferrer"&gt;Snapchat providing users with racist filters&lt;/a&gt;: users are being excluded and actively discriminated against.&lt;/p&gt;

&lt;p&gt;Products should empower users, not exclude them. So, how do we approach inclusive UX?&lt;/p&gt;

&lt;p&gt;You can discover a series of steps to do so in Ivana's powerful talk on YouTube, embedded below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=As5fhzBY5xk" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2FAs5fhzBY5xk%2F0.jpg" alt="Ivana McConnell - Your Algorithm isn't neutral..."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a similar vein, &lt;a href="https://twitter.com/jennyshen" rel="noopener noreferrer"&gt;Jenny Shen&lt;/a&gt; explored how we can design across cultures in her humorous, yet undoubtably thought-provoking talk, &lt;em&gt;Build Bridges, Not Walls. Design for Users Across Cultures&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Exploring what culture is, and why we should care, Jenny provided a series of unintuitive examples that illustrated how users in difficult cultures react to design decisions made by someone unfamiliar with their culture.&lt;/p&gt;

&lt;p&gt;Though I could attempt to reference her examples, I would not do them justice and I implore you to watch Jenny's talk at your earliest convenience. You can do so below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ER3534JJucc" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2FER3534JJucc%2F0.jpg" alt="Jenny Shen - Build bridges, not walls – Design for users across cultures"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A consistent theme runs through both talks: &lt;strong&gt;you have a bias and you need to consciously take action to ensure your user does experience the implications of your unintended, natural bias, which impacts race, culture, gender and social conditions.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;Concat() 2018&lt;/em&gt; conference was a memorable day: thought-provoking talks from a host of great speakers; high-quality local cuisine, and some of the best coffee I have ever had provided by an on-site barista; lovely attendees and, of course, a fantastic team.&lt;/p&gt;

&lt;p&gt;I have so many takeaways to think about from all the talks I watched, and a backlog of talks that I missed to catch-up on. The points I have discussed in this post only scrape the surface of the ideas circulated throughout the day, and I recommend that you watch the talks yourself and, of course, sign-up for next year's ticket... (fingers-crossed).&lt;/p&gt;

&lt;p&gt;And, in that vein…&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Here's Some &lt;em&gt;Other&lt;/em&gt; Reasons to Visit Salzburg
&lt;/h2&gt;

&lt;p&gt;The conference was a fantastic opportunity for me to explore Austria, having never visited the country before. Though historically known for salt mining - &lt;em&gt;Salzburg&lt;/em&gt; translates directly to 'Salt Fortress' - and more recently known as the birthplace of the world-famous composer Wolfgang Amadeus Mozart and the setting of The Sound of Music, Salzburg has a lot more to offer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenery
&lt;/h3&gt;

&lt;p&gt;Unlike many cities of the 19th century, Salzburg's buildings were spared knocking-down, thanks to a one-hundred-year period of economic neglect from the ruling Habsburg dynasty after the city joined Austria in 1816, ensuring the city was able to retain its distinctive appearance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4xtgawmtisynyw40ngu4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4xtgawmtisynyw40ngu4.jpg" alt="A photograph that doesn't remotely do Salzburg's beauty justice"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a result, modern day visitors are able to experience picturesque architecture that is difficult to find in many other places in Europe. And, with Salzburg being surrounded by mountains and various other vantage points, there is ample opportunity to be awed. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYGJ2tOr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYGJ2tOr.jpg" alt="Another photograph that doesn't remotely do Salzburg's beauty justice"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cuisine and Drinks
&lt;/h3&gt;

&lt;p&gt;Salzburg has quite the offering of delicious cuisine, and is also the home place of a number of delicacies, including Paul Furst's &lt;a href="http://www.original-mozartkugel.com/index_e.php" rel="noopener noreferrer"&gt;Original Salzburger Mozartkugel&lt;/a&gt; and the &lt;em&gt;Original Sacher Torte&lt;/em&gt;, the latter of which is available at the &lt;a href="https://www.sacher.com/hotel-wien-2/kulinarik/cafe-sacher-wien/" rel="noopener noreferrer"&gt;Café Confiserie Sacher&lt;/a&gt; (who never pass on an opportunity to remind you that they are offering not just any Sacher Torte, but the &lt;em&gt;Original Sacher Torte&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FizTRdHR.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FizTRdHR.jpg" alt="The "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to treats, there is no shortage of authentic food, including beef goulash, spinach dumplings, and frankfurter sausages. Even the coffee stood out. A common option in Salzburg is the &lt;em&gt;Melange&lt;/em&gt;: a filter coffee served with milk, whipped cream and, in most cases, a chocolate treat. All the coffee I tried in Salzburg was even served with a small glass of cold water.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbHDqHql.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbHDqHql.jpg" alt="Melange coffee from Cafe Mozart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Untersberg Mountain
&lt;/h3&gt;

&lt;p&gt;A short bus journey away from the city centre, in Grödig, there is a cable car that you can take to the snowy speaks of &lt;em&gt;Untersberg&lt;/em&gt; mountain. Though the cable car usually costs €25 for an ascent and descent, you can ride it for free with a &lt;a href="https://www.salzburg.info/en/hotels-offers/salzburg-card" rel="noopener noreferrer"&gt;Salzburg Card&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We were able to climb the mountain on a particularly clear day, after a full day of snow, and were able to enjoy the scorching sun, endless snow, and unforgettable views of Salzburg, &lt;em&gt;Watzmann&lt;/em&gt; mountain and, the German &lt;em&gt;Bundesland&lt;/em&gt; of Bavaria. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhmf24mf3qafse6k9w3ho.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhmf24mf3qafse6k9w3ho.jpg" alt="'Deep' photo of me enjoying the view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caption: Unintentionally 'deep' photo of me enjoying the view.&lt;/p&gt;

&lt;p&gt;No description or photographs can do the experience justice. If you find yourself in Salzburg, Grödig or anywhere nearby, this is an unmissable experience.&lt;/p&gt;

</description>
      <category>userexperience</category>
      <category>webdev</category>
      <category>concat</category>
      <category>conference</category>
    </item>
    <item>
      <title>What have been your biggest learning curves as developers? #discuss</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Mon, 08 Jan 2018 23:53:13 +0000</pubDate>
      <link>https://dev.to/adammckenna/what-have-been-your-biggest-learning-curves-as-developers-9l2</link>
      <guid>https://dev.to/adammckenna/what-have-been-your-biggest-learning-curves-as-developers-9l2</guid>
      <description>&lt;p&gt;There are so many areas in Computer Science and the technologies that make up this vast sector can range from basic to outlandishly complex and difficult.&lt;/p&gt;

&lt;p&gt;The web, for example, encapsulates just one area of the industry, yet in itself has an immeasurable amount of languages, frameworks, tools etc. I'm sure the typical web developer could rattle off 20-30 off the top of their head.&lt;/p&gt;

&lt;p&gt;But, each and every concept/language/technology/tool required some form of learning to begin to us - whether basic or otherwise.&lt;/p&gt;

&lt;p&gt;Tough learning curves can be occur for a number of reasons. Perhaps that language had poor or non-existent documentation; perhaps it was difficult to find support online or from peers for that tool; perhaps that technology required context from another technology to learn it effectively?&lt;/p&gt;

&lt;p&gt;Whatever the reason and whatever the concept/language/technology tool, it is very interesting, and often surprising, to discover what people in the industry have found to be the steepest learning curves, and why this was the case.&lt;/p&gt;

&lt;p&gt;And, perhaps by addressing and discussing some of the learning curves faced, we can begin to find solutions to the issues for future generations of developers.&lt;/p&gt;

&lt;p&gt;So, what have been your biggest learning curves, and why?&lt;/p&gt;

</description>
      <category>development</category>
      <category>programmers</category>
      <category>learning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Improve the performance of WebStorm (and other JetBrains IDEs)</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Mon, 08 Jan 2018 19:56:45 +0000</pubDate>
      <link>https://dev.to/adammckenna/improve-the-performance-of-webstorm-and-other-jetbrains-ides-11bc</link>
      <guid>https://dev.to/adammckenna/improve-the-performance-of-webstorm-and-other-jetbrains-ides-11bc</guid>
      <description>&lt;p&gt;Have you ever used WebStorm? What about PHPStorm, or, in fact, any of the IDEs in the JetBrains suite? They are an impressive collection of IDEs packed with features -- an integrated terminal, local history and VCS integration, "intelligent" imports, and much more. &lt;/p&gt;

&lt;p&gt;But, does this feature-bloat come at a price? Absolutely.&lt;/p&gt;

&lt;p&gt;The performance of WebStorm, and the other JetBrains IDEs, pales in comparison to the lighter text editors that are popular in the web community. &lt;em&gt;Visual Studio Code&lt;/em&gt; and &lt;em&gt;Atom&lt;/em&gt; come to mind.&lt;/p&gt;

&lt;p&gt;Fear not! There are solutions. &lt;/p&gt;

&lt;p&gt;But first, let's take a step back for those who aren't familiar with the IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebStorm?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/webstorm/" rel="noopener noreferrer"&gt;WebStorm&lt;/a&gt; is a popular, powerful web development IDE. It is one of a larger collective of IDEs developed by &lt;a href="https://www.jetbrains.com/" rel="noopener noreferrer"&gt;JetBrains&lt;/a&gt; - formerly known as &lt;em&gt;IntelliJ&lt;/em&gt;. These IDEs aim to offer the ultimate development environment for popular coding languages. &lt;/p&gt;

&lt;p&gt;Other JetBrains IDEs include &lt;em&gt;PHPStorm&lt;/em&gt; for PHP, &lt;em&gt;IntelliJ IDEA&lt;/em&gt;  for Java, &lt;em&gt;PyCharm&lt;/em&gt; for Python, and &lt;em&gt;ReSharper&lt;/em&gt; for C# (as a &lt;em&gt;Visual Studio&lt;/em&gt; extension), among others. &lt;/p&gt;

&lt;p&gt;Even &lt;em&gt;Android Studio&lt;/em&gt;, which is technically a &lt;em&gt;Google&lt;/em&gt; IDE, runs on the IntelliJ platform. With that in mind, most of the optimisations explored in this article can be transferred to other JetBrains IDEs. &lt;/p&gt;

&lt;p&gt;But, as we mentioned, although WebStorm is one of the most powerful IDEs available, it’s certainly not the most performant. In fact, on older machines, it can be a machine killer. &lt;/p&gt;

&lt;p&gt;Let's explore how to increase the load-time and performance of WebStorm by tweaking the out-of-the-box settings. &lt;/p&gt;

&lt;h2&gt;
  
  
  Optimising WebStorm's performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup Config Files
&lt;/h3&gt;

&lt;p&gt;We’re going to start by customising a few settings within the WebStorm directory. &lt;/p&gt;

&lt;p&gt;But first, in order to customise WebStorm settings, we need to create some configuration files. We'll create two config files: &lt;code&gt;idea.properties&lt;/code&gt; and &lt;code&gt;webstorm.vmoptions&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To create these files, open WebStorm and go to &lt;b&gt;Help&lt;/b&gt;. &lt;/p&gt;

&lt;p&gt;Select &lt;b&gt;Edit Custom Properties…&lt;/b&gt;. A dialog will prompt stating that the &lt;code&gt;idea.properties&lt;/code&gt; file does not exist. &lt;/p&gt;

&lt;p&gt;Click &lt;b&gt;Yes&lt;/b&gt; to create it. The file will open. Now you can add the config settings. This file is used for customising WebStorm properties.&lt;/p&gt;

&lt;p&gt;To create the other file, go again to &lt;b&gt;Help&lt;/b&gt; and select &lt;b&gt;Edit Custom VM Options...&lt;/b&gt;. &lt;/p&gt;

&lt;p&gt;A dialog will prompt stating that the &lt;code&gt;webstorm.vmoptions&lt;/code&gt; file does not exist.&lt;/p&gt;

&lt;p&gt;Click &lt;b&gt;Yes&lt;/b&gt; to create one. The file will open. Now you can add the config settings. This file is used for customising WebStorm Virtual Machine options.&lt;/p&gt;

&lt;p&gt;For future reference, these files can be found in the following directories:&lt;/p&gt;

&lt;p&gt;Windows 7 / 8 / 10 - &lt;code&gt;&amp;lt;SYSTEM DRIVE&amp;gt;\Users\&amp;lt;USER ACCOUNT NAME&amp;gt;\.&amp;lt;PRODUCT&amp;gt;&amp;lt;VERSION&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;OS X / macOS - &lt;code&gt;~/Library/Preferences/&amp;lt;PRODUCT&amp;gt;&amp;lt;VERSION&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Improve the Performance
&lt;/h3&gt;

&lt;p&gt;Now that our config files are setup, we can change WebStorm’s settings to optimise  performance.&lt;/p&gt;

&lt;p&gt;First, let's change some options within the &lt;code&gt;webstorm.vmoptions&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;Open the newly created file, select all of the options and replace them with the following snippet: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-Xms1024m 
-Xmx1536m 
-XX:MaxPermSize=1024m 
-XX:ReservedCodeCacheSize=512m 
-XX:+UseCompressedOops 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we are going to remove IDE latency using an experimental property called &lt;code&gt;zero-latency&lt;/code&gt; that was introduced in 2015. &lt;/p&gt;

&lt;p&gt;To do so, add the following line to your &lt;code&gt;idea.properties&lt;/code&gt; file: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;editor.zero.latency.typing=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We’re going to move on to generally optimising the usage of WebStorm by de-selecting unnecessary features. Doing so will reduce feature-bloat and increase system memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appearance and Behaviour
&lt;/h3&gt;

&lt;p&gt;To start, let’s disable automatic update checking and statistic sending within the &lt;b&gt;Appearance and Behaviour&lt;/b&gt; preferences.&lt;/p&gt;

&lt;p&gt;To do so, go to &lt;b&gt;Preferences&lt;/b&gt; and select &lt;b&gt;Appearance &amp;amp; Behaviour&lt;/b&gt;. &lt;/p&gt;

&lt;p&gt;Then go to &lt;b&gt;System Settings&lt;/b&gt; and select the &lt;b&gt;Updates&lt;/b&gt; tab. From here, de-select &lt;em&gt;Automatically check updates for…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, select the menu 'Data Sharing' from the System Settings and de-select &lt;em&gt;Send usage statistics&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editor
&lt;/h2&gt;

&lt;p&gt;Now, let’s change some settings in the &lt;b&gt;Editor&lt;/b&gt; preferences.&lt;/p&gt;

&lt;p&gt;Within &lt;b&gt;Preferences&lt;/b&gt;, go to the &lt;b&gt;Editor&lt;/b&gt; tab and select &lt;b&gt;Live Templates&lt;/b&gt;. De-select any templates that you do not use. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://emmet.io/" rel="noopener noreferrer"&gt;Emmet&lt;/a&gt; is a IDE plugin that helps improve HTML and CSS development workflow. &lt;/p&gt;

&lt;p&gt;It's a great plugin, but it comes with many options that go unused and waste valuable system memory. &lt;/p&gt;

&lt;p&gt;To remove these unnecessary options, go to the &lt;b&gt;Editor tab&lt;/b&gt; and select &lt;b&gt;Emmet&lt;/b&gt;. Browse through the options for CSS, JSX and HTML, and de-select any  options that you don't use.  &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Intentions&lt;/b&gt; is a powerful feature of the JetBrains application family. It suggests solutions to problems that it detects on-the-fly as you code. &lt;/p&gt;

&lt;p&gt;However, by default WebStorm has every option selected within the &lt;em&gt;Intentions&lt;/em&gt; preferences window. It's unlikely that you will use every technology/language listed, so de-select the options that you do not use. &lt;/p&gt;

&lt;p&gt;To deselect the options, go to the &lt;b&gt;Editor&lt;/b&gt; tab, select &lt;b&gt;Intentions&lt;/b&gt;. Again, de-select any non-applicable languages and technologies. &lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Almost there. Next, let’s fiddle with our plugins.&lt;/p&gt;

&lt;p&gt;Within &lt;b&gt;Preferences&lt;/b&gt;, go to the &lt;b&gt;Plugins&lt;/b&gt; tab. &lt;/p&gt;

&lt;p&gt;By default, all of the native plugins will be enabled. &lt;/p&gt;

&lt;p&gt;It is unlikely that you will make use of them all. Scroll through and de-select any plugins that are not applicable to the languages and technologies that you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Directories
&lt;/h2&gt;

&lt;p&gt;During startup, WebStorm loads every directory (folder) within a project. However, some of these directions, particularly vendor directories like the &lt;code&gt;node_modules&lt;/code&gt; directory, may never be touched within WebStorm. Loading these directories wastes valuable resource.&lt;/p&gt;

&lt;p&gt;To disable un-used directories, within &lt;b&gt;Preferences&lt;/b&gt;, go to &lt;b&gt;Directories&lt;/b&gt; and set any directories that are not edited within WebStorm as &lt;code&gt;Excluded&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Languages &amp;amp; Frameworks
&lt;/h2&gt;

&lt;p&gt;Within &lt;b&gt;Preferences&lt;/b&gt; go to &lt;b&gt;Languages &amp;amp; Frameworks &amp;gt; JavaScript &amp;gt; Libraries&lt;/b&gt; and de-select any libraries that are unused. &lt;/p&gt;

&lt;p&gt;If you are not using &lt;a href="http://compass-style.org/" rel="noopener noreferrer"&gt;Compass&lt;/a&gt; to generate CSS files from your Sass, ensure &lt;em&gt;‘Enable Compass support’&lt;/em&gt; is not enabled. To do so, go to &lt;b&gt;Languages &amp;amp; Frameworks &amp;gt; Compass&lt;/b&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;The &lt;b&gt;Web Browsers&lt;/b&gt; section is used to quickly launch your project into the enabled browsers. &lt;/p&gt;

&lt;p&gt;If you do not use this feature, disable it. To do so, within &lt;b&gt;Preferences&lt;/b&gt; go to &lt;b&gt;Web Browsers&lt;/b&gt; and de-select all browsers except your browser of choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, that's it.&lt;/p&gt;

&lt;p&gt;Now we’ve managed to clean up WebStorm, you should find a notable increase in start-up time and general performance so you can focus on the stuff that matters: web development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.freecodecamp.com/make-webstorm-better-with-these-customizations-c038c9e5f84b#.ifjrzkk00" rel="noopener noreferrer"&gt;Make WebStorm better with these customizations - Victor Savkin, FreeCodeCamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/29388626/how-to-speed-up-webstorm" rel="noopener noreferrer"&gt;How to speed up WebStorm - StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jetbrains.com/help/idea/2016.3/file-idea-properties.html" rel="noopener noreferrer"&gt;File 'idea.properties' - JetBrains documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jetbrains</category>
      <category>intellij</category>
      <category>webstorm</category>
      <category>performance</category>
    </item>
    <item>
      <title>How, and why, to clean SVG markup</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Tue, 24 Oct 2017 19:50:52 +0000</pubDate>
      <link>https://dev.to/adammckenna/how-and-why-to-clean-svg-markup-49i</link>
      <guid>https://dev.to/adammckenna/how-and-why-to-clean-svg-markup-49i</guid>
      <description>&lt;p&gt;You wouldn't think that the SVG format has been around for almost 20 years. &lt;/p&gt;

&lt;p&gt;Over the last few years, the popularity of the format has grown so phenomenally that you'd be forgiven for thinking it was a recent innovation. &lt;/p&gt;

&lt;p&gt;These days, it is common practice to provide your logo, graphics, charts, and the like as an SVG, instead of its pixellated bitmap counterparts. &lt;/p&gt;

&lt;p&gt;So, where did this file format come from? The SVG (&lt;em&gt;Scaleable Vector Graphic&lt;/em&gt;) format was brought to the table in 1999 by the W3C (&lt;em&gt;World Wide Web Consortium&lt;/em&gt;).  It's an XML based vector image format designed specifically for the web.&lt;/p&gt;

&lt;p&gt;One of the many beauties of vector images, including SVG, is that they can be scaled to any size without a loss of quality. Bitmap images, on the other hand, such as .jpg, .png, and .gif, pixelate when scaled beyond their natural size. &lt;/p&gt;

&lt;p&gt;Scalability makes the SVG format a natural fit for the responsive web. An SVG can easily be scaled for mobile, desktop, all the way to 5K displays, and everywhere in between and beyond.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F36z13rvrk142v181pz33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F36z13rvrk142v181pz33.png" alt="" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics" rel="noopener noreferrer"&gt;Image source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An SVG typically has a smaller file size than any of its bitmap counterparts. An SVG also supports several interesting use cases that bitmaps cannot, including animation and interaction with JavaScript. &lt;/p&gt;

&lt;p&gt;If you’re not yet convinced that SVGs are the future, I strongly recommend watching &lt;a href="https://www.youtube.com/watch?v=tsGa-gcckwY" rel="noopener noreferrer"&gt;this&lt;/a&gt; Chris Coyer video or reading &lt;a href="https://abookapart.com/products/practical-svg" rel="noopener noreferrer"&gt;Chris’ book, Practical SVG&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Convincing readers to use the format is not the purpose of this article. Rather, this article is a guide for those who have already adopted SVGs, and want to squeeze a little more out of the format.&lt;/p&gt;

&lt;p&gt;Let's explore how we can cleanup SVG markup, and why we probably should.&lt;/p&gt;

&lt;h2&gt;
  
  
  SVG Anatomy (SVG == Markup)
&lt;/h2&gt;

&lt;p&gt;When you preview an SVG in a browser or an image viewer, it will, more or less, behave as a bitmap. You can see the image rendered. Of course, the SVG will be sharper, and won't pixelate if you zoom in, but beyond that there is little difference.&lt;/p&gt;

&lt;p&gt;The difference is behind the scenes. SVG is XML-based. Behind every SVG there is readable, HTML-like markup. This means that you have readable line-by-line control, regardless of what tool churned out the file.&lt;/p&gt;

&lt;p&gt;Heck, SVGs could be coded from scratch, and often are. But, most SVGs are produced in a graphics editor, such as Adobe Illustrator, Inkscape or Sketch. These applications often export their SVG markup with superfluous, and sometimes outdated, elements and attributes.&lt;/p&gt;

&lt;p&gt;For example, here is the XML from an SVG icon created in &lt;em&gt;Adobe Illustrator&lt;/em&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="iso-8859-1"?&amp;gt;

&amp;lt;!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --&amp;gt;

&amp;lt;svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve"&amp;gt;

    &amp;lt;g&amp;gt;

        &amp;lt;path d="M45.563,29.174l-22-15c-0.307-0.208-0.703-0.231-1.031 0.058C22.205,14.289,22,14.629,22,15v30c0,0.371,0.205,0.711,0.533,0.884C22.679, 45.962,22.84,46,23,46c0.197,0,0.394-0.059,0.563-0.174l22-15 C45.836,30.64,46,30.331,46,30S45.836,29.36,45.563,29.174z M24,43.107V16.893L43.225,30L24,43.107z"/&amp;gt;

        &amp;lt;path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M30,58C14.561,58,2,45.439,2,30S14.561,2,30,2s28,12.561,28,28S45.439,58,30,58z"/&amp;gt;

    &amp;lt;/g&amp;gt;

&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you’re familiar with HTML, this will look quite familiar: it's just elements and attributes. &lt;/p&gt;

&lt;p&gt;And, just like HTML, we can optimise it.&lt;/p&gt;

&lt;p&gt;Let’s look at another example. This SVG markup is for a map marker icon generated by &lt;em&gt;Sketch&lt;/em&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&amp;gt;

&amp;lt;svg width="39px" height="39px" viewBox="0 0 39 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"&amp;gt;

    &amp;lt;!-- Generator: Sketch 39.1 (31720) - http://www.bohemiancoding.com/sketch --&amp;gt;

    &amp;lt;title&amp;gt;Hospital&amp;lt;/title&amp;gt;

    &amp;lt;desc&amp;gt;Created with Sketch.&amp;lt;/desc&amp;gt;

    &amp;lt;defs&amp;gt;

        &amp;lt;rect id="path-1" x="0" y="0" width="33" height="33" rx="9"&amp;gt;&amp;lt;/rect&amp;gt;

    &amp;lt;/defs&amp;gt;

    &amp;lt;g id="Maps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"&amp;gt;

        &amp;lt;g id="Map" transform="translate(-483.000000, -779.000000)"&amp;gt;

            &amp;lt;g id="Hospital" transform="translate(486.000000, 782.000000)"&amp;gt;

                &amp;lt;rect id="Rectangle-57" fill-opacity="0.599999964" fill="#FFFFFF" opacity="0.5" x="0" y="0" width="33" height="33" rx="9"&amp;gt;&amp;lt;/rect&amp;gt;

                &amp;lt;g id="Rectangle-57"&amp;gt;

                    &amp;lt;use stroke="#2D2D2D" stroke-width="6" fill-opacity="0.599999964" fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"&amp;gt;&amp;lt;/use&amp;gt;

                    &amp;lt;use stroke="#FF0000" stroke-width="3" xlink:href="#path-1"&amp;gt;&amp;lt;/use&amp;gt;

                &amp;lt;/g&amp;gt;

                &amp;lt;polygon id="Shape" fill="#FF0000" points="19.7149758 19.5157005..."&amp;gt;&amp;lt;/polygon&amp;gt;

            &amp;lt;/g&amp;gt;

        &amp;lt;/g&amp;gt;

    &amp;lt;/g&amp;gt;

&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sketch generated this simple icon with 21 lines of markup.&lt;/p&gt;

&lt;p&gt;Relative to a typical HTML file, that is not many lines. But, for a simple icon, it's much more than necessary. Most icons that I work with are around 4-10 lines.&lt;/p&gt;

&lt;p&gt;Why the bloat? There are several elements and attributes that are redundant and can be removed. Let's have a look at what they are, and why we can remove them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Markup can we remove?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  XML Prolog
&lt;/h3&gt;

&lt;p&gt;The first thing that we can remove is the first line: the XML prolog.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Most XML documents begin with a prolog. A prolog is one or more lines of code that provide information about the current XML document and related documents. &lt;/p&gt;

&lt;p&gt;If the SVG is going to be embedded within an HTML document or another SVG, which it most likely will be, the prolog is redundant and can be removed. &lt;/p&gt;

&lt;p&gt;Leaving the prolog will have no effect to the user, but removing it helps keep your code clean and reduces file size.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; version Attribute
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tag comes packaged with the &lt;code&gt;version&lt;/code&gt; attribute, indicating that it is using the latest version of SVG – &lt;em&gt;SVG 1.1&lt;/em&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;svg version=”1.1″ … &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This attribute has &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/version" rel="noopener noreferrer"&gt;no influence&lt;/a&gt; on the rendering of the SVG and can be removed. &lt;/p&gt;

&lt;h3&gt;
  
  
  XML Comments
&lt;/h3&gt;

&lt;p&gt;Did you see Sketch's obtrusive XML comment?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!– Generator: Sketch 39.1 (31720) – http://www.bohemiancoding.com/sketch →
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Although in certain contexts, XML comments can be helpful, this particular comment is redundant. We don't need to know where the icon came from.&lt;/p&gt;

&lt;p&gt;Many other graphic editors include XML comments when generating SVGs, and these comments can also be safely removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;desc&amp;gt;&lt;/code&gt; tags
&lt;/h3&gt;

&lt;p&gt;Next, we’re going to look at the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;desc&lt;/code&gt; elements. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;title&amp;gt;Hospital&amp;lt;/title&amp;gt;

&amp;lt;desc&amp;gt;Created with Sketch.&amp;lt;/desc&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;You may not want to remove these elements.&lt;/strong&gt; It depends upon the context in which the SVG will be used. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;desc&lt;/code&gt; tags are helpful for accessibility. The &lt;code&gt;title&lt;/code&gt; element is displayed on hover in certain browsers. Both elements may also be displayed instead of the graphic if there is a situation where the SVG paths cannot be rendered.&lt;/p&gt;

&lt;p&gt;If the SVG provides important context to the page, for example, a graph or chart, then you should keep the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;desc&lt;/code&gt; tags, and change their text content to convey the content of the graphic.&lt;/p&gt;

&lt;p&gt;On the other hand, if the SVG does not provide important context, for example, an icon or logo, then the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;desc&lt;/code&gt; tags can be removed. &lt;/p&gt;

&lt;p&gt;As I am working with an icon in this example, I removed the tags.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags
&lt;/h3&gt;

&lt;p&gt;The major clutter of the SVG markup in my example is the chain of &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags that serve as a wrapper for the SVG paths. &lt;/p&gt;

&lt;p&gt;Most of the &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; elements have a &lt;code&gt;transform&lt;/code&gt; attribute, among others.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;g id="Maps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"&amp;gt;

    &amp;lt;g id="Map" transform="translate(-483.000000, -779.000000)"&amp;gt;

        &amp;lt;g id="Hospital" transform="translate(486.000000, 782.000000)"&amp;gt;

            &amp;lt;rect ...&amp;gt;&amp;lt;/rect&amp;gt;

            &amp;lt;g id="Rectangle-57"&amp;gt;

                &amp;lt;use ...&amp;gt;&amp;lt;/use&amp;gt;

                &amp;lt;use ...&amp;gt;&amp;lt;/use&amp;gt;

            &amp;lt;/g&amp;gt;

            &amp;lt;polygon ...&amp;gt;&amp;lt;/polygon&amp;gt;

        &amp;lt;/g&amp;gt;

    &amp;lt;/g&amp;gt;

&amp;lt;/g&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;All of these &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; elements are redundant and can be removed. &lt;/p&gt;

&lt;p&gt;Why &lt;em&gt;Sketch&lt;/em&gt; decides to leave an endless trail of &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags in its wake is one of life's great mysteries. We may never know.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; &lt;code&gt;viewBox&lt;/code&gt; Attribute
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; &lt;code&gt;viewBox&lt;/code&gt; attribute is a complicated concept. &lt;/p&gt;

&lt;p&gt;I will not delve into it within this article, but I strongly recommend Sara Soueidan’s &lt;a href="https://www.sarasoueidan.com/blog/svg-coordinate-systems/" rel="noopener noreferrer"&gt;article&lt;/a&gt; if you are unfamiliar with the attribute.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;svg viewBox=”0 0 39 39″ … &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags were removed, the positioning of the SVG elements was slightly off by 3 pixels. I adjusted the starting point of the &lt;code&gt;viewBox&lt;/code&gt; to compensate.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;svg viewBox=”-3 -3 39 39″ … &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This isn’t ideal, but it’s better than the endless chain of &lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; tags and their non-sensical &lt;code&gt;transform&lt;/code&gt; attributes. &lt;/p&gt;

&lt;p&gt;Although I did, you may not have to make any edits to the &lt;code&gt;viewBox&lt;/code&gt; attribute. But, if you do, it is likely that you will have to use different values.&lt;/p&gt;

&lt;h3&gt;
  
  
  IDs
&lt;/h3&gt;

&lt;p&gt;Most of the SVG elements were generated with an &lt;code&gt;id&lt;/code&gt; attribute. The &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&gt; element, for example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;rect id=”Rectangle-57″ … /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unless you need to target these elements with JavaScript, these &lt;code&gt;id&lt;/code&gt; attributes can be stripped out. The only instances where the &lt;code&gt;id&lt;/code&gt; attributes are important are within the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;In my example, the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; block looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;defs&amp;gt;

    &amp;lt;rect id=”path-1″ x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″&amp;gt;&amp;lt;/rect&amp;gt;

&amp;lt;/defs&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The elements within the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; are not initialised within this block, but rather they are declared for future use. &lt;/p&gt;

&lt;p&gt;You can see the &lt;code&gt;path-1&lt;/code&gt; element defined within the &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; block is referenced later in the markup via a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; element:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;use xlink:href=”#path-1″ … &amp;gt;&amp;lt;/use&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That means we need to keep the &lt;code&gt;id&lt;/code&gt; attribute so that the &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; element can reference the &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&gt;. But, the &lt;code&gt;id&lt;/code&gt; value &lt;code&gt;path-1&lt;/code&gt; is not descriptive. I renamed it to &lt;code&gt;border&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;defs&amp;gt;

    &amp;lt;rect id=”border” x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″&amp;gt;&amp;lt;/rect&amp;gt;

&amp;lt;/defs&amp;gt;

&amp;lt;use xlink:href=”#border” … &amp;gt;&amp;lt;/use&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The new &lt;code&gt;id&lt;/code&gt; clearly describes the element.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Okay, lets address the elephant in the room...&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not use an automated SVG optimiser, like &lt;a href="https://github.com/svg/svgo" rel="noopener noreferrer"&gt;SVGO&lt;/a&gt; or &lt;a href="https://jakearchibald.github.io/svgomg/" rel="noopener noreferrer"&gt;SVGOMG&lt;/a&gt;?
&lt;/h3&gt;

&lt;p&gt;It's true. There are a number of automated tools that will optimise SVG markup for you. &lt;/p&gt;

&lt;p&gt;But, this can come at a cost.&lt;/p&gt;

&lt;p&gt;In some cases, automated tools can merge all of the SVGs layers, making the SVG harder to work with in future. &lt;/p&gt;

&lt;p&gt;To quote Sarah Soueidan:&lt;/p&gt;

&lt;blockquote&gt;[SVGO] can break the SVG as well as any structure you create in it for animation, for example. I use SVGO sparingly. Ai export is v clean.&lt;/blockquote&gt;

&lt;p&gt;Here is an interesting Twitter thread on the topic by Sara Soueidan et al &lt;a href="https://twitter.com/SaraSoueidan/status/922792186839748614" rel="noopener noreferrer"&gt;here&lt;/a&gt;, which is also the source of the above quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;And that’s it. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;svg width="39px" height="39px" fill="none" viewBox="-3 -3 39 39" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"&amp;gt;

    &amp;lt;defs&amp;gt;

        &amp;lt;rect id="border" x="0" y="0" width="33" height="33" rx="9"&amp;gt;&amp;lt;/rect&amp;gt;

    &amp;lt;/defs&amp;gt;

    &amp;lt;rect fill-opacity="0.6" fill="#FFFFFF" opacity="0.5" x="0" y="0" width="33" height="33" rx="9"&amp;gt;&amp;lt;/rect&amp;gt;

    &amp;lt;use xlink:href="#border" stroke="#2D2D2D" stroke-width="6" fill-opacity="0.599999964" fill="#FFFFFF" fill-rule="evenodd"&amp;gt;&amp;lt;/use&amp;gt;

    &amp;lt;use xlink:href="#border" stroke="#FF0000" stroke-width="3"&amp;gt;&amp;lt;/use&amp;gt;

    &amp;lt;polygon fill="#FF0000" points="19.7149758 19.5157005..."&amp;gt;&amp;lt;/polygon&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We’ve managed to reduce the lines of code down to 9 -- over 50% of the lines of code were removed. That’s pretty impressive.&lt;/p&gt;

&lt;p&gt;Now, you’re probably wondering what the point of all this cleanup was. &lt;/p&gt;

&lt;p&gt;Well, clean SVG markup has a myriad of benefits, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Maintainability – your SVGs are easier to edit and maintain, without ever opening an image editor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speed – less code means smaller file sizes, smaller file sizes means a faster loading web page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animation – it becomes notably easier to animate SVGs when the markup is optimised and free from redundant tags.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accessibility – image editors seldom focus on accessibility when generating markup. Having clean markup makes it easier to create accessible graphics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JavaScript – understandable markup makes it easier to integrate with JavaScript. For instance, sensible, unique &lt;code&gt;id&lt;/code&gt; attributes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While it is true that an SVG minifier, such as SVGOMG, can do most of the leg work for you, it can also damage the quality of the SVG. &lt;/p&gt;

&lt;p&gt;Do you have the time? Are you going to animate the SVGs? It's contextual and the choice is yours.&lt;/p&gt;

&lt;p&gt;Thanks for reading. &lt;/p&gt;

</description>
      <category>svg</category>
      <category>markup</category>
      <category>xml</category>
    </item>
    <item>
      <title>Writing Baseline Accessible Markup and Styles</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Mon, 04 Sep 2017 14:04:43 +0000</pubDate>
      <link>https://dev.to/adammckenna/writing-baseline-accessible-markup-and-styles</link>
      <guid>https://dev.to/adammckenna/writing-baseline-accessible-markup-and-styles</guid>
      <description>&lt;p&gt;Article originally posted &lt;a href="https://amckenna.co/articles/writing-baseline-accessible-markup-and-styles" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Ah, &lt;em&gt;accessibility&lt;/em&gt;... You'll find most developers you raise the subject to will begin drifting off, as though you've just performed a magic spell on them.&lt;/p&gt;

&lt;p&gt;But, what is accessibility and why are so many developers uninterested?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility (a11y) refers to how usable an application is to &lt;em&gt;all&lt;/em&gt; audiences&lt;/strong&gt;. An accessible application is usable by anyone, regardless of physical, visual or hearing impairments. The experience is not compromised for any users.&lt;/p&gt;

&lt;p&gt;That sounds like a lot of work. And it can be. That's &lt;em&gt;one&lt;/em&gt; reason why so many developers are uninterested. &lt;/p&gt;

&lt;p&gt;Most of my experience has been in development agencies. Within these organisations, the goal is to maximise profit: churn good products out the door in the least time possible. In this environment, accessibility becomes a &lt;em&gt;nice to have&lt;/em&gt;. At least, that's the perspective of a project manager or product owner. Ask a developer and they'll say: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Accessibility is boring. Who cares?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's &lt;em&gt;another&lt;/em&gt; reason why they are so uninterested. &lt;/p&gt;

&lt;p&gt;I disagree. I don't think it is boring. It can be rewarding and fun to create robust interfaces that can be used by a multitude of audiences.&lt;/p&gt;

&lt;p&gt;But, whether it's boring or fun is irrelevant. Lets talk about who &lt;em&gt;does&lt;/em&gt; care. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dlf.org.uk/content/key-facts" rel="noopener noreferrer"&gt;A study&lt;/a&gt; conducted in 2008 by the &lt;a href="https://www.gov.uk/government/organisations/disability-rights-commission" rel="noopener noreferrer"&gt;Disability Rights Commission&lt;/a&gt; found that over there are over &lt;strong&gt;6.9 million disabled people&lt;/strong&gt; of working age in the UK, representing 19% of the working population.&lt;/p&gt;

&lt;p&gt;That's almost &lt;strong&gt;1 in every 5 people.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The types of disabilities captured in this static vary dramatically. But, it does mean that 1 in every 5 website visitors may have a disability that your website should cater for. If they are blind, for instance, and your website has no support for screen readers, what can they do? They have been rejected from your product.&lt;/p&gt;

&lt;p&gt;An accessible product is a more viable product. The more accessible, the more users the website can accommodate. &lt;/p&gt;

&lt;p&gt;Not to mention the ethical implications, of course. If you are conscious of the implications of a non-accessible website, and you continue to avoid the implementation of accessible features, could it be argued that you are flat out rejecting users with accessibility requirements?&lt;/p&gt;

&lt;p&gt;So, the answer to the question: &lt;em&gt;who cares?&lt;/em&gt; The answer (should be): everyone involved in the project. Whether you're developing for the web, mobile, tablet, or a toaster. If your application has user interaction in any form, you must consider accessibility.&lt;/p&gt;

&lt;p&gt;Thankfully, there is a lot of "low-hanging fruit" that can be snatched. With relatively little effort, you &lt;em&gt;can&lt;/em&gt; make a massive impact to an application's accessibility. We're going to explore how. &lt;/p&gt;

&lt;p&gt;We'll look at accessibility in your code. As such, factors including colours, UX design patterns, and so on are out of the scope of this article. That being said, those factors are as relevant to accessibility as anything covered in this article.&lt;/p&gt;

&lt;p&gt;This article should also not be viewed as a comprehensive list of 'dos' and 'do nots', but rather a selection of considerations that I believe are important and easy to achieve.&lt;/p&gt;

&lt;p&gt;Without further ado, lets crack on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Tools
&lt;/h2&gt;

&lt;p&gt;As a developer, one of the main disabilities we need to cater for is visual impairment. We need to ensure that people who can barely see, or cannot see at all, can still navigate your application, find all the information they need, and interact with it with the same ease as any other user. &lt;/p&gt;

&lt;p&gt;Most visually impaired users navigate the web with a technology known as a &lt;em&gt;screen reader&lt;/em&gt;. A screen reader scans an HTML document, interprets the markup, and reads the information to the user. Screen readers are operated using a keyboard so that users can interact with links and other interactive elements.&lt;/p&gt;

&lt;p&gt;There are a plethora of screen readers available, but the most popular screen readers, by platform, are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows - &lt;a href="https://www.nvaccess.org/" rel="noopener noreferrer"&gt;NVDA&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mac - VoiceOver for Mac (built-in)&lt;/li&gt;
&lt;li&gt;iOS - VoiceOver on iOS (built-in)&lt;/li&gt;
&lt;li&gt;Android - &lt;a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback&amp;amp;hl=en_GB" rel="noopener noreferrer"&gt;Google TalkBack&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key to making screen readers useful is rich, descriptive markup and views. This is achieved by using semantic elements (e.g. &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, etc.) as intended, correct headings, descriptive imagery, hidden elements, usable elements, the WAI-ARIA suite and factoring in a variety of other considerations. Android and iOS also have their own tools for making elements accessible. &lt;/p&gt;

&lt;p&gt;We'll explore each of these in turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Labels
&lt;/h2&gt;

&lt;p&gt;You should always label interactive elements, including links, buttons (if the elements children do not provide an adequate description) and inputs. &lt;/p&gt;

&lt;p&gt;You should also provide labels for links and tabs that have icons, but have no visible text.&lt;/p&gt;

&lt;p&gt;Lets look at a real example. With the &lt;code&gt;a&lt;/code&gt; tag, a screen reader will read the content within the elements opening and closing tags. However, this is typically non-descriptive. For instance:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="about-us.html"&amp;gt;Read More&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this example, a screen reader will literally read &lt;em&gt;"read more"&lt;/em&gt; to the user. How often have you seen this on the web?&lt;/p&gt;

&lt;p&gt;It’s not very indicative of where the link leads. If the user was skimming through the page, the user would simply hear &lt;em&gt;"read more, read more, read more…,"&lt;/em&gt; with no understanding of what they would discover if they clicked the link.&lt;/p&gt;

&lt;p&gt;How can we fix this?&lt;/p&gt;

&lt;h3&gt;
  
  
  On the web
&lt;/h3&gt;

&lt;p&gt;Thankfully, on the web you can use WAI-ARIA to provide descriptive labels to links. &lt;/p&gt;

&lt;p&gt;WAI-ARIA is an acronym for &lt;a href="https://www.w3.org/WAI/intro/aria" rel="noopener noreferrer"&gt;Web Accessibility Initiative - Accessible Rich Internet Applications&lt;/a&gt;. It’s a tool for providing markup with rich, semantic meaning. ARIA provides a library of attributes that you can use to enhance HTML elements.&lt;/p&gt;

&lt;p&gt;One such example is &lt;code&gt;aria-label&lt;/code&gt;. You can use the &lt;code&gt;aria-label&lt;/code&gt; attribute to assign a specific value that will be read by a screen reader instead of the element's value.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="about-us.html" aria-label="Read More About The Team"&amp;gt;Read More&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Alternatively, you can use &lt;code&gt;aria-labelledby&lt;/code&gt; to give the element another element’s value.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1 id="title"&amp;gt;Read More About The Team"&amp;lt;/h1&amp;gt;

&amp;lt;a href="about-us.html" aria-labelledby="title"&amp;gt;Read More&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;On Android, the approach is similar. You can use &lt;code&gt;android:contentDescription&lt;/code&gt; on an element in the same way as &lt;code&gt;aria-label&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Button
    android:id="@+id/some_id"
    android:src="@drawable/search"
    android:contentDescription="@string/search"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Swift
&lt;/h3&gt;

&lt;p&gt;When writing Swift for iOS, you can use the &lt;code&gt;accessibilityLabel&lt;/code&gt; from the UIAccessibility API.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.navigationController.navigationBar.backItem.setAccessibilityLabel("back")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Forms and Input Placeholders
&lt;/h2&gt;

&lt;p&gt;If you have form elements or inputs, don’t rely on the &lt;code&gt;placeholder&lt;/code&gt; attribute as a label. The HTML5 specification warns against this as it does not work as a label for screen reader users. &lt;/p&gt;

&lt;p&gt;It also disappears for regular users once the input has been populated. This makes forms difficult to revise once complete. &lt;/p&gt;
&lt;h3&gt;
  
  
  On the web
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" name="message" placeholder="Message…"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instead, you should provide an associated text label for every input. You should also provide the label first, and set the label’s &lt;code&gt;for&lt;/code&gt; attribute to the name of the form element it refers to: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;label for="message"&amp;gt;Message&amp;lt;/label&amp;gt;
&amp;lt;input type="text" name="message" placeholder="Message…"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;Similar to HTML5, Android XML uses the &lt;code&gt;android:hint&lt;/code&gt; instead of the &lt;code&gt;placeholder&lt;/code&gt; attribute. It works in the same way, and should not replace a label for the same reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;EditText 
    android:id="@+id/edit_text" 
    android:hint="@string/aac_edit_text_about_label" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instead, add a TextView label for inputs and add the labelFor attribute with the id value of the input it belongs to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;TextView
    android:labelFor="@+id/edit_text"
    android:text="@string/aac_edit_text_about_label" /&amp;gt;

&amp;lt;EditText android:id="@+id/edit_text" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Swift
&lt;/h3&gt;

&lt;p&gt;Swift for iOS is slightly different. You should also not rely on the placeholder attribute for UITextFields:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let messageField = UITextField = UITextField (...);
messageField.placeholder = "Message…"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, unlike HTML5 and Android, there isn’t a way to connect a label to an input. Instead, you should use the accessibilityLabel attribute directly on the text input:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let messageField = UITextField = UITextField (...);
messageField.accessibilityLabel = "Message…"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The placeholder attribute itself is fine across all three platforms, and should be used where necessary. &lt;/p&gt;

&lt;p&gt;The problem is that developers use it as a replacement for a label. This is not its purpose. It should always be used alongside a label, not as a replacement. &lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Good Labels and Descriptions
&lt;/h2&gt;

&lt;p&gt;Providing labels and descriptions is important so that users understand an elements purpose, and the result of interacting with the element. &lt;/p&gt;

&lt;p&gt;It's also important to ensure that those labels and descriptions are well written. A poorly written label can do as much damage as having no label at all. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://material.io/guidelines/usability/accessibility.html#accessibility-writing" rel="noopener noreferrer"&gt;Google Material UI usability guidelines&lt;/a&gt; defines a set of rules by which to write good labels. These are ideal for most applications.&lt;/p&gt;

&lt;p&gt;Lets explore these rules:&lt;/p&gt;

&lt;h3&gt;
  
  
  Be succinct
&lt;/h3&gt;

&lt;p&gt;Keep labels short and ‘to the point’, ensuring the label is brief but descriptive. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;‘Logout Button. Logout of account &lt;a href="mailto:adam@gospelware.co.uk"&gt;adam@gospelware.co.uk&lt;/a&gt; and return to homepage’&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;‘Logout of &lt;a href="mailto:adam@gospelware.co.uk"&gt;adam@gospelware.co.uk&lt;/a&gt;’&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Avoid describing control type in text
&lt;/h3&gt;

&lt;p&gt;Labels should not describe the control type, whether it’s a button, link, field, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;'Message Field.'&lt;/p&gt;

&lt;p&gt;'Settings Button.'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Screen readers will announce the control type. Therefore, specifying the type will result in the type being announced to the user twice. &lt;/p&gt;

&lt;p&gt;In our example, a user would hear “Message Field. Field” and “Settings Button. Button.” &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;'Message.'&lt;/p&gt;

&lt;p&gt;'Settings.'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, omit the control type. In our second example, the user will hear “Settings Button” and “Message Field”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid describing control state in text
&lt;/h3&gt;

&lt;p&gt;For the same reasons, do not describe an element’s state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Accept Terms and Conditions is selected&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Accept Terms and Conditions&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Indicate what an element does
&lt;/h3&gt;

&lt;p&gt;Describe what an element does when interacted with. Do not describe the element itself nor the properties of the element.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Burger menu icon&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Pencil icon&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Show/hide navigation menu&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Edit&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Don’t mention the exact gesture or interaction
&lt;/h3&gt;

&lt;p&gt;Do not discuss a gesture or interaction, describe the task instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DON’T&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Tap to speak&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Click to start&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;DO&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Voice search&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Start game&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Dialogs
&lt;/h2&gt;

&lt;p&gt;Dialogs, or modals, are useful elements for conveying information. They are typically used to prompt a user for information, or to provide information that requires the user's immediate attention.&lt;/p&gt;

&lt;p&gt;At the time of writing, there is no native HTML5 tag that describes a dialog, although common 3rd party JavaScript libraries and frameworks, including &lt;a href="https://jqueryui.com/dialog/" rel="noopener noreferrer"&gt;jQuery&lt;/a&gt; and &lt;a href="https://material.angularjs.org/latest/demo/dialog" rel="noopener noreferrer"&gt;Angular Material&lt;/a&gt;, offer pre-built accessible dialogs.&lt;/p&gt;

&lt;p&gt;If you are not using a library or framework with out-of-the-box dialogs, you will need to use a regular old &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag with a few lines of JavaScript to prompt the dialog (this is out of the scope of this article). &lt;/p&gt;

&lt;p&gt;A typical dialog might look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="dialog"&amp;gt;
    Whoa, mate. You've made a mistake.
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the user encounters an error, ensure a label is provided and the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; uses the &lt;code&gt;role=”alert”&lt;/code&gt; attribute and value.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div role="alert"&amp;gt;
    &amp;lt;span class="close-icon" tabindex="0"&amp;gt;x&amp;lt;/span&amp;gt;
    The form has an error: you forgot to provide a message.
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;An element using &lt;code&gt;role=”alert”&lt;/code&gt; will be displayed to a screen reader user when the element appears in the UI. The element would typically be displayed via JavaScript or CSS as necessary.&lt;/p&gt;

&lt;p&gt;Both Android and iOS natively offer accessible dialogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images - 'alt' Attribute
&lt;/h2&gt;

&lt;p&gt;Another thing to consider for screen readers is imagery. Imagery used in an application falls under one of two categories: &lt;em&gt;decorative&lt;/em&gt; or &lt;em&gt;informative&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Decorative images, on the other hand, serve no purpose other than aesthetics. These images should be ignored by screen readers.&lt;/p&gt;

&lt;p&gt;Informative images present information to the user. They need to be delivered to the screen reader in text form, otherwise the images information will be lost. &lt;/p&gt;

&lt;p&gt;How do we solve this issue? This is where the &lt;code&gt;alt&lt;/code&gt; attribute comes in. &lt;/p&gt;

&lt;p&gt;If the image provides relevant information, for example a graph or info-graphic, you need to use the &lt;code&gt;img&lt;/code&gt; tag with an &lt;code&gt;alt&lt;/code&gt; attribute. The &lt;code&gt;alt&lt;/code&gt; attribute will describe the image's content. For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="political-graph.jpg" alt="Nationwide results at a glance: ..."&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, you should input data of any notable complexity into a table or similar layout, and rely on images for basic data.&lt;/p&gt;

&lt;p&gt;Decorative images include icons, logos, and backgrounds. Serve decorative images using the &lt;code&gt;background-image&lt;/code&gt; CSS property where possible. &lt;/p&gt;

&lt;p&gt;If the image cannot be served using the &lt;code&gt;background-image&lt;/code&gt; CSS property, the image should be served using the &lt;code&gt;img&lt;/code&gt; tag with an empty &lt;code&gt;alt&lt;/code&gt; attribute. When the &lt;code&gt;alt&lt;/code&gt; attribute is empty, the image is ignored by screen readers.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="decorative-icon.jpg" alt=""&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Headers
&lt;/h2&gt;

&lt;p&gt;Headers are used across websites to indicate page and section titles. They are delivered using the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt; tags. Here’s an example of a website header hierarchy taken from a random website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0wxfvhybee46txxdpj2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0wxfvhybee46txxdpj2r.png" alt="Gospelware.co.uk website headers" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="http://gospelware.co.uk" rel="noopener noreferrer"&gt;gospelware.co.uk&lt;/a&gt; tested via &lt;a href="http://www.seowebpageanalyzer.com/" rel="noopener noreferrer"&gt;seowebpageanalyzer.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only use header tags for titles. Do not use them for changing aesthetics. &lt;/p&gt;

&lt;p&gt;Header tags should only be used in descending hierarchy and should not be skipped. &lt;/p&gt;

&lt;p&gt;For example, if you use the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag, and need to use another heading below it, the next heading must be an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tag, or another &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag. This applies at every heading level. &lt;/p&gt;

&lt;p&gt;The document should always begin with an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag, and no other heading tags.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hidden Descriptions
&lt;/h2&gt;

&lt;p&gt;A user interface can provide a lot of context to information on a webpage. This information can be lost when the page is delivered as text via a screen reader. &lt;/p&gt;

&lt;p&gt;You can combat this by using hidden elements that are displayed to screen readers, but hidden from all other users. This can be achieved with a small chunk of clever CSS:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.hide {
   position: absolute !important;
   top: -9999px !important;
   left: -9999px !important;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Empty states
&lt;/h2&gt;

&lt;p&gt;An empty state refers to a short piece of text that informs a user that no data is present. &lt;span&gt;Here’s an example from Outlook:&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe59fzu2inf09fdztuj5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe59fzu2inf09fdztuj5e.png" alt="" width="607" height="833"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Empty states should always be provided in situations where data may be present, but none is. For example, a 'to-do' list or an email inbox.&lt;/p&gt;

&lt;p&gt;This means that screen reader users know right away that there is no data. Otherwise, they may wait a while under the assumption that the data is loading or that an issue has occurred that has prevented the data from displaying.&lt;/p&gt;
&lt;h2&gt;
  
  
  Styles
&lt;/h2&gt;

&lt;p&gt;Finally, lets briefly discuss CSS.&lt;/p&gt;

&lt;p&gt;Any elements that are clickable should have a hover state that visually indicates to the user that the element is clickable. This can be achieved using the CSS pseudo &lt;code&gt;hover&lt;/code&gt; selector:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.button:hover {
    background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;hover&lt;/code&gt; pseudo selector only works for mouse and touch-based devices. It does not work for elements that have been selected via a keyboard. &lt;/p&gt;

&lt;p&gt;As a result, if only &lt;code&gt;hover&lt;/code&gt; is used, users who do not, or cannot, use a mouse or touch device will not receive any visual indication that the current selected element is selected.&lt;/p&gt;

&lt;p&gt;To combat this, you should use the &lt;code&gt;focus&lt;/code&gt; pseudo selector alongside any instances of the &lt;code&gt;hover&lt;/code&gt; selector:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.button:hover,
.button:focus {
    background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As a last mention, there is also a new CSS pseudo selector that has been proposed, but is not yet fully implemented, called :focus-within. &lt;/p&gt;

&lt;p&gt;It lets you set styles on a parent element when any of the parent element’s child elements have been selected. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div:focus-within {
    background: yellow;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Although this is in an experimental phase, I am sure this will become widely supported soon. It serves as a reminder that the web is constantly becoming more and more accessible. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Perhaps it's true that accessibility is boring, and maybe accessibility is dull, and certainly accessibility does require more work.&lt;/p&gt;

&lt;p&gt;But, it is important. &lt;/p&gt;

&lt;p&gt;I truly believe anyone, regardless of any disability or ailment, should be able to enjoy the web - and mobile applications - just as much as any so-called "fully-abled" person. I’m sure you do too.&lt;/p&gt;

&lt;p&gt;If you do agree with this sentiment, then perhaps it’s time you start to reassess how you feel about accessibility. &lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  An aside: accessibility is difficult.
&lt;/h3&gt;

&lt;p&gt;Accessibility &lt;em&gt;is&lt;/em&gt; difficult, even with these quick wins, but why?&lt;/p&gt;

&lt;p&gt;I believe there are there two main factors that make accessibility difficult.&lt;/p&gt;

&lt;p&gt;The first is a lack of understanding or awareness of the issues that make applications inaccessible, and the steps to resolve those issues. There is a plethora of resources online to identify commons issues. The best way, of course, is to do real user testing with your website.&lt;/p&gt;

&lt;p&gt;The second is because it is difficult to empathise. This is an expansive topic. The best way to empathise is real use cases. Attaining feedback from real users with real disabilities using your application. Of course, this option is seldom available in most situations. &lt;/p&gt;

&lt;p&gt;Thankfully, &lt;a href="https://ericwbailey.design/" rel="noopener noreferrer"&gt;Eric Bailey&lt;/a&gt;, a Boston-based designer, has created a &lt;a href="https://empathyprompts.net" rel="noopener noreferrer"&gt;very useful website&lt;/a&gt; to emulate accessibility issues and help developers gain a bit of empathy. I highly recommend checking it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://material.io/guidelines/usability/accessibility.html#accessibility-writing" rel="noopener noreferrer"&gt;https://material.io/guidelines/usability/accessibility.html#accessibility-writing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/training/accessibility/accessible-app.html" rel="noopener noreferrer"&gt;https://developer.android.com/training/accessibility/accessible-app.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deque.com/blog/accessible-text-input-android/" rel="noopener noreferrer"&gt;https://www.deque.com/blog/accessible-text-input-android/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.paciellogroup.com/blog/2011/02/html5-accessibility-chops-the-placeholder-attribute/" rel="noopener noreferrer"&gt;https://www.paciellogroup.com/blog/2011/02/html5-accessibility-chops-the-placeholder-attribute/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/uikit/accessibility/uiaccessibility" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/uikit/accessibility/uiaccessibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_alert_role" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_alert_role&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://webaim.org/techniques/semanticstructure/" rel="noopener noreferrer"&gt;http://webaim.org/techniques/semanticstructure/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/places-its-tempting-to-use-display-none-but-dont/" rel="noopener noreferrer"&gt;https://css-tricks.com/places-its-tempting-to-use-display-none-but-dont/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.seowebpageanalyzer.com/" rel="noopener noreferrer"&gt;http://www.seowebpageanalyzer.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/documentation/objectivec/nsobject/1615181-accessibilitylabel" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/objectivec/nsobject/1615181-accessibilitylabel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/33077902/is-there-a-way-to-customise-accessibility-label-on-the-navigation-bar-back-butto" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/33077902/is-there-a-way-to-customise-accessibility-label-on-the-navigation-bar-back-butto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techopedia.com/definition/10165/accessibility-a11y" rel="noopener noreferrer"&gt;https://www.techopedia.com/definition/10165/accessibility-a11y&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>web</category>
      <category>html</category>
      <category>css</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Hi, I'm Adam McKenna</title>
      <dc:creator>Adam McKenna</dc:creator>
      <pubDate>Tue, 25 Apr 2017 09:41:01 +0000</pubDate>
      <link>https://dev.to/adammckenna/hi-im-adam-mckenna</link>
      <guid>https://dev.to/adammckenna/hi-im-adam-mckenna</guid>
      <description>&lt;p&gt;I have been coding for some years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/AdamMcQuiff" rel="noopener noreferrer"&gt;@AdamMcQuiff&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Newcastle upon Tyne.&lt;/p&gt;

&lt;p&gt;I work for &lt;a href="http://zetec-it.com" rel="noopener noreferrer"&gt;Zetec Digital&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: JavaScript, PHP, C#.&lt;/p&gt;

&lt;p&gt;I am currently learning more about API development.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
