Archiwum kategorii: CSS

The Critical Request

Post pobrano z: The Critical Request

Serving a website seems pretty simple: Send some HTML, the browser figures out what resources to load next. Then we wait patiently for the page to be ready.

Little may you know, a lot is going on under the hood.

Have you ever wondered how browser figures out which assets should be requested and in what order?

Today we’re going to take a look at how we can use resource priorities to improve the speed of delivery.

Resource priority at work

Most browsers parse HTML using a streaming parser—assets are discovered within the markup before it has been fully delivered. As assets are found, they’re added to a network queue along with a predetermined priority.

In Chrome today, there are a number of asset prioritization levels: Very Low, Low, Medium, High and Very high. Peeking into Chrome DevTools source shows that these are aliased to slightly different labels: Lowest, Low, Medium, High and Highest.

To see how your site is prioritizing requests, you can enable a priority column in the Chrome DevTools network request table.

If you’re using Safari Technology preview, the (new!) Priority column can be shown in exactly the same way.

Show the Priority column by right clicking any of the request table headings.

You’ll also find the priority for a given request in the Performance tab.

Resource timings and priorities are shown on hover

How does Chrome prioritize resources?

Each resource type (CSS, JavaScript, fonts, etc.) has their own set of rules that dictate how they’ll be prioritized. What follows is a non-exhaustive list of network priority plans:

HTML— Highest priority.

Styles—Highest priority. Stylesheets that are referenced using an @import directive will also be prioritized Highest, but they’ll be queued after blocking scripts.

Images are the only assets that can vary priority based on viewport heuristics. All images start with a priority of Low but will be upgraded to Medium priority when to be rendered within the visible viewport. Images outside the viewport (also known as „below the fold”) will remain at Low priority.

During the process of researching this article, I discovered (with the help of Paul Irish) that Chrome DevTools are currently misreporting images that have been upgraded to Medium as Low priority. Paul wrote up a bug report, which you can track here.

If you’re interested in reading the Chrome source that handles the image priority upgrade, start with UpdateAllImageResourcePriorities and ComputeResourcePriority.

Ajax/XHR/fetch()—High priority.

Scripts follow a complex loading prioritization scheme. (Jake Archibald wrote about this in detail during 2013. If you want to know the science behind it, I suggest you grab a cuppa and dive in). The TL;DR version is:

  • Scripts loaded using <script src="name.js"></script> will be prioritized as High if they appear in the markup before an image.
  • Scripts loaded using <script src="name.js"></script> will be prioritized as Medium if they’re appear in the markup after an image.
  • Scripts that use async or defer attributes will be prioritized as Low.
  • Scripts using type="module" will be prioritized as Low.

Fonts are a bit of a strange beast; they’re hugely important resources (who else loves the „’I see it!”, „Now it’s gone”, „Whoa, a new font!” game?), so it makes sense that fonts are downloaded at the Highest priority.

Unfortunately, most @font-face rules are found within an external stylesheet (loaded using something like: <link rel="stylesheet" href="file.css">). This means that web fonts are usually delayed until after the stylesheet has downloaded.

Even if your CSS file references a @font-face font, it will not be requested until it is used on a selector and that selector matches an element on the page. If you’ve built a single page app that doesn’t render any text until it renders, you’re delaying the fonts even further.

What makes a request critical?

Most websites effectively ask the browser to load everything for the page to be fully rendered, there is no concrete concept of „above the fold”.

Back in the day, browsers wouldn’t make more than 6 simultaneous requests per domain — people hacked around this by using assets-1.domain.tld, assets-2.domain.tld hosts to increase the number of asynchronous downloads but failed to recognize that there would be a DNS hit and TCP connection for each new domain and asset.

While this approach had some merits, many of us didn’t understand the full impacts and certainly didn’t have good quality browser developer tools to confirm these experiments.

Thankfully today, we have great tools at our disposal. Using CNN as an example, let’s identify assets that are absolutely required for the viewport to be visually ready (also known as useful to a someone trying to read it).

The user critical content is the masthead, and leading article.

There’s really only 5 things that are necessary to display this screen (and not all of them need to be loaded before the site is usable):

  • Most importantly, the HTML. If all else fails the user can still read the page.
  • CSS
  • The logo (A PNG background-image placed by CSS. This could probably be an inline SVG).
  • 4(!) web font weights.
  • The leading article image.

These assets (note the lack of JavaScript) are essential to the visuals that make up the main viewport of the page. These assets are the ones that should be loaded first.

Diving into the performance panel in Chrome shows us that around 50 requests are made before the fonts and leading image are requested.

CNN.com becomes fully rendered somewhere around the 9s mark. This was recorded using a 4G connection, with reasonably spotty connectivity.

There’s a clear mismatch between the requests that are required for viewing and the requests that are being made.

Controlling resource priorities

Now that we’ve defined what critical requests are, we can start to prioritize them using a few simple, powerful tweaks.

Preload (<link rel="preload" href="font.woff" />) instructs the browser to add font.woff to the browser’s download queue at a „High” priority.

Note: as="font" is the reason why font.woff would be downloaded as High priority — It’s a font, so it follows the priority plan discussed earlier in the „How does Chrome prioritise resources?” section.

Essentially, you’re telling the browser: You might not know it yet, but we’re going to need this.

This is perfect for those critical requests that we identified earlier. Web fonts can nearly always be categorized as absolutely critical, but there are some fundamental issues with how fonts are discovered and loaded:

  • We wait for the CSS to be loaded, parsed and applied before @font-face rules are discovered.
  • A font is not added to the browser’s network queue until it matches up its CSS rules to the DOM via the selectors.
  • This selector matching occurs during style recalculation. It doesn’t necessarily happen immediately after download. It can be delayed if the main thread is busy.

In most cases, fonts are delayed by a number of seconds, just because we’re not instructing the browser to download them in a timely fashion.

On a mobile device with a slow CPU, laggy connectivity, and without a properly-constructed fallback this can be an absolute deal breaker.

Preload in action: fonts

I ran two tests against calibreapp.com. On the first run, I’d changed nothing about the site at all. On the second, I added these two tags:

<link rel="preload" as="font" href="" type="font/woff2" crossorigin />

<link rel="preload" as="font" href="" type="font/woff2" crossorigin />

Below, you’ll see a visual comparison of the rendering of these two tests. The results are quite staggering:

The page rendered 3.5 seconds faster when the fonts were preloaded.

Bottom: Fonts are preloaded — The site finishes rendering in 5 seconds on a „emerging markets” 3G connection.

<link rel="preload"> also accepts a media="" attribute, which will selectively prioritize resources based on @media query rules:

<link rel="preload" href="article-lead-sm.jpg" as="image" type="image/jpeg" media="only screen and (max-width: 48rem)">

Here, we’re able to preload a particular image for small screen devices. Perfect for that „main hero image”.

As demonstrated above, a simple audit and a couple of tags later and we’ve vastly improved the delivery & render phase. Super.

Getting tough on web fonts

69% of sites use web fonts, and unfortunately, they’re providing a sub-par experience in most cases. They appear, then disappear, then appear again, change weights and jolt the page around during the render sequence.

Frankly, this sucks on almost every level.

As you’ve seen above, controlling the request order and priority of fonts has a massive effect on render speed. It’s clear that we should be looking to prioritize web font requests in most cases.

We can make further improvements using the CSS font-display property. allows us to control how fonts display during the process of web fonts being requested and loaded.

There are 4 options at your disposal, but I’d suggest using font-display: swap;, which will show the fallback font until the web font has loaded—at which point it’ll be replaced.

Given a font stack like this:

body {
  font-family: Calibre, Helvetica, Arial;
}

The browser will display Helvetica (or Arial, if you don’t have Helvetica) until the Calibre font has loaded. Right now, Chrome and Opera are the only browsers that support font-display, but it’s a step forward, and there’s no reason to not use it starting today.

Keeping on top of page performance

As you’re well aware, websites are never „complete”. There are always improvements to be made and it can feel overwhelming, quickly.

Calibre is an automated tool for auditing performance, accessibility and web best practices, it’ll help you stay on top of things.

As you’ve seen above, there are a few metrics that are key to understanding user performance.

  • First paint, tells us when the browser goes from „nothing to something”.
  • First meaningful paint, tells us when the browser has „rendered something useful”.
  • Finally, First Interactive will tell you when the page has fully rendered, and the JavaScript main thread has settled (low CPU activity for a number of seconds).
Here, we set a budget on CNN’s „First meaningful paint” for <5 seconds.

You can set budgets against all these key user experience metrics. When those budgets are exceeded (or met) your team will be notified by Slack, email or wherever you like.

Calibre displays network request priority, so you can be sure of the requests being made. Tweak priorities and improve performance.

I hope that you’ve learned some valuable skills to audit requests and their priorities, as well as sparked a few ideas to experiment with to make meaningful performance improvements.

