Subscribe to CSS-Tricks feed
Tips, Tricks, and Techniques on using Cascading Style Sheets.
Updated: 4 hours 21 min ago

Meet the New Dialog Element

Mon, 01/15/2018 - 23:36

Keith Grant discusses how HTML 5.2 has introduced a peculiar new element: <dialog>. This is an absolutely positioned and horizontally centered modal that appears on top of other content on a page. Keith looks at how to style this new element, the basic opening/closing functionality in JavaScript and, of course, the polyfills that we’ll need to get cross-browser support right.

Also, I had never heard of the ::backdrop pseudo element before. Thankfully the MDN documentation for this pseudo element digs into it a little bit more.

Direct Link to ArticlePermalink

Meet the New Dialog Element is a post from CSS-Tricks

Simplifying the Apple Watch Breathe App Animation With CSS Variables

Mon, 01/15/2018 - 15:00

When I saw the original article on how to recreate this animation, my first thought was that it could all be simplified with the use of preprocessors and especialy CSS variables. So let's dive into it and see how!

The result we want to reproduce. The structure

We keep the exact same structure.

In order to avoid writing the same thing multiple times, I chose to use a preprocessor.

My choice of preprocessor always depends on what I want to do, as, in a lot of cases, something like Pug offers more flexibility, but other times, Haml or Slim allow me to write the least amount of code, without even having to introduce a loop variable I wouldn't be needing later anyway.

Until recently, I would have probably used Haml in this case. However, I'm currently partial to another technique that lets me avoid setting the number of items both in the HTML and CSS preprocessor code, which means I avoid having to modify it in both if I need to use a different value at some point.

To better understand what I mean, consider the following Haml and Sass:

- 6.times do .item $n: 6; // number of items /* set styles depending on $n */

In the example above, if I change the number of items in the Haml code, then I need to also change it in the Sass code, otherwise things break. In a more or less obvious manner, the result is not the intended one anymore.

So we can go around that by setting the number of circles as the value of a CSS variable we later use in the Sass code. And, in this situation, I feel better using Pug:

- var nc = 6; // number of circles .watch-face(style=`--nc: ${nc}`) - for(var i = 0; i < nc; i++) .circle(style=`--i: ${i}`)

We've also set the index for every .circle element in a similar manner.

The basic styles

We keep the exact same styles on the body, no change there.

Just like for the structure, we use a preprocessor in order to avoid writing almost the same thing multiple times. My choice is Sass because that's what I'm most comfortable with, but for something simple like this demo, there's nothing in particular about Sass that makes it the best choice - LESS or Stylus do the job just as well. It's just faster for me to write Sass code, that's all.

But what do we use a preprocessor for?

Well, first of all, we use a variable $d for the diameter of the circles, so that if we want to make them bigger or smaller and also control how far out they go during the animation, we only have to change the value of this variable.

In case anyone is wondering why not use CSS variables here, it's because I prefer to only take this path when I need my variables to be dynamic. This is not the case with the diameter, so why write more and then maybe even have to come up with workarounds for CSS variable bugs we might run into?

$d: 8em; .circle { width: $d; height: $d; }

Note that we are not setting any dimensions on the wrapper (.watch-face). We don't need to.

In general, if the purpose of an element is just to be a container for absolutely positioned elements, a container on which we apply group transforms (animated or not) and this container has no visible text content, no backgrounds, no borders, no box shadows... then there's no need to set explicit dimensions on it.

A side effect of this is that, in order to keep our circles in the middle, we need to give them a negative margin of minus the radius (which is half the diameter).

$d: 8em; $r: .5*$d; .circle { margin: -$r; width: $d; height: $d; }

We also give them the same border-radius, mix-blend-mode and background as in the original article and we get the following result:

The expected result so far (live demo).

Well, we get the above in WebKit browsers and Firefox, as Edge doesn't yet support mix-blend-mode (though you can vote for implementation and please do that if you want to see it supported because your votes do count), so it shows us something a bit ugly:

The Edge result doesn't look that good.

To get around this, we use @supports:

.circle { /* same styles as before */ @supports not (mix-blend-mode: screen) { opacity: .75 } }

Not perfect, but much better:

Using @supports and opacity to fix the lack of mix-blend-mode support in Edge (live demo).

Now let's look a bit at the result we want to get:

The desired result.

We have six circles in total, three of them in the left half and three others in the right half. They all have a background that's some kind of green, those in the left half a bit more towards yellow and those in the right half a bit more towards blue.

If we number our circles starting from the topmost one in the right half and then going clockwise, we have that the first three circles are in the right half and have a bluish green background and the last three are in the left half and have a yellowish green background.

At this point, we've set the background for all the circles to be the yellowish blue one. This means we need to override it for the first half of the six circles. Since we cannot use CSS variables in selectors, we do this from the Pug code:

- var nc = 6; // number of circles style .circle:nth-child(-n + #{.5*nc}) { background: #529ca0 } .watch-face(style=`--nc: ${nc}`) - for(var i = 0; i < nc; i++) .circle(style=`--i: ${i}`)

In case you need a refresher on this, :nth-child(-n + a) selects the items at the valid indices we get for n ≥ 0 integer values. In our case, a = .5*nc = .5*6 = 3, so our selector is :nth-child(-n + 3).

If we replace n with 0, we get 3, which is a valid index, so our selector matches the third circle.

If we replace n with 1, we get 2, also a valid index, so our selector matches the second circle.

If we replace n with 2, we get 1, again valid, so our selector matches the first circle.

If we replace n with 3, we get 0, which isn't a valid index, as indices are not 0-based here. At this point, we stop as it becomes clear we won't be getting any other positive values if we continue.

The following Pen illustrates how this works - the general rule is that :nth-child(-n + a) selects the first a items:

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

Returning to our circular distribution, the result so far can be seen below:

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


First off, we make the wrapper relatively positioned and its .circle children absolutely positioned. Now they all overlap in the middle.

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

In order to understand what we need to do next, let's take a look at the following illustration:

The rightmost circle going from its initial to its final position (live).

The central points of the circles in the initial position are on the same horizontal line and a radius away from the rightmost circle. This means we can get to this final position by a translation of a radius $r along the x axis.

But what about the other circles? Their central points in the final position are also a radius away from their initial position, only along other lines.

All circles: initial position (dead in the middle) is a radius away from the final one for each and every one of them (live).

This means that, if we first rotate their system of coordinates until their x axis coincides with the line between the initial and final position of the central points and then translate them by a radius, we can get them all in the correct final position in a very similar manner.

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

Alright, but rotate each of them by what angle?

Well, we start from the fact that we have 360° on a circle around a point.

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

We have six circles distributed evenly, so the rotation difference between any two consecutive ones is 360°/6 = 60°. Since we don't need to rotate the rightmost .circle (the second one), that one's at 0°, which puts the one before (the first one) at -60°, the one after (the second one) at 60° and so on.

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

Note that -60° and 300° = 360° - 60° occupy the same position on the circle, so whether we get there by a clockwise (positive) rotation of 300° or by going 60° the other way around the circle (which gives us the minus sign) doesn't matter. We'll be using the -60° option in the code because it makes it easier to spot a convenient pattern in our case.

So our transforms look like this:

.circle { &:nth-child(1 /* = 0 + 1 */) { transform: rotate(-60deg /* -1·60° = (0 - 1)·360°/6 */) translate($r); } &:nth-child(2 /* = 1 + 1 */) { transform: rotate( 0deg /* 0·60° = (1 - 1)·360°/6 */) translate($r); } &:nth-child(3 /* = 2 + 1 */) { transform: rotate( 60deg /* 1·60° = (2 - 1)·360°/6 */) translate($r); } &:nth-child(4 /* = 3 + 1 */) { transform: rotate(120deg /* 2·60° = (3 - 1)·360°/6 */) translate($r); } &:nth-child(5 /* = 4 + 1 */) { transform: rotate(180deg /* 3·60° = (4 - 1)·360°/6 */) translate($r); } &:nth-child(6 /* = 5 + 1 */) { transform: rotate(240deg /* 4·60° = (5 - 1)·360°/6 */) translate($r); } }

This gives us the distribution we've been after:

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

However, it's very repetitive code that can easily be compacted. For any of them, the rotation angle can be written as a function of the current index and the total number of items:

.circle { /* previous styles */ transform: rotate(calc((var(--i) - 1)*360deg/var(--nc))) translate($r); }

This works in WebKit browsers and Firefox 57+, but fails in Edge and older Firefox browsers due to the lack of support for using calc() inside rotate() functions.

Fortunately, in this case, we have the option of computing and setting the individual rotation angles in the Pug code and then using them as such in the Sass code:

- var nc = 6, ba = 360/nc; style .circle:nth-child(-n + #{.5*nc}) { background: #529ca0 } .watch-face - for(var i = 0; i < nc; i++) .circle(style=`--ca: ${(i - 1)*ba}deg`) .circle { /* previous styles */ transform: rotate(var(--ca)) translate($r); }

We didn't really need the previous custom properties for anything else in this case, so we just got rid of them.

We now have a compact code, cross-browser version of the distribution we've been after:

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

Good, this means we're done with the most important part! Now for the fluff...

Finishing up

We take the transform declaration out of the class and put it inside a set of @keyframes. In the class, we replace it with the no translation case:

.circle { /* same as before */ transform: rotate(var(--ca)) } @keyframes circle { to { transform: rotate(var(--ca)) translate($r) } }

We also add the @keyframes set for the pulsing animation on the .watch-face element.

@keyframes pulse { 0% { transform: scale(.15) rotate(.5turn) } }

Note that we don't need both the 0% (from) and 100% (to) keyframes. Whenever these are missing, their values for the animated properties (just the transform property in our case) are generated from the values we'd have on the animated elements without the animation.

In the circle animation case, that's rotate(var(--ca)). In the pulse animation case, scale(1) gives us the same matrix as none, which is the default value for transform so we don't even need to set it on the .watch-face element.

We make the animation-duration a Sass variable, so that, if we ever want to change it, we only need to change it in one place. And finally, we set the animation property on both the .watch-face element and the .circle elements.

$t: 4s; .watch-face { position: relative; animation: pulse $t cubic-bezier(.5, 0, .5, 1) infinite alternate } .circle { /* same as before */ animation: circle $t infinite alternate }

Note that we're not setting a timing function for the circle animation. This is ease in the original demo and we don't set it explicitly because it's the default value.

And that's it - we have our animated result!

We could also tweak the translation distance so that it's not exactly $r, but a slightly smaller value (something like .95*$r for example). This can also make the mix-blend-mode effect a bit more interesting:

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

Bonus: the general case!

The above is for six .circle petals in particular. Now we'll see how we can adapt it so that it works for any number of petals. Wait, do we need to do more than just change the number of circle elements from the Pug code?

Well, let's see what happens if we do just that:

The result for nc equal to 6 (left), 8 (middle) and 9 (right).

The results don't look bad, but they don't fully follow the same pattern - having the first half of the circles (the bluish green ones) on the right side of a vertical symmetry line and the second half (yellowish green) on the left side.

We're pretty close in the nc = 8 case, but the symmetry line isn't vertical. In the nc = 9 case however, all our circles have a yellowish green background.

So let's see why these things happen and how we can get the results we actually want.

Making :nth-child() work for us

First off, remember we're making half the number of circles have a bluish green background with this little bit of code:

.circle:nth-child(-n + #{.5*nc}) { background: #529ca0 }

But in the nc = 9 case, we have that .5*nc = .5*9 = 4.5, which makes our selector :nth-child(-n + 4.5). Since 4.5 is not an integer, the selector isn't valid and the background doesn't get applied. So the first thing we do here is floor the .5*nc value:

style .circle:nth-child(-n + #{~~(.5*nc)}) { background: #529ca0 }

This is better, as for a nc value of 9, the selector we get is .circle:nth-child(-n + 4), which gets us the first 4 items to apply a bluish green background on them:

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

However, we still don't have the same number of bluish green and yellowish green circles if nc is odd. In order to fix that, we make the circle in the middle (going from the first to the last) have a gradient background.

By "the circle in the middle" we mean the circle that's an equal number of circles away from both the start and the end. The following interactive demo illustrates this, as well as the fact that, when the total number of circles is even, we don't have a middle circle.

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

Alright, how do we get this circle?

Mathematically, this is the intersection between the set containing the first ceil(.5*nc) items and the set containing all but the first floor(.5*nc) items. If nc is even, then floor(.5*nc) and ceil(.5*nc) are equal and our intersection is the empty set ∅. This is illustrated by the following Pen:

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

We get the first ceil(.5*nc) items using :nth-child(-n + #{Math.ceil(.5*nc)}), but what about the other set?

In general, :nth-child(n + a) selects all but the first a - 1 items:

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

So in order to get all but the first floor(.5*nc) items, we use :nth-child(n + #{~~(.5*nc) + 1}).

This means we have the following selector for the middle circle:

:nth-child(n + #{~~(.5*nc) + 1}):nth-child(-n + #{Math.ceil(.5*nc)})

Let's see what this gives us.

  • If we have 3 items, our selector is :nth-child(n + 2):nth-child(-n + 2), which gets us the second item (the intersection between the {2, 3, 4, ...} and {2, 1} sets)
  • If we have 4 items, our selector is :nth-child(n + 3):nth-child(-n + 2), which doesn't catch anything (the intersection between the {3, 4, 5, ...} and {2, 1} sets is the empty set ∅)
  • If we have 5 items, our selector is :nth-child(n + 3):nth-child(-n + 3), which gets us the third item (the intersection between the {3, 4, 5, ...} and {3, 2, 1} sets)
  • If we have 6 items, our selector is :nth-child(n + 4):nth-child(-n + 3), which doesn't catch anything (the intersection between the {4, 5, 6, ...} and {3, 2, 1} sets is the empty set ∅)
  • If we have 7 items, our selector is :nth-child(n + 4):nth-child(-n + 4), which gets us the fourth item (the intersection between the {4, 5, 6, ...} and {4, 3, 2, 1} sets)
  • If we have 8 items, our selector is :nth-child(n + 5):nth-child(-n + 4), which doesn't catch anything (the intersection between the {5, 6, 7, ...} and {4, 3, 2, 1} sets is the empty set ∅)
  • If we have 9 items, our selector is :nth-child(n + 5):nth-child(-n + 5), which gets us the fifth item (the intersection between the {5, 6, 7, ...} and {5, 4, 3, 2, 1} sets)

Now that we can select the item in the middle when we have an odd number of them in total, let's give it a gradient background:

- var nc = 6, ba = 360/nc; style .circle:nth-child(-n + #{~~(.5*nc)}) { background: var(--c0) } | .circle:nth-child(n + #{~~(.5*nc) + 1}):nth-child(-n + #{Math.ceil(.5*nc)}) { | background: linear-gradient(var(--c0), var(--c1)) | } .watch-face(style=`--c0: #529ca0; --c1: #61bea2`) - for(var i = 0; i < nc; i++) .circle(style=`--ca: ${(i - 1)*ba}deg`)

The reason why we use a top to bottom gradient is that, ultimately, we want this item to be at the bottom, split into two halves by the vertical symmetry line of the assembly. This means we first need to rotate it until its x axis points down and then translate it down along this new direction of its x axis. In this position, the top of the item is in the right half of the assembly and the bottom of the item is in the left half of the assembly. So, if we want a gradient from the right side of the assembly to the left side of the assembly, this is a top to bottom gradient on that actual .circle element.

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

Using this technique, we have now solved the issue of the backgrounds for the general case:

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

Now all that's left to do is make the symmetry axis vertical.

Taming the angles

In order to see what we need to do here, let's focus on the desired positioning in the top part. There, we want to always have two circles (the first in DOM order on the right and the last in DOM order on the left) symmetrically positioned with respect to the vertical axis that splits our assembly into two halves that mirror each other.

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

The fact that they're symmetrical means the vertical axis splits the angular distance between them ba (which is 360° divided by the total number of circles nc) into two equal halves.

Angles formed by vertical symmetry line and the radial lines to the central points of the top angles are both equal to half a base angle (live).

So both are half a base angle (where the base angle ba is 360° divided by the total number of circles nc) away from the vertical symmetry axis, one in the clockwise direction and the other one the other way.

The upper half of the symmetry axis is at -90° (which is equivalent to 270°).

Degree values around the circle (live).

So in order to get to the first circle in DOM order (the one at the top on the right), we start from 0°, go by 90° in the negative direction and then by half a base angle back in the positive direction (clockwise). This puts the first circle at .5*ba - 90 degrees.

How to get the angle the first circle is placed at (live).

After that, every other circle is at the angle of the previous circle plus a base angle. This way, we have:

  • the first circle (index 0, selector :nth-child(1)) is at ca₀ = .5*ba - 90 degrees
  • the second circle (index 1, selector :nth-child(2)) is at ca₁ = ca₀ + ba = ca₀ + 1*ba degrees
  • the third circle (index 2, selector :nth-child(3)u) is at ca₂ = ca₁ + ba = ca₀ + ba + ba = ca₀ + 2*ba degrees
  • in general, the circle of index k is at caₖ = caₖ₋₁ + ba = ca₀ + k*ba degrees

So the the current angle of the circle at index i is .5*ba - 90 + i*ba = (i + .5)*ba - 90 degrees:

- var nc = 6, ba = 360/nc; //- same as before .watch-face(style=`--c0: #529ca0; --c1: #61bea2`) - for(var i = 0; i < nc; i++) .circle(style=`--ca: ${(i + .5)*ba - 90}deg`)

This gives our final Pen, where we only need to change nc from the Pug code to change the result:

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

Simplifying the Apple Watch Breathe App Animation With CSS Variables is a post from CSS-Tricks

New flexbox guides on MDN

Fri, 01/12/2018 - 19:37

MDN released a comprehensive guide to Flexbox with new and updated materials by Rachel Andrew. The guide includes 11 posts demonstrating layouts, use cases and everything you could possibly want or need to know on the topic. All of the related Flexbox properties are nicely and conveniently attached to the table of contents, making this extremely easy to use.

In this post, Rachel adds helpful thoughts and context about Flexbox. Her comment on Flexbox initially being treated as a silver bullet solution for all our layout issues struck me:

Prior to Grid shipping, Flexbox was seen as the spec to solve all of our layout problems, yet a lot of the difficulty in using Flexbox is when we try to use it to create the kind of two-dimensional layouts that Grid is designed for. Once again, we find ourselves fighting to persuade a layout method to do things it wasn’t designed to do.

Guilty as charged. I remember being so eager to ditch floats and learn a new syntax that I treated Flexbox as a square peg trying to be fit into a round hole. That definitely bit me on at least one project.

Most importantly about this guide is that it forms a sort of trifecta of reference materials on layout specifications provided by CSS: Flexbox, Grid and other Box Alignment properties.

Oh, and while we're on the topic, we have Flexbox and Grid guides right here on CSS-Tricks. You can never learn too much, right?

Direct Link to ArticlePermalink

New flexbox guides on MDN is a post from CSS-Tricks

Third-Party Scripts

Fri, 01/12/2018 - 14:55

Trent Walton:

My latest realization is that delivering a performant, accessible, responsive, scalable website isn’t enough: I also need to consider the impact of third-party scripts. No matter how solid I think my prototype is, it doesn’t absolve me from paying attention to what happens during implementation, specifically when it comes to the addition of these third-party scripts.

I recently had a conversation with a friend working on quite a high profile e-commerce site. They were hired to develop the site, but particularly with performance in mind. They were going the PWA route, but were immediately hamstrung by third-party scripts. One of them, apparently unavoidably, couldn't be HTTPS, meaning the site was immediately disqualified from being a PWA. They could still do a good job in many other areas, but right and left their great performance work was slaughtered by third-party scripts. I don't envy being in that position.

It's often the fault of "tag managers." There are a bunch of them out there. Here's a marketing pitch for one of them:

Marketers want tag management that’s simple, reliable, and integrates easily with existing systems ... You’ll launch programs faster, so you can make swifter decisions.

In other words, "Give your marketing team the ability to add whatever third-party JavaScript they want quickly without having to go through your normal deployment process." I can understand why they are needed in some organizations, but it still sends chills up my spine.

Third-party scripts could conceivably be a part of a design style guide. Right alongside your buttons and modals could be a list of the third-party scripts in place on a site. Brad Frost:

The idea is that someone (or as Trent points out, some *thing*) could hypothetically crawl through all the included scripts on a site, and display them in the in style guide alongside all the color swatches, icons, UI components, etc. After all, they affect the end user experience just as much (if not more) than all those other design elements. You can visually weight them based on how gnarly they are and thus have thoughtful conversations with your team — especially those folks are carelessly chucking in all these performance-damning scripts — about the pros and cons of each script that gets included.

Third-party scripts are probably the #1 cause of poor performance and bad UX on the web. It's no wonder things like AMP exist. The fact that it disallows third-party scripts is probably the largest contributor to it making sites fast. Controversial as hell, though, in its other choices.

As fate would have it, third-party JavaScript is even more dangerous than it ever has been, thanks to Spectre and Meltdown. Jorgé:

Q: Is JavaScript vulnerable in my browser?
A: Yes, browsing a web can give access to third parties to your machine's memory beyond the browser.


More on Third-Party JavaScript

If you, like Trent, are planning to bone up on your third-party JavaScript chops, here's a bunch of stuff from other developers in the past few years digging into it all. Some of this is targeted at you being the deliverer of the third-party JavaScript.

Third Party JavaScript (In the Third Person) Slides by Alex Sexton Presentation slide

View Presentation

On Third-Party Javascript - The Principles by Gergely Nemeth

When serving third-party JavaScript applications the size of it and the cache policy are crucial, as both not just affect the time your users have to wait to see the application, but also your monthly bills.

See also: Writing third-party Javascript the integration part in a nutshell.

Read Post

Third-Party Javascript by Ben Vinegar and Anton Kovalyov

amzn_assoc_tracking_id = "csstricks-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_design = "enhanced_links"; amzn_assoc_asins = "1617290548"; amzn_assoc_placement = "adunit"; amzn_assoc_linkid = "5b25672b1eb04d67cf22c6b254ad7924";

Things to Know (and Potential Dangers) with Third-Party Scripts by Yaphi Berhanu

The web is full of third-party scripts. Sites use them for ads, analytics, retargeting, and more. But this isn't always the whole story. Scripts can track your behavior, your preferences, and other information.

Read Post

I’m harvesting credit card numbers and passwords from your site. Here’s how. by David Gilbertson

My goal is simply to point out that any site that includes third party code is alarmingly vulnerable, in a completely undetectable way.

Read Post

Ain't No Party Like A Third-Party JS Party by Rebecca Murphey

You thought you had the hang of this whole JavaScript thing, but now you're in the world of third-party JavaScript, where all you control is a single script tag and where it's all but impossible to dream up every hostile environment in which your code will be expected to work. "It works on my machine" has never rung quite so hollow. In this talk, we'll take a look at some of the delightful bugs we've had to solve at Bazaarvoice while working on the third-party JavaScript app that collects and displays ratings and reviews for some of the world's largest retailers.

Watch Video

(Subscription required)

3rd Party Javascript Management Cheat Sheet

The invocation of 3rd party JS code in a web application requires consideration for 3 risks in particular:

  1. The loss of control over changes to the client application,
  2. The execution of arbitrary code on client systems,
  3. The disclosure or leakage of sensitive information to 3rd parties.

Read Post

Third-Party Scripts is a post from CSS-Tricks

Small Tweaks That Can Make a Huge Impact on Your Website’s Accessibility

Thu, 01/11/2018 - 17:33

For a beginner, accessibility can be daunting. With all of the best intentions in the world, the learning curve to developing compliant, fully accessible websites and apps is huge. It's also hard to find the right advice, because it's an ever-changing and increasingly crowded landscape.

I've written this post to give you some tips on small things that can make a big difference, while hopefully not affecting your development process too much.

Let's dive in!

Document Structure and Semantics

It probably doesn't come as much of a surprise that structuring your HTML in an organized, semantic way will make a big difference. Screen readers rely on a well-structured document in order to follow a coherent narrative, so make sure that you're using the elements that the HTML5 spec provides responsively and effectively.

If you’re unsure about how to markup your work correctly, check out resources such as HTML5 Doctor, Code Academy and of course, CSS-Tricks. You can also check out articles like “Writing HTML with accessibility in mind” and “Semantic Structure” to get you going in the right direction.

Let's look at three specific things that can help ensure a well-structured and semantic document.

Use a Single <main> Element

A good example of building a responsible, semantic document structure is only using one <main> element. This should serve as a signpost for the most important content of the page for your user.

Add an ID to it and offer a skip link in your main <header> like so:

<header role="banner"> <h1>Your main page title</h1> <a href="#main-content">Skip to the main content</a> </header> <!-- Further down the document --> <main id="main-content"> <!-- Put your main body of content in here and other really important stuff --> </main>

This little trick should help your screen reader users out in a big way, because they can go ahead and skip the fancy bits and dive right into your important content. It’s also great for keyboard users for the same reason.

Another nice touch is to add a :focus style to the skip link that makes it visible. Try pressing your tab key on this post. Pretty neat, right?

Use Elements Appropriately

So, <button> elements are a pain in the butt to style right? That doesn’t mean you should attach your JavaScript events to a <div> or an <a href="#"> though. You see, when you use a <button>, you get keyboard events for free. You’re also helping screen reader users out because it’ll announce the element correctly. Check out this example:

document.getElementsByTagName('button')[0].addEventListener('click', evt => { alert('Oh, hey there!'); });

If a user focused on that button and hit the enter key, that event would fire. That makes both yours and the users' lives a bit easier. Well worth it, right?

See the Pen Button click example by Andy Bell (@hankchizljaw) on CodePen.

Get Your Heading Hierarchy Locked-Down

It's really common for screen reader users to navigate a page by using the heading structure. That means we should help them out and create a nice hierarchy for them. Let's take a look at a standard blog post:

<main id="main-content"> <article> <!-- The page title is up in the main <header> in this instance --> <h2>My awesome blog post</h2> <p>Vestibulum id ligula porta felis euismod semper.</p> <p>Vestibulum id ligula porta felis euismod semper.</p> <h3>A sub-section of this post</h3> <p>Vestibulum id ligula porta felis euismod semper.</p> <h4>A sub-section of the sub-section</h4> <p>Vestibulum id ligula porta felis euismod semper.</p> </article> </main>

With that sample, the user can navigate to the start of "My awesome blog post" and then have the ability to skip to sub-sections and nested sub-sections easily. They can also skip back up. It's just a nice way of helping them consume the content you've produced as easily as possible.

It can be recommended that a page has a single <h1> element, even though the W3C HTML5 spec says you can have many. I personally agree with the use of a single <h1>, but you can have many, as long as you follow a nice structure and hierarchy. That's the key here.

Get Your Color Contrast Right

To be WCAG 2.0 AA compliant, you need to have a contrast ratio of 4:5:1 for normal text. This is your paragraphs, buttons, navigation, etc. You need to go for a ratio of 3:1 for larger text, such as headings. I'd say this should be your minimum as it's incredibly achievable with tools such as Tota11y, Contrast and the WebAim contrast checker. You can still get plenty of color balance and variation in your design too.

The reason that contrast is so important is because there's so much variation in environment that you probably don't even consider, such as bright sunlight and poor quality displays. Add this to a visual impairment or, say, a migraine and you're potentially causing problems for your users.

Getting the contrast right will have a huge, positive effect across a wide spectrum of your users.

Responsible Text Labels

We’ve all built out a list of items with a non-descriptive, but visually appealing "More" button, right? More what though? We need to be more responsible with this and provide some context.

One way to achieve this is by visually hiding descriptive text with CSS and hiding the non-descriptive text from screen readers. It’s tempting to use display: none;, but screen readers can ignore elements with that set, so we need to be more creative. I use something like this little helper:

.visually-hidden { display: block; height: 0px; width: 0px; overflow: hidden; clip: rect(1px, 1px, 1px, 1px); visibility: hidden; }

With this CSS in place, we can do something like this:

<a href="/link-to-your-page"> <!-- This is hidden from a screen reader, but visible visually --> <span aria-hidden="true">More</span> <!-- This is visible to a screen reader, but visually hidden --> <span class="visually-hidden">Continue reading: "Your post title here"</span> </a>

A sighted user will only see “More” and a screen reader user will hear “Continue reading: 'Your post title here.'" Both sets of users are happy.

You can also achieve the above by using an aria-label on the <a> tag. This will override the text within for a screen-reader:

<a href="/link-to-your-page" aria-label="Continue reading: 'Your post title here'"> More </a> Small Typography Tweaks With a Big Impact

It's always worth remembering that people with a visual impairment or learning difficulty could be trying to read your content, so some small tweaks to your typography can go a long way.

A body of content such as an article should be sized at 16px (or equivalent unit) at a minimum. It's also worth increasing your line-height to around 1.5 too. Space between lines can help readers with dyslexia to understand your content better. The combination of size and space is also great for older people and/or short-of-sight people. Even small summaries and aside content should be at least 12px (or equivalent unit). Anything smaller than that will alienate users who struggle to read.

Another trick is to highlight key words and phrases if your content is quite complex. This not only benefits users who are slightly slower at processing content but it also helps people who like to scan over an article, like I do.

Lastly on this section, I'd advise you to be careful with your font choices. Fonts with complex ligatures and decorative elements can be really distracting, so maybe limit the usage of those to key, large headings only. It's also been advised that sans-serif fonts are better for readers with dyslexia. Check out this article for more on that and other text formatting tips.

Enhance Keyboard Support

There are a few little tweaks you can do to help users who primarily use their keyboard to navigate your website.

Say you've got a little button that shows a dialogue when you click it. You should attach an event to the escape key that hides it. Here's a sample snippet:

document.addEventListener('keyup', (evt) => { if(evt.keyCode === 27) { // Run whatever code hides your dialogue } });

See the Pen Escape key demo by Andy Bell (@hankchizljaw) on CodePen.

Another tweak you can do for our keyboard-navigating buddies is not hiding focus from them. Browsers give us focus states for free with outline. I know it can look ugly, but hot-damn it’s useful for keyboard users. If you want to get rid of that blue glow, I get it—just please use the :focus pseudo selector to add an obvious state change to it instead. Here's a sample:

.your-element { background: red; } .your-element:focus { outline: none; /* Reset the default */ box-shadow: 0 0 0 3px black; /* A very obvious state change */ } Don't Rely on Color Alone to Communicate State Changes

Let’s end on a really important one. Color shouldn’t be relied upon alone to communicate state changes. Take this scenario as an example:

You’ve got a button that posts a form. You wrote some neat JavaScript that makes it go grey while it sends the data. It then either turns green or red, depending on what the status is.

For a colorblind user, this is a nightmare. To them, the button may have barely changed enough for them to notice, so they may just keep clicking and clicking while getting really frustrated. This isn’t ideal.

So, instead of relying on color, let’s enhance that with a status message that supports the button’s state on response.

See the Pen Enhanced state change communication demo by Andy Bell (@hankchizljaw) on CodePen.

That sample is a great way to quickly communicate to the user that something has changed and the use of color, text and iconography clearly communicates that change. Disabling the button whilst the response is processed is also a great help to the user.

Wrapping Up

These little tips should make a big difference to your users, and I hope you dive into your projects and implement some of them.

You should also keep learning about accessibility. I recommend following people such as Heydon Pickering, Scott O’Hara, Laura Kalbag, and Rob Dobson on Twitter. I also recommend that you check out resources such as Inclusive Components and the A11y Project.

The greater your knowledge gets, the better your websites and products will be for a much wider audience. That can only be a good thing, right?

Small Tweaks That Can Make a Huge Impact on Your Website’s Accessibility is a post from CSS-Tricks

​Incapsula’s Global DDoS Threat Landscape Report

Thu, 01/11/2018 - 17:32

(This is a sponsored post.)

The newly released Q3 2017 Global DDoS Threat Landscape Report features insights on attacks and mitigation. These are some of the key findings:

  • Bitcoin was one of the most targeted industries
  • High packet rate attacks grew more common
  • A third of network layer attacks were highly persistent
  • Botnet activity out of India and Turkey continued to climb

Learn about the top attacked countries, industries, and vectors here and how to protect your site with Incapsula.

Direct Link to ArticlePermalink

​Incapsula’s Global DDoS Threat Landscape Report is a post from CSS-Tricks

HTML 5.2 is Done, HTML 5.3 is Coming

Wed, 01/10/2018 - 19:48

The W3C has completed its second round of HTML5 recommendations for implementation. The entire announcement is worth a read because there are interesting tidbits that provide more context and personnel changes within W3C, but the highlights of this recommendation are nicely summed up:

Many of the features added integrate other work done in W3C. The Payment Request API promises to make commerce on the Web far easier, reducing the risks of making a mistake or being caught by an unscrupulous operator. New security features such as Content Security Policy protect users more effectively, while new work incorporated from ARIA helps developers offer people with disabilities a good user experience of their applications.

There are also semantic changes to HTMl elements that are worth noting:

Clarifications and bug fixes bring the HTML Recommendation closer to what has been deployed recently. The definition for the main element has been updated to support modern responsive design patterns, the style element can be used inside the body element. Numerous constraints on code have been loosened, while where necessary for interoperability or security a few have been carefully reinforced.

And, spoiler alert! HTML 5.3 is officially in its first public working draft.

Direct Link to ArticlePermalink

HTML 5.2 is Done, HTML 5.3 is Coming is a post from CSS-Tricks


Wed, 01/10/2018 - 19:48

Here’s an interesting and super useful Chrome extension by Nitin Tulswani that measures React component performance:

React Performance Devtool is a browser extension for inspecting the performance of React Components. It statistically examines the performance of React components based on the measures which are collected by React using window.performance API. Along with the browser extension, the measures can also be inspected in a console.

Also, if you’re interested in learning more about the process of this tool, there’s a great thread that digs into the history of the project.

Direct Link to ArticlePermalink

react-perf-devtool is a post from CSS-Tricks

The latest ways to deal with the cascade, inheritance and specificity

Wed, 01/10/2018 - 14:24

The cascade is such an intrinsic part of CSS that they put it right there in the name. If you’ve ever needed to use !important to affect specificity in the cascade, you’ll know that it can be a tricky thing to deal with. In the early days of CSS, it was common to see highly specific selectors like this:

#sidebar ul li {}

We’re all much better at managing specificity nowadays. It’s a widely accepted best practice to keep specificity low and flat—to shun ID selectors, to make liberal use of classes, and to avoid unnecessary nesting. But there are still plenty of situations where a more specific selector will be useful. With the introduction of a newly proposed pseudo-class, more support of the shadow DOM, and the use of the all property, we will soon be able to handle inheritance and specificity in new and exciting ways.

The :is Pseudo-Class

Lea Verou recently proposed this new pseudo-class specifically designed to control specificity. It’s already made its way to the CSS Level 4 Selectors spec. Lea has a write up of why it’s useful and there’s some coverage of it in the CSS-Tricks almanac.

Let’s take :not as an example. The specificity of :not is equal to the specificity of its argument. This makes using :not rather painful. Take the following as an example:

See the Pen :not and specificity by CSS-Tricks (@css-tricks) on CodePen.

We might expect that the .red class would have higher specificity because it is lower in the cascade. However, for any styles to override div:not(.foobar) they would need to at least match the specificity of a combined element selector (div) and class selector (.foobar). Another approach would be div.red, but there is a better way. This is where :is can help.

div:is(:not(.foobar)) { background-color: black; }

The :not selector no longer adds any specificity, so the total specificity of the above selector is simply that of one element selector (div). The .red class would now be able to override it in the cascade. Once implemented, specificity hacks will be a thing of the past.

Shadow DOM

Today, many people are using classes in HTML like this:

<form class="site-search site-search--full"> <input type="text" class="site-search__field"> <button type="Submit" class="site-search__button">search</button> </form>

When using shadow DOM, rather than following a verbose naming convention, we’ll be able to omit classes altogether. Styles defined within the shadow DOM are scoped to apply only within the component. Styling can be achieved with simple element selectors without worrying about whether the selectors will interfere with elements elsewhere on the page.

See the Pen shadow dom by CSS GRID (@cssgrid) on CodePen.

It’s liberating to write such easy CSS. No more effort spent naming things. Shadow DOM looks like it is finally making its way to full browser support. It's likely to make it into the next release of Firefox while Edge have implementation as a high priority.

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

DesktopChromeOperaFirefoxIEEdgeSafari5340NoNoNoTPMobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox11.0-11.2NoNo6262No The all Property

The all property is a way of setting all CSS properties at once—everything from align-content to z-index. What values does it accept? I can’t think of any use case when I’d want all properties to inherit, but that’s an option. Then there’s initial which is more like applying a CSS reset where all the styles are gone. No padding. No margin. The initial value is set per property, regardless of the element it is applied to. The initial value of display is inline, even if you apply it to a div. The font-style of an em tag is normal, as is the font-weight of a strong tag. Link text will be black. You get the idea. (You can find the initial value of any CSS property on MDN.) This does perhaps limit its usefulness, going further than we might like by removing all styles, regardless of context.

See the Pen all: initial by CSS GRID (@cssgrid) on CodePen.

Sadly, the most useful value for all is also the least widely implemented: revert. It can remove the styles that you as a developer have applied, while leaving the default user-agent styles intact. We’ve all seen a page of HTML without a stylesheet—black Times New Roman on a white (transparent) background with blue underlined links. If you really want to avoid inheritance, then all: revert has you covered. All divs will be display: block and spans will be inline. All em tags will be italic and strong tags will be bold. Links will be blue and underlined.

See the Pen all: revert by CSS GRID (@cssgrid) on CodePen.

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

DesktopChromeOperaFirefoxIEEdgeSafariNoNoNoNoNo9.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox9.3NoNoNoNoNo The future?

CSS-in-JS is a cry for help. We at @csswg should pay attention to this and address the issues before it gets worse.https://t.co/lWQ4ct61ir

— Lea Verou (@LeaVerou) May 24, 2017

The miscellany of rival unstandardized methods for writing CSS-in-JS was an attempt to sidestep these same issues. That approach has gained popularity over the last several years. Some of its proponents have deemed inheritance, the cascade and specificity as fundamentally flawed design decisions of the language. The CSS Working Group at the W3C is responding by improving the power of CSS and the native web platform. It will be interesting to see the outcome…

The latest ways to deal with the cascade, inheritance and specificity is a post from CSS-Tricks

Making CSS Animations Feel More Natural

Tue, 01/09/2018 - 15:59

It used to be that designers designed and coders coded. There was no crossover, and that’s the way it was. But with the advent of CSS transitions and animations, those lines are blurring a bit. It’s no longer as simple as the designer dictating the design and the coder transcribing—designers must now know something about code, and coders must know something about design in order to effectively collaborate.

As an example, let’s say a designer asks a developer to make a box bounce. That’s it—no additional instruction. Without some cross-knowledge and a common vocabulary, both sides are a little lost in this communication: the developer doesn’t have enough information to fully realize the designer’s vision, but the designer doesn’t really know what the options are and how to communicate them. With a very basic interpretation, you might end up with something that looks like this:

See the Pen Bouncing Box 1 by Brandon Gregory (@pulpexploder) on CodePen.

Not very exciting. Although, to be fair, this does meet all of the criteria given. We can definitely do better than this, though.

The first thing to look at is the timing function. In the above example, we’re using a linear timing function, which means that the box is constantly moving at the same speed. In some cases, this is desirable; however, in the real world, motion usually doesn’t work like that.

An easy fix is to simply change the timing function to ease. This makes the beginning and ending of each animation a little slower than the middle part, which adds a more natural look to some animations. Here’s the box with the easing function turned on:

See the Pen Bouncing Box 2 by Brandon Gregory (@pulpexploder) on CodePen.

This is a slight improvement, but there’s still a lot of work to be done. The box still looks mechanical and stiff, with the same animation occurring in the same timeframe over and over. Adding a slight delay between bounces adds some visual contrast that seems a little more natural:

See the Pen Bouncing Box 3 by Brandon Gregory (@pulpexploder) on CodePen.

The box now looks like it’s jumping rather than simply moving up and down. There’s a little wind-up and cool-down between jumps that mimics what a live creature might do if given the same instruction. Even though we have no reference for what a jumping box would look like, we all have a pretty good idea of what a jumping creature would look like. Because we know what would happen in nature, by mimicking that, the animation feels more natural. But we can do more to make that wind-up feel a little more weighty.

If you watch cartoons, you’ll notice that natural movements are often exaggerated, creating a caricature of real life. When done well, this can feel just as natural as something in the real world, with the added bonus of infusing a little charm and character into the animation.

At this stage, collaboration between the designer and developer is crucial — but many designers may not even be aware that these options exist. It may be up to the developer to pitch this possibility to the designer.

By adding some subtle distortion to the scale of the box, we can add a lot to the animation:

See the Pen Bouncing Box 4 by Brandon Gregory (@pulpexploder) on CodePen.

Now, the box has character. It feels alive. There are many things to tweak, but this is already moving much farther than the original instruction — in a very good way!

We’re going to go a step further and add a little rebound at the end of the jump:

See the Pen Bouncing Box 5 by Brandon Gregory (@pulpexploder) on CodePen.

The second bounce is making this feel more alive, but something still seems off. The bounce looks stiff compared to the rest of the animation. We need to add another bit of distortion like we did for the wind-up:

See the Pen Bouncing Box 6 by Brandon Gregory (@pulpexploder) on CodePen.

That subtle distortion at the end makes the rebound seem much more natural. Overall, a huge improvement from our basic linear bounce in the first example.

That right there may be exactly what we’re looking for, but further tweaks to the rate of movement can be made with a custom cubic Bézier curve:

See the Pen Bouncing Box 7 by Brandon Gregory (@pulpexploder) on CodePen.

Without both the designer and the developer aware of basic animation principles and controls, this level of customization is impossible. Really, this article just scratches the surface of both fields. If you’re a web designer or a web developer who works with designers, I’d strongly urge you to read up on both.

For animation principles, The Illusion of Life: Disney Animation by Ollie Johnston and Frank Thomas is a great primer on how to make that caricature of real life seem alive and real. With that common language in place, communication and collaboration between designers and developers becomes much easier.

amzn_assoc_tracking_id = "csstricks-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_design = "enhanced_links"; amzn_assoc_asins = "0786860707"; amzn_assoc_placement = "adunit"; amzn_assoc_linkid = "26ac1508fd6ec7043cb51eb46b883858";

For the technical controls and variations of CSS animation, the possibilities are nearly endless. Delay and timing are simple to adjust. As mentioned, if you don’t like the out-of-the-box ease timing function, it’s very possible to create your own using a cubic-bezier(). You can also adjust the level of distortion you want to bring the animation closer to or further from reality. The important thing is that both the designer and developer are thinking about these variations rather than blindly taking everything without customization. Shared knowledge and collaboration can make even simple animations into great ones.

More Resources

Making CSS Animations Feel More Natural is a post from CSS-Tricks

WordPress User Survey Data for 2015-2017

Mon, 01/08/2018 - 20:54

A grand total of 77,609 responses from WordPress users and professionals collected by Automattic between 2015 and 2017. The stats for 2015 and 2016 have been shared at the annual State of the Word address and 2017 marks the first time they have been published on WordPress News.

A few items that caught my attention at first glance:

  • Between 66% and 75% of WordPress users installed WordPress on their own. In other words, they were savvy enough to do it without the help of a developer. Hosting providers were next up and clocked in at 13-14% of installs.
  • WordPress professionals described their clients as large and enterprise companies only 6-7% of the time. I guess this makes sense if those companies are relying on in-house resourcing, but I still would have pegged this higher.
  • What do users love most about WordPress? It's simple and user-friendly (49-52%). What frustrates them most about it? Plugins and themes (19-28%). Seems like those two would go hand-in-hand to some degree.

I'm not a statistician and have no idea how much the results of these surveys accurately reflect the 26% of all sites on the internet that are powered by WordPress, but it sure is interesting.

Direct Link to ArticlePermalink

WordPress User Survey Data for 2015-2017 is a post from CSS-Tricks

Careful Now

Mon, 01/08/2018 - 20:52

Tom Warren's "Chrome is turning into the new Internet Explorer 6" for The Verge has a title that, to us front-end web developers, suggests that Chrome is turning into a browser far behind in technology and replete with tricky bugs. Aside from the occasional offhand generic, "Chrome is getting so bad lately," comments you hear, we know that's not true. Chrome often leads the pack for good web tech.

Instead, it's about another equally concerning danger: developers building sites specifically for Chrome. In theory, that's not really a thing thing, because if you build a website with web standards (of which there isn't really much of an alternative) it'll work in Chrome like any other modern web browser. But it is a thing if you build the site to somehow block other browsers and only allow Chrome. Warren:

Google has been at the center of a lot of “works best with Chrome” messages we’re starting to see appear on the web. Google Meet, Allo, YouTube TV, Google Earth, and YouTube Studio Beta all block Windows 10’s default browser, Microsoft Edge, from accessing them and they all point users to download Chrome instead. Google Meet, Google Earth, and YouTube TV are also not supported on Firefox with messages to download Chrome.

I wouldn't call it an epidemic but it's not a good trend. Best I can tell, it's server-side UA sniffing that entirely blocks the sites:


If anything, I'd think you'd just let people use the site and display a warning if you're really worried some particular feature might not work. Or even better, fix it. I have no behind-the-scenes knowledge of why they made the choice to block certain browsers, but it's hard to imagine a technical limitation that would force it. And if it is, I'd suggest letting it be very publicly known to incentivize the other browsers to support what is needed, assuming it's an established standard.

Even more concerning than browser-specific websites is seeing browsers ship non-standardized features just because they want them, not behind any vendor prefix or flag. There was a time when web developers would have got out the pitchforks if a browser was doing this, but I sense some complacency seeping in.

These days, the vibe is more centered around complaining about other browsers lack of support for things. For example, one browser ships something, we see one green dot in caniuse, and we lambast the other browsers to catch up. Instead, we might ask, was it a good idea to ship that feature yet?

No modern browser is shipping vendor prefixes anymore since we all ultimately decided that was a bad idea. A side effect of that is that shipping a new feature in CSS or JavaScript is all the riskier. I would think shipping an unprefixed feature to a stable version of the browser would mean the feature is standardized and not going to significantly change. Yet, it's been happening.

In CSS, Chrome shipped motion-* properties, but then that all changed to offset-*, and the old motion-* properties just stopped working. That's more than just annoying, that kind of thing helps developers justify saying, "I just build this site for Chrome, if you wanna use it, use Chrome." Fine for a demo, perhaps, but bad for the web industry as a whole. Again, I have no special insight into why this happens, I'm just a developer looking in from the outside.

Here's another CSS one I just saw the other day. People are excited about text-decoration-skip: ink; because it looks great and helps people. They are using it a lot. But apparently, that's not the correct name for it? It's been changed to text-decoration-skip-ink: auto; and so Chrome 64 is canning text-decoration-skip: ink; which is confusing even to people at Google.

Chris Krycho had a take on it recently as well:

Over the past few years, I’ve increasingly seen articles with headlines that run something like, “New Feature Coming To the Web” — followed by content which described how Chrome had implemented an experimental new feature. “You’ll be able to use this soon!” has been the promise.

The reality is a bit more complicated. Sometimes, ideas the Chrome team pioneers make their way out to the rest of the browsers and become tools we can all use. Sometimes… they get shelved because none of the other browsers decide to implement them.

Many times, when this latter tack happens, developers grouse about the other browser makers who are “holding the web back.” But there is a fundamental problem in this way of looking at things: Chrome isn’t the standard. The fact that Chrome proposes something, and even the fact that a bunch of developers like it, does not a standard make. Nor does it impose an obligation to other browsers to prioritize it, or even to ship it.

This isn't all to throw Chrome under the bus. I'm a Chrome fan. I'm sure there are examples from all the major vendors in the same vein. I'd just like my two cents to be careful now. The web is the best platform to build for and generally heading in a direction that makes that even truer. The easiest way to screw that up is not being careful with standards.

Careful Now is a post from CSS-Tricks

Tales of a Non-Unicorn: A Story About the Roller Coaster of Job Searching

Mon, 01/08/2018 - 15:51

Hey there! It's Lara, author of the infamous"Tales of a Non-Unicorn: A Story About the Trouble with Job Titles and Descriptions" from a couple years back. If you haven't read that original article, I recommend skimming it to give you some context for this one, but I think you'll still find value here even if you don't.

A lot has happened since I wrote that article in 2015, and this follow-up has been in the works for a good six months. I ended up, not with a solution for the job titles conundrum or a manifesto about the importance of HTML and CSS, rather a simple, honest story about my roller coaster ride.

Okay, enough dilly-dally. Let's go!


In the aftermath of the FizzBuzz drama in 2015, I doubled down on my freelance business and did really well. I got a great contract gig with startup in New York refactoring a Haml/Bootstrap situation that paid the bills and then some. I hired an assistant and started the Tackle Box, an online school sort-of-thing where I taught web development and WordPress. I made a little money off that one, too. I spoke at a handful of conferences and meetups, taught a bunch of classes, and generally had the pedal to the metal.

Then I got really, really tired.

I was sick of writing emails, sick of sending invoices, and sick of being on the computer all the damn time. I wanted to go to work and then leave work at work; something that is very hard to do in our industry, and extra difficult when you are your own boss. I enjoyed coding sometimes, but it was all about the billable hour. Why should I write code or be on the computer at all if I'm not being paid for it? This was burnout, that thing that's become a weird, convoluted rite of passage in our industry.

I wanted to shut down Lara Schenck, LLC and be a ski bum. And you know what? I did. It was time for a break, and I took one for about six months.

Ski Bum Sabbatical

I left New York City in August of 2016 and moved back to my family's farm near Pittsburgh. I got a job cleaning horse stalls for $7/hr at the stable where I used to ride when I was a kid. My plan was to gradually ramp down business while I lived rent-free and prepared myself for the simple life. That December, I would be starting work as a bartender at Goldminer's Daughter Lodge in Alta, Utah, a tiny ski town outside of Salt Lake City. Room and board were included in the job; I'd make enough pocket money for booze, and my life would consist of skiing, sleeping, and socializing. No emails.

Just down the winding road from Alta Ski Area.

The simple life was okay for a little bit, but bartending at a 3:2 beer bar and skiing every day wasn't as fulfilling as I'd hoped. I cut the season short and moved to Los Angeles in March with my partner at the time. We had a mutual friend with an open room in Hollywood, and I was starved for city-living. (I have since learned that LA is not the city-living I expected, at all, but that's another conversation.)

Time to Get a Job (for real this time)

I formally announced I was back on the scene, reached out to old clients and people from my New York network, and was even on a podcast out of the gate. None of that translated into much paying work. Luckily, I had a cushion of savings to float me for a few months (Freelancing Rule #1: You must have savings), but my heart just wasn't in the freelance hustle this time. The prospect of negotiating contracts and engaging new leads was nauseating rather than exciting, and the small business website work I did was no longer the challenging and invigorating experience it had been before.

I decided to get a full-time job, for real this time. Once again, I wanted to work on a team and on bigger projects. I was tired of doing everything myself, and I wanted to learn from and share my experience with others. And, you know, a regular paycheck.

I set to work applying for jobs, putting long hours into carefully crafted cover letters. I had several promising interviews, got my hopes way up a couple of times, and received zero job offers. For one particular role, I'd gotten as far as discussing salary requirements and start dates, and was expecting an offer letter within the week. Then, the next week they were all of a sudden no longer hiring. I didn't run into any FizzBuzz, for better or for worse.

I started to question why my designer/developer skillset appeared to hold so little value now when I'd felt so in demand just a year ago. I stubbornly refused to learn React just so I could have it on my resume—I'm great at other important things, why can't people see that?! I wondered whether the five years of self-employment was a hindrance, or was there something fundamentally wrong with how I interviewed? Did I shoot myself in the foot with this whole "non-unicorn" thing in the first place?

These months were a major ego-check. It turns out, full-time jobs aren't something you can just "get." It's just not that easy, for me at least.

The Value of HTML and CSS

Responding to job posts with those carefully crafted cover letters had a very low return on investment so I decided to change my approach. Instead of putting my time into writing said cover letters, I would focus on writing about real things and becoming a better developer, and the jobs would come to me. I launched a well-thought-out redesign of my website, published a Reverse Job Post, and buckled down on my JavaScript studies.

This was right around the time Mandy Michael wrote "Is there any value in people who cannot write JavaScript?" which hit the nail on the head. I wrote a question into ShopTalk show about this phenomenon and mentioned to Chris that I'd love to come on the show and talk about it if they'd like. The next day, Chris invited both Mandy and me to come on the show and hash it out:

HTML and CSS are valuable, but intimate knowledge of them has become more of a specialist role. Perhaps, one can position their skills as HTML, CSS, plus something else (e.g. UI design or WordPress). The nature of products and rapid feature releases deem quality HTML and CSS an afterthought at many companies so at the moment, maybe the demand just isn't there. Perhaps the rise in accessibility awareness, design systems, and time lost debugging bad CSS will change the tide?

The episode was well received; I was obviously not the only one struggling with this issue. I made a Github repository called Front-end Discourse with the intention of gathering and synthesizing opinions and coming up with a plan of action on the job titles front. Chris even wrote about the job titles conundrum here on CSS-Tricks. The momentum was there; this could be my thing!

But then...I let it die.

An Unexpected Twist

A few days after the ShopTalk episode came out, I received this tweet:

Umm...that's a link to a Google job post.

I thought it was a joke at first, but nope, the tweet author sent me an email later that day, and it was the real deal! They'd been referred to me by a benevolent figure in the web industry whom I'd never met. I had a call with them and another member of their team, and it was magical. They told me all about a new team starting within Developer Relations at Google that would be working to improve the "Web Content Ecosystem." Web Content Ecosystem? That's WordPress! And they were recruiting me! Holy sh#t, this actually happens!

This was my dream job, not a front-end designer/developer role. I didn't even know this was a job! I had already been doing this work on my own time for several years: teaching and speaking about WordPress, writing informational blog posts, recording videos, and helping people use WordPress more responsibly. And they would move me to San Francisco! I was not a huge fan of Los Angeles.

Unfortunately, Google doesn't just "give" people jobs...you have to interview.

Computer Science Bootcamp

Now we have me, the designer who applied for a JS job and failed FizzBuzz, preparing for the Google interview otherwise known as the grandparent of all technical white-boarding interviews. It was time to swallow any feelings I had toward this interviewing style and get to work.

I had three weeks until a "coaching call" that would unofficially determine whether or not I could skip the technical phone screening and jump straight to the day of on-site interviews because, duh, this was meant to be. Luckily, this coincided with a lull in freelance work, which had also been picking up, so for about a week and a half, I put myself through a self-directed computer science bootcamp. On the way, I wrote a bunch of blog posts about what I learned.

Oh, how I longed to write that Tales of a Non-Unicorn: I GOT A JOB AT GOOGLE, F@#KERS!!! follow-up for all those Reddit haters after it was said and done!

The day of the coaching call arrived, and it was fantastic! I was a little slow on the coding question, but it wasn't as hard as I'd thought, I aced the role-related questions, and the interviewer was excellent. I heard back from the recruiter who was coordinating with me, and he said I could go straight to the on-site interviews.

In the meantime, I went to WordCamp US in Nashville where this particular team at Google was a sponsor. I got to meet a few of the folks I'd be working with, and it seemed like such a great fit. This Google interest and being at WordCamp made me question why, at the beginning of my job search, I had seen my knowledge of WordPress as such a secondary skillset. WordPress is everywhere! And its awesome! I mean, sure, it's not that "cool" yet, but mark my words, it will be in the "cool" ranks soon enough.

The Non-Unicorn Interviews at Google

In the week leading up to the interview, I focused on researching the role and beefing up my passion for improving WordPress and helping those who work with it. This was not a software engineering role, after all; in Developer Relations, passion for and knowledge of your subject is more important than knowing binary tree traversal, right?

Google flew me to San Francisco and put me up in a nice hotel. I had a full day of four interviews—usually, it's five, one was canceled—and a long, enjoyable lunch with the folks I'd been in touch with from the get-go. I didn't feel great about my performance in the technical parts of the interviews, but I did my best and my strategy was to come off as a great coworker who knows when to ask for help. When in doubt, I remembered the strong correlation between "hard interview" and "received offer" on Google's Glassdoor profile.

Back in LA, freelance work kept me busy while I waited for a verdict, which wasn't long. I felt relatively zen about the whole thing. Yes, I had my hopes up, but if it didn't work out, I at least had work to pay the bills, and it wasn't going half-bad. I'd been contracting with an agency and learning a lot; it wasn't the small business WordPress sites I'd been building all by myself previously.

The Thursday after my Monday interview, I got a call from my recruiter contact. They were not going to proceed with the approval process at this time. He said I showed some very promising "Google-y" qualities, but my performance in the coding portion of the interviews wasn't strong enough. He said he had it in his calendar to reconnect with me in six months, and that he would keep an eye out for less technical roles that might be a better fit.


Incredibly, I was able to fend off the majority of the anger and the "I'm a failure and I suck at everything" thoughts that go hand-in-hand with rejection, maybe in part because I received such a nice email from one of the people I'd been in touch with throughout the process. He had applied three times before he got a job there—which apparently is not uncommon—and this simply meant I'd be taking a slightly different path. They were all bummed I didn't make it.

This brings us back to the present. I don't feel sour about algorithms or white-boarding interviews...I have another one to get ready for in six months! Unless, of course, another really awesome opportunity comes my way in the meantime. Who knows.

This whole job search has been such a ridiculous roller coaster of hopes slowly going up then crashing down. If there's one thing I've learned, it's that I still don't know where I'll end up, but I'm doing my best and I'll keep doing it until the right thing comes along.


Whew, that was a lot! Thanks for making it this far. A+ for you, reader!


Before I wrap this thing up, I want to make a few observations about this whole job searching process that I hope can help others on their roller coaster ride.

  1. Algorithms and white-boarding interviews aren't necessarily bad. I think they can be implemented badly. The Big Tech Companies are fully aware that they miss out on great candidates because of algorithm questions, but this interviewing strategy is so good at filtering out bad candidates that they keep it around. It sucks for us, but I don't see that changing anytime soon. Plus, I learned a hell of a lot of stuff preparing for it, and it's made me a better developer and better human being.
  2. Write a "Reverse Job Post." I don't recall where I learned about it, but here's mine for reference. Even if no one reads it, it's a great way to figure out what type of job and company you are looking for, and you could totally paste a link to it in the cover letter field for an application and call it a day.
  3. Learn computer science fundamentals. I know we are already inundated with things to learn, so it's hard to preach this, but having context for what the tools we use actually are has helped me a lot. For example, two months ago I would have had a hard time wrapping my mind around GraphQL, but in my interview preparation I learned about graphs and tree data structures, so I was able to understand the concept relatively easily. Cracking the Coding Interview is not a good place to start, BaseCS and the Impostor's Handbook are. Also, stay tuned for some relevant articles here on CSS-Tricks, from yours truly!
  4. Don't spend all of your time on job boards. It's a crapshoot. I think there are great job boards, but in general, no matter how quality the listing, whether or not the position is actually available or accurately represented in the post is a toss-up.
  5. Be vocal. I doubt any of this Google stuff would have happened if I hadn't written into ShopTalk show and asked Chris to have me on the episode. If you have an impulse to write something or have a question or feel the urge to tweet at someone you don't know, do it (but be a good person about it, obviously). The more web people that know you exist, the more likely it is that something will come your way.

Those are some things that helped me, but I still don't have a job, so maybe don't listen to what I say. I don't know. It's an incredibly difficult and demeaning process, and there's no secret sauce that works for everyone. Our industry is a young one, and as far as I'm aware, there is no such thing as a surefire career path in web development.

I hope I don't write another "Tales of a Non-Unicorn" installment. The whole idea of a "unicorn" is bogus, anyway. We are all just people, with different levels of knowledge in different areas, and if you can honestly say you're doing your best then I think that's all you can do.

What I will be writing, however, are some "Computer Science Study Guides" for the self-taught developer, here on CSS-Tricks, and maybe some stuff about how cool WordPress is nowadays. At the very least, "Intro To Algorithms" will be coming at you, soon!

How about you, reader?

Have you been on this roller coaster ride, too? Where did you end up? What advice can you offer to those of us who are still in the midst of our journey?

Tales of a Non-Unicorn: A Story About the Roller Coaster of Job Searching is a post from CSS-Tricks

Monitoring unused CSS by unleashing the raw power of the DevTools Protocol

Fri, 01/05/2018 - 20:38

From Johnny's dev blog:

The challenge: Calculate the real percentage of unused CSS

Our goal is to create a script that will measure the percentage of unused CSS of this page. Notice that the user can interact with the page and navigate using the different tabs.

DevTools can be used to measure the amount of unused CSS in the page using the Coverage tab. Notice that the percentage of unused CSS after the page loads is ~55%, but after clicking on each of the tabs, more CSS rules are applied and the percentage drops down to just ~15%.

That's why I'm so skeptical of anything that attempts to measure "unused CSS." This is an incredibly simple demo (all it does is click some tabs) and the amount of unused CSS changes dramatically.

If you are looking for accurate data on how much unused CSS is in your codebase, in an automated fashion, you'll need to visit every single URL on your site and trigger every possible event on every element and continue doing that until things stop changing. Then do that for every possible state a user could be in—in every possible browser.

Here's another incredibly exotic way I've heard of it being done:

  1. Wait a random amount of time after the page loads
  2. Loop through all the selectors in the CSSOM
  3. Put a querySelector on them and see if it finds anything or not
  4. Report those findings back to a central database
  5. Run this for enough time on a random set of visitors (or all visitors) that you're certain is a solid amount of data representing everywhere on your site
  6. Take your set of selectors that never matched anything and add a tiny 1px transparent GIF background image to them
  7. Run that modified CSS for an equal amount of time
  8. Check your server logs to make sure those images were never requested. If they were, you were wrong about that selector being unused, so remove it from the list
  9. And the end of all that, you have a set of selectors in your CSS that are very likely to be unused.

Clever, but highly unlikely that anyone is using either of these methods in a consistent and useful way.

I'm a little scared for tools like Lighthouse that claim to audit your unused CSS telling you to "remove unused rules from stylesheets to reduce unnecessary bytes consumed by network activity." The chances seem dangerously high that someone runs this, finds this so-called unused CSS and deletes it only to discover it wasn't really unused.

Direct Link to ArticlePermalink

Monitoring unused CSS by unleashing the raw power of the DevTools Protocol is a post from CSS-Tricks

`font-size` With All Viewport Units

Fri, 01/05/2018 - 18:39

We've covered fluid type a number of times. This page probably covers it in the best detail. It's a little more complicated than simply using a vw unit to set the font-size since that's far too dramatic. Ideally, the font-size is literally fluid between minimum and maximum values.

Someday there will be min-font-size and max-font-size (probably), but until then, our fluid type implementations will probably need to resort to some @media queries to lock those mins/maxes.


Around a year ago Matt Smith documented a technique I had missed. It calculates font-size using a little bit of vw, a little bit of vh, and a little bit of the smaller of the two...

:root { font-size: calc(1vw + 1vh + .5vmin); }

Of course, it depends on the font and what you are doing with it, but it seems to me this tempers the curve such that you might not really need a min and max.

Direct Link to ArticlePermalink

`font-size` With All Viewport Units is a post from CSS-Tricks

A Round-Up of 2017 Round-Ups

Fri, 01/05/2018 - 15:03

This week marked the beginning of a new year and with it came a slew of excellent write-ups from folks in our industry reflecting on the year past. We thought it would be nice to compile them together for easy reference. If you know of any others that should be on everyone's radar, please leave it in the comments.

Now on to the round-up of round-ups!

Rachel Andrew

Having been wandering the globe talking about CSS Grid for almost five years, Grid finally shipped in browsers in 2017. This was good, as I didn’t really want to be some kind of CSS vapourware lady. I knew Grid was important the first time I read the initial spec. I had no idea how my championing of the specification would change my life, and allow me to get to work with so many interesting people.

Read More

Geri Coady

One of my biggest achievements this year was the release of my second book, Color Accessibility Workflows, published by A Book Apart. I’m hugely grateful for any opportunity to talk about color and how it can impact people in the digital world, and writing for A Book Apart has long been a dream of mine.

Read More

Monica Dinculescu

You can tell I hate writing year in reviews because this one is really, really late. I tend to hate bragging, and I definitely hate introspective and, in particular, I always think I am underperforming (and that’s fine). However, that’s usually not true, and writing a year in review forces me to see the awesome things I did, so even if I did end up underperforming, at least I can learn from that. That’s the whole point of post-mortems, right?

Read More

Sarah Drasner

This year has been a surreal one for me. I’ve had years that were particularly tough, years that trended more cheerfully, but 2017 was unique and bizarre because I felt an immense guilt in my happiness.

I think this might have been the year I found the most personal happiness, but the giant caveat in everything was watching the world divide, watching racism, sexism and hatred rise, and seeing some real damage that incurred on people’s lives around the world.

Read More

Brad Frost

Throughout 2017, when people asked how I was doing, I’d say “Great…for the things I can control.” 2017 was a rough year at a macro level for everybody, and I found myself coping with the state of the world in a number of different ways. But on a personal level, I had a rewarding year full of a lot of work, a lot of travel, and even some major life changes.

Read More

Geoff Graham

It feels kind of weird to include my own round-up, but whatever.

I've typically set goals for myself at the start of each year and followed up on them somewhere towards the end of the year. Unfortunately, the last time I did that out loud was in 2014. I’ve been pretty quiet about my goals and general life updates since then and it’s certainly not for lack of things to write about. So, I’m giving this whole reflection thing the ol’ college go once again.

Read More

Jeremy Keith

Jeremy published 78 blog posts in 2017 (or 6.5 per month as he calculates it) and noted his personal favorites.

Read More

Zach Leatherman

I had an incredibly productive year of side projects, learning, and blog posts—I can attribute almost all of that rediscovered time and energy to quitting Facebook very early in the year. It’s also been amazing to see my daughter grow and learn—she turned two this year and I really love being a dad. We now have our own secret handshake and it’s my favorite thing.

Read More

Ethan Marcotte

And finally, one of the things I’m most proud of is, well, this little website, which I launched hastily just over a year ago. And over the last entirely-too-eventful year, I’ve surprised myself with just how much it helped to be blogging again. Because while the world’s been not-so-lightly smoldering, it felt—and feels—good to put words in a place where I can write, think, and tinker, a place that isn’t Twitter, a place that’s mine.

Read More

Eric Meyer

While this is not so much a reflection on the past year, Eric did mark the new year with a livestream redesign of his personal website—the first design update in 13 years.

My core goal was to make the site, particularly blog posts, more readable and inviting. I think I achieved that, and I hope you agree. The design should be more responsive-friendly than before, and I think all my flex and grid uses are progressively enhanced. I do still need to better optimize my use of images, something I hope to start working on this week.

Read More

Dave Rupert

My big work task this year was building a Pattern Library and it’s exciting to see that work beginning to roll out. The most gratifying aspect is seeing the ultimate Pattern Library thesis proven out: Speed. Pages load faster, CMS integrations are faster, and we can successfully turn out new production pages within a 1-day turnaround.

Read More

David Walsh

David used the new year to think about and plot upcoming goals.

Every turn of the year is a new opportunity to start over, set goals, and renew optimism that time can heal wounds and drive us to change and achieve. For me 2018 is my most important year in a long time; 2018 needs to serve as a turning point for this blog and my career.

Read More

Trent Walton

Dave, Reagan, and I celebrated our 10th official year as Paravel. In addition to some shorter-term projects, we undertook a large-scale pattern library and front-end update that is rolling out in phases this year. We’ve also enjoyed bringing in 6+ collaborators/teams to assist with projects when the need has arisen. I bet we do more of this in 2018—collaborating with friends has been fun.

Read More


Think we'd leave out our own round-up? Of all the site stats Chris shared in this post, this one nicely summed up the action around here in 2017:

We were on a publishing roll though! We published 595 posts, blowing away last year with only 442, the previous record. We also published 50 pages (i.e. snippets/videos/almanac entries) beating 43 last year. Certainly, we're in favor of quality over quantity, but I think this is a healthy publishing pace when our goal is to be read, in a sense, like a magazine.

Read More

A Round-Up of 2017 Round-Ups is a post from CSS-Tricks

Front-End Performance Checklist

Thu, 01/04/2018 - 20:01

Vitaly Friedman swings wide with a massive list of performance considerations. It's a well-considered mix of old tactics (cutting the mustard, progressive enhancement, etc.) and newer considerations (tree shaking, prefetching, etc.). I like the inclusion of a quick wins section since so much can be done for little effort; it's important to do those things before getting buried in more difficult performance tasks.

Speaking of considering performance, Philip Walton recently dug into what interactive actually means, in a world where we throw around acronyms like TTI:

But what exactly does the term “interactivity” mean?

I think most people reading this article probably know what the word “interactivity” means in general. The problem is, in recent years the word has been given a technical meaning (e.g. in the metric “Time to Interactive” or TTI), and unfortunately the specifics of that meaning are rarely explained.

One reason is that the page depends on JavaScript and that JavaScript hasn't downloaded, parsed, and run yet. That reason is well-trod, but there is another one: the "main thread" might be busy doing other stuff. That is a particularly insidious enemy of performance, so definitely read Philip's article to understand more about that.

Also, if you're into front-end checklists, check out David Dias' Front-End Checklist.

Direct Link to ArticlePermalink

Front-End Performance Checklist is a post from CSS-Tricks

26 Fabulous Scripts Fonts

Thu, 01/04/2018 - 16:24

(This is a sponsored post.)

Just $9.

They are nicely constructed as well, with stylistic alternates, ligatures, punctuation, extra characters, and multilingual support.

Direct Link to ArticlePermalink

26 Fabulous Scripts Fonts is a post from CSS-Tricks

Fun Times With Sizing Grid Elements

Thu, 01/04/2018 - 16:24

Chris showed us a little while back that CSS grid areas and their elements are not necessarily the same size. It's an interesting point because one might assume that putting things into a grid area would make those things occupy the entire space, but grid areas actually reserve the space defined by the grid and set the element's justify-content and align-items properties to a stretch value by default.

So... yes, they are the same size, but not necessarily.

Chris ended his post by asking "who cares?" while indicating no one in particular. The point was much more geared toward calling this out as a starting point for folks who need to align content in the grid.

I'm not sure I have a better answer, but it made me think it would be fun if we could leverage those auto-assigned stretch values to adapt a user interface in interesting ways.

I'm not saying any of these are great use cases. In fact, they may be downright silly. That said, maybe they can be the starting point for other ideas.

Stretching Form Fields

One idea is to add some interaction to form fields. If our <form> is the grid container then we can set text inputs where they start at their default width using the start value and then expanding them to the full width of the container by switching to the stretch value on a :focus state:

.grid__form { display: grid; } .grid__input { justify-self: start; } .grid__input:focus { justify-self: stretch; }

See the Pen CSS Grid: Grid Child Stretch on Focus by Geoff Graham (@geoffgraham) on CodePen.

Then again, we can already do something similar with Flexbox but with the benefit of the flex being an animated property:

See the Pen Flexbox: Child Stretch on Focus by Geoff Graham (@geoffgraham) on CodePen.

I'm honestly not sure where expanding form fields on focus would make for great UX but it's certainly fun to play with.

Curtain Opening Effect Re-Visited

We posted a good ol' fashioned CSS trick last year that uses the checkbox hack to create the effect of a curtain opening to reveal content behind it.

See the Pen OXJMmY by Geoff Graham (@geoffgraham) on CodePen.

That used widths and positioning to move things around on click, but we could have done something similar with Grid. Again, this is less robust because it lacks animation and the does not allow the curtain to fully open, but it does show how we can leverage the stretch, start and end values of a grid element and its sizing to achieve some interesting ideas.

See the Pen CSS Grid Curtain Reveal by Geoff Graham (@geoffgraham) on CodePen.

What Else?

The fact that grid elements are not always the size of the grid area is a nice tip to keep in our back pockets as we develop layouts. I'd bet we can come up with more ideas to take that concept to another level and have fun with it as a group. Share 'em if you have 'em!

Fun Times With Sizing Grid Elements is a post from CSS-Tricks

CodePen’s Most Hearted of 2017

Thu, 01/04/2018 - 00:26

The most fun year-end list there is, if you ask me.

Direct Link to ArticlePermalink

CodePen’s Most Hearted of 2017 is a post from CSS-Tricks