Developer News

Scroll to the Future

Css Tricks - Thu, 04/19/2018 - 3:57am

This is an interesting read on the current state of scrollbars and how to control their behavior across operating systems and browsers. The post also highlights a bunch of stuff I didn’t know about, like Element.scrollIntoView() and the scroll-behavior CSS property.

My favorite part of all though? It has to be this bit:

In the modern web, relying heavily on custom JavaScript to achieve identical behavior for all clients is no longer justified: the whole idea of “cross-browser compatibility” is becoming a thing of the past with more CSS properties and DOM API methods making their way into standard browser implementations.

In our opinion, Progressive Enhancement is the best approach to follow when implementing non-trivial scrolling in your web projects.

Make sure you can provide the best possible minimal, but universally supported UX, and then improve with modern browser features in mind.

Speaking of the cross-browser behavior of scrollbars, Louis Hoebregts also has a new post that notes how browsers do not include the scrollbar when dealing with vw units and he provides a nice way of handling it with CSS custom properties.

Direct Link to ArticlePermalink

The post Scroll to the Future appeared first on CSS-Tricks.


Css Tricks - Thu, 04/19/2018 - 3:56am

(This is a sponsored post.)

Huge thanks to Kinsta for sponsoring CSS-Tricks this week! We're big fans of WordPress around here, and know some of you out there are too. So this might come of interest: Kinsta is WordPress hosting that runs on Google Cloud Platform. And in fact, it's officially recommended by Google Cloud for fully-managed WordPress hosting.

What does that matter? Well, when you go with a cloud host you're entering a new realm of reliability. For example, your site is run in its own isolated container, including all the software required to run it. Familiar stuff like PHP, MySQL, and Nginx. Those resources are 100% private and not shared between anyone else - not even other sites of yours.

Spinning up a site is incredibly easy from their nice dashboard

You aren't on your own here. Yes, you're using powerful low-level infrastructure from Google Cloud Platform, but you get site management comfort from the Kinsta dashboard:

As you spin up a site, you can select from any of 15 global data center locations. You can even pick a different location for every site, as you need, for no additional cost.

Serious speed

You'll be on the latest versions of important software, like PHP 7.2 and HHVM, which if you haven't heard, is smokin' fast.

Beyond that, there is built-in server-level caching, so you can rest easy that everything possible is being done to make sure your WordPress site is fast without you having to do much.


Install WordPress as you spin up a site this easily:

As a WordPress site owner, you'll care about these things:
  • At the pro plan, they'll migrate your site for free.
  • At the business plan, you get SSH and WP-CLI access.
  • If you're somehow hacked, they'll fix it for you.
  • The servers are optimized to work particularly well with popular plugins like WooCommerce or Easy Digital Downloads.
  • The support staff are 24/7 and WordPress developers themselves.
It's worth putting a point on a few other things that you either already care about as a developer, or should.
  • Free CDN - At no additional cost, your assets will be served from a CDN. That's great for performance and a requirement for some performance auditing tools that clients care more and more about.
  • Git support - You can pull and push your site from a Git repo on any of the major services, like you expect as a developer.
  • Free SSL and security - Don't worry about hand-managing your SSL certificates.
  • Easy staging environments - It's just one click to build a staging environment and another click to push it live from there when you're ready.
  • Automatic daily backups - Or even hourly if you wish. Plus, you can restore from any of these backups with a click.
  • GeoIP - Use the visitors geographic location to do things like cache location-specific data and content more effectively.
What's going on with your site will be no mystery

New Relic provides performance monitoring and analysis. Plus you dashboard will expose to you resource usage at a glance!

Serious WordPress power at affordable prices.

Go check out Kinsta

Direct Link to ArticlePermalink

The post Kinsta appeared first on CSS-Tricks.

VuePress Static Site Generator

Css Tricks - Wed, 04/18/2018 - 6:01am

VuePress is a new tool from Vue creator Evan You that spins up Vue projects that are more on the side of websites based on content and markup than progressive web applications and does it with a few strokes of the command line.

We talk a lot about Vue around here, from a five-part series on getting started with it to a detailed implementation of a serverless checkout cart

But, like anything new, even the basics of getting started can feel overwhelming and complex. A tool like VuePress can really lower the barrier to entry for many who (like me) are still wrapping our heads around the basics and tinkering with the concepts.

There are alternatives, of course! For example, Nuxt is already primed for this sort of thing and also makes it easy to spin up a Vue project. Sarah wrote up a nice intro to Nuxt and it's worth checking out, particularly if your project is a progressive web application. If you're more into React but love the idea of static site generating, there is Gatsby.

Direct Link to ArticlePermalink

The post VuePress Static Site Generator appeared first on CSS-Tricks.

Creating a Panning Effect for SVG

Css Tricks - Wed, 04/18/2018 - 3:15am

Earlier this month on the Animation at Work Slack, we had a discussion about finding a way to let users pan inside an SVG.

I made this demo below to show how I'd approach this question:

See the Pen Demo - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

Here are the four steps to make the above demo work:

  1. Get mouse and touch events from the user
  2. Calculate the mouse offsets from its origin
  3. Save the new viewBox coordinates
  4. Handle dynamic viewport

Let's check those steps one by one more thoroughly.

1. Mouse & Touch Events

To get the mouse or touch position, we first need to add event listeners on our SVG. We can use the Pointer Events to handle all kind of pointers (mouse/touch/stylus/...) but those events are not yet supported by all browsers. We will need to add some fallback to make sure all users will be able to drag the SVG.

// We select the SVG into the page var svg = document.querySelector('svg'); // If browser supports pointer events if (window.PointerEvent) { svg.addEventListener('pointerdown', onPointerDown); // Pointer is pressed svg.addEventListener('pointerup', onPointerUp); // Releasing the pointer svg.addEventListener('pointerleave', onPointerUp); // Pointer gets out of the SVG area svg.addEventListener('pointermove', onPointerMove); // Pointer is moving } else { // Add all mouse events listeners fallback svg.addEventListener('mousedown', onPointerDown); // Pressing the mouse svg.addEventListener('mouseup', onPointerUp); // Releasing the mouse svg.addEventListener('mouseleave', onPointerUp); // Mouse gets out of the SVG area svg.addEventListener('mousemove', onPointerMove); // Mouse is moving // Add all touch events listeners fallback svg.addEventListener('touchstart', onPointerDown); // Finger is touching the screen svg.addEventListener('touchend', onPointerUp); // Finger is no longer touching the screen svg.addEventListener('touchmove', onPointerMove); // Finger is moving }