Your critical request checklist:

  • ✅ Enable the Priority column in Chrome DevTools.
  • ✅ Decide which requests must be made before users can see a fully rendered page.
  • ✅ Reduce the number of required critical requests where possible.
  • ✅ Use for assets that will probably be used on the next page of the site.
  • ✅ Use <link https://example.com/other/styles.css rel=preload as=style> nopush HTTP headers to tell the browser which resources to preload before the HTML has been fully delivered.
  • 🚫 HTTP/2 Server push is thorny. Probably avoid it. (See this informative document by Tom Bergan, Simon Pelchat and Michael Buettner, as well as Jake Archibald’s „HTTP/2 Push is tougher than I thought”)
  • ✅ Use font-display: swap; with web fonts where possible.
  • ⏱ Are web fonts being used? Can they be removed? If no: prioritize them and use WOFF2!
  • ⏱ Is a late loading script delaying your single page app from displaying anything at all?
  • 📹 Check this great free screencast by Front End Center that shows how load webfonts with the best possible fallback experience.
  • 🔍 View chrome://net-internals/#events and load a page — this logs network related events.
  • No request is faster than no request. ✌️

The Critical Request is a post from CSS-Tricks

Simple Server Side Rendering, Routing, and Page Transitions with Nuxt.js

Post pobrano z: Simple Server Side Rendering, Routing, and Page Transitions with Nuxt.js

A bit of a wordy title, huh? What is server side rendering? What does it have to do with routing and page transitions? What the heck is Nuxt.js? Funnily enough, even though it sounds complex, working with Nuxt.js and exploring the benefits of isn’t too difficult. Let’s get started!

Server side rendering

You might have heard people talking about server side rendering as of late. We looked at one method to do that with React recently. One particularly compelling aspect is the performance benefits. When we render our HTML, CSS, and JavaScript on the server, we often have less JavaScript to parse both initially and on subsequent updates. This article does really well going into more depth on the subject. My favorite takeaway is:

By rendering on the server, you can cache the final shape of your data.

Instead of grabbing JSON or other information from the server, parsing it, then using JavaScript to create layouts of that information, we’re doing a lot of those calculations upfront, and only sending down the actual HTML, CSS, and JavaScript that we need. This can reap a lot of benefits with caching, SEO, and speed up our apps and sites.

What is Nuxt.js?

Server side rendering sounds pretty nice, but you’re probably wondering if it’s difficult to set up. I’ve been using Nuxt.js for my Vue applications lately and found it surprisingly simple to work with. To be clear: you don’t need to use Nuxt.js in particular to do server side rendering. I’m just a fan of this tool for many reasons. I ran some tests last month and found that Nuxt.js had even higher lighthouse scores out of the gate than Vue’s PWA template, which I thought was impressive.

Nuxt.js is a higher-level framework that you can use with a CLI command that you can use to create universal Vue applications. Here are some, not all, of the benefits:

  • Server-Side Rendering
  • Automatic Code Splitting
  • Powerful Routing System
  • Great lighthouse scores out of the gate 🐎
  • Static File Serving
  • ES6/ES7 Transpilation
  • Hot reloading in Development
  • Pre-processors: SASS, LESS, Stylus, etc
  • Write Vue Files to create your pages and layouts!
  • My personal favorite: easily add transitions to your pages

Let’s set up a basic application with some routing to see the benefits for ourselves.

Getting Set up

The first thing we need to do if you haven’t already is download Vue’s CLI. You can do so globally with this command:

npm install -g vue-cli

# ... or ...
 
yarn add global vue-cli

You will only need to do this once, not every time you use it.

Next, we’ll use the CLI to scaffold a new project, but we’ll use Nuxt.js as the template:

vue init nuxt/starter my-project
cd my-project
yarn  # or...  npm install
npm run dev

You’ll see the progress of the app being built and it will give you a dedicated development server to check out: http://127.0.0.1:3000/. This is what you’ll see right away (with a pretty cool little animation):

Screenshot of Nuxt starting screen

Let’s take a look at what’s creating this initial view of our application at this point. We can go to the `pages` directory, and inside see that we have an `index.vue` page. If we open that up, we’ll see all of the markup that it took to create that page. We’ll also see that it’s a `.vue` file, using single file components just like any ordinary `vue` file, with a template tag for the HTML, a script tag for our scripts, where we’re importing a component, and some styles in a style tag. (If you aren’t familiar with these, there’s more info on what those are here.) The coolest part of this whole thing is that this `.vue` file doesn’t require any special setup. It’s placed in the `pages` directory, and Nuxt.js will automatically make this server-side rendered page!

Let’s create a new page and set up some routing between them. In `pages/index.vue`, dump the content that’s already there, and replace it with:

<template>
  <div class="container">
    <h1>Welcome!</h1>
    <p><nuxt-link to="/product">Product page</nuxt-link></p>
  </div>
</template>

<style>
.container {
  font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
  padding: 60px;
}
</style>

Then let’s create another page in the pages directory, we’ll call it `product.vue` and put this content inside of it:

<template>
  <div class="container">
    <h1>This is the product page</h1>
    <p><nuxt-link to="/">Home page</nuxt-link></p>
  </div>
</template>

Right away, you’ll see this:

Ta-da! 🏆
Right away, we have server side rendering, routing between pages (if you check out the URL you can see it’s going between the index page and product page), and we even have a sweet little green loader that zips across the top. We didn’t have to do much at all to get that going.

You might have noticed in here, there’s a special little element: <nuxt-link to="/">. This tag can be used like an a tag, where it wraps around a bit of content, and it will set up an internal routing link between our pages. We’ll use to="/page-title-here" instead of an href.

Now, let’s add some transitions. We’ll do this in a few stages: simple to complex.

Creating Page Transitions

We already have a really cool progress bar that runs across the top of the screen as we’re routing and makes the whole thing feel very zippy. (That’s a technical term). While I like it very much, it won’t really fit the direction we’re headed in, so let’s get rid of it for now.

We’re going to go into our `nuxt.config.js` file and change the lines:

/*
** Customize the progress-bar color
*/
loading: { color: '#3B8070' },

to

loading: false,

You’ll also notice a few other things in this nuxt.config.js file. You’ll see our meta and head tags as well as the content that will be rendered inside of them. That’s because we won’t have a traditional `index.html` file as we do in our normal CLI build, Nuxt.js is going to parse and build our `index.vue` file together with these tags and then render the content for us, on the server. If you need to add CSS files, fonts, or the like, we would use this Nuxt.js config file to do so.

Now that we have all that down, let’s understand what’s available to us to create page transitions. In order to understand what’s happening on the page that we’re plugging into, we need to review how the transition component in Vue works. I’ve written an article all about this here, so if you’d like deeper knowledge on the subject, you can check that out. But what you really need to know is this: under the hood, Nuxt.js will plug into the functionality of Vue’s transition component, and gives us some defaults and hooks to work with:

transition component hooks

You can see here that we have a hook for what we want to happen right before the animation starts enter, during the animation/transition enter-active, and when it finishes. We have these same hooks for when something is leaving, prepended with leave instead. We can make simple transitions that just interpolate between states, or we could plug a full CSS or JavaScript animation into them.

Usually in a Vue application, we would wrap a component or element in <transition> in order to use this slick little functionality, but Nuxt.js will provide this for us at the get-go. Our hook for the page will begin with, thankfully- page. All we have to do to create an animation between pages is add a bit of CSS that plugs into the hooks:

.page-enter-active, .page-leave-active {
  transition: all .25s ease-out;
}
.page-enter, .page-leave-active {
  opacity: 0;
  transform-origin: 50% 50%;
}

I’m also going to add an extra bit of styling here so that you can see the page transitions a little easier:

html, body {
  font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
  background: #222;
  color: white;
  width: 100vw;
  height: 100vh;
}

a, a:visited {
  color: #3edada;
  text-decoration: none;
}

.container {
  padding: 60px;
  width: 100vw;
  height: 100vh;
  background: #444;
}

Right now we’re using a CSS Transition. This only gives us the ability to designate what to do in the middle of two states. We could do something a little more interesting by having an animation adjust in a way that suggests where something is coming from and going to. For that to happen, we could separate out transitions for page-enter and page-leave-active classes, but it’s a little more DRY to use a CSS animation and specify where things are coming from and going to, and plug into each for .page-enter-active, and .page-leave-active:

.page-enter-active {
  animation: acrossIn .45s ease-out both;
} 

.page-leave-active {
  animation: acrossOut .65s ease-in both;
} 

@keyframes acrossIn {
  0% {
    transform: translate3d(-100%, 0, 0);
  }
  100% {
    transform: translate3d(0, 0, 0);
  }
}

@keyframes acrossOut {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(100%, 0, 0);
  }
}

Let’s also add a little bit of special styling to the product page so we can see the difference between these two pages:

<style scoped>
  .container {
    background: #222;
  }
</style>

This scoped tag is pretty cool because it will apply the styles for this page/vue file only. If you have heard of CSS Modules, you’ll be familiar with this concept.

We would see this (this page is for demo purposes only, that’s probably too much movement for a typical page transition):

Now, let’s say we have a page with a totally different interaction. For this page, the movement up and down was too much, we just want a simple fade. For this case, we’d need to rename our transition hook to separate it out.

