Hey hey `font-display`

Y’all know about font-display? It’s pretty great. It’s a CSS property that you can use within @font-face blocks to control how, visually, that font loads. Font loading is really pretty damn complicated. Here’s a guide from Zach Leatherman to prove it, which includes over 10 font loading strategies, including strategies that involve critical inline CSS of subsets of fonts combined with loading the rest of the fonts later through JavaScript. It ain’t no walk in the park.

Using font-display is kinda like a walk in the park though. It’s just a single line of CSS. It doesn’t solve everything that Zach’s more exotic demos do, but it can go a long way with that one line. It’s notable to bring up right now, as support has improved a lot lately. It’s now in Firefox 58+, Chrome 60+, Safari 11.1+, iOS 11.3+, and Chrome on Android 64+. Pretty good.

What do you get from it? The ability to control font-display for the Masses by Jeremy Wagner

  • If you really dislike FOUT, font-display: optional might be your jam by me
  • Reminder:

    FOUT = Flash of Unstyled Text
    FOIT = Flash of Invisible Text

    Neither is great. In a perfect world, our custom fonts just show up immediately. But since that’s not a practical possibility, we pick based on our priorities.

    The best resource out there about it is Monica Dinculescu’s explainer page:

    i’d summarize those values choices like this:

    • If you’re OK with FOUT, you’re probably best off with font-display: swap; which will display a fallback font fairly fast, but swap in your custom font when it loads.
    • If you’re OK with FOIT, you’re probably best off with font-display: block; which is fairly similar to current browser behavior, where it shows nothing as it waits for the custom font, but will eventually fall back.
    • If you only want the custom font to show at all if it’s there immediately, font-display: optional; is what you want. It’ll still load in the background and be there next page load probably.

    Those are some pretty decent options for a single line of CSS. But again, remember if you’re running a major text-heavy site with custom fonts, Zach’s guide can help you do more.

    I’d almost go out on a limb and say: every @font-face block out there should have a font-display property. With the only caveat being you’re doing something exotic and for some reason want the browser default behavior.

    Wanna hear something quite unfortunate? We already mentioned font-display: block;. Wouldn’t you think it, uh, well, blocked the rendering of text until the custom font loads? It doesn’t. It’s still got a swap period. It would be the perfect thing for something like icon fonts where the icon (probably) has no meaning unless the custom font loads. Alas, there is no font-display solution for that.

    And, hey gosh, wouldn’t it be nice if Google Fonts allowed us to use it?

    The post Hey hey `font-display` appeared first on CSS-Tricks.

    1 HTML Element + 5 CSS Properties = Magic!

    Let’s say I told you we can get the results below with just one HTML element and five CSS properties for each. No SVG, no images (save for the background on the root that’s there just to make clear that our one HTML element has some transparent parts), no JavaScript. What would you think that involves?

    Screenshots. On the left, a screenshot of equal radial slices of a pie with transparent slices (gaps) in between them. The whole assembly has a top to bottom gradient (orange to purple). On the right, the XOR operation between what we have on the left and a bunch of concentric ripples. Again, the whole assembly has the same top to bottom gradient.
    The desired results.

    Well, this article is going to explain just how to do this and then also show how to make things fun by adding in some animation.

    CSS-ing the Gradient Rays

    The HTML is just one <div>.

    <div class='rays'></div>

    In the CSS, we need to set the dimensions of this element and we need to give it a background so that we can see it. We also make it circular using border-radius:

    .rays { width: 80vmin; height: 80vmin; border-radius: 50%; background: linear-gradient(#b53, #f90);
    }

    And… we’ve already used up four out of five properties to get the result below:

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

    So what’s the fifth? mask with a repeating-conic-gradient() value!

    Let’s say we want to have 20 rays. This means we need to allocate $p: 100%/20 of the full circle for a ray and the gap after it.

    Illustration. Shows how we slice the disc to divide it into equal rays and gaps.
    Dividing the disc into rays and gaps (live).

    Here we keep the gaps in between rays equal to the rays (so that’s .5*$p for either a ray or a space), but we can make either of them wider or narrower. We want an abrupt change after the ending stop position of the opaque part (the ray), so the starting stop position for the transparent part (the gap) should be equal to or smaller than it. So if the ending stop position for the ray is .5*$p, then the starting stop position for the gap can’t be bigger. However, it can be smaller and that helps us keep things simple because it means we can simply zero it.

    SVG illustration. Connects the stop positions from the code to the actual corresponding points on the circle defining the repeating conic gradient.
    How repeating-conic-gradient() works (live).
    $nr: 20; // number of rays
    $p: 100%/$nr; // percent of circle allocated to a ray and gap after .rays { /* same as before */ mask: repeating-conic-gradient(#000 0% .5*$p, transparent 0% $p);
    }

    Note that, unlike for linear and radial gradients, stop positions for conic gradients cannot be unitless. They need to be either percentages or angular values. This means using something like transparent 0 $p doesn’t work, we need transparent 0% $p (or 0deg instead of 0%, it doesn’t matter which we pick, it just can’t be unitless).

    Screenshot of equal radial slices of a pie with transparent slices (gaps) in between them. The whole assembly has a top to bottom gradient (orange to purple).
    Gradient rays (live demo, no Edge support).

    There are a few things to note here when it comes to support:

    • Edge doesn’t support masking on HTML elements at this point, though this is listed as In Development and a flag for it (that doesn’t do anything for now) has already shown up in about:flags.
      Screenshot showing the about:flags page in Edge, with the 'Enable CSS Masking' flag highlighted.
      The Enable CSS Masking flag in Edge.
    • conic-gradient() is only supported natively by Blink browsers behind the Experimental Web Platform features flag (which can be enabled from chrome://flags or opera://flags). Support is coming to Safari as well, but, until that happens, Safari still relies on the polyfill, just like Firefox.
      Screenshot showing the Experimental Web Platform Features flag being enabled in Chrome.
      The Experimental Web Platform features flag enabled in Chrome.
    • WebKit browsers still need the -webkit- prefix for mask properties on HTML elements. You’d think that’s no problem since we’re using the polyfill which relies on -prefix-free anyway, so, if we use the polyfill, we need to include -prefix-free before that anyway. Sadly, it’s a bit more complicated than that. That’s because -prefix-free works via feature detection, which fails in this case because all browsers do support mask unprefixed… on SVG elements! But we’re using mask on an HTML element here, so we’re in the situation where WebKit browsers need the -webkit- prefix, but -prefix-free won’t add it. So I guess that means we need to add it manually:
      $nr: 20; // number of rays
      $p: 100%/$nr; // percent of circle allocated to a ray and gap after
      $m: repeating-conic-gradient(#000 0% .5*$p, transparent 0% $p); // mask .rays { /* same as before */ -webkit-mask: $m; mask: $m;
      }

      I guess we could also use Autoprefixer, even if we need to include -prefix-free anyway, but using both just for this feels a bit like using a shotgun to kill a fly.

    Adding in Animation

    One cool thing about conic-gradient() being supported natively in Blink browsers is that we can use CSS variables inside them (we cannot do that when using the polyfill). And CSS variables can now also be animated in Blink browsers with a bit of Houdini magic (we need the Experimental Web Platform features flag to be enabled for that, but we also need it enabled for native conic-gradient() support, so that shouldn’t be a problem).

    In order to prepare our code for the animation, we change our masking gradient so that it uses variable alpha values:

    $m: repeating-conic-gradient( rgba(#000, var(--a)) 0% .5*$p, rgba(#000, calc(1 - var(--a))) 0% $p);

    We then register the alpha --a custom property:

    CSS.registerProperty({ name: '--a', syntax: '<number>', initialValue: 1;
    })

    And finally, we add in an animation in the CSS:

    .rays { /* same as before */ animation: a 2s linear infinite alternate;
    } @keyframes a { to { --a: 0 } }

    This gives us the following result:

    Animated gif. We animate the alpha of the gradient stops, such that the rays go from fully opaque to fully transparent, effectively becoming gaps, while the opposite happens for the initial gaps, they go from fully transparent to fully opaque, thus becoming rays. At any moment, the alpha of either of them is 1 minus the alpha of the other, so they complement each other.
    Ray alpha animation (live demo, only works in Blink browsers with the Experimental Web Platform features flag enabled).

    Meh. Doesn’t look that great. We could however make things more interesting by using multiple alpha values:

    $m: repeating-conic-gradient( rgba(#000, var(--a0)) 0%, rgba(#000, var(--a1)) .5*$p, rgba(#000, var(--a2)) 0%, rgba(#000, var(--a3)) $p);

    The next step is to register each of these custom properties:

    for(let i = 0; i < 4; i++) { CSS.registerProperty({ name: `--a${i}`, syntax: '<number>', initialValue: 1 - ~~(i/2) })
    }

    And finally, add the animations in the CSS:

    .rays { /* same as before */ animation: a 2s infinite alternate; animation-name: a0, a1, a2, a3; animation-timing-function: /* easings from easings.net */ cubic-bezier(.57, .05, .67, .19) /* easeInCubic */, cubic-bezier(.21, .61, .35, 1); /* easeOutCubic */
    } @for $i from 0 to 4 { @keyframes a#{$i} { to { --a#{$i}: #{floor($i/2)} } }
    }

    Note that since we’re setting values to custom properties, we need to interpolate the floor() function.

    Animated gif. This time, the alpha of each and every stop (start and end of ray, start and end of gap) is animated independently via its own CSS variable. The alphas at the start and end of the ray both go from 1 to 0, but using different timing functions. The alphas at the start and end of the gap both go from 0 to 1, but, again, using different timing functions.
    Multiple ray alpha animations (live demo, only works in Blink browsers with the Experimental Web Platform features flag enabled).

    It now looks a bit more interesting, but surely we can do better?

    Let’s try using a CSS variable for the stop position between the ray and the gap:

    $m: repeating-conic-gradient(#000 0% var(--p), transparent 0% $p);

    We then register this variable:

    CSS.registerProperty({ name: '--p', syntax: '<percentage>', initialValue: '0%'
    })

    And we animate it from the CSS using a keyframe animation:

    .rays { /* same as before */ animation: p .5s linear infinite alternate
    } @keyframes p { to { --p: #{$p} } }

    The result is more interesting in this case:

    Animated gif. The stop position between the ray an the gap animates from 0 (when the ray is basically reduced to nothing) to the whole percentage $p allocated for a ray and the gap following it (which basically means we don't have a gap anymore) and then back to 0 again.
    Alternating ray size animation (live demo, only works in Blink browsers with the Experimental Web Platform features flag enabled).

    But we can still spice it up a bit more by flipping the whole thing horizontally in between every iteration, so that it’s always flipped for the reverse ones. This means not flipped when --p goes from 0% to $p and flipped when --p goes back from $p to 0%.

    The way we flip an element horizontally is by applying a transform: scalex(-1) to it. Since we want this flip to be applied at the end of the first iteration and then removed at the end of the second (reverse) one, we apply it in a keyframe animation as well—in one with a steps() timing function and double the animation-duration.

     $t: .5s; .rays { /* same as before */ animation: p $t linear infinite alternate, s 2*$t steps(1) infinite;
    } @keyframes p { to { --p: #{$p} } } @keyframes s { 50% { transform: scalex(-1); } }

    Now we finally have a result that actually looks pretty cool:

    Animated gif. We have the same animation as before, plus a horizontal flip at the end of every iteration which creates the illusion of a circular sweep instead of just increasing and then decreasing rays, as the rays seems to now decrease from the start after they got to their maximum size incresing from the end.
    Alternating ray size animation with horizontal flip in between iterations (live demo, only works in Blink browsers with the Experimental Web Platform features flag enabled).

    CSS-ing Gradient Rays and Ripples

    To get the rays and ripples result, we need to add a second gradient to the mask, this time a repeating-radial-gradient().

    SVG illustration. Connects the stop positions from the code to the actual corresponding points on the circle defining the repeating radial gradient.
    How repeating-radial-gradient() works (live).
    $nr: 20;
    $p: 100%/$nr;
    $stop-list: #000 0% .5*$p, transparent 0% $p;
    $m: repeating-conic-gradient($stop-list), repeating-radial-gradient(closest-side, $stop-list); .rays-ripples { /* same as before */ mask: $m;
    }

    Sadly, using multiple stop positions only works in Blink browsers with the same Experimental Web Platform features flag enabled. And while the conic-gradient() polyfill covers this for the repeating-conic-gradient() part in browsers supporting CSS masking on HTML elements, but not supporting conic gradients natively (Firefox, Safari, Blink browsers without the flag enabled), nothing fixes the problem for the repeating-radial-gradient() part in these browsers.

    This means we’re forced to have some repetition in our code:

    $nr: 20;
    $p: 100%/$nr;
    $stop-list: #000, #000 .5*$p, transparent 0%, transparent $p;
    $m: repeating-conic-gradient($stop-list), repeating-radial-gradient(closest-side, $stop-list); .rays-ripples { /* same as before */ mask: $m;
    }

    We’re obviously getting closer, but we’re not quite there yet:

    Screenshot. We have the same radial slices with equal gaps in between, and over them, a layer of ripples - concentric rings with gaps equal to their width in between them. The whole thing has a top to bottom gradient (orange to purple) with transparent parts where the gaps of the two layers intersect.
    Intermediary result with the two mask layers (live demo, no Edge support).

    To get the result we want, we need to use the mask-composite property and set it to exclude:

    $m: repeating-conic-gradient($stop-list) exclude, repeating-radial-gradient(closest-side, $stop-list);

    Note that mask-composite is only supported in Firefox 53+ for now, though Edge should join in when it finally supports CSS masking on HTML elements.

    Screenshot. We have the same result as before, except now we have performed a XOR operation between the two layers (rays and ripples).
    XOR rays and ripples (live demo, Firefox 53+ only).

    If you think it looks like the rays and the gaps between the rays are not equal, you’re right. This is due to a polyfill issue.

    Adding in Animation

    Since mask-composite only works in Firefox for now and Firefox doesn’t yet support conic-gradient() natively, we cannot put CSS variables inside the repeating-conic-gradient() (because Firefox still falls back on the polyfill for it and the polyfill doesn’t support CSS variable usage). But we can put them inside the repeating-radial-gradient() and even if we cannot animate them with CSS keyframe animations, we can do so with JavaScript!

    Because we’re now putting CSS variables inside the repeating-radial-gradient(), but not inside the repeating-conic-gradient() (as the XOR effect only works via mask-composite, which is only supported in Firefox for now and Firefox doesn’t support conic gradients natively, so it falls back on the polyfill, which doesn’t support CSS variable usage), we cannot use the same $stop-list for both gradient layers of our mask anymore.

    But if we have to rewrite our mask without a common $stop-list anyway, we can take this opportunity to use different stop positions for the two gradients:

    // for conic gradient
    $nc: 20;
    $pc: 100%/$nc;
    // for radial gradient
    $nr: 10;
    $pr: 100%/$nr;

    The CSS variable we animate is an alpha --a one, just like for the first animation in the rays case. We also introduce the --c0 and --c1 variables because here we cannot have multiple positions per stop and we want to avoid repetition as much as possible:

    $m: repeating-conic-gradient(#000 .5*$pc, transparent 0% $pc) exclude, repeating-radial-gradient(closest-side, var(--c0), var(--c0) .5*$pr, var(--c1) 0, var(--c1) $pr); body { --a: 0; /* layout, backgrounds and other irrelevant stuff */
    } .xor { /* same as before */ --c0: #{rgba(#000, var(--a))}; --c1: #{rgba(#000, calc(1 - var(--a)))}; mask: $m;
    }

    The alpha variable --a is the one we animate back and forth (from 0 to 1 and then back to 0 again) with a little bit of vanilla JavaScript. We start by setting a total number of frames NF the animation happens over, a current frame index f and a current animation direction dir:

    const NF = 50; let f = 0, dir = 1;

    Within an update() function, we update the current frame index f and then we set the current progress value (f/NF) to the current alpha --a. If f has reached either 0 of NF, we change the direction. Then the update() function gets called again on the next refresh.

    (function update() { f += dir; document.body.style.setProperty('--a', (f/NF).toFixed(2)); if(!(f%NF)) dir *= -1; requestAnimationFrame(update)
    })();

    And that’s all for the JavaScript! We now have an animated result:

    Animated gif. We animate the alpha of the gradient stops, such that the ripples go from fully opaque to fully transparent, effectively becoming gaps, while the opposite happens for the initial gaps, they go from fully transparent to fully opaque, thus becoming ripples. At any moment, the alpha of either of them is 1 minus the alpha of the other, so they complement each other. In this case, the animation is linear, the alpha changing at the same rate from start to finish.
    Ripple alpha animation, linear (live demo, only works in Firefox 53+).

    This is a linear animation, the alpha value --a being set to the progress f/NF. But we can change the timing function to something else, as explained in an earlier article I wrote on emulating CSS timing functions with JavaScript.

    For example, if we want an ease-in kind of timing function, we set the alpha value to easeIn(f/NF) instead of just f/NF, where we have that easeIn() is:

    function easeIn(k, e = 1.675) { return Math.pow(k, e)
    }

    The result when using an ease-in timing function can be seen in this Pen (working only in Firefox 53+). If you’re interested in how we got this function, it’s all explained in the previously linked article on timing functions.

    The exact same approach works for easeOut() or easeInOut():

    function easeOut(k, e = 1.675) { return 1 - Math.pow(1 - k, e)
    }; function easeInOut(k) { return .5*(Math.sin((k - .5)*Math.PI) + 1)
    }

    Since we’re using JavaScript anyway, we can make the whole thing interactive, so that the animation only happens on click/tap, for example.

    In order to do so, we add a request ID variable (rID), which is initially null, but then takes the value returned by requestAnimationFrame() in the update() function. This enables us to stop the animation with a stopAni() function whenever we want to:

     /* same as before */ let rID = null; function stopAni() { cancelAnimationFrame(rID); rID = null
    }; function update() { /* same as before */ if(!(f%NF)) { stopAni(); return } rID = requestAnimationFrame(update)
    };

    On click, we stop any animation that may be running, reverse the animation direction dir and call the update() function:

    addEventListener('click', e => { if(rID) stopAni(); dir *= -1; update()
    }, false);

    Since we start with the current frame index f being 0, we want to go in the positive direction, towards NF on the first click. And since we’re reversing the direction on every click, it results that the initial value for the direction must be -1 now so that it gets reversed to +1 on the first click.

    The result of all the above can be seen in this interactive Pen (working only in Firefox 53+).

    We could also use a different alpha variable for each stop, just like we did in the case of the rays:

    $m: repeating-conic-gradient(#000 .5*$pc, transparent 0% $pc) exclude, repeating-radial-gradient(closest-side, rgba(#000, var(--a0)), rgba(#000, var(--a1)) .5*$pr, rgba(#000, var(--a2)) 0, rgba(#000, var(--a3)) $pr);

    In the JavaScript, we have the ease-in and ease-out timing functions:

    const TFN = { 'ease-in': function(k, e = 1.675) { return Math.pow(k, e) }, 'ease-out': function(k, e = 1.675) { return 1 - Math.pow(1 - k, e) }
    };

    In the update() function, the only difference from the first animated demo is that we don’t change the value of just one CSS variable—we now have four to take care of: --a0, --a1, --a2, --a3. We do this within a loop, using the ease-in function for the ones at even indices and the ease-out function for the others. For the first two, the progress is given by f/NF, while for the last two, the progress is given by 1 - f/NF. Putting all of this into one formula, we have:

    (function update() { f += dir; for(var i = 0; i < 4; i++) { let j = ~~(i/2); document.body.style.setProperty( `--a${i}`, TFN[i%2 ? 'ease-out' : 'ease-in'](j + Math.pow(-1, j)*f/NF).toFixed(2) ) } if(!(f%NF)) dir *= -1; requestAnimationFrame(update)
    })();

    The result can be seen below:

    Animated gif. This time, the alpha of each and every stop (start and end of ripple, start and end of gap) is animated independently via its own CSS variable. The alphas at the start and end of the ripple both go from 1 to 0, but using different timing functions. The alphas at the start and end of the gap both go from 0 to 1, but, again, using different timing functions.
    Multiple ripple alpha animations (live demo, only works in Firefox 53+).

    Just like for conic gradients, we can also animate the stop position between the opaque and the transparent part of the masking radial gradient. To do so, we use a CSS variable --p for the progress of this stop position:

    $m: repeating-conic-gradient(#000 .5*$pc, transparent 0% $pc) exclude, repeating-radial-gradient(closest-side, #000, #000 calc(var(--p)*#{$pr}), transparent 0, transparent $pr);

    The JavaScript is almost identical to that for the first alpha animation, except we don’t update an alpha --a variable, but a stop progress --p variable and we use an ease-in-out kind of function:

    /* same as before */ function easeInOut(k) { return .5*(Math.sin((k - .5)*Math.PI) + 1)
    }; (function update() { f += dir; document.body.style.setProperty('--p', easeInOut(f/NF).toFixed(2)); /* same as before */
    })();
    Animated gif. The stop position between the ripple an the gap animates from 0 (when the ripple is basically reduced to nothing) to the whole percentage $pr allocated for a ripple and the gap following it (which basically means we don't have a gap anymore) and then back to 0 again.
    Alternating ripple size animation (live demo, only works in Firefox 53+).

    We can make the effect more interesting if we add a transparent strip before the opaque one and we also animate the progress of the stop position --p0 where we go from this transparent strip to the opaque one:

    $m: repeating-conic-gradient(#000 .5*$pc, transparent 0% $pc) exclude, repeating-radial-gradient(closest-side, transparent, transparent calc(var(--p0)*#{$pr}), #000, #000 calc(var(--p1)*#{$pr}), transparent 0, transparent $pr);

    In the JavaScript, we now need to animate two CSS variables: --p0 and --p1. We use an ease-in timing function for the first and an ease-out for the second one. We also don’t reverse the animation direction anymore:

    const NF = 120, TFN = { 'ease-in': function(k, e = 1.675) { return Math.pow(k, e) }, 'ease-out': function(k, e = 1.675) { return 1 - Math.pow(1 - k, e) } }; let f = 0; (function update() { f = (f + 1)%NF; for(var i = 0; i < 2; i++) document.body.style.setProperty(`--p${i}`, TFN[i ? 'ease-out' : 'ease-in'](f/NF); requestAnimationFrame(update)
    })();

    This gives us a pretty interesting result:

    Animated gif. We now have one extra transparent circular strip before the opaque and transparent ones we previously had. Initially, both the start and end stop positions of this first strip and the following opaque one are 0, so they're both reduced to nothing and the whole space is occupied by the last transparent strip. The end stop positions of both strips then animate from 0 to the whole percentage $pr allocated for one repetition of our radial gradient, but with different timing functions. The end stop position of the first opaque strip animates slowly at first and faster towards the end (ease-in), while the end stop position of the opaque strip animates faster at first and slower towards the end (ease-out). This makes the opaque strip in the middle grow from nothing at first as its end stop position increases faster than that of the first transparent strip (which determines the start stop position of the opaque strip), then shrink back to nothing as its end stop position ends up being equal to $pr, just like the end stop position of the first transparent strip. The whole cycle then repeats itself.
    Double ripple size animation (live demo, only works in Firefox 53+).

    The post 1 HTML Element + 5 CSS Properties = Magic! appeared first on CSS-Tricks.

    Displaying the Weather With Serverless and Colors

    I like to jog. Sometimes it’s cold out. Sometimes it’s cold out, but it looks like it isn’t. The sun is shining, the birds are chirping. Then you step outside in shorts and a t-shirt and realize you have roughly 2 minutes before exposure sets in.

    I decided to solve this first world problem using a lightbulb to display a certain color based on what the temperature outside is. It works better than I expected, and that’s saying something because usually nothing works out like I want it to.

    This was a fun project to build, and since it is essentially a hosted service running on a timer, it’s a perfect use case for Serverless.

    Now you might be thinking, “um, wouldn’t it be easier to just check the weather?” Well it would, but then I wouldn’t have an excuse to buy an expensive lightbulb or write an article with the word “Serverless.”

    So let’s look at how you can build your own Weather Bulb. The final code is not complicated, but it does have some interesting pieces that are worth noting. By the way, did I mention that it’s Serverless?

    Building the Weather Bulb

    The first thing you are going to need is the bulb. You can’t have a Weather Bulb sans bulb. Say the word “bulb” out loud about 10 times and you’ll notice what a bizarre word it is. Bulb, bulb, bulb, bulb — see? Weird.

    I am using the LIFX Mini Color. It’s not *too* expensive, but more importantly, it’s got an API that is wide open.

    The API has two methods of authentication. The first contains the word “OAuth” and I’m already sorry that you had to read that. Don’t worry, there is an easier way that doesn’t involve OAu…. that which won’t be named.

    The second way is to register an application with LIFX. You get back a key and all you have to do is pass that key with any HTTP request. That’s what I’m using for this demo.

    For instance, if we wanted to change the bulb color to blue, we can just pass color: blue to the /state endpoint.

    The API supports a few different color formats, including named colors (like red, blue), hex values, RBG, Kevlin, hue brightness and saturation. This is important because it factors into what proved to be the hardest part of this project: turning temperature into color.

    Representing Temperature With Color

    If you’ve ever watched a weather report, you’ll be familiar with the way that meteorology represents weather conditions with color on a map.

    Usually, this is done to visualize precipitation. You have probably seen that ominous green strip of storms bearing down on you on a weather map while you try to figure out if you should get in the bathtub because you’re in the path of a tornado. Or maybe that’s just all of us unlucky souls here in America’s Tornado Alley.

    Color is also used to represent temperature. This is precisely what I wanted to do with the bulb. The tough thing is that there doesn’t seem to be a standardized way to do this. Some maps show it as solid colors in bands. In this case blue might represent the band from 0℉ – 32℉.

    Others have it as a gradient scale which is more precise. This is what I was after for the Weather Bulb.

    My first stab at solving this was just to Google “temperature color scale” and other various iterations of that search term. I got back a lot of information about Kelvin.

    Kelvin is a representation of the temperature of a color. Literally. For any light source (light bulb, the sun, ect) the actual temperature of that source will affect the color of the light it emits. A fire burns a yellowish red color. The hotter that fire gets, the more it moves towards white. Hence the saying, “white hot”. So if someone ever says “red hot,” you can correct them in front of everyone because who doesn’t love a pedantic jerk?

    The LIFX bulb supports Kelvin, so you might think that this would work. After all, this is the Kelvin scale….

    The problem is that there is simply not enough color variation because these are not actual colors, but rather the tinge of color that a light is emitting based on it’s “temperature.” Here is the Kelvin color wheel that comes with the LIFX app.

    These colors are barely distinguishable from one another on the bulb. Not exactly what I was after.

    That leaves me with trying to convert the color to either Hex, RGB or some other format. This is tough because where do you begin? I spent an embarrassing amount of time adjust RGB scale values between blue for cold (0, 0, 255) and red for hot (255, 0, 0). It was about this time that it dawned on me that maybe HSL would be a better way to go here. Why? Because hue is a whole lot easier to understand.

    Hue

    Hue is a representation of color on a scale between 0 and 360. This is why we often see color represented on a wheel (360°). That’s a vast oversimplification, but unless you want me to start talking about wavelengths, let’s go with that definition.

    The hue color wheel looks like this….

    If we flatten it out, it’s easier to reason about.

    We’re ready to convert temperature to color. The first thing we need to do is figure out a set temperature range. I went with 0℉ to 100℉. We can’t work with infinite temperature color combinations. Numbers go on forever, colors do not. It can only get so hot before our bulb is just bright red all the time, and that’s 100℉. The same is true for cold.

    If light blue represents 0℉, I can start at about the 200 mark on the hue scale. Red will represent 100℉. You can see that red is at both extremes, so I can move either left OR right, depending on what colors I want to use to represent the temperature. It’s not the same as the colors they use in actual weather programs, but who cares? Obviously not me.

    I chose to go right because there is no pink on the left and pink is my favorite color. I also felt like pink represents warm a bit better than green. Green is rain and tornadoes.

    Now we can back into a hue based on temperature. Ready? Here we go.

    Let’s pretend it’s a brisk 50℉ outside.

    If 100℉ is the hottest we go (360) and 0℉ is the coldest (200), then we have a color scale of 160 points. To figure out where in that 160 point range we need to be, we can divide the current temperature by the upper bound of 100℉ which will give us the exact percentage we need to move in our range, or 50%. If we move 50% of the way into a 160 point range, that leaves us at 80. Since we are starting at 200, that gives us a hue of 280.

    That sounds complicated, but only because word problems in math SUCK. Here’s how the code looks when it’s all said and done…

    let hue = 200 + (160 * ( temperature / 100 ));

    OK! We’ve got a dynamic color scale based on hue, and wouldn’t you know it, we can just pass the hue to LIFX as simply as we pass a named color.

    Now we just need to find out what the current temperature is, back into a hue and do that every few minutes. Serverless, here we come!

    Serverless Timer Functions

    Serverless is all the rage. It’s like HTML5 used to be: it doesn’t matter what it is, it only matters that you know the word and are not afraid to use it in a blog post.

    For this example, we’ll use Azure Functions because there is support for timer triggers, and we can test those timer triggers locally before we deploy using VS Code. One of the things about Serverless that irritates me to no end is when I can’t debug it locally.

    Using the Azure Functions Core Tools and the Azure Functions Extension for VS Code, I can create a new Serverless project and select a Timer Trigger.

    Timer Triggers in Azure Functions are specified as Cron Expressions. Don’t worry, I didn’t know what that was either.

    Cron Expressions allow you to get very specific with interval definition. Cron breaks things down into second, minute, hour, day, month, year. So if you wanted to run something every second of every minute of every hour of every day of every year, your expression would look like this…

    * * * * * *

    If you wanted to run it every day at 10:15, it would look like this…

    * 15 10 * * *

    If you wanted to run it every 5 minutes (which is what Azure defaults to), you specify that by saying “when minutes is divisible by 5.”

    0 */5 * * * *

    For the purposes of this function, we set it to 2 minutes.

    I am using a 2 minute interval because that’s how often we can call the weather API for free 💰.

    Getting the Forecast From DarkSky

    DarkSky has a wonderful weather API that you can call up to 1,000 times per day for free. If there are 1,440 minutes in a day (and there are), that means we can call DarkSky every 1.44 minutes per day and stay in the free zone. I just rounded up to 2 minutes because temperature doesn’t change that fast.

    This is what our function looks like when we call the DarkSky API. All of my tokens, keys, latitude and longitude settings are in environment variables so they aren’t hardcoded. Those are set in the local.settings.json file. I used axios for my HTTP requests because it is a magical, magical package.

    const axios = require('axios'); module.exports = function (context, myTimer) { // build up the DarkSky endpoint let endpoint = `${process.env.DS_API}/${process.env.DS_SECRET}/${process.env.LAT}, ${process.env.LNG}`; // use axios to call DarkSky for weather axios .get(endpoint) .then(response => { let temp = Math.round(response.data.currently.temperature); // TODO: Set the color of the LIFX bulb }) .catch(err => { context.log(err.message); });
    };

    Now that I have the temperature, I need to call the LIFX API. And wouldn’t you know it, someone has already created an npm package to do this called lifx-http-api. This is why you love JavaScript.

    Setting the Bulb Hue

    After the weather result comes back, I need to use the LIFX API instance and call the setState method. This method returns a promise which means that we need to nest promises. Nesting promises can get out of hand and could land us right back in callback hell, which is what we’re trying to avoid with promises in the first place.

    Instead, we’ll handle the first promise and then return Promise.all which we can handle at another top-level then. This just prevents us from nesting then statements.

    Remember kids, promises are just socially acceptable callbacks.

    const axios = require('axios');
    const LIFX = require('lifx-http-api'); let client = new LIFX({ bearerToken: process.env.LIFX_TOKEN
    }); module.exports = function (context, myTimer) { // build up the DarkSky endpoint let endpoint = <code>${process.env.DS_API}/${process.env.DS_SECRET}/${ process.env.LAT },${process.env.LNG}<code>; // use axios to call DarkSky for weather axios .get(endpoint) .then(response => { let temp = Math.round(response.data.currently.temperature); // make sure the temp isn't above 100 because that's as high as we can go temp = temp < 100 ? temp : 100; // determine the hue let hue = 200 + (160 * (temp / 100)); // return Promise.all so we can resolve at the top level return Promise.all([ data, client.setState('all', { color: <code>hue:${hue}<code> }) ]); }) .then(result => { // result[0] contains the darksky result // result[1] contains the LIFX result context.log(result[1]); }) .catch(err => { context.log(err.message); });
    };

    Now we can run this thing locally and watch our timer do it’s thang.

    That’s it! Let’s deploy it.

    Deploying Weather Bulb

    I can create a new Functions project from the VS Code extension.

    I can right-click that to “Open in portal” where I can define a deployment source so it sucks my code in from Github and deploys it. This is ideal because now whenever I push a change to Github, my application automatically gets redeployed.

    All Hail the Weather Bulb

    Now just sit back and behold the soft glow of the Weather Bulb! Why look at the actual temperature when you can look at this beautiful shade of hot pink instead?

    Can you guess what the temperature is based on what you know from this article? The person who leaves a comment and gets the closest will get a free LIFX lightbulb from me (because I ❤️ all of you), or the cost of the bulb if you are outside the U.S. (~$40).

    You can grab all of the code for this project from Github.

    The post Displaying the Weather With Serverless and Colors appeared first on CSS-Tricks.

    Simple Swipe With Vanilla JavaScript

    I used to think implementing swipe gestures had to be very difficult, but I have recently found myself in a situation where I had to do it and discovered the reality is nowhere near as gloomy as I had imagined.

    This article is going to take you, step by step, through the implementation with the least amount of code I could come up with. So, let’s jump right into it!

    The HTML Structure

    We start off with a .container that has a bunch of images inside:

    <div class='container'> <img src='img1.jpg' alt='image description'/> ...
    </div>

    Basic Styles

    We use display: flex to make sure images go alongside each other with no spaces in between. align-items: center middle aligns them vertically. We make both the images and the container take the width of the container’s parent (the body in our case).

    .container { display: flex; align-items: center; width: 100%; img { min-width: 100%; /* needed so Firefox doesn't make img shrink to fit */ width: 100%; /* can't take this out either as it breaks Chrome */ }
    }

    The fact that both the .container and its child images have the same width makes these images spill out on the right side (as highlighted by the red outline) creating a horizontal scrollbar, but this is precisely what we want:

    Screenshot showing this very basic layout with the container and the images having the same width as the body and the images spilling out of the container to the right, creating a horizontal scrollbar on the body.
    The initial layout (see live demo).

    Given that not all the images have the same dimensions and aspect ratio, we have a bit of white space above and below some of them. So, we’re going to trim that by giving the .container an explicit height that should pretty much work for the average aspect ratio of these images and setting overflow-y to hidden:

    .container { /* same as before */ overflow-y: hidden; height: 50vw; max-height: 100vh;
    }

    The result can be seen below, with all the images trimmed to the same height and no empty spaces anymore:

    Screenshot showing the result after limiting the container's height and trimming everything that doesn't fit vertically with overflow-y. This means we now have a horizontal scrollbar on the container itself.
    The result after images are trimmed by overflow-y on the .container (see live demo).

    Alright, but now we have a horizontal scrollbar on the .container itself. Well, that’s actually a good thing for the no JavaScript case.

    Otherwise, we create a CSS variable --n for the number of images and we use this to make .container wide enough to hold all its image children that still have the same width as its parent (the body in this case):

    .container { --n: 1; width: 100%; width: calc(var(--n)*100%); img { min-width: 100%; width: 100%; width: calc(100%/var(--n)); }
    }

    Note that we keep the previous width declarations as fallbacks. The calc() values won’t change a thing until we set --n from the JavaScript after getting our .container and the number of child images it holds:

    const _C = document.querySelector('.container'), N = _C.children.length; _C.style.setProperty('--n', N)

    Now our .container has expanded to fit all the images inside:

    Layout with expanded container (live demo).

    Switching Images

    Next, we get rid of the horizontal scrollbar by setting overflow-x: hidden on our container’s parent (the body in our case) and we create another CSS variable that holds the index of the currently selected image (--i). We use this to properly position the .container with respect to the viewport via a translation (remember that % values inside translate() functions are relative to the dimensions of the element we have set this transform on):

    body { overflow-x: hidden } .container { /* same styles as before */ transform: translate(calc(var(--i, 0)/var(--n)*-100%));
    }

    Changing the --i to a different integer value greater or equal to zero, but smaller than --n, brings another image into view, as illustrated by the interactive demo below (where the value of --i is controlled by a range input):

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

    Alright, but we don’t want to use a slider to do this.

    The basic idea is that we’re going to detect the direction of the motion between the "touchstart" (or "mousedown") event and the "touchend" (or "mouseup") and then update --i accordingly to move the container such that the next image (if there is one) in the desired direction moves into the viewport.

    function lock(e) {}; function move(e) {}; _C.addEventListener('mousedown', lock, false);
    _C.addEventListener('touchstart', lock, false); _C.addEventListener('mouseup', move, false);
    _C.addEventListener('touchend', move, false);

    Note that this will only work for the mouse if we set pointer-events: none on the images.

    .container { /* same styles as before */ img { /* same styles as before */ pointer-events: none; }
    }

    Also, Edge needs to have touch events enabled from about:flags as this option is off by default:

    Screenshot showing the 'Enable touch events' option being set to 'Only when a touchscreen is detected' in about:flags in Edge.
    Enabling touch events in Edge.

    Before we populate the lock() and move() functions, we unify the touch and click cases:

    function unify(e) { return e.changedTouches ? e.changedTouches[0] : e };

    Locking on "touchstart" (or "mousedown") means getting and storing the x coordinate into an initial coordinate variable x0:

    let x0 = null; function lock(e) { x0 = unify(e).clientX };

    In order to see how to move our .container (or if we even do that because we don’t want to move further when we have reached the end), we check if we have performed the lock() action, and if we have, we read the current x coordinate, compute the difference between it and x0 and resolve what to do out of its sign and the current index:

    let i = 0; function move(e) { if(x0 || x0 === 0) { let dx = unify(e).clientX - x0, s = Math.sign(dx); if((i > 0 || s < 0) && (i < N - 1 || s > 0)) _C.style.setProperty('--i', i -= s); x0 = null }
    };

    The result on dragging left/ right can be seen below:

    Animated gif. Shows how we switch to the next image by dragging left/ right if there is a next image in the direction we want to go. Attempts to move to the right on the first image or left on the last one do nothing as we have no other image before or after, respectively.
    Switching between images on swipe (live demo). Attempts to move to the right on the first image or left on the last one do nothing as we have no other image before or after, respectively.

    The above is the expected result and the result we get in Chrome for a little bit of drag and Firefox. However, Edge navigates backward and forward when we drag left or right, which is something that Chrome also does on a bit more drag.

    Animated gif. Shows how Edge navigates the pageview backward and forward when we swipe left or right.
    Edge navigating the pageview backward or forward on left or right swipe.

    In order to override this, we need to add a "touchmove" event listener:

    _C.addEventListener('touchmove', e => {e.preventDefault()}, false)

    Alright, we now have something functional in all browsers, but it doesn’t look like what we’re really after… yet!

    Smooth Motion

    The easiest way to move towards getting what we want is by adding a transition:

    .container { /* same styles as before */ transition: transform .5s ease-out;
    }

    And here it is, a very basic swipe effect in about 25 lines of JavaScript and about 25 lines of CSS:

    Working swipe effect (live demo).

    Sadly, there’s an Edge bug that makes any transition to a CSS variable-depending calc() translation fail. Ugh, I guess we have to forget about Edge for now.

    Refining the Whole Thing

    With all the cool swipe effects out there, what we have so far doesn’t quite cut it, so let’s see what improvements can be made.

    Better Visual Cues While Dragging

    First off, nothing happens while we drag, all the action follows the "touchend" (or "mouseup") event. So, while we drag, we have no indication of what’s going to happen next. Is there a next image to switch to in the desired direction? Or have we reached the end of the line and nothing will happen?

    To take care of that, we tweak the translation amount a bit by adding a CSS variable --tx that’s originally 0px:

    transform: translate(calc(var(--i, 0)/var(--n)*-100% + var(--tx, 0px)))

    We use two more event listeners: one for "touchmove" and another for "mousemove". Note that we were already preventing backward and forward navigation in Chrome using the "touchmove" listener:

    function drag(e) { e.preventDefault() }; _C.addEventListener('mousemove', drag, false);
    _C.addEventListener('touchmove', drag, false);

    Now let’s populate the drag() function! If we have performed the lock() action, we read the current x coordinate, compute the difference dx between this coordinate and the initial one x0 and set --tx to this value (which is a pixel value).

    function drag(e) { e.preventDefault(); if(x0 || x0 === 0) _C.style.setProperty('--tx', `${Math.round(unify(e).clientX - x0)}px`)
    };

    We also need to make sure to reset --tx to 0px at the end and remove the transition for the duration of the drag. In order to make this easier, we move the transition declaration on a .smooth class:

    .smooth { transition: transform .5s ease-out; }

    In the lock() function, we remove this class from the .container (we’ll add it again at the end on "touchend" and "mouseup") and also set a locked boolean variable, so we don’t have to keep performing the x0 || x0 === 0 check. We then use the locked variable for the checks instead:

    let locked = false; function lock(e) { x0 = unify(e).clientX; _C.classList.toggle('smooth', !(locked = true))
    }; function drag(e) { e.preventDefault(); if(locked) { /* same as before */ }
    }; function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx); if((i > 0 || s < 0) && (i < N - 1 || s > 0)) _C.style.setProperty('--i', i -= s); _C.style.setProperty('--tx', '0px'); _C.classList.toggle('smooth', !(locked = false)); x0 = null }
    };

    The result can be seen below. While we’re still dragging, we now have a visual indication of what’s going to happen next:

    Swipe with visual cues while dragging (live demo).

    Fix the transition-duration

    At this point, we’re always using the same transition-duration no matter how much of an image’s width we still have to translate after the drag. We can fix that in a pretty straightforward manner by introducing a factor f, which we also set as a CSS variable to help us compute the actual animation duration:

    .smooth { transition: transform calc(var(--f, 1)*.5s) ease-out; }

    In the JavaScript, we get an image’s width (updated on "resize") and compute for what fraction of this we have dragged horizontally:

    let w; function size() { w = window.innerWidth }; function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx), f = +(s*dx/w).toFixed(2); if((i > 0 || s < 0) && (i < N - 1 || s > 0)) { _C.style.setProperty('--i', i -= s); f = 1 - f } _C.style.setProperty('--tx', '0px'); _C.style.setProperty('--f', f); _C.classList.toggle('smooth', !(locked = false)); x0 = null }
    }; size(); addEventListener('resize', size, false);

    This now gives us a better result.

    Go back if insufficient drag

    Let’s say that we don’t want to move on to the next image if we only drag a little bit below a certain threshold. Because now, a 1px difference during the drag means we advance to the next image and that feels a bit unnatural.

    To fix this, we set a threshold at let’s say 20% of an image’s width:

    function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx), f = +(s*dx/w).toFixed(2); if((i > 0 || s < 0) && (i < N - 1 || s > 0) && f > .2) { /* same as before */ } /* same as before */ }
    };

    The result can be seen below:

    We only advance to the next image if we drag enough (live demo).

    Maybe Add a Bounce?

    This is something that I’m not sure was a good idea, but I was itching to try anyway: change the timing function so that we introduce a bounce. After a bit of dragging the handles on cubic-bezier.com, I came up with a result that seemed promising:

    Animated gif. Shows the graphical representation of the cubic Bézier curve, with start point at (0, 0), end point at (1, 1) and control points at (1, 1.59) and (.61, .74), the progression on the [0, 1] interval being a function of time in the [0, 1] interval. Also illustrates how the transition function given by this cubic Bézier curve looks when applied on a translation compared to a plain ease-out.
    What our chosen cubic Bézier timing function looks like compared to a plain ease-out.
    transition: transform calc(var(--f)*.5s) cubic-bezier(1, 1.59, .61, .74);
    Using a custom CSS timing function to introduce a bounce (live demo).

    How About the JavaScript Way, Then?

    We could achieve a better degree of control over more natural-feeling and more complex bounces by taking the JavaScript route for the transition. This would also give us Edge support.

    We start by getting rid of the transition and the --tx and --f CSS variables. This reduces our transform to what it was initially:

    transform: translate(calc(var(--i, 0)/var(--n)*-100%));

    The above code also means --i won’t necessarily be an integer anymore. While it remains an integer while we have a single image fully into view, that’s not the case anymore while we drag or during the motion after triggering the "touchend" or "mouseup" events.

    Annotated screenshots illustrating what images we see for --i: 0 (1st image), --i: 1 (2nd image), --i: .5 (half of 1st and half of 2nd) and --i: .75 (a quarter of 1st and three quarters of 2nd).
    For example, while we have the first image fully in view, --i is 0. While we have the second one fully in view, --i is 1. When we’re midway between the first and the second, --i is .5. When we have a quarter of the first one and three quarters of the second one in view, --i is .75.

    We then update the JavaScript to replace the code parts where we were updating these CSS variables. First, we take care of the lock() function, where we ditch toggling the .smooth class and of the drag() function, where we replace updating the --tx variable we’ve ditched with updating --i, which, as mentioned before, doesn’t need to be an integer anymore:

    function lock(e) { x0 = unify(e).clientX; locked = true
    }; function drag(e) { e.preventDefault(); if(locked) { let dx = unify(e).clientX - x0, f = +(dx/w).toFixed(2); _C.style.setProperty('--i', i - f) }
    };

    Before we also update the move() function, we introduce two new variables, ini and fin. These represent the initial value we set --i to at the beginning of the animation and the final value we set the same variable to at the end of the animation. We also create an animation function ani():

    let ini, fin; function ani() {}; function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx), f = +(s*dx/w).toFixed(2); ini = i - s*f; if((i > 0 || s < 0) && (i < N - 1 || s > 0) && f > .2) { i -= s; f = 1 - f } fin = i; ani(); x0 = null; locked = false; }
    };

    This is not too different from the code we had before. What has changed is that we’re not setting any CSS variables in this function anymore but instead set the ini and the fin JavaScript variables and call the animation ani() function.

    ini is the initial value we set --i to at the beginning of the animation that the "touchend"/ "mouseup" event triggers. This is given by the current position we have when one of these two events fires.

    fin is the final value we set --i to at the end of the same animation. This is always an integer value because we always end with one image fully into sight, so fin and --i are the index of that image. This is the next image in the desired direction if we dragged enough (f > .2) and if there is a next image in the desired direction ((i > 0 || s < 0) && (i < N - 1 || s > 0)). In this case, we also update the JavaScript variable storing the current image index (i) and the relative distance to it (f). Otherwise, it’s the same image, so i and f don’t need to get updated.

    Now, let’s move on to the ani() function. We start with a simplified linear version that leaves out a change of direction.

    const NF = 30; let rID = null; function stopAni() { cancelAnimationFrame(rID); rID = null
    }; function ani(cf = 0) { _C.style.setProperty('--i', ini + (fin - ini)*cf/NF); if(cf === NF) { stopAni(); return } rID = requestAnimationFrame(ani.bind(this, ++cf))
    };

    The main idea here is that the transition between the initial value ini and the final one fin happens over a total number of frames NF. Every time we call the ani() function, we compute the progress as the ratio between the current frame index cf and the total number of frames NF. This is always a number between 0 and 1 (or you can take it as a percentage, going from 0% to 100%). We then use this progress value to get the current value of --i and set it in the style attribute of our container _C. If we got to the final state (the current frame index cf equals the total number of frames NF, we exit the animation loop). Otherwise, we just increment the current frame index cf and call ani() again.

    At this point, we have a working demo with a linear JavaScript transition:

    Version with linear JavaScript transition (live demo).

    However, this has the problem we initially had in the CSS case: no matter the distance, we have to have to smoothly translate our element over on release ("touchend" / "mouseup") and the duration is always the same because we always animate over the same number of frames NF.

    Let’s fix that!

    In order to do so, we introduce another variable anf where we store the actual number of frames we use and whose value we compute in the move() function, before calling the animation function ani():

    function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx), f = +(s*dx/w).toFixed(2); /* same as before */ anf = Math.round(f*NF); ani(); /* same as before */ }
    };

    We also need to replace NF with anf in the animation function ani():

    function ani(cf = 0) { _C.style.setProperty('--i', ini + (fin - ini)*cf/anf); if(cf === anf) { /* same as before */ } /* same as before */
    };

    With this, we have fixed the timing issue!

    Version with linear JavaScript transition at constant speed (live demo).

    Alright, but a linear timing function isn’t too exciting.

    We could try the JavaScript equivalents of CSS timing functions such as ease-in, ease-out or ease-in-out and see how they compare. I’ve already explained in a lot of detail how to get these in the previously linked article, so I’m not going to go through that again and just drop the object with all of them into the code:

    const TFN = { 'linear': function(k) { return k }, 'ease-in': function(k, e = 1.675) { return Math.pow(k, e) }, 'ease-out': function(k, e = 1.675) { return 1 - Math.pow(1 - k, e) }, 'ease-in-out': function(k) { return .5*(Math.sin((k - .5)*Math.PI) + 1) }
    };

    The k value is the progress, which is the ratio between the current frame index cf and the actual number of frames the transition happens over anf. This means we modify the ani() function a bit if we want to use the ease-out option for example:

    function ani(cf = 0) { _C.style.setProperty('--i', ini + (fin - ini)*TFN['ease-out'](cf/anf)); /* same as before */
    };
    Version with ease-out JavaScript transition (live demo).

    We could also make things more interesting by using the kind of bouncing timing function that CSS cannot give us. For example, something like the one illustrated by the demo below (click to trigger a transition):

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

    The graphic for this would be somewhat similar to that of the easeOutBounce timing function from easings.net.

    Animated gif. Shows the graph of the bouncing timing function. This function has a slow, then accelerated increase from the initial value to its final value. Once it reaches the final value, it quickly bounces back by about a quarter of the distance between the final and initial value, then going back to the final value, again bouncing back a bit. In total, it bounces three times. On the right side, we have an animation of how the function value (the ordinate on the graph) changes in time (as we progress along the abscissa).
    Graphical representation of the timing function.

    The process for getting this kind of timing function is similar to that for getting the JavaScript version of the CSS ease-in-out (again, described in the previously linked article on emulating CSS timing functions with JavaScript).

    We start with the cosine function on the [0, 90°] interval (or [0, π/2] in radians) for no bounce, [0, 270°] ([0, 3·π/2]) for 1 bounce, [0, 450°] ([0, 5·π/2]) for 2 bounces and so on… in general it’s the [0, (n + ½)·180°] interval ([0, (n + ½)·π]) for n bounces.

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

    The input of this cos(k) function is in the [0, 450°] interval, while its output is in the [-1, 1] interval. But what we want is a function whose domain is the [0, 1] interval and whose codomain is also the [0, 1] interval.

    We can restrict the codomain to the [0, 1] interval by only taking the absolute value |cos(k)|:

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

    While we got the interval we wanted for the codomain, we want the value of this function at 0 to be 0 and its value at the other end of the interval to be 1. Currently, it’s the other way around, but we can fix this if we change our function to 1 - |cos(k)|:

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

    Now we can move on to restricting the domain from the [0, (n + ½)·180°] interval to the [0, 1] interval. In order to do this, we change our function to be 1 - |cos(k·(n + ½)·180°)|:

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

    This gives us both the desired domain and codomain, but we still have some problems.

    First of all, all our bounces have the same height, but we want their height to decrease as k increases from 0 to 1. Our fix in this case is to multiply the cosine with 1 - k (or with a power of 1 - k for a non-linear decrease in amplitude). The interactive demo below shows how this amplitude changes for various exponents a and how this influences the function we have so far:

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

    Secondly, all the bounces take the same amount of time, even though their amplitudes keep decreasing. The first idea here is to use a power of k inside the cosine function instead of just k. This manages to make things weird as the cosine doesn’t hit 0 at equal intervals anymore, meaning we don’t always get that f(1) = 1 anymore which is what we’d always need from a timing function we’re actually going to use. However, for something like a = 2.75, n = 3 and b = 1.5, we get a result that looks satisfying, so we’ll leave it at that, even though it could be tweaked for better control:

    Screenshot of the previously linked demo showing the graphical result of the a = 2.75, n = 3 and b = 1.5 setup: a slow, then fast increase from 0 (for f(0)) to 1, bouncing back down less than half the way after reaching 1, going back up and then having another even smaller bounce before finishing at 1, where we always want to finish for f(1).
    The timing function we want to try.

    This is the function we try out in the JavaScript if we want some bouncing to happen.

    const TFN = { /* the other function we had before */ 'bounce-out': function(k, n = 3, a = 2.75, b = 1.5) { return 1 - Math.pow(1 - k, a)*Math.abs(Math.cos(Math.pow(k, b)*(n + .5)*Math.PI)) }
    };

    Hmm, seems a bit too extreme in practice:

    Version with a bouncing JavaScript transition (live demo).

    Maybe we could make n depend on the amount of translation we still need to perform from the moment of the release. We make it into a variable which we then set in the move() function before calling the animation function ani():

    const TFN = { /* the other function we had before */ 'bounce-out': function(k, a = 2.75, b = 1.5) { return 1 - Math.pow(1 - k, a)*Math.abs(Math.cos(Math.pow(k, b)*(n + .5)*Math.PI)) }
    }; var n; function move(e) { if(locked) { let dx = unify(e).clientX - x0, s = Math.sign(dx), f = +(s*dx/w).toFixed(2); /* same as before */ n = 2 + Math.round(f) ani(); /* same as before */ }
    };

    This gives us our final result:

    Version with the final bouncing JavaScript transition (live demo).

    There’s definitely still room for improvement, but I don’t have a feel for what makes a good animation, so I’ll just leave it at that. As it is, this is now functional cross-browser (without have any of the Edge issues that the version using a CSS transition has) and pretty flexible.

    The post Simple Swipe With Vanilla JavaScript appeared first on CSS-Tricks.

    Keep Pixelated Images Pixelated as They Scale

    This is a little reminder that there is a CSS property for helping control what happens to images as they scale up: image-rendering.

    We’re quite used to the idea that scaling an image larger than its natural size (upscaling) causes it to be blurry. As awful as that is, it’s the browser doing the best it can to algorithmically smooth out an image over more pixels than it has data. But let’s say you’d really rather not it do that. Say the image is already pixel-y (pixel art), or you prefer the look of a pixelated upscaling.

    You can do it!

    img { image-rendering: pixelated; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges;
    }

    It’s a bit awkward in that the spec offers three values: auto, pixelated, and crisp-edges. Both pixelated and crisp-edges, for pixel art, appear to do the same thing to me, although the spec talks about them slightly differently (pixelated recommends the “nearest neighbor” or similar algorithm while crisp-edges isn’t as specific).

    Adding to the awkwardness, Chrome only supports pixelated and Firefox only supports crisp-edges, and for the deepest browser support, you gotta prefix it to -moz-crisp-edges. Fortunately, you can smash them all together and it seems fine.

    Here’s an example with and without, using an image from James T. I found on Tumblr:

    See the Pen pixelated images by Chris Coyier (@chriscoyier) on CodePen.

    The post Keep Pixelated Images Pixelated as They Scale appeared first on CSS-Tricks.

    Methods, Computed, and Watchers in Vue.js

    One of the reasons I love working with Vue is because of how useful methods, computed, and watchers are, and the legibility of their distinction. Until understanding all three, it’s difficult to leverage the functionality of Vue to its full potential. Still, the majority of people I see confused about this framework tend to also be confused about the differences here, so let’s dig in.

    In case you need a quick answer and don’t have time to read through the entire article, here’s a small TL;DR:

    • Methods: These are exactly what they sound like they might be (yay, naming!). They’re functions that hang off of an object—typically the Vue instance itself or a Vue component.
    • Computed: These properties may at first look like they’d be used like a method, but are not. In Vue, we use data to track changes to a particular property that we’d like to be reactive. Computed properties allow us to define a property that is used the same way as data, but can also have some custom logic that is cached based on its dependencies. You can consider computed properties another view into your data.
    • Watchers: These are allowing you a peek into the reactivity system. We’re offered some hooks with which to observe any properties that are stored by Vue. If we want to add a bit of functionality each time something changes, or respond to a particular change, we could watch a property and apply some logic. This means that the name of the watcher has to match what we’re trying to observe.

    If any of this sounds confusing, don’t worry! We’ll dive in further below and hopefully address any confusion. If you’re familiar with vanilla JavaScript already, methods may be pretty obvious to you, aside from one or two caveats. It might then behoove you (I love that phrase) to skip to the Computed and Watchers sections.

    Methods

    Methods are likely something you’re going to use a lot while working with Vue. They’re aptly named as, in essence, we’re hanging a function off of an object. They’re incredibly useful for connecting functionality to directives for events, or even just creating a small bit of logic to be reused like any other function. You can call a method within another method, for example. You can also call a method inside a lifecycle hook. They’re very versatile.

    Here’s a simple demo to demonstrate:

    See the Pen Slim example of methods by Sarah Drasner (@sdras) on CodePen.

    <code class="language-css"><div id="app"> <button @click="tryme">Try Me</button> <p>{{ message }}</p>
    </div>
    new Vue({ el: '#app', data() { return { message: null } }, methods: { tryme() { this.message = Date() } }
    })

    We could have also executed the logic in the directive itself like <button @click="message = Date()">Try Me</button>, which works very well for this small example. However, as the complexity of our application grows, it’s more common to do as we see above to break it out to keep it legible. There’s also a limit to the logic that Vue will allow you to express in a directive—for instance, expressions are allowed but statements are not.

    You may notice that we’re be able to access this method within that component or Vue instance, and we can call any piece of our data here, in this case, this.message. You don’t have to call a method like you’d call a function within a directive. For example, @click=”methodName()” is unnecessary. You can reference it with @click=”methodName”, unless you need to pass a parameter, such as @click=”methodName(param)”.

    Using directives to call methods is also nice because we have some existing modifiers. One such example that’s very useful is .prevent, which will keep a submit event from reloading the page, used like this:

    <form v-on:submit.prevent="onSubmit"></form>

    There are many more, here are just a few.

    Computed

    Computed properties are very valuable for manipulating data that already exists. Anytime you’re building something where you need to sort through a large group of data and you don’t want to rerun those calculations on every keystroke, think about using a computed value.

    Some good candidates include, but are not limited to:

    • Updating a large amount of information while a user is typing, such as filtering a list
    • Gathering information from your Vuex store
    • Form validation
    • Data visualizations that change depending on what the user needs to see

    Computed properties are a vital part of Vue to understand. They are calculations that will be cached based on their dependencies and will only update when needed. They’re extremely performant when used well and extraordinarily useful. There are many large libraries that handle this kind of logic that you can now eliminate with only a few lines of code.

    Computed properties aren’t used like methods, though at first, they might look similar- you’re stating some logic in a function and returning- but the name of that function becomes a property that you’d then use in your application like data.

    If we needed to filter this big list of names of heroes based on what the user was typing, here’s how we would do it. We’re keeping this really simple so you can get the base concepts down. Originally our list would output in our template using names, which we store in data:

    new Vue({ el: '#app', data() { return { names: [ 'Evan You', 'John Lindquist', 'Jen Looper', 'Miriam Suzanne', ... ] } }
    })
    <div id="app"> <h1>Heroes</h1> <ul> <li v-for="name in names"> {{ name }} </li> </ul>
    </div>

    Now let’s create a filter for those names. We’ll start by creating an input with v-model that will originally be an empty string, but we’ll eventually use to match and filter through our list. We’ll call this property findName and you can see it referenced both on the input and in the data.

    <label for="filtername">Find your hero:</label>
    <input v-model="findName" id="filtername" type="text" />
    data() { return { findName: '', names: [ 'Evan You', 'John Lindquist', ... ] }
    }

    Now, we can create the computed property that will filter all of the names based on what the user has typed into the input, so anything in our findName property. You’ll note that I’m using regex here to make sure that mismatched capitalization doesn’t matter, as users will typically not capitalize as they type.

    computed: { filteredNames() { let filter = new RegExp(this.findName, 'i') return this.names.filter(el => el.match(filter)) }
    }

    And now we’ll update what we’re using in the template to output from this:

    <ul> <li v-for="name in names"> {{ name }} </li>
    </ul>

    …to this:

    <ul> <li v-for="name in filteredNames"> {{ name }} </li>
    </ul>

    And it filters for us on every keystroke! We only had to add a couple of lines of code to make this work, and didn’t have to load any additional libraries.

    See the Pen Filter a list with Computed- end by Sarah Drasner (@sdras) on CodePen.

    I can’t tell you how much time I save by using them. If you’re using Vue and haven’t explored them yet, please do, you’ll thank yourself.

    Watchers

    Vue has nice abstractions, and anyone who has been a programmer for a while will usually tell you that abstractions can be a pain because you’ll eventually get to a use case they can’t solve. However, this situation is accounted for, because Vue grants us some deeper access to into the reactivity system, which we can leverage as hooks to observe anything that’s changing. This can be incredibly useful because, as application developers, most of what we’re responsible for are things that change.

    Watchers also allow us to write much more declarative code. You’re no longer tracking everything yourself. Vue is already doing it under the hood, so you can also have access to changes made to any properties it’s tracking, in data, computed, or props, for example.

    Watchers are incredibly good for executing logic that applies to something else when a change on a property occurs (I first heard this way of putting it from Chris Fritz, but he says he might have also heard it from someone else ☺️). This isn’t a hard rule- you can absolutely use watchers for logic that refers to the property itself, but it’s a nice way of looking at how watchers are immediately different from computed properties, where the change will be in reference to the property we intend to use.

    Let’s run through the most simple example possible so you get a taste of what’s happening here.

    new Vue({ el: '#app', data() { return { counter: 0 } }, watch: { counter() { console.log('The counter has changed!') } }
    })

    As you can see in the code above, we’re storing counter in data, and by using the name of the property as the function name, we’re able to watch it. When we reference that counter in watch, we can observe any change to that property.

    Transitioning State With Watchers

    If the state is similar enough, you can even simply transition the state with watchers. Here’s an example I built from scratch of a chart with Vue. As the data changes, the watchers will update it and simply transition between them.

    SVG is also good for a task like this because it’s built with math.

    See the Pen Chart made with Vue, Transitioning State by Sarah Drasner (@sdras) on CodePen.

    watch: { selected: function(newValue, oldValue) { var tweenedData = {} var update = function () { let obj = Object.values(tweenedData); obj.pop(); this.targetVal = obj; } var tweenSourceData = { onUpdate: update, onUpdateScope: this } for (let i = 0; i < oldValue.length; i++) { let key = i.toString() tweenedData[key] = oldValue[i] tweenSourceData[key] = newValue[i] } TweenMax.to(tweenedData, 1, tweenSourceData) }
    }

    What happened here?

    • First we created a dummy object that will get updated by our animation library.
    • Then we have an update function that is invoked on each tween step. We use this to push the data.
    • Then we create an object to hold the source data to be tweened and the function pointer for update events.
    • We create a for loop, and turn the current index into a string
    • Then we can tween over the our target dummy object, but we’ll only do this for the specific key

    We could also use animation in watchers to create something like this time difference dial. I travel a bit and all my coworkers are in different areas, so I wanted a way to track what local time we were all in, as well as some signification of the change from daytime/nighttime as well.

    See the Pen Vue Time Comparison by Sarah Drasner (@sdras) on CodePen.

    Here we’re watching the checked property, and we’ll fire different methods that contain timeline animations that change the hue and saturation and some other elements based on the relative association to the current time. As mentioned earlier- the change occurs on the dropdown, but what we’re executing is logic that’s applied elsewhere.

    watch: { checked() { let period = this.timeVal.slice(-2), hr = this.timeVal.slice(0, this.timeVal.indexOf(':')); const dayhr = 12, rpos = 115, rneg = -118; if ((period === 'AM' && hr != 12) || (period === 'PM' && hr == 12)) { this.spin(`${rneg - (rneg / dayhr) * hr}`) this.animTime(1 - hr / dayhr, period) } else { this.spin(`${(rpos / dayhr) * hr}`) this.animTime(hr / dayhr, period) } }
    },

    There are also a number of other interesting things about watchers, for instance: we’re given access to both the new and old versions of the property as parameters, we can specify deep if we’d like to watch a nested object. For more detailed information, there’s a lot of good information in the guide.

    You can see how watchers can be incredibly useful for anything that’s updating—be it form inputs, asynchronous updates, or animations. If you’re curious how reactivity in Vue works, this part of the guide is really helpful. If you’d like to know more about reactivity in general, I really enjoyed Andre Staltz’ post and the Reactivity section of Mike Bostock’s A Better Way to Code.

    Wrapping Up

    I hope this was a helpful breakdown on how to use each, and speeds up your application development process by using Vue efficiently. There’s a stat out there that we spend 70% of our time as programmers reading code and 30% writing it. Personally, I love that, as a maintainer, I can look at a codebase I’ve never seen before and know immediately what the author has intended by the distinction made from methods, computed, and watchers.

    The post Methods, Computed, and Watchers in Vue.js appeared first on CSS-Tricks.

    A Quick Way to Remember the Difference Between `justify-content` and `align-items`

    I was talking with a pal the other day and moaning about flexbox for the millionth time because I had momentarily forgotten the difference between the justify-content and align-items properties.

    “How do I center an element horizontally with flex again?” I wondered. Well, that was when she gave me what I think is the best shorthand way of remembering how the two work together.

    She said that justify-content positions elements across the horizontal axis because the word itself is longer than align-items. At first I thought this was a really silly idea but now this is how I remember it. I even used it five minutes ago when I needed to make these two quick demos:

    See the Pen justify-content: center by Robin Rendle (@robinrendle) on CodePen.

    See the Pen align-items: center by Robin Rendle (@robinrendle) on CodePen.

    So, to summarize:

    • justify-content: longer word: horizontal alignment
    • align-items: shorter word: vertical alignment

    This had me thinking if there are there any other mnemonic devices or ways that to remember complex things in CSS? Are there any other tricks you’d recommend? It sort of reminds me of the way kids are taught to remember the names of planets with things like, “My Very Educated Mother Just Showed Us Nine” where the first letter in each word represents the first letter of each planet: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune.

    The post A Quick Way to Remember the Difference Between `justify-content` and `align-items` appeared first on CSS-Tricks.

    Solved With CSS! Colorizing SVG Backgrounds

    CSS is getting increasingly powerful, and with features like CSS grid and custom properties (also known as CSS variables), we’re seeing some really creative solutions emerging. The possibilities are still being explored on what CSS can do to make writing UI’s simpler, and that’s exciting!

    One of those is now one of my favorite CSS features: filters. Let’s look at how we can use filters to solve a problem you may have encountered when working with SVG as a background image on an element.

    CSS Filters

    First, let’s start by with an overview of filters. They include the following functions:

    • blur()
    • brightness()
    • contrast()
    • drop-shadow()
    • grayscale()
    • hue-rotate()
    • invert()
    • opacity()
    • saturate()
    • sepia()

    These effects can also be achieved with SVG filters or WebGL shaders, but CSS filters are the easiest way to implement basic transformations in the most browser-efficient manner. Because they are shortcuts of SVG filter effects, you can also use filter: url() and specify a filter effect ID onto any element. If you want to play around with custom filters, I recommend checking out cssfilters.co.

    The Problem: Editing SVG Backgrounds

    I love using the SVG (scalable vector graphics) format for web design. SVG is a great image format for the web, and since it’s based on code, it allows for high-quality responsive and interactive content. When you inject SVG onto the page, you have access to each of its internal elements and their properties, allowing you to animate them, update values (such as color), and dynamically inject additional information. SVG is also a great icon format, especially instead of icon fonts, and in smaller UI elements due to its high quality (think: retina screens) and small image size (think: performance).

    I find that often, when SVG is used for these smaller elements, or as a large area of illustration, it’s included as a background image for simplicity. The drawback to this is that the SVG is no longer under your control as a developer. You can’t adjust individual properties, like fill color, of an SVG background because it is treated just like any image. This color conundrum can be solved with CSS! Filters to the rescue!

    Adjusting Brightness

    The first time I discovered the SVG background challenge was when I was working on a website that had white SVG icons for social share icons that lived on a background determined to match that application. When these icons were moved onto a white background, they were no longer visible. Instead of creating a new icon, or changing the markup to inject inline SVG, you can use filter: brightness().

    With the brightness filter, any value greater than 1 makes the element brighter, and any value less than 1 makes it darker. So, we can make those light SVG’s dark, and vice versa!

    What I did above was create a dark class with filter: brightness(0.1). You can also do the opposite for darker icons. You can lighten icons by creating a light class with something like filter: brightness(100) or whatever is suitable to your needs.

    Icons with a fill color of #000, or rgb(0,0,0) will not brighten. You need to have a value greater than 0 in any of the rgb channels. fill: rgb(1,1,1) works great with a high brightness value such as brightness(1000), but even brightness(1000) will not work on pure black. This is not an issue with light colors and white.

    Adjusting Color

    We’ve now seen how to adjust light and dark values with a brightness() filter, but that doesn’t always get us the desired effect. What if we want to inject some color into those icons? With CSS filters, we can do that. One little hack is to use the sepia filter along with hue-rotate, brightness, and saturation to create any color we want.

    From white, you can use the following mixtures to get the navy, blue, and pink colors above:

    .colorize-pink { filter: brightness(0.5) sepia(1) hue-rotate(-70deg) saturate(5);
    } .colorize-navy { filter: brightness(0.2) sepia(1) hue-rotate(180deg) saturate(5);
    } .colorize-blue { filter: brightness(0.5) sepia(1) hue-rotate(140deg) saturate(6);
    }

    The world is your oyster here. SVG is just one use case for multiple filters. You can apply this to any media type—images, gifs, video, iframes, etc., and support is pretty good, too:

    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
    18* 15* 35 No 17 6*

    Mobile / Tablet

    iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
    6.0-6.1* 37* No 4.4* 64 57

    One final note here is to remember your user! Filters will not work in Internet Explorer, so please send a visible image to all of your users (i.e. don’t use a white SVG with an applied filter on a white background, because your IE users will not see anything). Also, remember to use alternative text for icon accessibility, and you’ll be golden to use this technique in your own applications!

    The post Solved With CSS! Colorizing SVG Backgrounds appeared first on CSS-Tricks.

    Focusing on Focus Styles

    Not everyone uses a mouse to browse the internet. If you’re reading this post on a smartphone, this is obvious! What’s also worth pointing out is that there are other forms of input that people use to get things done. With these forms of input comes the need for focus styles.

    People

    People are complicated. We don’t necessarily perform the same behaviors consistently, nor do we always make decisions that make sense from an outsider’s perspective. Sometimes we even do something just to… do something. We get bored easily: tinkering, poking, and prodding things to customize them to better suit our needs, regardless of their original intent.

    People are also mortal. We can get sick and injured. Sometimes both at once. Sometimes it’s for a little while, sometimes it’s permanent. Regardless, it means that sometimes we’re unable to do things we want or need to do in the way we’re used to.

    People also live in the world. Sometimes we’re put into an environment where external factors conspire to prevent us from doing something the way that we’re accustomed to doing it. Ever been stuck at your parents’ house during the holidays and had to use their ancient-yet-still-serviceable desktop computer? It’s like that.

    Input

    Both mouse and touch input provide an indicator for interaction. For touch, it is obvious: Your finger acts as the bridge that connects your mind to the item on the screen it wants to activate. For mice, a cursor serves as a proxy for your finger.

    However, these aren’t the only forms of input available to us. Keyboards are ubiquitous and can do just about anything a mouse or touch input can accomplish, provided you know all the right keys to press in the right order. Sometimes it’s even easier and faster than using a mouse!

    Think about the last time you were using Cut, Copy, Paste, and Save functionality. Maybe it was the last time you were working on a spreadsheet? Were you switching between mouse and keyboard input to get things done as efficiently as possible? You probably didn’t give that behavior a second thought, but it’s a great example of switching input on the fly to best accomplish a goal. Heck, maybe you even took some “me time” during this thankless task to poke the Like button on Facebook on your smartphone.

    If you have trouble using your hands, other options are available: Wands, sticks, switches, sip and puff devices, voice recognition, and eye tracking technology can all create input in a digital system. These devices will identify a content area and activate it. This is similar to how you can hit the tab key on a keyboard and the next cell in a spreadsheet will be highlighted, indicating that it has been moved to and is ready to be edited.

    In this video, video editor and accessibility consultant Christopher Hills demonstrates the capabilities of Switch Control, software that helps people experiencing motor control impairments use hardware switches to operate their computing devices.

    It’s worth pointing out that you could be relying on this technology one day, even if it’s only for a little bit. Maybe you broke both of your arms in an unfortunate mountain biking accident, and want to order some self-pity takeout while you recuperate. Maybe you’re driving and want to text your family safely. Or maybe you’ll just get old. It’s not difficult to think of other examples, it’s just not a concept people like to dwell on.

    If it’s interactive, it needs a focus style

    We can’t always know who is visiting our websites and web apps, why they’re visiting, what they’re going to do when they get there, what conditions they are experiencing, what emotions they’re feeling, or what input they may use. Analytics might provide some insight, but does not paint a full picture. It’d be foolish to have the tail wag the dog and optimize the entire experience based on this snapshot of limited information.

    It’s also important to know that not everyone who uses assistive technology wants to be identified as an assistive technology user. Nor should they be forced to disclose this. Power users—people who leverage keyboard shortcuts, specialized software, and browser extensions—may appear to navigate like a user of assistive technology, yet may not be experiencing any disability conditions. Again, people are complicated!

    What we can do is preemptively provide an experience that works for everyone, regardless of ability or circumstance.

    Identify and activate

    :focus

    With these alternate forms of input, how do we identify something to show it can be activated? Fortunately, CSS has this problem handled—we use the :focus and :active selectors.

    The grammar is straightforward. Want to outline a link in orange when a user focuses on it? Here’s how to describe it:

    a:focus { outline: 3px solid orange;
    }

    This outline will appear when someone navigates to the link, be it by clicking or tapping, tabbing to it via keyboard input, or using switch input to highlight it.

    A common misconception is that the focus style can only use the outline property. It’s worth noting that :focus is a selector like any other, meaning that it accepts the full range of CSS properties. I like to play with background color, underlining, and other techniques that don’t adjust the component’s current size, so as to not shift page layout when the selector is activated.

    Then say we want to remove the link’s underline when activated to communicate a shift in state. Remember: links use underlines!

    a:active { text-decoration: none;
    }

    It’s important to make sure the state changes, from resting to focused to activated, are distinct. This means that each transition should be unique when compared to the component’s other states, allowing the user to understand that a change has occurred.

    We also want to make sure these state changes don’t rely on color alone, to best accommodate people experiencing color blindness and/or low vision. Here’s how a color-only state change might look to a person with Deuteranopia, commonly known as Red-Green colorblindness:

    I purposely removed the underline and the browser’s native focus ring from the link in the video to better illustrate the issue of discoverability. When trying to tab around the page to determine what is interactive, it isn’t immediately obvious that there is a link present. If colorblindness is also a factor, the state change when hovered won’t be apparent—this is even more apparent with the addition of cataracts.

    :focus-within

    :focus-within—a focus-related pseudo class selector with a very Zen-sounding name—can apply styling to a parent element when one of its children receives focus. The focus event bubbles out until it encounters a CSS rule asking it to apply its styling instructions.

    A common use case for this selector would be to apply styling to an entire form when one of its input elements receives focus. In the example below, I’m scaling up the size of the entire form slightly, unless the user has expressed a desire for a reduced animation experience:

    See the Pen :focus-within Demo by Eric Bailey (@ericwbailey) on CodePen.

    The selector is still relatively new, so I’m sure we’ll get more clever applications as time goes on.

    Politics

    People also have opinions. Unfortunately, sometimes these opinions are uninformed. Outside the practice of accessibility there’s the prevalent notion that focus styles are “ugly” and many designers and developers remove them for the sake of perceived aesthetics. Sometimes they’re not even aware they’re propagating someone else’s opinion—many CSS resets include a blanket removal of focus styles and are incorporated as a foundational project dependency with no questions asked.

    This decision excludes people. Websites and web apps aren’t close-cropped trophies to be displayed without context on a dribbble profile, nor are they static screenshots on a slick corporate sales deck. They exist to be read and acted upon, and there’s rules that help ensure that the largest possible amount of people can do exactly that.

    :focus-visible

    The fact of the matter is that sometimes people will insist on removing focus styles, and have enough clout to force their cohorts to carry out their vision. This flies in the face of rules that stipulate that focus mechanisms must be visible for websites to be truly accessible. To get around this, we have the :focus-visible pseudo-selector.

    :focus-visible pseudo-selector styling kicks in when the browser determines that a focus event occurred, and User Agent heuristics inform it that non-pointer input is being used. That’s a fancy way of saying it shows focus styling when activated via input via other than mouse cursor or finger tap.

    The video of this CodePen demonstrates how different styling is applied based on the kind of input the link receives. When a link is hovered and clicked on via mouse input, its underline is removed and shifts down slightly. When tabbed to via keyboard input, :focus-visible applies a stark background color to the link instead.

    Chromium has recently announced its intent to implement :focus-visible. Although browser support is currently extremely limited, a polyfill is available. Both it and :focus-within are in the Selectors Level 4 Editor’s Draft, and therefore likely to have native support in the major browsers sooner than later.

    You may know :focus-visible by its other name, :-moz-focusring. This vendor prefixed pseudo-selector is Mozilla’s implementation of the idea, predating the :focus-visible proposal by seven years. Unlike other vendor prefixed CSS, we’re not going to have to worry about autoprefixing support! Firefox honors a :focus-visible declaration as well as :-moz-focusring, ensuring there will be parity for our selector names between the two browsers.

    One step forward, one step back

    Browser support is a bit of a rub—the web is more than just Chrome and Firefox. While the polyfill may provide support where there is none natively, it’s extra data to download, extra complexity to maintain, and extra fragility added to your payload.

    There’s also the fact that devices are far less binary about their input types than they used to be. The Surface, Microsoft’s flagship computer, offers keyboard, trackpad, stylus, camera, voice, and touch capability out of the box. WebAIM’s 2017 Screen Reader Survey revealed that mobile devices may be augmented by keyboard input more than you may think. Heuristics are nice, but like analytics, may not paint a complete picture.

    Another point to consider is that focus styles can be desirable for mouse users. Their presence is a clear and unambiguous indication of interactivity, which is a great affordance for people with low vision conditions, cognitive concerns, and people who are less technologically adept. Extraordinarily technologically adept people, ones who grok that screen readers and keyboard shortcuts are essentially Vim for a GUI, will want the focus state to be apparent as they use the keyboard to dance across the screen.

    Part of building a robust, resilient web involves building a strong core experience that works in every browser. The vanilla :focus selector enjoys both wide and deep support to the degree that it’s a safe bet that even exotic browsers will honor it.

    The world is full of things that some people may see as ugly, while others find them to be beautiful. Personally, I don’t see focus styles as an eyesore. As a designer, I think that it’s a foundational part of creating a mature design system. As a developer, describing state is just business as usual. As a person, I enjoy helping to keep the web open and accessible, as it was intended to be.


    If you’d like to learn more about the subject, UX Designer Caitlin Geier has a great writeup on focus indicators.

    The post Focusing on Focus Styles appeared first on CSS-Tricks.

    Quick Reminder that Details/Summary is the Easiest Way Ever to Make an Accordion

    Gosh bless the <details> element. Toss some content inside it and you have an accessible expand-for-more interaction with just about zero work.

    See the Pen Simple details. by Chris Coyier (@chriscoyier) on CodePen.

    Toss a <summary> in there to customize what the expander text says.

    See the Pen Multiple Details/Summary by Chris Coyier (@chriscoyier) on CodePen.

    Works great for FAQs.

    There is really no limit to how you can style them. If you don’t like the default focus ring, you can remove that, but make sure to put some kind of styling back.

    Here I’ve used a header element for each expandable section, which has a focus state that mimics other interactive elements on the page.

    The only browser that doesn’t support this are the Microsoft ones (and Opera Mini which makes sense—it doesn’t really do interactive).

    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
    12 15 49 No No 6

    Mobile / Tablet

    iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
    6.0-6.1 37 No 4 64 57

    But even then, it’s just like all the sections are opened, so it’s not a huge deal:

    Wanna style that default triangle? Strangely enough, the standard way to do that is through the list-style properties. But Blink-based browsers haven’t caught up to that yet, so they have a proprietary way to do it. They can be combined though. Here’s an example of replacing it with an image:

    summary { list-style-image: url(right-arrow.svg);
    } summary::-webkit-details-marker { background: url(right-arrow.svg); color: transparent;
    }

    See the Pen Custom Markers on Details/Summary by Chris Coyier (@chriscoyier) on CodePen.

    Unfortunately, they don’t turn, and there is no way to animate the default triangle either. One idea might be to target the :focus state and swap backgrounds:

    See the Pen Custom Markers on Details/Summary by Geoff Graham (@geoffgraham) on CodePen.

    But that seems to be limited to WebKit and Blink and, even then, the arrow will return once the item is out of focus even if the item is still expanded.

    The post Quick Reminder that Details/Summary is the Easiest Way Ever to Make an Accordion appeared first on CSS-Tricks.