Because we could have touch events and pointer events, we need to create a tiny function to returns to coordinates either from the first finger either from a pointer.

// This function returns an object with X & Y values from the pointer event function getPointFromEvent (event) { var point = {x:0, y:0}; // If event is triggered by a touch event, we get the position of the first finger if (event.targetTouches) { point.x = event.targetTouches[0].clientX; point.y = event.targetTouches[0].clientY; } else { point.x = event.clientX; point.y = event.clientY; } return point; }

Once the page is ready and waiting for any user interactions, we can start handling the mousedown/touchstart events to save the original coordinates of the pointer and create a variable to let us know if the pointer is down or not.

// This variable will be used later for move events to check if pointer is down or not var isPointerDown = false; // This variable will contain the original coordinates when the user start pressing the mouse or touching the screen var pointerOrigin = { x: 0, y: 0 }; // Function called by the event listeners when user start pressing/touching function onPointerDown(event) { isPointerDown = true; // We set the pointer as down // We get the pointer position on click/touchdown so we can get the value once the user starts to drag var pointerPosition = getPointFromEvent(event); pointerOrigin.x = pointerPosition.x; pointerOrigin.y = pointerPosition.y; } 2. Calculate Mouse Offsets

Now that we have the coordinates of the original position where the user started to drag inside the SVG, we can calculate the distance between the current pointer position and its origin. We do this for both the X and Y axis and we apply the calculated values on the viewBox.

// We save the original values from the viewBox var viewBox = { x: 0, y: 0, width: 500, height: 500 }; // The distances calculated from the pointer will be stored here var newViewBox = { x: 0, y: 0 }; // Function called by the event listeners when user start moving/dragging function onPointerMove (event) { // Only run this function if the pointer is down if (!isPointerDown) { return; } // This prevent user to do a selection on the page event.preventDefault(); // Get the pointer position var pointerPosition = getPointFromEvent(event); // We calculate the distance between the pointer origin and the current position // The viewBox x & y values must be calculated from the original values and the distances newViewBox.x = viewBox.x - (pointerPosition.x - pointerOrigin.x); newViewBox.y = viewBox.y - (pointerPosition.y - pointerOrigin.y); // We create a string with the new viewBox values // The X & Y values are equal to the current viewBox minus the calculated distances var viewBoxString = `${newViewBox.x} ${newViewBox.y} ${viewBox.width} ${viewBox.height}`; // We apply the new viewBox values onto the SVG svg.setAttribute('viewBox', viewBoxString); document.querySelector('.viewbox').innerHTML = viewBoxString; }

If you don't feel comfortable with the concept of viewBox, I would suggest you first read this great article by Sara Soueidan.

3. Save Updated viewBox

Now that the viewBox has been updated, we need to save its new values when the user stops dragging the SVG.

This step is important because otherwise we would always calculate the pointer offsets from the original viewBox values and the user will drag the SVG from the starting point every time.