Let’s create another page, we’ll call it the contact page and create it in the pages directory.

<template>
  <div class="container">
    <h1>This is the contact page</h1>
    <p><nuxt-link to="/">Home page</nuxt-link></p>
  </div>
</template>

<script>
export default {
  transition: 'fadeOpacity'
}
</script>

<style>
.fadeOpacity-enter-active, .fadeOpacity-leave-active {
  transition: opacity .35s ease-out;
}

.fadeOpacity-enter, .fadeOpacity-leave-active {
  opacity: 0;
}
</style>

Now we can have two-page transitions:

You can see how we could build on these further and create more and more streamlined CSS animations per page. But from here let’s dive into my favorite, JavaScript animations, and create page transitions with a bit more horsepower.

Javascript Hooks

Vue’s <transition> component offers some hooks to use JavaScript animation in place of CSS as well. They are as follows, and each hook is optional. The :css="false" binding lets Vue know we’re going to use JS for this animation:

<transition 
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"

  @before-Leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
  :css="false">
 
 </transition>

The other thing we have available to us are transition modes. I’m a big fan of these, as you can state that one animation will wait for the other animation to finish transitioning out before transitioning in. The transition mode we will work with will be called out-in.

We can do something really wild with JavaScript and the transition mode, again, we’re going a little nuts here for the purposes of demo, we would usually do something much more subtle:

In order to do something like this, I’ve run yarn add gsap because I’m using GreenSock for this animation. In my `index.vue` page, I can remove the existing CSS animation and add this into the <script> tags:

import { TweenMax, Back } from 'gsap'

export default {
  transition: {
    mode: 'out-in',
    css: false,
    beforeEnter (el) {
      TweenMax.set(el, {
        transformPerspective: 600,
        perspective: 300,
        transformStyle: 'preserve-3d'
      })
    },
    enter (el, done) {
      TweenMax.to(el, 1, {
        rotationY: 360,
        transformOrigin: '50% 50%',
        ease: Back.easeOut
      })
      done()
    },
    leave (el, done) {
      TweenMax.to(el, 1, {
        rotationY: 0,
        transformOrigin: '50% 50%',
        ease: Back.easeIn
      })
      done()
    }
  }
}

All of the code for these demos exist in my Intro to Vue repo for starter materials if you’re getting ramped up learning Vue.

One thing I want to call out here is that currently there is a bug for transition modes in Nuxt.js. This bug is fixed, but the release hasn’t come out yet. It should be all fixed and up to date in the upcoming 1.0 release, but in the meantime, here is a working simple sample demo, and the issue to track.

With this working code and those JavaScript hooks we can start to get much fancier and create unique effects, with different transitions on every page:

Here’s the site that the demo was deployed to if you’d like to see it live: https://nuxt-type.now.sh/ as well as the repo that houses the code for it: https://github.com/sdras/nuxt-type

Navigation

In that last demo you might have noticed we had a common navigation across all of the pages what we routed. In order to create this, we can go into the `layouts` directory, and we’ll see a file called `default.vue`. This directory will house the base layouts for all of our pages, „default” being the, uhm, default 🙂

Right away you’ll see this:

<template>
  <div>
    <nuxt/>
  </div>
</template>

That special <nuxt/> tag will be where our `.vue` pages files will be inserted, so in order to create a navigation, we could insert a navigation component like this:

<template>
  <div>
    <img class="moon" src="~assets/FullMoon2010.png" />
    <Navigation />
    <nuxt/>
  </div>
</template>

<script>
import Navigation from '~components/Navigation.vue'

export default {
  components: {
    Navigation
  }
}
</script>

I love this because everything is kept nice and organized between our global and local needs.

I then have a component called Navigation in a directory I’ve called `components` (this is pretty standard fare for a Vue app). In this file, you’ll see a bunch of links to the different pages:

<nav>
  <div class="title">
    <nuxt-link to="/rufina">Rufina</nuxt-link>
    <nuxt-link to="/prata">Prata</nuxt-link>
    <nuxt-link exact to="/">Playfair</nuxt-link>
  </div>
</nav>

You’ll notice I’m using that <nuxt-link> tag again even though it’s in another directory, and the routing will still work. But that last page has one extra attribute, the exact attribute: <nuxt-link exact to="/">Playfair</nuxt-link> This is because there are many routes that match just the `/` directory, all of them do, in fact. So if we specify exact, Nuxt will know that we only mean the index page in particular.

Further Resources

If you’d like more information about Nuxt, their documentation is pretty sweet and has a lot of examples to get you going. If you’d like to learn more about Vue, I’ve just made a course on Frontend Masters and all of the materials are open source here, or you can check out our Guide to Vue, or you can go to the docs which are extremely well-written. Happy coding!


Simple Server Side Rendering, Routing, and Page Transitions with Nuxt.js is a post from CSS-Tricks

A Collection of Interesting Facts about CSS Grid Layout

Post pobrano z: A Collection of Interesting Facts about CSS Grid Layout

A few weeks ago I held a CSS Grid Layout workshop. Since I’m, like most of us, also pretty new to the topic, I learned a lot while preparing the slides and demos.
I decided to share some of the stuff that was particularly interesting to me, with you.

Have fun!

Negative values lower than -1 may be used for grid-row-end and grid-column-end

In a lot of code examples and tutorials you will see that you can use grid-column-start: 1 and grid-column-end: -1 (or the shorthand grid-column: 1 / -1) to span an element from the first line to the last. My friend Max made me aware that it’s possible to use lower values than -1 as well.

.grid-item {
  grid-column: 1 / -2;
}

For example, you can set grid-column: 1 / -2 to span the cells between the first and the second to last line.

See the Pen Grid item from first to second to last by Manuel Matuzovic (@matuzo) on CodePen.

It’s possible to use negative values in grid-column/row-start

Another interesting thing about negative values is that you can use them on grid-column/row-start as well. The difference between positive and negative values is that with negative values the placement will come from the opposite side. If you set grid-column-start: -2 the item will be placed on the second to last line.

.item {
  grid-column-start: -3;
  grid-row: -2;
}

See the Pen Negative values in grid-column/row-start by Manuel Matuzovic (@matuzo) on CodePen.

Generated content pseudo-elements (::before and ::after) are treated as grid items

It may seem obvious that pseudo-elements generated with CSS become grid items if they’re within a grid container, but I wasn’t sure about that. So I created a quick demo to verify it. In the following Pen you can see that generated elements become grid- and flex-items if they are within a corresponding container.

See the Pen Experiment: Pseudo elements as grid items by Manuel Matuzovic (@matuzo) on CodePen.

Animating CSS Grid Layout properties

According to the CSS Grid Layout Module Level 1 specification there are 5 animatable grid properties:

  • grid-gap, grid-row-gap, grid-column-gap
  • grid-template-columns, grid-template-rows

Currently only the animation of grid-gap, grid-row-gap, grid-column-gap is implemented and only in Firefox and Firefox Mobile. I wrote a post about animating CSS Grid Layout properties, where you’ll find some more details and a demo.

The value of grid-column/row-end can be lower than the start value

In level 4 of the CSS Grid Garden game I learned that the value of grid-column-end or grid-row-end may be lower than the respective start equivalent.

.item:first-child {
  grid-column-end: 2;
  grid-column-start: 4;
}

The item in the above code will start on the 4th line and end on the 2nd, or in other words, start on the 2nd line and end on the 4th.

See the Pen Lower grid-column-end value than grid-column-start by Manuel Matuzovic (@matuzo) on CodePen.

Using the `span` keyword on grid-column/row-start and grid-column/row-end

A grid item by default spans a single cell. If you want to change that, the span keyword can be quite convenient. For example setting grid-column-start: 1 and grid-column-end: span 2 will make the grid item span two cells, from the first to the third line.

You can also use the span keyword with grid-column-start. If you set grid-column-end: -1 and grid-column-start: span 2 the grid-item will be placed at the last line and span 2 cells, from the last to third to last line.

See the Pen CSS Grid Layout: span keyword by Manuel Matuzovic (@matuzo) on CodePen.

grid-template-areas and implicit named lines

If you create template areas in a grid, you automatically get four implicit named lines, two naming the row-start and row-end and two for the column-start and column-end. By adding the -start or -end suffix to the name of the area, they’re applicable like any other named line.

.grid {
  display: grid;
  grid-template-columns: 1fr 200px 200px;
  grid-template-areas: 
    "header header header"
    "articles ads posts"
}

.footer {
  grid-column-start: ads-start;
  grid-column-end: posts-end;
}

See an example for implicit named lines in this Pen.

Grid is available in the insider version of Microsoft Edge

Support for CSS Grid Layout is pretty great since all major browsers, except IE and Edge, support it. For a lot of projects you can start using CSS Grid Layouts today. Support for Microsoft Edge will probably come pretty soon, because it’s already available in the insider version of Microsoft Edge.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
57 44 52 11* 16 10.1

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
10.3 No No 56 59 54