function onPointerUp() { // The pointer is no longer considered as down isPointerDown = false; // We save the viewBox coordinates based on the last pointer offsets viewBox.x = newViewBox.x; viewBox.y = newViewBox.y; } 4. Handle Dynamic Viewport

If we set a custom width on our SVG, you may notice while dragging on the demo below that the bird is moving either faster or slower than your pointer.

See the Pen Dynamic viewport - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

On the original demo, the SVG's width is exactly matching its viewBox width. The actual size of your SVG may also be called viewport. In a perfect situation, when the user is moving their pointer by 1px, we want the viewBox to translate by 1px.

But, most of the time, the SVG has a responsive size and the viewBox will most likely not match the SVG viewport. If the SVG's width is twice as big than the viewBox, when the user moves their pointer by 1px, the image inside the SVG will translate by 2px.

To fix this, we need to calculate the ratio between the viewBox and the viewport and apply this ratio while calculating the new viewBox. This ratio must also be updated whenever the SVG size may change.

// Calculate the ratio based on the viewBox width and the SVG width var ratio = viewBox.width / svg.getBoundingClientRect().width; window.addEventListener('resize', function() { ratio = viewBox.width / svg.getBoundingClientRect().width; });

Once we know the ratio, we need to multiply the mouse offsets by the ratio to proportionally increase or reduce the offsets.

function onMouseMove (e) { [...] newViewBox.x = viewBox.x - ((pointerPosition.x - pointerOrigin.x) * ratio); newViewBox.y = viewBox.y - ((pointerPosition.y - pointerOrigin.y) * ratio); [...] }

Here's how this works with a smaller viewport than the viewBox width:

See the Pen Smaller viewport - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

And another demo with a viewport bigger than the viewBox width:

See the Pen Bigger viewport - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

[Bonus] Optimizing the code

To make our code a bit shorter, there are two very useful concepts in SVG we could use.

SVG Points

The first concept is to use SVG Points instead of basic Javascript objects to save the pointer's positions. After creating a new SVG Point variable, we can apply some Matrix Transformation on it to convert the position relative to the screen to a position relative to the current SVG user units.

Check the code below to see how the functions getPointFromEvent() and onPointerDown() have changed.

// Create an SVG point that contains x & y values var point = svg.createSVGPoint(); function getPointFromEvent (event) { if (event.targetTouches) { point.x = event.targetTouches[0].clientX; point.y = event.targetTouches[0].clientY; } else { point.x = event.clientX; point.y = event.clientY; } // We get the current transformation matrix of the SVG and we inverse it var invertedSVGMatrix = svg.getScreenCTM().inverse(); return point.matrixTransform(invertedSVGMatrix); } var pointerOrigin; function onPointerDown(event) { isPointerDown = true; // We set the pointer as down // We get the pointer position on click/touchdown so we can get the value once the user starts to drag pointerOrigin = getPointFromEvent(event); }

By using SVG Points, you don't even have to handle transformations applied on your SVG! Compare the following two examples where the first is broken when a rotation is applied on the SVG and the second example uses SVG Points.

See the Pen Demo + transformation - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

See the Pen Demo Bonus + transform - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

SVG Animated Rect

The second unknown concept in SVG we can use to shorten our code, is the usage of Animated Rect.

Because the viewBox is actually considered as an SVG Rectangle (x, y, width, height), we can create a variable from its base value that will automatically update the viewBox if we update this variable.

See how easier it is now to update the viewBox of our SVG!

// We save the original values from the viewBox var viewBox = svg.viewBox.baseVal; function onPointerMove (event) { if (!isPointerDown) { return; } event.preventDefault(); // Get the pointer position as an SVG Point var pointerPosition = getPointFromEvent(event); // Update the viewBox variable with the distance from origin and current position // We don't need to take care of a ratio because this is handled in the getPointFromEvent function viewBox.x -= (pointerPosition.x - pointerOrigin.x); viewBox.y -= (pointerPosition.y - pointerOrigin.y); }

And here is the final demo. See how much shorter the code is now? 😀

See the Pen Demo Bonus - SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.


This solution is definitely not the only way to go to handle such behavior. If you are already using a library to deal with your SVGs, it may already have a built-in function to handle it.

I hope this article may help you to understand a bit more how powerful SVG can be! Feel free to contribute to the code by commenting with your ideas or alternatives to this solution.


The post Creating a Panning Effect for SVG appeared first on CSS-Tricks.

Hey hey `font-display`

Css Tricks - Tue, 04/17/2018 - 3:41am

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 FOUT and FOIT as is right for your project, two things that both kinda suck in regards to font loading. We've got a couple posts on it around here:


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!

Css Tricks - Mon, 04/16/2018 - 3:26am

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?

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.

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.

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).

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.
    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.
    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:

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 */ 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.

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:

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:

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().

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:

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.

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;'--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:

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); `--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:

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;'--p', easeInOut(f/NF).toFixed(2)); /* same as before */ })(); 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++)`--p${i}`, TFN[i ? 'ease-out' : 'ease-in'](f/NF); requestAnimationFrame(update) })();

This gives us a pretty interesting result:

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.

Museum of Websites

Css Tricks - Mon, 04/16/2018 - 3:26am

The team at Kapwing has collected a lot of images from the Internet Archive’s Wayback Machine and presented a history of how the homepage of popular websites like Google and the New York Times have changed over time. It’s super interesting.

I particularly love how Amazon has evolved from a super high information dense webpage that sort of looks like a blog to basically a giant carousel that takes over the whole screen.

Direct Link to ArticlePermalink

The post Museum of Websites appeared first on CSS-Tricks.

BigCommerce: eCommerce Your Way (and Design Awards!)

Css Tricks - Mon, 04/16/2018 - 3:15am

Huge thanks to BigCommerce for sponsoring CSS-Tricks this week!

Here's the basics: BigCommerce is a hosted eCommerce platform. In just a few minutes, anybody can build their own online store. From a personal perspective, I'd suggest to any of my friends and family to go this route. CMS-powered websites are complicated enough, let alone feature-packed eCommerce websites. Please go with a solution that does it all for you so your site will look and work great and you can focus on your actual business.

Feature-packed is a fair descriptor, I'd say, as your BigCommerce site isn't just a way to post some products and take money for them. You can manage inventory if you like, manage all your shipping, and (I bet this is appealing to many of you): get those products over to other sales platforms like Amazon, eBay, Facebook and Instagram.

But I'm a developer! I'd like full control over my site.

Heck yeah you do. And you'll have it with BigCommerce. That's what Stencil is, their framework that powers BigCommerce sites. You'll have complete control over whatever you need with Stencil. Change the templates, the styling, add whatever libraries you want and need. You can even work on your BigCommerce site locally, and push you changes up as needed through the Stencil CLI.

If you'd like an overview of the Stencil tech stack, here you go:

Just to wet your whistle:

  • Native SCSS support
  • A base pattern library named Citadel, built on top of ZURB Foundation
  • Naming based on BEM / SUIT CSS
  • JavaScript helpers via stencil-utils library
  • Templating via Handlebars

Get good at Stencil, and you can create BigCommerce themes you can sell! &#x1f4b0;

The Design Awards!

Each year, BigCommerce holds design awards to give a showcase to all the wonderfully designed BigCommerce sites out there and the people who build them. I'm afraid submissions are already closed, but now's the time for social voting! If you're so inclined, you can go vote for your favorites for the People's Choice awards.

Vote here up to once per day for your favorite BigCommerce store.

I'm lending a hand as a judge as well, so stay tuned later this month for all the winner announcements.

The post BigCommerce: eCommerce Your Way (and Design Awards!) appeared first on CSS-Tricks.

Some Recent Live Coding Favorites

Css Tricks - Sat, 04/14/2018 - 8:00am

There is no shortage of videos out there where you can watch people code with an educational vibe. A golden age, one might say. Here are a few that I've watched and really enjoyed lately:

The post Some Recent Live Coding Favorites appeared first on CSS-Tricks.

New CSS Features Are Enhancing Everything You Know About Web Design

Css Tricks - Fri, 04/13/2018 - 4:45am

We just hit you with a slab of observations about CSS Grid in a new post by Manuel Matuzovi?. Grid has been blowing our minds since it was formally introduced and Jen Simmons is connecting it (among other new features) to what she sees as a larger phenomenon in the evolution of layouts in web design.

From Jeremy Keith's notes on Jen's talk, "Everything You Know About Web Design Just Changed " at An Event Apart Seattle 2018:

This may be the sixth such point in the history of the web. One of those points where everything changes and we swap out our techniques ... let’s talk about layout. What’s next? Intrinsic Web Design.

Why a new name? Why bother? Well, it was helpful to debate fluid vs. fixed, or table-based layouts: having words really helps. Over the past few years, Jen has needed a term for “responsive web design +”.

That "+" is the intrinsic nature of the web. Should you use flexible image sizes or fixed images sizes? Why not both and let the context decide? CSS Grid plays a role in this because it introduced new methods for layouts to respond to the intrinsic context of the element, such as the fr unit and the minmax() function. We don't necessarily need media queries to make a layout responsive. And, similarly, we can choose to use a fixed layout that goes into a fluid one.

Unlike me, Peter Anglea was there at the presentation and posted a video that wonderfully articulates the concept even further. Also, Jen's slides!

While applying a name may help conceptualize a change, I'm not so sure that "Intrinsic Web Design" is changing everything we know about web design. I like to think of it more as enhancing what we understand about it. Whatever the semantics, what these new CSS features are undoubtedly doing is making CSS less complex, even if the pace of these changes can be dizzying at times and appear that what we know has been turned upside-down.

The post New CSS Features Are Enhancing Everything You Know About Web Design appeared first on CSS-Tricks.

Another Collection of Interesting Facts About CSS Grid

Css Tricks - Fri, 04/13/2018 - 3:45am

Last year, I assembled A Collection of Interesting Facts about CSS Grid Layout after giving a workshop. This year, I worked on another workshop and I've learned some more exciting facts about the layout spec we all so love.

Of course, I'm not going to keep my knowledge to myself. I'm happy to share my findings once again with you, the CSS-Tricks community.

Understanding how the `grid` shortcut works

Sometimes, reading and understanding parts of the grid—or actually any other—spec can be very hard.

For example, it took me quite a while to understand how to use the grid shorthand properly. The specification states that the valid values are:

<‘grid-template’> | <‘grid-template-rows’> / [ auto-flow && dense? ] <‘grid-auto-columns’>? | [ auto-flow && dense? ] <‘grid-autwo-rows’>? / <‘grid-template-columns’>

You can make sense of it if you take your time or if you're experienced in reading specs. I tried several combinations and all of them failed. What eventually helped me was a note in the spec:

Note that you can only specify the explicit or the implicit grid properties in a single grid declaration.

Rachel Andrew has a series of posts that help explain how to read a specification, using CSS Grid as an example.

So, we can specify a multitude of things using the grid shorthand, but just not all of them at once. Here are some examples.

Using `grid` in favor of `grid-template`

The grid-template property is a shorthand for setting grid-template-columns, grid-template-rows, and grid-template-areas in a single declaration. We can do the same with the grid shorthand, which is a little shorter.

grid: "one one" 200px "two four" "three four" / 1fr 2fr; /* shorthand for: */ /* grid-template-areas: "one one" "two four" "three four"; grid-template-rows: 200px; grid-template-columns: 1fr 2fr; */

This shorthand creates three rows and two columns, with four named grid areas. The first row has an explicit height of 200px, while the second and the third have an implicit height of auto. The first column has a width of 1fr and the second a width of 2fr.

See the Pen grid shorthand - areas, explicit rows and columns by Manuel Matuzovic (@matuzo) on CodePen.

Want to know more about the difference between an explicit and an implicit grid? Check out this post I wrote on the topic here on CSS-Tricks.

We don't have to specify areas if we don't need them. We can use the grid shorthand just for defining explicit rows and columns. The following two snippets are essentially doing the same thing:

grid-template-rows: 100px 300px; grid-template-columns: 3fr 1fr; grid: 100px 300px / 3fr 1fr; Handling implicit rows and columns

It's possible to use the grid shorthand to specify grid-auto-flow as well, but it doesn't exactly work as we might expect. We don't just add the row or column keyword somewhere in the declaration. Instead, we have to use the auto-flow keyword on the correct side of the slash.

If it's to the left of the slash, the shorthand sets grid-auto-flow to row and creates explicit columns.

grid: auto-flow / 200px 1fr; /* shorthand for: */ /* grid-auto-flow: row; grid-template-columns: 200px 1fr; */

If it's to the right of the slash, the shorthand sets grid-auto-flow to column and creates explicit rows.

grid: 100px 300px / auto-flow; /* shorthand for: */ /* grid-template-rows: 100px 300px; grid-auto-flow: column; */

We can also set the size of implicit tracks together with the auto-flow keyword, which respectively sets grid-auto-rows or grid-auto-columns to the specified value.

grid: 100px 300px / auto-flow 200px; /* shorthand for: */ /* grid-template-rows: 100px 300px; grid-auto-flow: column; grid-auto-columns: 200px; */

See the Pen grid shorthand - explicit rows and implicit columns by Manuel Matuzovic (@matuzo) on CodePen.

Feature queries in Edge

Checking support for CSS Grid works great with Feature Queries because all browsers that support Grid also understand feature queries. This means that we can check if a browser supports the old or the new spec, or both. Both, you ask? Starting with Edge 16, Edge does not just support the new spec, but the old one as well.

So, if you want to differentiate between versions of Edge that support the new spec and those that don't, you have to write your queries like this:

/* Edge 16 and higher */ @supports (display: -ms-grid) and (display: grid) { div { width: auto; } } /* Edge 15 and lower */ @supports (display: -ms-grid) and (not (display: grid)) { div { margin: 0 } }

Here's a handy little demo, that displays which feature query triggers in the browser you opened it with.

See the Pen display: grid support test by Manuel Matuzovic (@matuzo) on CodePen.

As a side note, you shouldn't go overboard with (mis)using feature queries for browser sniffing, because browser detection is bad.

Specifying the exact number of items per column

Grid is great for page layouts, but it can be very useful on a component level as well. One of my favorite examples is the ability to specify the exact amount of items per column in a multi-column component.

Let's say we have a list of 11 items and we want to add a new column after every fourth item. The first thing we want to do after setting display: grid on the parent is to change the way the grid auto-placement algorithm works. By default, it fills in each row, in turn, adding new rows as necessary. If we set grid-auto-flow to column, grid will fill each column in turn instead, which is what we want. The last thing we have to do is specify the number of items per column. This is possible by defining as many explicit rows as needed using the grid-template-rows property. We can set the height of each row explicitly or just make them as big as their contents by using the auto keyword.

ul { display: grid; grid-template-rows: auto auto auto auto; /* or shorter and easier to read: */ /* grid-template-rows: repeat(4, auto); */ grid-auto-flow: column; }

If we have to change the number of items per column to 5, we just add another track to the track listing or we make use of the repeat-notation instead and just change the first parameter to the desired value (grid-template-rows: repeat(5, auto)).

See the Pen Limited number of items per column by Manuel Matuzovic (@matuzo) on CodePen.

Sticky footers with CSS Grid

There are many ways to create sticky footers in CSS. Some of them are hacky and complicated, but it's pretty straightforward with Grid.

Let's say we have a *classic* header, main content and footer page structure.

<body> <header>HEADER</header> <main>MAIN</main> <footer>FOOTER</footer> </body>

First, we set the height of html and body to at least 100% of the viewport to make sure the page always uses the full vertical space. Then we apply grid-template-rows to split the body into three rows. The first (header) and the last (footer) row can have whatever size we want. If we want them to always be as big as their contents, we simply set the height to auto. The row in the middle (main) should always fill up the rest of the space. We don't have to calculate the height because we can use the fraction unit to achieve that.

html { height: 100%; } body { min-height: 100%; display: grid; grid-template-rows: auto 1fr auto; }

As a result, the main body grows and the footer adjusts accordingly and stays at the bottom of the viewport.

See the Pen CSS Grid Layout Sticky Footer by Manuel Matuzovic (@matuzo) on CodePen.

Automatic minimum size of grid items

Recently, Florian tweeted that he was wondering why truncating single line text within a grid item was so complicated. His example perfectly illustrates an interesting fact about grid items.

The starting situation is a three-column grid with a paragraph in each grid item.

<div class="grid"> <div class="item"> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo ipsum exercitationem voluptate, autem veritatis enim soluta beatae odio accusamus molestiae, perspiciatis sunt maiores quam. Deserunt, aliquid inventore. Ullam, fugit dicta. </p> </div> </div> .grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px; }

Each paragraph should only be single-line and display an ellipsis at the end of the line if the paragraph is longer than its parent item. Florian solved that by setting white-space to nowrap, which forces a single line, hiding overflow and setting text-overflow to ellipsis.

p { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

This would have worked perfectly fine on a block element, but in this grid example, the columns expand to the width of the single-line paragraph:

See the Pen Automatic minimum size of grid items by Manuel Matuzovic (@matuzo) on CodePen.

Broadly speaking, this happens, because a grid item can't be smaller than its children. The default min-width of a grid-item (or flex-item) is set to auto, which according to the spec:

...applies an automatic minimum size in the specified axis to grid items whose overflow is visible and which span at least one track whose min track sizing function is auto.

This makes grid and flex items more flexible, but sometimes it's not desirable that the content is able to stretch its parent items width. To avoid that we can either change the overflow property of the grid-item to something other than visible or set the min-width to 0.

See the Pen Truncate Text in CSS Grid by Manuel Matuzovic (@matuzo) on CodePen.

Read more about Automatic Minimum Size of Grid Items in the grid spec.

Wrapping up

Hopefully these recent takeaways help you feel more comfortable writing and using Grid as they have for me. There's a lot of detail in this new specification, but it becomes more interesting and understandable with more use.

The post Another Collection of Interesting Facts About CSS Grid appeared first on CSS-Tricks.

It’s Time for an RSS Revival

Css Tricks - Thu, 04/12/2018 - 11:31am

Brian Barrett:

Tired of Twitter? Facebook fatigued? It's time to head back to RSS.

I'm an RSS reader lover, so I hate to admit it, but RSS ain't going mainstream. It was too nerdy 20 years ago and it's too nerdy now. RSS is still incredibly useful technology, but I can't see it taking off alone.

For RSS to take off, it needs some kind of abstraction. Like Flipboard, where you can get started reading stuff right away and feeding it RSS isn't something you need to handle manually. Apple News is kinda like that. I'm a little love/hate with Apple News though. I like reading stuff in it, but I've stopped publishing in it because it became too much work to get right and have it look good. It's like managing a second site, unlike RSS which just brainlessly works when your CMS supports it. A little-known feature of Apple News was that it used to be able to function as an RSS reader, but they removed that a couple of years ago. Boooooo.

Podcasts have the right abstraction. People listen through apps that combine discoverability (or at least searchability) with the place you actually subscribe and listen. Ironically, RSS-based.

Digg has been a bit like Flipboard or Apple News: a combination of a very nice RSS reader but also curated content. They've just nuked their reader seemingly out of nowhere though, so clearly something wasn't going well there. There have been so many nukings of RSS readers, it makes you wonder. Is it the XML thing? Could JSON Feed save it or does that complicate things even more? Is the business model just too hard to crack?

After the Google Reader shutdown, I had gone with Feedly for a while. I can't even remember why now, but ultimately something bugged me about it and I ended up going with Digg. I know loads of people really love Feedly though so it's worth a shot for those of you looking for a reader.

Brian also links up The Old Reader and Inoreader. Me, I've gone for FeedBin.

Someday, we'll have to throw a feed-sharing party where we can all share our favorite feeds and fill up them readers. This site's is at a predictable URL. Dave Winer also has a new project kinda tracking feed popularity.

Direct Link to ArticlePermalink

The post It’s Time for an RSS Revival appeared first on CSS-Tricks.

Wufoo and Worldpay

Css Tricks - Thu, 04/12/2018 - 11:30am

(This is a sponsored post.)

Huge thanks to Wufoo for sponsoring CSS-Tricks this week! Like it says in the sidebar on this very site, we’ve been using Wufoo for literally over a decade. It’s the easiest and most powerful way to build web forms on the web.

Here’s something brand new from the Wufoo team: now in addition to payment providers like PayPal and Stripe, you can choose Worldpay.

This will be a huge upgrade for international users, and really any users with international customers. It’s already incredibly easy to create forms that take payments with Wufoo, now you can do it in local currencies like the £ Pound, € Euro, Canadian $ Dollar, Norwegian Krone, Swedish Krona, and more. And not just take payments in them, but be paid yourself in that currency. Nice.

Direct Link to ArticlePermalink

The post Wufoo and Worldpay appeared first on CSS-Tricks.

Working With the new CSS Typed Object Model

Css Tricks - Thu, 04/12/2018 - 4:05am

Eric Bidelman introduces the CSS Typed Object Model. It looks like it's going to make dealing with getting and setting style values through JavaScript easier and less error-prone. Less stringy, more number-y when appropriate.

Like if we wanted to know the padding of an element, classically we'd do:

var el = document.querySelector("#thing"); var style = window.getComputedStyle(el); console.log(style.padding);

And we'd get "20px" as a string or whatever it is.

One of these new API's lets us pull it off like this:

console.log( el.computedStyleMap().get('padding').value, el.computedStyleMap().get('padding').unit );

And we get 20 as a real number and "px" as a string.

There is also attributeStyleMap with getters and setters, as well as functions for each of the values (e.g. CSS.px() CSS.vw()).

Eric counts the benefits:

  1. Few bugs.
  2. Arithmetic operations & unit conversion.
  3. Value clamping & rounding.
  4. Better performance.
  5. Error handling.
  6. Naming matches CSS exactly.

Direct Link to ArticlePermalink

The post Working With the new CSS Typed Object Model appeared first on CSS-Tricks.

How to Create a Component Library From SVG Illustrations

Css Tricks - Thu, 04/12/2018 - 4:01am

I’ve recently published my first ever open source npm package! It makes SVG illustrations from unDraw into customizable React components.

Here’s a GIF that shows what I mean:

What’s unDraw?

unDraw is a collection of MIT licensed illustrations for every project you can imagine and create. It’s a constantly updated collection of beautiful SVG images that you can use completely free and without attribution.

While unDraw is still fairly new, its open source nature means that it’s being used by a range of products already. Here it is on the newly launched design mentoring site called MentorOla, alongside a language site I’ve been working on myself called Little Lingua:

Left: MentorOla by Marc Andrew, Right: Little Lingua]

While using React to build the Little Lingua website, I discovered that converting SVGs into React components made them much more manageable and even more customizable as illustrations.

Because of this usefulness, I wanted to release a library of unDraw React components as an open source npm package to bring the beauty of unDraw to the largest of JavaScript audiences in a simple way:

Framework Nov. 2016 Oct. 2017 % Change React 2,564,601 7,040,410 174.5% Angular 1,289,953 2,168,899 68.1% Backbone 663,610 837,372 31.6% Angular.js 616,135 1,081,796 75.6% Vue 6,231 874,424 13,933.%

Source: JavaScript Frameworks by the Numbers

John Hannah, who authored the the JavaScript Frameworks by the Numbers report:

React absolutely dominates. It’s by far the most downloaded according to these numbers...

A lot of inspiration to put this package together came from Miuki Miu’s project React Kawaii, where she did largely the same thing, and a bit more:

Her article outlines the overall concept of SVGs as React Components, and here I will go into more of the details involved in my own process including putting together Styleguideist documentation. Here’s everything that will be covered:

  1. How to convert SVG illustrations into customisable React Components
  2. How to use Styleguideist to produce simple, interactive documentation
  3. How to release an npm package (since it was my first time doing this)
1. SVG Illustrations as React Components

When you visit unDraw, it’s currently possible to customize one primary color of each SVG illustration right from the website:

The SVG download you get when you grab the image is pretty tedious to customize any further, as there’s many color values to change. If that SVG is converted to a React component though, it becomes really easy! Compare the two:

unDraw designer SVG vs. React Component

Essentially, the SVG is held within a React component, which is very simple to interface with. You just pass properties to the Component (e.g. skinColor/hairColor/primaryColor), which then sprinkles them into the SVG.

You can do this in just three steps:

Convert the SVG to JSX

There are some awesome tools out there to convert SVGs into the JSX code that’s used in a React component’s render() method. The first one I used was the first one I came across: SVG to JSX—it was also the first Google search result &#x1f609;. As it says on the tin, any JSX code is generated from any SVG you paste in:

SVG to JSX converter by Balaj Marius

Once you’ve got your JSX, paste it into your React component like so:

import React from 'react'; import PropTypes from 'prop-types'; const UndrawDesigner = props => ( <svg id='780c6f38–12e9–4526–8343–95ef18389740' dataName='Layer 1' xmlns=''> // all your svg code </svg> ); export default UndrawDesigner;

That’s it! Now you can use this as a component by dropping this into your code:


Right now, you’ll be stuck with the default colors of your SVG. Let’s make those colors easy to change:

Make it Customizable With Props

We can use the benefits of React to make the illustration customisable by adding *props* as placeholders that are used to fill the *color attributes* of the SVG/JSX in your component:

<svg xmlns=''> <path fill={props.hairColor} d='...' /> <path fill={props.hairColor} d='...' /> <ellipse fill={props.skinColor} cx='...' cy='...' rx='...' ry='...' /> <ellipse fill={props.skinColor} cx='...' cy='...' rx='...' ry='...' /> <!-- etc --> </svg>

To make sure you’re replacing the right fill attributes, you can open the SVG in your browser, and identify colors using your browser’s inspector tools:

You can see the color here is rgb(226,189,149) . Convert that to a hex code. There’s many ways to do this, one is searching "colorpicker” in Google :

Since a single color is often used in numerous places in an SVG illustration (e.g. left hand, right hand, face will be the same), there will be many places a color needs replacing. To do it quickly, grab the HEX code, and do a find-and-replace in your component, replacing the color attribute with your prop name, e.g. {props.skinColor} .

Do this with as many colors/elements of your SVG as you’d like to make customizable, ensuring your props are named so that they’re easy for other people to understand and use.

Add PropType definitions and Default Colors

Once you’ve finished adding your props, it’s good practice to define them as propTypes. This will also help when we make awesome documentation for our components. Add them like so (make sure you’ve got prop-types installed in your project):

UndrawDesigner.propTypes = { /** * Hex color */ skinColor: PropTypes.string, /** * Hex color */ hairColor: PropTypes.string, /** * Hex color */ primaryColor: PropTypes.string, };

Finish up your component by defining some default colors, right before the export statement. This ensures a fallback color will be used if no props are passed to the component:

UndrawDesigner.defaultProps = { skinColor: '#e2bd95', primaryColor:'#6c68fb', hairColor:'#222' }; export default UndrawDesigner;

After doing this, your component will be ready to accept values for each of the attributes defined. For example, in UndrawDesigner, we can make a little gray human by passing in various types of gray for skin and hair. Nice and simple:

It’s that much simpler, really. If you want to go beyond changing colors, read Miuki Miu's article, where she cleverly adds smaller common components that are used as facial expressions across larger components:

2. Making the Style Guide

To make the React illustrations more useful to everyone, it’s possible to create a living style guide of the components using React Styleguidist. It’s not much extra work, either.

Because of how Stylguidist works with React, it’s really straightforward to create documentation from the components we have. Styleguidist requires two main things to generate documentation from our components:

  1. Clear PropType definitions
  2. Component examples

We’ve already taken care of the first one in the previous section. The comments above each PropType definition is also important, as it gets displayed in the end documentation:

Adding component examples is also straightforward—add a to the folder of your component with an example of how it would be used. The contents may look something like this:

// UndrawResponsive example ```js <UndrawResponsive height='250px' primaryColor='#6c68fb' accentColor='#43d1a0' /> ```

You can find out more in the Styleguidist documentation.

Once you’ve got those two in place, installing and running Styleguidist will create the documentation like magic. Follow the instructions here to install and run it.

3. Releasing the npm package

At this stage, I had a folder of React components with unDraw illustrations, but it’s useless to any other project. Here are the steps I took to turn them into an npm module:

  1. Create a brand new React project using Facebook’s create-react-app
  2. Copy over the react components you’d like to release an npm module into src/node_modules/components of your creat-react-app project
  3. Follow these steps outlined by Pavel Lokhmakov

Finally, to publish your module, create an npm account and follow these two short videos of the npm documentation:

  1. How to create Node.js modules
  2. How to publish and update a package

That’s it! There are over 100 unDraw illustrations by Katerina Limpitsouni on unDraw. At the moment, I’ve only added a handful of those to the unDraw npm package, but will be adding more each week.

Check out the GitHub repository here. I’ll also be releasing the code for the LittleLingua soon, the website that makes use of this unDraw npm package. It’s built with unDraw’s production-ready MIT licensed theme, called evie, which I’ve also converted into React components.

To learn more about transforming SVG illustrations into components, check out Elizabet Oliveira’s talk about her side project, React Kawaii which was also nominated as “Fun Side Project of the Year” at the React Amsterdam Open Source Awards:

The post How to Create a Component Library From SVG Illustrations appeared first on CSS-Tricks.

List Rendering and Vue’s v-for Directive

Css Tricks - Wed, 04/11/2018 - 3:56am

List rendering is one of the most commonly used practices in front-end web development. Dynamic list rendering is often used to present a series of similarly grouped information in a concise and friendly format to the user. In almost every web application we use, we can see lists of content in numerous areas of the app.

In this article we'll gather an understanding of Vue’s v-for directive in generating dynamic lists, as well as go through some examples of why the key attribute should be used when doing so.

Since we'll be explaining things thoroughly as we start to write code, this article assumes you’ll have no or very little knowledge with Vue (and/or other JavaScript frameworks).

Case Study: Twitter

We’re going to use Twitter as the case study for this article.

When logged in and in the main index route of Twitter we’re presented with a view similar to this:

On the homepage, we’ve become accustomed to seeing a list of trends, a list of tweets, a list of potential followers, etc. The content displayed in these lists depends on a multitude of factors—our Twitter history, who we follow, our likes, etc. As a result, we can say all this data is dynamic.

Though this data is dynamically obtained, the way this data is shown remains the same. This is in part due to using reusable web components.

For example; we can see the list of tweets as a list of single tweet-component items. We can think of tweet-component as a shell that takes data of sorts, such as the username, handle, tweet and avatar, among other pieces, and that simply displays those pieces in a consistent markup.

Let’s say we wanted to render a list of components (e.g. a list of tweet-component items) based on a large data source obtained from a server. In Vue, the first thing that should come to mind to accomplish this is the v-for directive.

The v-for directive

The v-for directive is used to render a list of items based on a data source. The directive can be used on a template element and requires a specific syntax along the lines of:

Let’s see an example of this in practice. First, we’ll assume we’ve already obtained a collection of tweet data:

const tweets = [ { id: 1, name: 'James', handle: '@jokerjames', img: '', tweet: "If you don't succeed, dust yourself off and try again.", likes: 10, }, { id: 2, name: 'Fatima', handle: '@fantasticfatima', img: '', tweet: 'Better late than never but never late is better.', likes: 12, }, { id: 3, name: 'Xin', handle: '@xeroxin', img: '', tweet: 'Beauty in the struggle, ugliness in the success.', likes: 18, } ]

tweets is a collection of tweet objects with each tweet containing details of that particular tweet—a unique identifier, the name/handle of the account, tweet message, etc. Let’s now attempt to use the v-for directive to render a list of tweet components based on this data.

First and foremost, we’ll create the Vue instance—the heart of the Vue application. We’ll mount/attach our instance to a DOM element of id app and assign the tweets collection as part of the instance’s data object.

new Vue({ el: '#app', data: { tweets } });

We’ll now go ahead and create a tweet-component that our v-for directive will use to render a list. We’ll use the global Vue.component constructor to create a component named tweet-component:

Vue.component('tweet-component', { template: ` <div class="tweet"> <div class="box"> <article class="media"> <div class="media-left"> <figure class="image is-64x64"> <img :src="tweet.img" alt="Image"> </figure> </div> <div class="media-content"> <div class="content"> <p> <strong>{{}}</strong> <small>{{tweet.handle}}</small> <br> {{tweet.tweet}} </p> </div> <div class="level-left"> <a class="level-item"> <span class="icon is-small"><i class="fas fa-heart"></i></span> <span class="likes">{{tweet.likes}}</span> </a> </div> </div> </article> </div> </div> `, props: { tweet: Object } });

A few interesting things to note here.

  1. The tweet-component expects a tweet object prop as seen in the prop validation requirement (props: {tweet: Object}). If the component is rendered with a tweet prop that is not an object, Vue will emit warnings.
  2. We’re binding the properties of the tweet object prop on to the component template with the help of the Mustache syntax: {{ }}.
  3. The component markup adapts Bulma’s Box element as it represents a good resemblance to a tweet.

In the HTML template, we’ll need to create the markup where our Vue app will be mounted (i.e. the element with the id of app). Within this markup, we’ll use the v-for directive to render a list of tweets. Since tweets is the data collection we’ll be iterating over, tweet will be an appropriate alias to use in the directive. In each rendered tweet-component, we’ll also pass in the iterated tweet object as props for it to be accessed in the component.

<div id="app" class="columns"> <div class="column"> <tweet-component v-for="tweet in tweets" :tweet="tweet"/> </div> </div>

Regardless of how many more tweet objects would be introduced to the collection; or how they’ll change over time—our set up will always render all the tweets in the collection in the same markup we expect.

With the help of some custom CSS, our app will look something like this:

See the Pen Simple Twitter Feed #1 by Hassan Dj (@itslit) on CodePen.

Though everything works as expected, we may be prompted with a Vue tip in our browser console:

[Vue tip]: <tweet-component v-for="tweet in tweets">: component lists rendered with v-for should have explicit keys...

You may not be able to see the warning in the browser console when running the code through CodePen.

Why is Vue telling us to specify explicit keys in our list when everything works as expected?


It’s common practice to specify a key attribute for every iterated element within a rendered v-for list. This is because Vue uses the key attribute to create unique bindings for each node’s identity.

Let’s explain this some more—if there were any dynamic UI changes to our list (e.g. order of list items gets shuffled), Vue will opt towards changing data within each element instead of moving the DOM elements accordingly. This won’t be an issue in most cases. However, in certain instances where our v-for list depends on DOM state and/or child component state, this can cause some unintended behavior.

Let’s see an example of this. What if our simple tweet component now contained an input field that will allow the user to directly respond to the tweet message? We’ll ignore how this response could be submitted and simply address the new input field itself:

We’ll include this new input field on to the template of tweet-component:

Vue.component('tweet-component', { template: ` <div class="tweet"> <div class="box"> // ... </div> <div class="control has-icons-left has-icons-right"> <input class="input is-small" placeholder="Tweet your reply..." /> <span class="icon is-small is-left"> <i class="fas fa-envelope"></i> </span> </div> </div> `, props: { tweet: Object } });

Assume we wanted to introduce another new feature into our app. This feature would involve allowing the user to shuffle a list of tweets randomly.

To do this; we can first include a “Shuffle!” button in our HTML template:

<div id="app" class="columns"> <div class="column"> <button class="is-primary button" @click="shuffle">Shuffle!</button> <tweet-component v-for="tweet in tweets" :tweet="tweet"/> </div> </div>

We’ve attached a click event listener on the button element to call a shuffle method when triggered. In our Vue instance; we’ll create the shuffle method responsible in randomly shuffling the tweets collection in the instance. We’ll use lodash’s _shuffle method to achieve this:

new Vue({ el: '#app', data: { tweets }, methods: { shuffle() { this.tweets = _.shuffle(this.tweets) } } });

Let’s try it out! If we click shuffle a few times; we’ll notice our tweet elements get randomly assorted with each click.

See the Pen Simple Twitter Feed #2 by Hassan Dj (@itslit) on CodePen.

However, if we type some information in the input of each component then click shuffle; we’ll notice something peculiar happening:

Since we haven’t opted to using the key attribute, Vue has not created unique bindings to each tweet node. As a result, when we’re aiming to reorder the tweets, Vue takes the more performant saving approach to simply change (or patch) data in each element. Since the temporary DOM state (i.e. the inputted text) remains in place, we experience this unintended mismatch.