If you want to learn more about Grids check out The Complete Guide to Grid, Getting Started with CSS Grid, Grid By Example and my Collection of Grid demos on CodePen.


A Collection of Interesting Facts about CSS Grid Layout is a post from CSS-Tricks

​Edit your website, from your website

Post pobrano z: ​Edit your website, from your website

Stuck making „a few easy changes” to the website for someone? Component IO makes it quick and simple for you or your team to make edits (even for non-technical users).

You can manage content with a WYSIWYG editor or instantly update HTML, CSS, and JavaScript right from your website. Make changes faster, empower your team, and avoid redeployment bugs. Works with every web technology, from WordPress to Rails to React.

Join hundreds of projects already using Component IO, with a free tier and plans from $7.95/mo. It’s built to make web development easier for everyone.

Try it free

Direct Link to Article — Permalink


​Edit your website, from your website is a post from CSS-Tricks

One Illustration, Three SVG outputs

Post pobrano z: One Illustration, Three SVG outputs

Let’s say we draw the same vector graphic in different design applications and export each one as SVG for use on the web. Should we expect the same SVG file from each application?

On the one hand, we might expect each file to be the same because of our past history with exporting images. Applications have typically been consistent at saving JPGs, PNGs, and GIFs with perhaps minor differences to the overall file size.

On the other hand, SVG is different than our typical image file and our expectations might need to adapt to those differences. The output of SVG might be visual, but what we’re really talking about is math and code. That means an SVG file is a little more comparable to a CSS file that has been compiled from a preprocessor. Your results may vary based on the method used to compile the code.

I decided to draw the same illustration in Illustrator, Sketch, and Figma and compare exported SVG code. This post will summarize those results.

About the Illustration

It’s nothing fancy. A basic plus sign with a white fill on top of a circle with a black fill. The idea was to use something that’s close to an icon that would be common on any site.

The illustration was drawn three times, once in each application. Making the icon in one application then copying and pasting it in another didn’t seem like a fair comparison. This allowed each application to interpret the SVG from its own native tools. I’m not the most skilled illustrator, so I made the illustration once, then traced it in the other applications to ensure everything was to scale and that all the points were nearly identical.

About the Comparison

It’s worth noting that this post is not at all concerned about the „best” export of the group. What’s more interesting is (1) whether there are differences in how SVG code is compiled and (2) how those possible difference might affect a front-end workflow or even influence which application is better suited for a particular project.

Here’s what is being compared:

  • File Size
  • Code Structure
  • Naming Standards

One more thing with mentioning is that we’re assuming default export options in this comparison. Illustrator has a robust set of options that can completely change how an SVG file is saved, where the others do not. I decided to use the default Illustrator export settings, with the minor exception of not minifying the code on export.

All good? Let’s look at the results.

Side by Side Code Comparison

See the Pen One Illustration, Three SVG Outputs by Geoff Graham (@geoffgraham) on CodePen.

Table Comparison

Comparison Illustrator Sketch Figma
Export Settings Yes No No
File Size 701 Bytes 946 Bytes 1 KB
XML Header No Yes No
Includes <height> and <width> attributes No Yes Yes
Includes viewBox Attribute Yes Yes Yes
SVG ID Yes No No
SVG ID Name Generated NA NA
SVG Data Name Attribute Layer Name NA NA
Title Tag (<title>) File Name Artboard Name Layer Name
Description Tag (<description>) NA Created with Sketch Created with Figma
Includes Definitions (<defs>) No Yes Yes
Includes Groups (<g>) Yes Yes Yes
Group ID Name NA Organized by Page Name, Artboard, Group, then Layer Organized by Frame, Group, then Layer
Includes Use (<use>) No No Yes

Comparison Summary

Those are some pretty interesting results. Like I mentioned earlier, the goal here is not to declare a winner of who does things best™ but to gauge whether there are differences — and there certainly are differences!

File Size

One huge benefit of SVG, in general, is its small file size versus raster images. That benefit shines in all three cases. For example, the same icon exported as a PNG in Sketch came out to 12KB. Sketch’s SVG output is 97% savings from its PNG counterpart.

I’m not particularly sure that the differences in file sizes between the three results here are all that crucial, despite the fact that Illustrator’s output results in a file size that is ~30% smaller than Figma’s output. I only say that because it’s likely that the SVG file that gets used in production gets minified and cached in the same fashion that makes it all very negligible.

That said, the fact that there is a file size difference at all might influence which build tools you use for your SVG workflow and how the settings for that build tool are configured.

Code Structure

The difference in file size really comes down to how each application structures the code it compiles. For example, where Figma is super into grouping and defining shapes and paths for the sake of making them more reusable in different contexts, Illustrator avoids them altogether and tends to make the file easier to drop inline.

Again, the goal is not to determine whether one approach is better than the other, but recognize that there are different philosophies going into the generated file and let that help determine the right tool for the current job. You might get a smaller file size in one instance, but perhaps more flexibility in another, depending on your needs and priorities.

Naming Standards

Another case in point is how Illustrator uses unique generated IDs on the <svg> element by default. That makes dropping the file inline much less likely to conflict with other inline files where a designer may have used the same file, artboard or layer names across multiple files. By contrast, neither Sketch nor Figma uses an ID directly on the SVG element.

There are build tools that will help craft ID and class names but, if you are tasked with editing an SVG file manually or have to use a file as it’s provided to you for some reason, then knowing how an application names things might influence how you approach your work.

Wrapping Up

The biggest takeaway for me from this comparison is a reminder that SVG is code at the end of the day. The applications we use to illustration vector graphics are simply a GUI for creating code and the way that code gets written is likely to be different based on who is writing it.

It’s really no different than something like the CodePen Rodeo (when is the next one, by the way?) where a single design is provided and many people go off to code it in their own ways. There is no „right” way to code it, but it’s fun to see how different people take different paths to achieve the same deliverable.

The bottom line underscored by this comparison is that we can’t take the assets we have for granted. As much as we may enjoy the fact that machines are willing to make decisions on our behalf, a front-end workflow is still overwhelmingly a subjective task and influences how we do our jobs.


One Illustration, Three SVG outputs is a post from CSS-Tricks

Musings on HTTP/2 and Bundling

Post pobrano z: Musings on HTTP/2 and Bundling

HTTP/2 has been one of my areas of interest. In fact, I’ve written a few articles about it just in the last year. In one of those articles I made this unchecked assertion:

If the user is on HTTP/2: You’ll serve more and smaller assets. You’ll avoid stuff like image sprites, inlined CSS, and scripts, and concatenated style sheets and scripts.

I wasn’t the only one to say this, though, in all fairness to Rachel, she qualifies her assertion with caveats in her article. To be fair, it’s not bad advice in theory. HTTP/2’s multiplexing ability gives us leeway to avoid bundling without suffering the ill effects of head-of-line blocking (something we’re painfully familiar with in HTTP/1 environments). Unraveling some of these HTTP/1-specific optimizations can make development easier, too. In a time when web development seems more complicated than ever, who wouldn’t appreciate a little more simplicity?

As with anything that seems simple in theory, putting something into practice can be a messy affair. As time has progressed, I’ve received great feedback from thoughtful readers on this subject that has made me re-think my unchecked assertions on what practices make the most sense for HTTP/2 environments.

The case against bundling

The debate over unbundling assets for HTTP/2 centers primarily around caching. The premise is if you serve more (and smaller) assets instead of a giant bundle, caching efficiency for return users with primed caches will be better. Makes sense. If one small asset changes and the cache entry for it is invalidated, it will be downloaded again on the next visit. However, if only one tiny part of a bundle changes, the entire giant bundle has to be downloaded again. Not exactly optimal.

Why unbundling could be suboptimal

There are times when unraveling bundles makes sense. For instance, code splitting promotes smaller and more numerous assets that are loaded only for specific parts of a site/app. This makes perfect sense. Rather than loading your site’s entire JS bundle up front, you chunk it out into smaller pieces that you load on demand. This keeps the payloads of individual pages low. It also minimizes parsing time. This is good, because excessive parsing can make for a janky and unpleasant experience as a page paints and becomes interactive, but has not yet not fully loaded.

But there’s a drawback to this we sometimes miss when we split assets too finely: Compression ratios. Generally speaking, smaller assets don’t compress as well as larger ones. In fact, if some assets are too small, some server configurations will avoid compressing them altogether, as there are no practical gains to be made. Let’s look at how well some popular JavaScript libraries compress:

Filename Uncompressed Size Gzip (Ratio %) Brotli (Ratio %)
jquery-ui-1.12.1.min.js 247.72 KB 66.47 KB (26.83%) 55.8 KB (22.53%)
angular-1.6.4.min.js 163.21 KB 57.13 KB (35%) 49.99 KB (30.63%)
react-0.14.3.min.js 118.44 KB 30.62 KB (25.85%) 25.1 KB (21.19%
jquery-3.2.1.min.js 84.63 KB 29.49 KB (34.85%) 26.63 KB (31.45%)
vue-2.3.3.min.js 77.16 KB 28.18 KB (36.52%)
zepto-1.2.0.min.js 25.77 KB 9.57 KB (37.14%)
preact-8.1.0.min.js 7.92 KB 3.31 KB (41.79%) 3.01 KB (38.01%)
rlite-2.0.1.min.js 1.07 KB 0.59 KB (55.14%) 0.5 KB (46.73%)

Sure, this comparison table is overkill, but it illustrates a key point: Large files, as a rule of thumb, tend to yield higher compression ratios than smaller ones. When you split a large bundle into teeny tiny chunks, you won’t get as much benefit from compression.

Of course, there’s more to performance than asset size. In the case of JavaScript, we may want to tip our hand toward smaller page/template-specific files because the initial load of a specific page will be more streamlined with regard to both file size and parse time. Even if those smaller assets don’t compress as well individually. Personally, that would be my inclination if I were building an app. On traditional, synchronous „site”-like experiences, I’m not as inclined to pursue code-splitting.

Yet, there’s more to consider than JavaScript. Take SVG sprites, for example. Where these assets are concerned, bundling appears more sensible. Especially for large sprite sets. I performed a basic test on a very large icon set of 223 icons. In one test, I served a sprited version of the icon set. In the other, I served each icon as individual assets. In the test with the SVG sprite, the total size of the icon set represents just under 10 KB of compressed data. In the test with the unbundled assets, the total size of the same icon set was 115 KB of compressed data. Even with multiplexing, there’s simply no way 115 KB can be served faster than 10 KB on any given connection. The compression doesn’t go far enough on the individualized icons to make up the difference. Technical aside: The SVG images were optimized by SVGO in both tests.

Side note: One astute commenter has pointed out that Firefox dev tools show that in the unsprited test, approximately 38 KB of data was transferred. That could affect how you optimize. Just something to keep in mind.

Browsers that don’t support HTTP/2

Yep, this is a thing. Opera Mini in particular seems to be a holdout in this regard, and depending on your users, this may not be an audience segment to ignore. While around 80% of people globally surf with browsers that can support HTTP/2, that number declines in some corners of the world. Shy of 50% of all users in India, for example, use a browser that can communicate to HTTP/2 servers (according to caniuse, anyway). This is at least the picture for now, and support is trending upward, but we’re a long ways from ubiquitous support for the protocol in browsers.

What happens when a user talks to an HTTP/2 server with a browser that doesn’t support it? The server falls back to HTTP/1. This means you’re back to the old paradigms of performance optimization. So again, do your homework. Check your analytics and see where your users are coming from. Better yet, leverage caniuse.com’s ability to analyze your analytics and see what your audience supports.

The reality check

Would any sane developer architect their front end code to load 223 separate SVG images? I hope not, but nothing really surprises me anymore. In all but the most complex and feature-rich applications, you’d be hard-pressed to find so much iconography. But, it could make more sense for you to coalesce those icons in a sprite and load it up front and reap the benefits of faster rendering on subsequent page navigations.

Which leads me to the inevitable conclusion: In the nooks and crannies of the web performance discipline there are no simple answers, except „do your research”. Rely on analytics to decide if bundling is a good idea for your HTTP/2-driven site. Do you have a lot of users that only go to one or two pages and leave? Maybe don’t waste your time bundling stuff. Do your users navigate deeply throughout your site and spend significant time there? Maybe bundle.

This much is clear to me: If you move your HTTP/1-optimized site to an HTTP/2 host and change nothing in your client-side architecture, it’s not going to be a big deal. So don’t trust blanket statements some web developer writing blog posts (i.e., me). Figure out how your users behave, what optimizations makes the best sense for your situation, and adjust your code accordingly. Good luck!


Cover of Web Performance in Action

Jeremy Wagner is the author of Web Performance in Action, an upcoming title from Manning Publications. Use coupon code sswagner to save 42%.

Check him out on Twitter: @malchata


Musings on HTTP/2 and Bundling is a post from CSS-Tricks

Did CSS get more complicated since the late nineties?

Post pobrano z: Did CSS get more complicated since the late nineties?

Hidde de Vries gathers some of the early thinking about CSS:

There is quite a bit of information on the web about how CSS was designed. Keeping it simple was a core principle. It continued to be — from the early days and the first implementations in the late nineties until current developments now.

The four main design principles listed are fascinating:

  • Authors can specify as much or little as they want
  • It is not a programming language by design
  • They are agnostic as to which medium they are used for
  • It is stream-based

So… did it?

I think lots has changed since the early nineties, but not really things that touch on how we apply CSS to structured markup.

Direct Link to Article — Permalink


Did CSS get more complicated since the late nineties? is a post from CSS-Tricks

Let’s say you wanna open source a little thing…

Post pobrano z: Let’s say you wanna open source a little thing…

Let’s say you’ve written a super handy little bit of JavaScript. Nice! Well done, you. Surely, the world can benefit from this. A handful of people, at least. No need to keep this locked up. You’ve benefitted from open source tremendously in your career. This is the perfect opportunity to give back!

Let’s do this.

You’re going to need to chuck it into a GitHub repo. That’s like table stakes for open source. This is where people can find it, link to it, see the code, and all that. It’s a place you can push changes to if you need to.

You’ll need to pick a license for it. If the point of this is „giving back” you really do need to, otherwise, it’s essentially like you have the exclusive copyright of it. It’s somewhat counter-intuitive, but picking a license opens up usage, rather than tightening it.

You’ll need to put a README in there. As amazingly self-documenting you think your code is, it isn’t. You’ll need some plain-language writing in there to explain what your thing is and does. Usage samples are vital.

You’ll probably wanna chuck some demos in there, too. Maybe a whole `/demos/` directory so the proof can be in the pudding.

While you’ve made some demos, you might as well puts some tests in there. Those go hand-in-hand. Tests give people who might use your thing some peace of mind that it’s going to work and that as an author you care about making sure it does. If you plan to keep your thing updated, tests will ensure you don’t break things as you make changes.

Speaking of people using your thing… just how are they going to do that? You probably can’t just leave a raw function theThing () in `the-thing.js`! This isn’t the 1800’s, they’ll tell you. You didn’t even wrap an IIFE around it?! You should have at least made it a singleton.

People are going to want to const theThing = require("the-thing.js"); that sucker. That’s the CommonJS format, which seems reasonable. But that’s kinda more for Node.js than the browser, so it also seems reasonable to use define() and return a function, otherwise known as AMD. Fortunatly there is UMD, which is like both of those at the same time.

Wait wait wait. ES6 has now firmly arrived and it has its own module format. People are for sure going to want to import { theThing } from './the-thing.js';, which means you’re going to need to export function theThing() { }.

So what should you do here? Heck if I know. I’m sure someone smart will say something in the comments.

Whatever you decide though, you’ll probably separate that „module” concern away from your authored code. Perhaps a build process can help get all that together for you. Perhaps you can offer your thing in all the different module formats, so everybody is happy. What do you use for that build process? Grunt? Gulp? Too old? The hip thing these days is an npm script, which is just some terminal commands put into a `package.json` file.

While your build processing, you might as well have that thing run your tests. You also might as well create an uglified version. Every library has a `the-thing.min.js`, right? You might as well put all that auto generated stuff into a `/dist/` folder. Maybe you’ll even be super hip and not check that into the repo. If you want this thing, you grab the repo and build it yourself!

Still, you do want people to use this thing. Having the public repo isn’t enough, it’s also going to need to go on npm, which is a whole different site and world. Hopefully, you’ve done some naming research early, as you’ll need to name your package and that must be unique. There is a variety of other stuff to know here too, like making sure the repo is clean and you’ve ignored things you don’t want everyone to download with the package.

Wait what about Yarn? Isn’t that the new npm or something? You might want to publish there too. Some folks are hanging onto Bower as well, so you might wanna make your thing work there too.

OK! Done! Better take a quick nap and get ready for the demands to start rolling in on the issues board!

Just kidding everything will be fine.


Let’s say you wanna open source a little thing… is a post from CSS-Tricks

More Gotchas Getting Inline SVG Into Production—Part II

Post pobrano z: More Gotchas Getting Inline SVG Into Production—Part II

The following is a guest post by Rob Levin and Chris Rumble. Rob and Chris both work on the product design team at Mavenlink. Rob is also creator and host of the SVG Immersion Podcast and wrote the original 5 Gotchas article back in ’14. Chris, is a UI and Motion Designer/Developer based out of San Francisco. In this article, they go over some additional issues they encountered after incorporating inline SVGs in to Mavenlink’s flagship application more then 2 years ago. The article illustrations were done by Rob and—in the spirit of our topic—are 100% vector SVGs!

Explorations in Debugging

Wow, it’s been over 2 years since we posted the 5 Gotchas Getting SVG Into Production article. Well, we’ve encountered some new gotchas making it time for another follow up post! We’ll label these 6-10 paying homage to the first 5 gotchas in the original post 🙂

Gotcha Six: IE Drag & Drop SVG Disappears

SVG Disappears After Drag and Drop in IE

If you take a look at the animated GIF above, you’ll notice that I have a dropdown of task icons on the left, I attempt to drag the row outside of the sortable’s container element, and then, when I drop the row back, the SVG icons have completely disappeared. This insidious bug didn’t seem to happen on Windows 7 IE11 in my tests, but, did happen in Windows 10’s IE11! Although, in our example, the issue is happening due to use of a combination of jQuery UI Sortable and the nestedSortable plugin (which needs to be able to drag items off the container to achieve the nesting, any sort of detaching of DOM elements and/or moving them in the DOM, etc., could result in this disappearing behavior. Oddly, I wasn’t able to find a Microsoft ticket at time of writing, but, if you have access to a Windows 10 / IE11 setup, you can see for yourself how this will happen in this simple pen which was forked from fergaldoyle. The Pen shows the same essential disappearing behavior happening, but, this time it’s caused by simply moving an element containing an SVG icon via JavaScript’s appendChild.

A solution to this is to reset the href.baseVal attribute on all <use> elements that descend from event.target container element when a callback is called. For example, in the case of using Sortable, we were able to call the following method from inside Sortable’s stop callback:

function ie11SortableShim(uiItem) {
  function shimUse(i, useElement) {
    if (useElement.href && useElement.href.baseVal) {
      // this triggers fixing of href for IE
      useElement.href.baseVal = useElement.href.baseVal;
    }
  }

  if (isIE11()) {
    $(uiItem).find('use').each(shimUse);
  }
};

I’ve left out the isIE11 implementation, as it can be done a number of ways (sadly, most reliably through sniffing the window.navigator.userAgent string and matching a regex). But, the general idea is, find all the <use> elements in your container element, and then reassign their href.baseVal to trigger to IE to re-fetch those external xlink:href’s. Now, you may have an entire row of complex nested sub-views and may need to go with a more brute force approach. In my case, I also needed to do:

$(uiItem).hide().show(0);

to rerender the row. Your mileage may vary 😉

If you’re experiencing this outside of Sortable, you likely just need to hook into some „after” event on whatever the parent/container element is, and then do the same sort of thing.

As I’m boggled by this IE11 specific issue, I’d love to hear if you’ve encountered this issue yourself, have any alternate solutions and/or greater understanding of the root IE issues, so do leave a comment if so.

Gotcha Seven: IE Performance Boosts Replacing SVG4Everybody with Ajax Strategy

Performance Issues

In the original article, we recommended using SVG4Everybody as a means of shimming IE versions that don’t support using an external SVG definitions file and then referencing via the xlink:href attribute. But, it turns out to be problematic for performance to do so, and probably more kludgy as well, since it’s based off user agent sniffing regex. A more „straight forward” approach, is to use Ajax to pull in the SVG sprite. Here’s a slice of our code that does this which is, essentially, the same as what you’ll find in the linked article:

  loadSprite = null;

  (function() {
    var loading = false;
    return loadSprite = function(path) {
      if (loading) {
        return;
      }
      return document.addEventListener('DOMContentLoaded', function(event) {
        var xhr;
        loading = true;
        xhr = new XMLHttpRequest();
        xhr.open('GET', path, true);
        xhr.responseType = 'document';
        xhr.onload = function(event) {
          var el, style;
          el = xhr.responseXML.documentElement;
          style = el.style;
          style.display = 'none';
          return document.body.insertBefore(el, document.body.childNodes[0]);
        };
        return xhr.send();
      });
    };
  })();

  module.exports = {
    loadSprite: loadSprite,
  };

The interesting part about all this for us, was that—on our icon-heavy pages—we went from ~15 seconds down to ~1-2 seconds (for first uncached page hit) in IE11.

Something to consider about using the Ajax approach, you’ll need to potentially deal with a „flash of no SVG” until the HTTP request is resolved. But, in cases where you already have a heavy initial loading SPA style application that throws up a spinner or progress indicator, that might be a sunk cost. Alternatively, you may wish to just go ahead and inline your SVG definition/sprite and take the cache hit for better-percieved performance. If so, measure just how much you’re increasing the payload.

Gotcha Eight: Designing Non-Scaling Stroke Icons

In cases where you want to have various sizes of the same icon, you may want to lock down the stroke sizes of those icons…

Why, what’s the issue?

Strokes VS Fills

Imagine you have a height: 10px; width: 10px; icon with some 1px shapes and scale it to 15px. Those 1px shapes will now be 1.5px which ends up creating a soft or fuzzy icon due to borders being displayed on sub-pixel boundaries. This softness also depends on what you scale to, as that will have a bearing on whether your icons are on sub-pixel boundaries. Generally, it’s best to control the sharpness of your icons rather than leaving them up to the will of the viewer’s browser.

The other problem is more of a visual weight issue. As you scale a standard icon using fills, it scales proportionately…I can hear you saying „SVG’s are supposed to that”. Yes, but being able to control the stroke of your icons can help them feel more related and seen as more of a family. I like to think of it like using a text typeface for titling, rather than a display or titling typeface, you can do it but why when you could have a tight and sharp UI.

Prepping the Icon

I primarily use Illustrator to create icons, but plenty of tools out there will work fine. This is just my workflow with one of those tools. I start creating an icon by focusing on what it needs to communicate not really anything technical. After I’m satisfied that it solves my visual needs I then start scaling and tweaking it to fit our technical needs. First, size and align your icon to the pixel grid (⌘⌥Y in Illustrator for pixel preview, on a Mac) at the size you are going to be using it. I try to keep diagonals on 45° and adjust any curves or odd shapes to keep them from getting weird. No formula exists for this, just get it as close as you can to something you like. Sometimes I scrap the whole idea if it’s not gonna work at the size I need and start from scratch. If it’s the best visual solution but no one can identify it… it’s not worth anything.

Exporting AI

I usually just use the Export As „SVG” option in Illustrator, I find it gives me a standard and minimal place to start. I use the Presentation Attributes setting and save it off. It will come out looking something like this:

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <title>icon-task-stroke</title>
  <polyline points="5.5 1.5 0.5 1.5 0.5 4.5 0.5 17.5 17.5 17.5 17.5 1.5 12.5 1.5" fill="none" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <rect x="5.5" y="0.5" width="7" height="4" fill="none" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <line x1="3" y1="4.5" x2="0.5" y2="4.5" fill="none" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <line x1="17.5" y1="4.5" x2="15" y2="4.5" fill="none" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <polyline points="6 10 8 12 12 8" fill="none" stroke="#ffa800" stroke-miterlimit="10" stroke-width="1"/>
</svg>

I know you see a couple of 1/2 pixels in there! Seems like there are a few schools of thought on this. I prefer to have the stroke line up to the pixel grid as that is what will display in the end. The coordinates are placed on the 1/2 pixel so that your 1px stroke is 1/2 on each side of the path. It looks something like this (in Illustrator):

Strokes on the Pixel Grid

Gotcha Nine: Implementing Non-Scaling Stroke

Clean Up

Galactic Vacuum

Our Grunt task, which Rob talks about in the previous article, cleans up almost everything. Unfortunately for the non-scaling-stroke you have some hand-cleaning to do on the SVG, but I promise it is easy! Just add a class to the paths on which you want to restrict stroke scaling. Then, in your CSS add a class and apply the attribute vector-effect: non-scaling-stroke; which should look something like this:

.non-scaling-stroke {
  vector-effect: non-scaling-stroke;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
  <title>icon-task-stroke</title>
  <polyline class="non-scaling-stroke" points="5.5 1.5 0.5 1.5 0.5 4.5 0.5 17.5 17.5 17.5 17.5 1.5 12.5 1.5" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <rect class="non-scaling-stroke" x="5.5" y="0.5" width="7" height="4" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <line class="non-scaling-stroke" x1="3" y1="4.5" x2="0.5" y2="4.5" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <line class="non-scaling-stroke" x1="17.5" y1="4.5" x2="15" y2="4.5" stroke="#b6b6b6" stroke-miterlimit="10"/>
  <polyline class="non-scaling-stroke" stroke="currentcolor" points="6 10 8 12 12 8" stroke="#ffa800" stroke-miterlimit="10" stroke-width="1"/>
</svg>

This keeps the strokes, if specified, from changing (in other words, the strokes will remain at 1px even if the overall SVG is scaled) when the SVG is scaled. We also add fill: none; to a class in our CSS script where we also control the stroke color as they will fill with #000000 by default.That’s it! Now, you have beautiful pixel adherent strokes that will maintain stroke width!

And after all is said and done (and you have preprocessed via grunt-svgstore per the first article), your SVG will look like this in the defs file:

<svg>
  <symbol viewBox="0 0 18 18" id="icon-task-stroke">
    <title>icon-task-stroke</title>
    <path class="non-scaling-stroke" stroke-miterlimit="10" d="M5.5 1.5h-5v16h17v-16h-5"/>
    <path class="non-scaling-stroke" stroke-miterlimit="10" d="M5.5.5h7v4h-7zM3 4.5H.5M17.5 4.5H15"/>
    <path class="non-scaling-stroke" stroke="currentColor" stroke-miterlimit="10" d="M6 10l2 2 4-4"/>
  </symbol>
</svg>

CodePen Example

The icon set on the left is scaling proportionately, and on the right, we are using the vector-effect: non-scaling-stroke;. If your noticing that your resized SVG icon’s strokes are starting to look out of control, the above technique will give you the ability to lock those babies down.

See the Pen SVG Icons: Non-Scaling Stroke by Chris Rumble (@Rumbleish) on CodePen.

Gotcha Ten: Accessibility

Accessible planet illustration

With everything involved in getting your SVG icon system up-and-running, it’s easy to overlook accessibility. That’s a shame, because SVGs are inherently accessible, especially if compared to icon fonts which are known to not always play well with screen readers. At bare minimum, we need to sprinkle a bit of code to prevent any text embedded within our SVG icons from being announced by screen readers. Although we’d love to just add a <title> tag with alternative text and „call it a day”, the folks at Simply Accessible have found that Firefox and NVDA will not, in fact, announce the <title> text.

Their recommendation is to apply the aria-hidden="true" attribute to the <svg> itself, and then add an adjacent span element with a .visuallyhidden class. The CSS for that visually hidden element will be hidden visually, but its text will available to the screen reader to announce. I’m bummed that it doesn’t feel very semantic, but it may be a reasonable comprimise while support for the more intuitively reasonable <title> tag (and combinations of friends like role, aria-labelledby, etc.) work across both browser and screen reader implementations. To my mind, the aria-hidden on the SVG may be the biggest win, as we wouldn’t want to inadvertantly set off the screen reader for, say, 50 icons on a page!

Here’s the general patterns borrowed but alterned a bit from Simply Accessible’s pen:

<a href="/somewhere/foo.html">
    <svg class="icon icon-close" viewBox="0 0 32 32" aria-hidden="true">
        <use xlink:href="#icon-close"></use>
    </svg>
    <span class="visuallyhidden">Close</span>
</a>

As stated before, the two things interesting here are:

  1. aria-hidden attribute applied to prevent screen readers from announcing any text embedded within the SVG.
  2. The nasty but useful visuallyhidden span which WILL be announced by screen reader.

Honestly, if you would rather just code this with the <title> tag et al approach, I wouldn’t necessarily argue with you as it this does feel kludgy. But, as I show you the code we’ve used that follows, you could see going with this solution as a version 1 implementation, and then making that switch quite easily when support is better…

Assuming you have some sort of centralized template helper or utils system for generating your use xlink:href fragments, it’s quite easy to implement the above. We do this in Coffeescript, but since JavaScript is more universal, here’s the code that gets resolved to:

  templateHelpers = {
    svgIcon: function(iconName, iconClasses, iconAltText) {
      var altTextElement = iconAltText ? "" + iconAltText + "" : '';
      var titleElement = iconTitle ? "<title>" + iconTitle + "</title>" : '';
      iconClasses = iconClasses ? " " + iconClasses : '';
      return this.safe.call(this, "<svg aria-hidden='true' class='icon-new " + iconClasses + "'><use xlink:href='#" + iconName + "'>" + titleElement + "</use></svg>" + altTextElement);
    },
    ...

Why are we putting the <title> tag as a child of <use> instead of the <svg>? According to Amelia Bellamy-Royds(Invited Expert developing SVG & ARIA specs @w3c. Author of SVG books from @oreillymedia), you will get tooltips in more browsers.

Here’s the CSS for .visuallyhidden. If you’re wondering why we’re doing it this particular why and not, say, display: none;, or other familiar means, see Chris Coyier’s article which explains this in depth:

.visuallyhidden {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    width: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    position: absolute;
}

This code is not meant to be used „copy pasta” style, as your system will likely have nuanced differences. But, it shows the general approach, and, the important bits are:

  • the iconAltText, which allows the caller to provide alternative text if it seems appropriate (e.g. the icon is not purely decorative)
  • the aria-hidden="true" which now, is always placed on the SVG element.
  • the .visuallyhidden class will hide the element visually, while still making the text in that element available for screen readers

As you can see, it’d be quite easy to later refactor this code to use the <title> approach usually recommended down the road, and at least the maintainence hit won’t be bad should we choose to do so. The relevant refactor changes would likely be similar to:

var aria = iconAltText ? 'role="img" aria-label="' + iconAltText + '"' : 'aria-hidden="true"';
return this.safe.call(this, "<svg " + aria + " class='icon-new " + iconClasses + "'><use xlink:href='#" + iconName + "'>" + titleElement + "</use></svg>");

So, in this version (credit to Amelia for the aria part!), if the caller passes alternative text in, we do NOT hide the SVG, and, we also do not use the visually hidden span technique, while adding the role and aria-label attributes to the SVG. This feels much cleaner, but the jury is out on whether screen readers are going to support this approach as well as using the visually hidden span technique. Maybe the experts (Amelia and Simply Accessible folks), will chime in on the comments 🙂

Bonus Gotcha: make viewBox width and height integers or scaling gets funky

If you have an SVG icon that you export with a resulting viewBox like: viewBox="0 0 100 86.81", you may have issues if you use transform: scale. For example, if your generally setting the width and height equal as is typical (e.g. 16px x 16px), you might expect that the SVG should just center itself in it’s containing box, especially if you’re using the defaults for preserveAspectRatio. But, if you attempt to scale it at all, you’ll start to notice clipping.

In the following Adobe Illustrator screen capture, you see that „Snap to Grid” and „Snap to Pixel” are both selected:

Align and Snap to Pixel Grid

The following pen shows the first three icons getting clipped. This particular icon (it’s defined as a <symbol> and then referenced using the xlink:href strategy we’ve already went over), has a viewBox with non-integer height of 86.81, and thus we see the clipping on the sides. The next 3 examples (icons 4-6), have integer width and heights (the third argument to viewBox is width and the fourth is height), and does not clip.

See the Pen SVG Icons: Scale Clip Test 2 by Rob Levin (@roblevin) on CodePen.

Conclusions

The above challenges are just some of the ones we’ve encountered at Mavenlink having had a comprehensive SVG icon system in our application for well over 2 years now. The mysterious nature of some of these is par for the course given our splintered world of various browsers, screen readers, and operating systems. But, perhaps these additional gotchas will help you and your team to better harden your SVG icon implementations!


More Gotchas Getting Inline SVG Into Production—Part II is a post from CSS-Tricks

Glue Cross-Browser Responsive Irregular Images with Sticky Tape

Post pobrano z: Glue Cross-Browser Responsive Irregular Images with Sticky Tape

I recently came across this Atlas of Makers by Vasilis van Gemert. Its fun and quirky appearance made me look under the hood and it was certainly worth it! What I discovered is that it was actually built making use of really cool features that so many articles and talks have been written about over the past few years, but somehow don’t get used that much in the wild – the likes of CSS Grid, custom properties, blend modes, and even SVG.

SVG was used in order to create the irregular images that appear as if they were glued onto the page with the pieces of neon sticky tape. This article is going to explain how to recreate that in the simplest possible manner, without ever needing to step outside the browser. Let’s get started!

The first thing we do is pick an image we start from, for example, this pawesome snow leopard:

Fluffy snow leopard walking through the snow, looking up at the camera with an inquisitive face.
The image we’ll be using: a fluffy snow leopard.

The next thing we do is get a rough polygon we can fit the cat in. For this, we use Bennett Feely’s Clippy. We’re not actually going to use CSS clip-path since it’s not cross-browser yet (but if you want it to be, please vote for it – no sign in required), it’s just to get the numbers for the polygon points really fast without needing to use an actual image editor with a ton of buttons and options that make you give up before even starting.

We set the custom URL for our image and set custom dimensions. Clippy limits these dimensions based on viewport size, but for us, in this case, the actual dimensions of the image don’t really matter (especially since the output is only going to be % values anyway), only the aspect ratio, which is 2:3 in the case of our cat picture.

Clippy screenshot showing from where to set custom dimensions and URL. The custom dimensions need to satisfy a 2:3 ratio so we pick 540 = 2*270 for the width and 810 = 3*270 for the height.
Clippy: setting custom dimensions and URL.

We turn on the „Show outside clip-path” option on to make it easier to see what we’ll be doing.

Animated gif. Illustrates turning on the 'Show outside clip-path' option. This is going to be useful later, while picking the vertices of the polygon that roughly clips the image around the cat, so that we can see outside the partial polygon we have before we get all the points.
Clippy: turning on the „Show outside clip-path” option.

We then choose to use a custom polygon for our clipping path, we select all the points, we close the path and then maybe tweak some of their positions.

Clippy: selecting the points of a custom polygon that very roughly approximates the shape of the cat.

This has generated the CSS clip-path code for us. We copy just the list of points (as % values), bring up the console and paste this list of points as a JavaScript string:

let coords = '69% 89%, 84% 89%, 91% 54%, 79% 22%, 56% 14%, 45% 16%, 28% 0, 8% 0, 8% 10%, 33% 33%, 33% 70%, 47% 100%, 73% 100%';

We get rid of the % characters and split the string:

coords = coords.replace(/%/g, '').split(', ').map(c => c.split(' '));

We then set the dimensions for our image:

let dims = [736, 1103];

After that, we scale the coordinates we have to the dimensions of our image. We also round the values we get because we’re sure not to need decimals for a rough polygonal approximation of the cat in an image that big.

coords = coords.map(c => c.map((c, i) => Math.round(.01*dims[i]*c)));

Finally, we bring this to a form we can copy from dev tools:

`[${coords.map(c => `[${c.join(', ')}]`).join(', ')}]`;
Screenshot of the steps described above in the dev tools console.
Screenshot of the steps above in the dev tools console.

Now we move on to generating our SVG with Pug. Here’s where we use the array of coordinates we got at the previous step:

- var coords = [[508, 982], [618, 982], [670, 596], [581, 243], [412, 154], [331, 176], [206, 0], [59, 0], [59, 110], [243, 364], [243, 772], [346, 1103], [537, 1103]];
- var w = 736, h = 1103;

svg(viewBox=[0, 0, w, h].join(' '))
  clipPath#cp
    polygon(points=coords.join(' '))
  image(xlink:href='snow_derpard.jpg' 
        width=w height=h 
        clip-path='url(#cp)')

This gives us the irregular shaped image we’ve been after:

See the Pen by thebabydino (@thebabydino) on CodePen.

Now let’s move on to the pieces of sticky tape. In order to generate them, we use the same array of coordinates. Before doing anything else at this step, we read its length so that we can loop through it:

-// same as before
- var n = coords.length;

svg(viewBox=[0, 0, w, h].join(' '))
  -// same as before
  - for(var i = 0; i < n; i++) {
  
  - }

Next, within this loop, we have a random test to decide whether we have a strip of sticky tape from the current point to the next point:

- for(var i = 0; i < n; i++) {
  - if(Math.random() > .5) {
    path(d=`M${coords[i]} ${coords[(i + 1)%n]}`)
  - }
- }

At first sight, this doesn’t appear to do anything.

However, this is because the default stroke is none. Making this stroke visible (by setting it to an hsl() value with a randomly generated hue) and thicker reveals our sticky tape:

stroke: hsl(random(360), 90%, 60%);
stroke-width: 5%;
mix-blend-mode: multiply

We’ve also set mix-blend-mode: multiply on it so that overlap becomes a bit more obvious.

See the Pen by thebabydino (@thebabydino) on CodePen.

Looks pretty good, but we still have a few problems here.

The first and most obvious one being that this isn’t cross-browser. mix-blend-mode doesn’t work in Edge (if you want it, don’t forget to vote for it). The way we can get a close enough effect is by making the stroke semitransparent just for Edge.

My initial idea here was to do this in a way that’s only supported in Edge for now: using a calc() value whose result isn’t an integer for the RGB components. The problem is that we have an hsl() value, not an rgb() one. But since we’re using Sass, we can extract the RGB components:

$c: hsl(random(360), 90%, 60%);
stroke: $c;
stroke: rgba(calc(#{red($c)} - .5), green($c), blue($c), .5)

The last rule is the one that gets applied in Edge, but is discarded due to the calc() result in Chrome and simply due to the use of calc() in Firefox, so we get the result we want this way.

Screenshot of the Chrome (left) and Firefox (right) dev tools showing how the second stroke rule is seen as invalid and discarded by both browsers
The second stroke rule seen as invalid in Chrome (left) and Firefox (right) dev tools.

However, this won’t be the case anymore if the other browsers catch up with Edge here.

So a more future-proof solution would be to use @supports:

path {
  $c: hsl(random(360), 90%, 60%);
  stroke: rgba($c, .5);

  @supports (mix-blend-mode: multiply) { stroke: $c }
}

The second problem is that we want our strips to expand a bit beyond their end points. Fortunately, this problem has a straightforward fix: setting stroke-linecap to square. This effectively makes our strips extend by half a stroke-width beyond each of their two ends.

See the Pen by thebabydino (@thebabydino) on CodePen.

The final problem is that our sticky strips get cut off at the edge of our SVG. Even if we set the overflow property to visible on the SVG, the container our SVG is in might cut it off anyway or an element coming right after might overlap it.

So what we can try to do is increase the viewBox space all around the image by an amount we’ll call p that’s just enough to fit our sticky tape strips.

-// same as before
- var w1 = w + 2*p, h1 = h + 2*p;

svg(viewBox=[-p, -p, w1, h1].join(' '))
  -// same as before

The question here is… how much is that p amount?

Well, in order to get that value, we need to take into account the fact that our stroke-width is a % value. In SVG, a % value for something like the stroke-width is computed relative to the diagonal of the SVG region. In our case, this SVG region is a rectangle of width w and height h. If we draw the diagonal of this rectangle, we see that we can compute it using Pythagora’s theorem in the yellow highlighted triangle.

SVG illustration showing the SVG rectangle and highlighting half of it - a right triangle where the catheti are the SVG viewBox width and height and the hypotenuse is the SVG diagonal.
The diagonal of the SVG rectangle can be computed from a right triangle where the catheti are the SVG viewBox width and height.

So our diagonal is:

- var d = Math.sqrt(w*w + h*h);

From here, we can compute the stroke-width as 5% of the diagonal. This is equivalent to multiplying the diagonal (d) with a .05 factor:

- var f = .05, sw = f*d;

Note that this is moving from a % value (5%) to a value in user units (.05*d). This is going to be convenient as, by increasing the viewBox dimensions we also increase the diagonal and, therefore, what 5% of this diagonal is.

The stroke of any path is drawn half inside, half outside the path line. However, we need to increase the viewBox space by more than half a stroke-width. We also need to take into account the fact that the stroke-linecap extends beyond the endpoints of the path by half a stroke-width:

SVG illustration showing how the stroke is drawn half on one side of the path line, half on the other side and how a square linecap causes it to expand by half a stroke-width beyond its endpoints.
The effect of stroke-width and stroke-linecap: square.

Now let’s consider the situation when a point of our clipping polygon is right on the edge of our original image. We only consider one of the polygonal edges that have an end at this point in order to simplify things (everything is just the same for the other one).

We take the particular case of a strip along a polygonal edge having one end E on the top edge of our original image (and of the SVG as well).

Screenshot showing the result of the latest demo and highlighting an edge which has an end on the top boundary of the original image.
Highlighting a polygonal edge which has one endpoint on the top boundary of the original image.

We want to see by how much this strip can extend beyond the top edge of the image in the case when it’s created with a stroke and the stroke-linecap is set to square. This depends on the angle formed with the top edge and we’re interested in finding the maximum amount of extra space we need above this top boundary so that no part of our strip gets cut off by overflow.

In order to understand this better, the interactive demo below allows us to rotate the strip and get a feel for how far the outer corners of the stroke creating this strip (including the square linecap) can extend:

See the Pen by thebabydino (@thebabydino) on CodePen.

As the demo above illustrates by tracing the position of the outer corners of the stroke including the stroke-linecap, the maximum amount of extra space needed beyond the image boundary is when the line segment between the endpoint on the edge E and the outer corner of the stroke including the linecap at that endpoint (this outer corner being either A or B, depending on the angle) is vertical and this amount is equal to the length of the segment.

Given that the stroke extends by half a stroke-width beyond the end point, both in the tangent and in the normal direction, it results that the length of this line segment is the hypotenuse of a right isosceles triangle whose catheti each equal half a stroke-width:

SVG illustration showing how to get the segment between the path's endpoint and one of the outer corners of the stroke including the linecap: it's the hypotenuse in an isosceles triangle where the catheti are half a stroke width, along the normal direction because half the stroke is on one side of the path line while the other half is on the other and along the tangent direction because we have square linecap.
The segment connecting the endpoint to the outer corner of the stroke including the linecap is the hypotenuse in a right isosceles triangle where the catheti are half a stroke-width.

Using Pythagora’s theorem in this triangle, we have:

- var hw = .5*sw;
- var p = Math.sqrt(hw*hw + hw*hw) = hw*Math.sqrt(2);

Putting it all together, our Pug code becomes:

/* same coordinates and initial dimensions as before */
- var f = .05, d = Math.sqrt(w*w + h*h);
- var sw = f*d, hw = .5*sw;
- var p = +(hw*Math.sqrt(2)).toFixed(2);
- var w1 = w + 2*p, h1 = h + 2*p;

svg(viewBox=[-p, -p, w1, h1].join(' ') 
    style=`--sw: ${+sw.toFixed(2)}px`)
  /* same as before */

while in the CSS we’re left to tweak that stroke-width for the sticky strips:

stroke-width: var(--sw);

Note that we cannot make --sw a unitless value in order to then set the stroke-width to calc(var(--sw)*1px) – while in theory this should work, in practice Firefox and Edge don’t yet support using calc() values for stroke-* properties.

The final result can be seen in the following Pen:

See the Pen by thebabydino (@thebabydino) on CodePen.


Glue Cross-Browser Responsive Irregular Images with Sticky Tape is a post from CSS-Tricks