Here’s a diagram that shows us the data that gets patched on to each element and the DOM state that remains in place:

To avoid this; we’ll have to assign a unique key to every tweet-component rendered in the list. We’ll use the id of a tweet to be the unique identifier since we should safely say a tweet’s id shouldn’t be equal to that of another. Because we’re using dynamic values, we’ll use the v-bind directive to bind our key to the

<div id="app" class="columns"> <div class="column"> <button class="is-primary button" @click="shuffle">Shuffle!</button> <tweet-component v-for="tweet in tweets" :tweet="tweet" :key="" /> </div> </div>

Now, Vue recognizes each tweet’s node’s identity; and thus will reorder the components when we intend on shuffling the list.

Since each tweet component is now being moved accordingly, we can take this a step further and use Vue’s transition-group to show how the elements are being reordered.

To do this, we’ll add the transition-group element as a wrapper to the v-for list. We'll specify a transition name of tweets and declare that the transition group should be rendered as a div element.

<div id="app" class="columns"> <div class="column"> <button class="is-primary button" @click="shuffle">Shuffle!</button> <transition-group name="tweets" tag="div"> <tweet-component v-for="tweet in tweets" :tweet="tweet" :key="" /> </transition-group> </div> </div>

Based on the name of the transition, Vue will automatically recognize if any CSS transitions/animations have been specified. Since we aim to invoke a transition for the movement of items in the list; Vue will look for a specified CSS transition along the lines of tweets-move (where tweets is the name given to our transition group). As a result, we'll manually introduce a .tweets-move class that has a specified type and time of transition:

#app .tweets-move { transition: transform 1s; }

This is a very brief look into applying list transitions. Be sure to check out the Vue docs for detailed information on all the different types of transitions that can be applied!

Our tweet-component elements will now transition appropriately between locations when a shuffle is invoked. Give it a try! Type some information in the input fields and click “Shuffle!” a few times.

See the Pen Simple Twitter Feed #3 by Hassan Dj (@itslit) on CodePen.

Pretty cool, right? Without the key attribute, the transition-group element can’t be used to create list transitions since the elements are patched in place instead of being reordered.

Should the key attribute always be used? It’s recommended. The Vue docs specify that the key attribute should only be omitted if:

  • We intentionally want the default manner of patching elements in place for performance reasons.
  • The DOM content is simple enough.

And there we have it! Hopefully this short article portrayed how useful the v-for directive is as well as provided a little more context to why the key attribute is often used. Let me know if you may have any questions/thoughts whatsoever!

If you liked my style of writing and are potentially interested in learning how to build apps with Vue.js, you may like the book Fullstack Vue: The Complete Guide to Vue.js that I helped publish! The book covers numerous facets of Vue including but not restricted to routing, simple state management, form handling, Vuex, server persistence, and testing. If you're interested, you can get more information from our website,

The post List Rendering and Vue’s v-for Directive appeared first on CSS-Tricks.

Going Offline

Css Tricks - Wed, 04/11/2018 - 3:55am

Jeremy Keith has written a new book all about service workers and offline functionality that releases at the end of the month. The first chapter is posted on A List Apart. Now that the latest versions of iOS and macOS Safari support service workers, I can’t think of a better time to learn about how progressive web apps work under the hood. In fact, here's an example of a simple offline site and a short series on making web apps work offline.

News of Jeremy's book had me going back through his previous book, Resilient Web Design, where I half-remembered this super interesting quote from Chapter 4:

If you build something using web technologies, and someone visits with a web browser, you can’t be sure how many of the web technologies will be supported. It probably won’t be 100%. But it’s also unlikely to be 0%. Some people will visit with iOS devices. Others will visit with Android devices. Some people will get 80% or 90% of what you’ve designed. Others will get just 20%, 30%, or 50%. The web isn’t a platform. It’s a continuum.

I love this idea of the web as a continuum that’s constantly improving and growing over time and so I’m sure Jeremy’s latest book will be just as fun and interesting.

Direct Link to ArticlePermalink

The post Going Offline appeared first on CSS-Tricks.

Displaying the Weather With Serverless and Colors

Css Tricks - Tue, 04/10/2018 - 3:48am

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 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 &#x1f4b0;.

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(; // 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(; // 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

Css Tricks - Mon, 04/09/2018 - 3:00am

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:

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:

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;'--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:

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))'--i', i -= s); x0 = null } };

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

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.

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)'--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))'--i', i -= s);'--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)) {'--i', i -= s); f = 1 - f }'--tx', '0px');'--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, I came up with a result that seemed promising:

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.

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);'--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) {'--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) {'--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) {'--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

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:

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.

`:focus-visible` and backwards compatibility

Css Tricks - Sun, 04/08/2018 - 2:56am

Patrick H. Lauke covers the future CSS pseudo class :focus-visible. We're in the early days of browser support, but it aims to solve an awkward situation:

... focus styles can often be undesirable when they are applied as a result of a mouse/pointer interaction. A classic example of this are buttons which trigger a particular action on a page, such as advancing a carousel. While it is important that a keyboard user is able to see when their focus is on the button, it can be confusing for a mouse user to find the look of the button change after they clicked it – making them wonder why the styles “stuck”, or if the state/functionality of the button has somehow changed.

If we use :focus-within instead of :focus, that gives the browser the freedom to not apply focus styles when it determines it's unnecessary, but still does when, for example, the element is tabbed to.

The scary part is "instead of". We can just up and switch with browser support as it is. Not even @supports can help us. But Patrick has some ideas.

button:focus { /* some exciting button focus styles */ } button:focus:not(:focus-visible) { /* undo all the above focused button styles if the button has focus but the browser wouldn't normally show default focus styles */ } button:focus-visible { /* some even *more* exciting button focus styles */ }

Direct Link to ArticlePermalink

The post `:focus-visible` and backwards compatibility appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.