Developer News

The Fragmented, But Evolving State of CSS-in-JS

Css Tricks - Thu, 12/20/2018 - 4:43am

TLDR: The CSS-in-JS community has converged on a consistent API.

Not so long ago, a Facebook engineer compiled a list of the available CSS-in-JS methodologies. It wasn’t short:

aphrodite, babel-plugin-css-in-js, babel-plugin-pre-style, bloody-react-styled, classy, csjs, css-constructor, css-light, css-loader, css-ns, cssobj, cssx-loader, cxs, electron-css, emotion, es-css-modules, freestyler, glamor, glamorous, hiccup-css, hyperstyles, i-css, j2c, jsxstyle, linaria, nano-css, pre-style, radium, react-css-builder, react-css-components, react-css-modules, react-cssom, react-fela, react-free-style, react-inline-css, react-inline-style, react-inline, react-jss, react-look, react-native-web, react-statics-styles, react-styl, react-style, react-styleable, react-stylematic, react-theme, react-vstyle, reactcss, restyles, scope-styles, smart-css, stile-react-media-queries, stilr, stylable, style-it, styled-components, styled-jsx, styletron-react, styling, superstyle, typestyle, uranium

Such a fragmented ecosystem was far from appealing. Which one should you pick, (if any)?

Contributing to Javascript fatigue — you need at most one. Also feel free to not learn any.

GitHub stars are one useful metric:

However, GitHub stars say nothing about a project’s trajectory — perhaps they were accumulated long ago and the repo has since fallen out of favor or is no longer maintained. Glamor has plenty of open issues, and hasn’t seen a commit in over a year. Its author advises:

...it mostly works, I'm not going to do any major changes… if you need something more modern, I'd recommend emotion, it mostly matches glamor's api, and is actively maintained.

The similarly named Glamorous was recently deprecated with its author also recommending users switch to Emotion:

At the time, Emotion had some features that Styled Components didn’t. Since then, Styled Components has made some big announcements.

Styled Components sells itself as the CSS-in-JS library for people that *like* CSS. Styled Components gained popularity by utilizing tagged template literals — allowing developers to *just write CSS* in the same syntax they already know, but inside JavaScript files. While this has proven popular, some developers prefer to [write styles as JavaScript objects. Emotion offered flexibility — developers could choose how to write their styles. Styled Components eventually followed suit.

styled-components v3.3.0 is out with first-class object support! 😍

Lots of people have been asking for this, your wishes have been heard! Shoutout to @probablyup for taking care of this release.

👉 https://t.co/yOHWg78nF4 pic.twitter.com/Ic8fZdAFVs

— Max Stoiber (@mxstbr) May 25, 2018

Emotion also offers a css prop, which Styled Components didn’t have, until…

🎉 Announcing support for the css prop in styled-components! 🎉

This has been a long time coming, hope y'all enjoy! ✨

👉 https://t.co/DMdrG6uviZ

Huge shoutout to @satya164 for coming up with the ingenious implementation! 👏

— Max Stoiber (@mxstbr) November 26, 2018

The rival CSS-in-JS libraries have stolen from each other until landing upon the same feature set and the same syntax — Emotion and Styled Components have an almost identical API. What once felt like a total mess of competing methodologies and libraries now feels somewhat stable. Even if CSS-in-JS hasn’t standardized on a dependency, it now has standardized a way of doing things — they’re just implemented differently:

Internally, quite a bit. SC has a lot of complexity around organizing style tag order.
Re css prop: SC requires Babel plugin and uses the entire SC custom component creation. Emotion will skip the custom component if it can and just renders the element with the className directly

— Kye Hohenberger (@tkh44) December 7, 2018

Styled Components is by far the most popular CSS-in-JS library, but Emotion has seen a rapid increase in usage.

Both are used by some major companies. Styled Components are utilized by plenty of large companies, including Bloomberg, Atlassian, Reddit, Target, BBC News, The Huffington Post, Coinbase, Patreon, Vogue, Ticketmaster, Lego, InVision and Autodesk just to name a few.

Emotion boasts fewer recognizable names, but has been recently adopted by the New York Times.

Great article about the launch of our new Story designs on the NYT today. It mentions our Shared Components initiative - would have been impossible without Emotion / CSS-in-JS. Absolute game-changer. Living in the future. https://t.co/pZLDJjsbEr

— Scott Taylor (@wonderboymusic) May 8, 2018

While these libraries certainly do seem to be most popular amongst React users, they can be used with other frameworks. While they seem to have converged on the same features at last, it’s difficult to say whether this is the end point of CSS-in-JS, or whether we’ll see a continued evolution from here.

The post The Fragmented, But Evolving State of CSS-in-JS appeared first on CSS-Tricks.

WooCommerce

Css Tricks - Thu, 12/20/2018 - 4:27am

(This is a sponsored post.)

I just read a nicely put together story about WooCommerce over on the CodeinWP blog. WooCommerce started life as WooThemes, sort of a "premium themes" business started by just a couple of fellas who had never even met in person. Two years and a few employees later they launch WooCommerce, and 2 years after that it hits a million downloads. A major success story, to be sure, but a collaborative and remote-work based one that wasn't exactly overnight. Another 2 years and Automattic picks them up and the WooThemes part is spun down.

Now we're 3-4 years into WooCommerce being an Automattic project and it's looking at nearly 60 million downloads, 4 million of which are active. A number they are saying is about 30% of all eCommerce on the web. Daaaaang. I've used WooCommerce a number of times and it always does a great job for me.

Direct Link to ArticlePermalink

The post WooCommerce appeared first on CSS-Tricks.

Fighting FOIT and FOUT Together

Css Tricks - Wed, 12/19/2018 - 4:30am

Lots from Divya with the setup:

There are 2 kinds of problems that can arise when using webfonts; Flash of invisible text (FOIT) and Flash of Unstyled Text (FOUT) ... If we were to compare them, FOUT is of course the lesser of the two evils

If you wanna fight FOIT, the easiest tool is the font-display CSS property. I like the optional value because I generally dislike the look of fonts swapping.

If you want to fight them both, one option is to preload the fonts:

<link rel="preload" href="/fonts/awesome-l.woff2" as="font" />

But...

Preload is your friend, but not like your best friend ... preloading in excess can significantly worsen performance, since preloads block initial render.

Just like CSS does.

In a conversation with Scott Jehl, he pointed out to me that "preloads block initial render" isn't quite true, and he put together a test case. A <link rel="preload" ...> resource doesn't block rendering in and of itself.

Even huge sites aren't doing much about font loading perf. Roel Nieskens:

I expected major news sites to be really conscious about the fonts they use, and making sure everything is heavily optimised. Turns out a simple Sunday afternoon of hacking could save a lot of data: we could easily save roughly 200KB

Fonts are such big part of web perf, so let's get better at it! Here's Zach Leatherman at the Performance.now() conference:

Part of the story is that we might just have lean on JavaScript to do the things we need to do. Divya again:

Web fonts are primarily CSS oriented. It can therefore feel like bad practice to reach for JavaScript to solve a CSS issue, especially since JavaScript is a culprit for an ever increasing page weight.

But sometimes you just have to do it in order to get what you need done. Perhaps you'd like to handle page visibility yourself? Here's Divya's demonstration snippet:

const font = new fontFace("My Awesome Font", "url(/fonts/my-awesome-font.woff2)" format('woff2')") font.load().then (() => { document.fonts.add(font); document.body.style.fontFamily = "My Awesome Font, serif"; // we can also control visibility of the page based on a font loading // var content = document.getElementById("content"); content.style.visibility = "visible"; })

But there are a bunch of other reasons. Zach has documented them:

  • Because, as you load in fonts, each of them can cause repaints and you want to group them.
  • Because the user has indicated they want to use less data or reduce motion.
  • Because you'd like to be kind to slow networks.
  • Because you're using a third-party that can't handle font-display.

The post Fighting FOIT and FOUT Together appeared first on CSS-Tricks.

Google Fonts and font-display

Css Tricks - Wed, 12/19/2018 - 4:26am

The font-display descriptor in @font-face blocks is really great. It goes a long way, all by itself, for improving the perceived performance of web font loading. Loading web fonts is tricky stuff and having a tool like this that works as well as it does is a big deal for the web.

It's such a big deal that Google's own Pagespeed Insights / Lighthouse will ding you for not using it. A cruel irony, as their own Google Fonts (easily the most-used repository of custom fonts on the web) don't offer any way to use font-display.

Summarized by Daniel Dudas here:

Google Developers suggests using Lighthouse -> Lighthouse warns about not using font-display on loading fonts -> Web page uses Google Fonts the way it's suggested on Google Fonts -> Google Fonts doesn't supports font-display -> Facepalm.

Essentially, we developers would love a way to get font-display in that @font-face block that Google serves up, like this:

@font-face { font-family: "Open Sans Regular"; src: url("..."); font-display: swap; }

Or, some kind of alternative that is just as easy and just as effective.

Seems like query params is a possibility

When you use a Google Font, they give you a URL that coughs up a stylesheet and makes the font work. Like this:

https://fonts.googleapis.com/css?family=Roboto

They also support URL params for a variety of things, like weights:

https://fonts.googleapis.com/css?family=Open+Sans:400,700

And subsets:

http://fonts.googleapis.com/css?family=Creepster&text=TRICKS https://fonts.googleapis.com/css?family=Open+Sans:400,700&amp;subset=cyrillic

So, why not...

http://fonts.googleapis.com/css?family=Creepster&font-display=swap

The lead on the project says that caching is an issue with that (although it's been refuted by some since they already support arbitrary text params).

Adding query params reduces x-site cache hits. If we end up with something for font-display plus a bunch of params for variable fonts that could present us with problems.

They say that again later in the thread, so it sounds unlikely that we're going to get query params any time soon, but I'd love to be wrong.

Option: Download & Self-Host Them

All Google Fonts are open source, so we can snag a copy of them to use for whatever we want.

Once the font files are self-hosted and served, we're essentially writing @font-face blocks to link them up ourselves and we're free to include whatever font-display we want.

Option: Fetch & Alter

Robin Richtsfeld posted an idea to run an Ajax call from JavaScript for the font, then alter the response to include font-display and inject it.

const loadFont = (url) => { // the 'fetch' equivalent has caching issues var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { let css = xhr.responseText; css = css.replace(/}/g, 'font-display: swap; }'); const head = document.getElementsByTagName('head')[0]; const style = document.createElement('style'); style.appendChild(document.createTextNode(css)); head.appendChild(style); } }; xhr.send(); } loadFont('https://fonts.googleapis.com/css?family=Rammetto+One');

Clever! Although, I'm not entirely sure how this fits into the world of font loading. Since we're now handling loading this font in JavaScript, the loading performance is tied to when and how we're loading the script that runs this. If we're going to do that, maybe we ought to look into using the official webfontloader?

Option: Service Workers

Similar to above, we can fetch the font and alter it, but do it at the Service Worker level so we can cache it (perhaps more efficiently). Adam Lane wrote this:

self.addEventListener("fetch", event => { event.respondWith(handleRequest(event)) }); async function handleRequest(event) { const response = await fetch(event.request); if (event.request.url.indexOf("https://fonts.googleapis.com/css") === 0 && response.status < 400) { // Assuming you have a specific cache name setup const cache = await caches.open("google-fonts-stylesheets"); const cacheResponse = await cache.match(event.request); if (cacheResponse) { return cacheResponse; } const css = await response.text(); const patched = css.replace(/}/g, "font-display: swap; }"); const newResponse = new Response(patched, {headers: response.headers}); cache.put(event.request, newResponse.clone()); return newResponse; } return response; }

Even Google agrees that using Service Workers to help Google Fonts is a good idea. Workbox, their library for abstracting service worker management, uses Google Fonts as the first demo on the homepage:

// Cache the Google Fonts stylesheets with a stale while revalidate strategy. workbox.routing.registerRoute( /^https:\/\/fonts\.googleapis\.com/, workbox.strategies.staleWhileRevalidate({ cacheName: 'google-fonts-stylesheets', }), ); // Cache the Google Fonts webfont files with a cache first strategy for 1 year. workbox.routing.registerRoute( /^https:\/\/fonts\.gstatic\.com/, workbox.strategies.cacheFirst({ cacheName: 'google-fonts-webfonts', plugins: [ new workbox.cacheableResponse.Plugin({ statuses: [0, 200], }), new workbox.expiration.Plugin({ maxAgeSeconds: 60 * 60 * 24 * 365, }), ], }), ); Option: Cloudflare Workers

Pier-Luc Gendreau looked into using Cloudflare workers to handle this, but then followed up with Supercharge Google Fonts with Cloudflare and Service Workers, apparently for even better perf.

It has a repo.

Option: Wait for @font-feature-values

One of the reasons Google might be dragging its heels on this (they've said the same), is that there is a new CSS @rule called @font-feature-values that is designed just for this situation. Here's the spec:

This mechanism can be used to set a default display policy for an entire font-family, and enables developers to set a display policy for @font-face rules that are not directly under their control. For example, when a font is served by a third-party font foundry, the developer does not control the @font-face rules but is still able to set a default font-display policy for the provided font-family. The ability to set a default policy for an entire font-family is also useful to avoid the ransom note effect (i.e. mismatched font faces) because the display policy is then applied to the entire font family.

There doesn't seem to be much movement at all on this (just a little), but it doesn't seem pretty awesome to wait on it.

The post Google Fonts and font-display appeared first on CSS-Tricks.

Ease-y Breezy: A Primer on Easing Functions

Css Tricks - Tue, 12/18/2018 - 9:28am

During the past few months, I’ve been actively teaching myself how to draw and animate SVG shapes. I’ve been using CSS transitions, as well as tools like D3.js, react-motion and GSAP, to create my animations.

One thing about animations in general and the documentation these and other animation tools recommend is using easing functions. I’ve been working with them in some capacity over the years, but to be honest, I would never know which function to choose for which kind of animation. Moreover, I did not know about the magic that goes into each of these functions, the notable differences between them, and how to use them effectively. But I was fine with that because I knew that easing functions somehow “smoothed” things out and mostly made my work look realistic.

Here, I present to you what I learned about easing functions in the form of a primer that I hope gives you a good understanding as you dig into animations.

How I got into easing functions

I tried to re-create a pattern called rotating snakes, an optical illusion that tricks the brains into thinking that circles rotate and “dance” when they are not.

I quickly found a gap in my knowledge when trying to build this out. It’s hard! But in the process, I discovered that easing functions play a big role in it.

I turned to JavaScript to draw a bunch of concentric circles in SVG using a library:

for (i = 1; i <= 10; i++) { drawCircle({radius: i * 10}); }

This was the result:

But that clearly does not look anything like the picture.

As I thought things through, I realized that I was looking for a certain property. I wanted the change in radius of the concentric circles to be small at the beginning and then become larger as the radius increases.

This means that the linear increase in radius using i++ won’t do the trick. We need a better formula to derive the radius. So, my next attempt looked something like this:

let i = 1; let radiusList = []; let radius = 0; while (i <= 10) { drawCircle({radius: i * 10}); if(i < 4) { i = i + 0.5 } else { i = i + 1 } }

...which got me this:

Hmm, still not what I wanted. In fact, this deviates even further from the pattern. Plus, this code is hardly customizable unwieldy to maintain.

So, I turned to math for one last attempt.

What we need is a function that changes the radius organically and exponentially. I had an “Aha!” moment and maybe you already see it, too. Easing functions will do this!

The radius of each circle should increase slowly at first, then quickly as the circles go outward. With easing, we can make move things along a curve that can slow and speed up at certain points.

A quick Google search landed me at this gist which is a well-documents list of easing functions and really saved my day. Each function takes one input value, runs formulae. and provides an output value. The input value has to be between 0 and 1. (We will dig into this reasoning later.)

A quadratic easing function looked promising because all it does is square the value it receives:

function (t) { return t*t }

Here’s the code I wound up using:

const easing = (t) => { return t*t } for(i = 0; i<=1; i=i+0.05) { const r = easing(i) * 40; drawCircle(r); }

And we have a winner!

The difference between this pattern and my first two attempts was night and day. Yay for easing functions!

This little experience got me really interested in what else easing functions could do. I scoured the internet for cool information. I found old articles, mostly related to Flash and ActionScript which had demos showing different line graphs.

That’s all pretty outdated, so here’s my little primer on easing functions.

What are easing functions?

They’re a type of function that takes a numeric input between 0 and 1. That number runs through the specified function and returns another number between 0 and 1. A value between 0-1 multiplied by another value between 0-1 always results in a value between 0-1. This special property helps us make any computation we want while remaining within specific bounds.

The purpose of an easing function is to get non-linear values from linear value inputs.

This is the crux of what we need to know about easing functions. The explanations and demos here on out are all geared towards driving home this concept.

Easing functions are a manifestation of the interpolation concept in mathematics. Interpolation is the process of finding the set of points that lie on a curve. Easing functions are essentially drawing a curve from point 0 to point 1 by interpolating (computing) different sets of points along the way.

Robert Penner was the first to define easing functions and create formulae for different ones in his book.

The five types of easing functions

There are five types of easing functions. They can be mixed, inverted and even mashed together to form additional, more complex functions. Let’s dig into each one.

Linear easing functions

This is the most basic form of easing. If the interval between the points we interpolate between 0 and 1 are constant, then we then form a linear easing function.

Going back to the concentric circles example earlier, increasing the radius of the initial circle by a constant amount (10px in that example) makes a linear function.

It should come as no surprise that linear is the default easing function. They’re extremely simple because there is no curve to the animation and the object moves in a straight, consistent direction. That said, linear functions have their drawbacks. For example, linear animations tend to feel unnatural or even robotic because real-life objects rarely move with such perfect, straight motion.

Quadratic easing functions

A quadratic easing function is created by multiplying a value between 0 and 1 by itself (e.g. 0.5*0.5). As we learned earlier, we see that this results in a value that is also between 0 and 1 (e.g. 0.5*0.5 = 0.25).

To demonstrate, let’s make 10 values between 0 and 1 with a quadratic function.

const quad_easing = (t) => t*t; let easing_vals = []; for(let i = 0; i < 1; i +=0.1) { easing_vals.push(quad_easing(i)); }

Here’s a table of all the values we get:

Input Value (x-axis) Quadratic Eased Value (y-axis) 0 0 0.1 0.01 0.2 0.04 0.3 0.09 0.4 0.16 0.5 0.25 0.6 0.36 0.7 0.49 0.8 0.64 0.9 0.81 1 1

If we were to plot this value on a graph with x-axis as the original value and y-axis as the eased value, we would get something like this:

Notice something? The curve is practically the same as the ease-in functions we commonly find, even in CSS!

Cubic, Quartic and Quintic easing functions

The final three types of easing functions behave the same, but work with a different value.

A cubic easing function is creating by multiplying a value between 0 and 1 by itself three times. In other words, it’s some value (e.g. t), cubed (e.g. t3).

Quartic functions do the same, but to the power of 4. So, if t is our value, we’re looking at t4

And, as you have already guessed, a quintic function runs to the power of 5.

The following demo will give you a way to play around with the five types of functions for a good visual of how they differ from one another.

See the Pen Plotting Easing functions by Pavithra Kodmad (@pkodmad) on CodePen.

Easing in and easing out…or both!

“An ease-in-out is a delicious half-and-half combination, like a vanilla-chocolate swirl ice cream cone.”
— Robert Penner

Ease in and ease out might be the most familiar easing animations. They often smooth out a typical linear line by slowing down at the start or end (or both!) of an animation.

Ease-in and ease-out animations can be created using any of the non-linear functions we’ve already looked at, though cubic functions are most commonly used. In fact, the CSS animation property comes with ease-in and ease-out values right out of the box, via the animation-timing-function sub-property.

  • ease-in: This function starts slow but ends faster.
  • ease-out: This function starts fast and ends slower.
  • ease-in-out: This function acts as a combination of the others, starting fast, slowing down in the middle, then ending faster.

See the Pen Easing demo by Pavithra Kodmad (@pkodmad) on CodePen.

Go ahead and play around with them on this cubic-bezier.com.

These curves can be created in JavaScript as well. I personally like and use the bezier-easing library for it. Easing.js is another good one, as is D3’s library (with a nice example from Mike Bostock). And, if jQuery is more your thing, check out this plugin or even this one.

See, it’s pretty “ease”-y!

I hope this little primer helps illustrate easing functions and interpolation in general. There are so many ways these functions can make animations more natural and life-like. Have a look at Easing.css for a UI that allows you to create custom curves and comes with a slew of preset options.

I hope the next time you use an easing function, it won’t be a blackbox to you. You now have a baseline understanding to put easing functions to use and open up a ton of possibilities when working with animations.

More on easing

We’ve only scratched the surface of easing functions here, but there are other good resources right here on CSS-Tricks worth checking out to level up even further.

The post Ease-y Breezy: A Primer on Easing Functions appeared first on CSS-Tricks.

How to Worry About npm Package Weight

Css Tricks - Tue, 12/18/2018 - 4:59am

It's all too easy to go crazy with the imports and end up with megabytes upon megabytes of JavaScript. It can be a problem as that weight burdens each and every visitor from our site, very possibly delaying or stopping them from doing what they came to do on the site. Bad for them, worse for you.

There is all sorts of ways to keep an eye on it.

You could have a peak on Bundlephobia

Bundlephobia will give you a look at the total size — both zipped and unzipped — along with download times, the number of required sub-dependencies it has, and whether or not it can be tree-shaked (tree-shook? tree-shaken?).

Speaking of "phobia," there is also Package Phobia that shows the publish and install sizes of individual packages:

You could let VS Code tell you right in the editor

Your import and require statements can lett you know the size of that particular inclusion with the Import Cost extension.

You could look at a data visualization

The Webpack Bundle Analyzer does that.

You could check out the sizes with text output

Cost of modules is another analyzer, but it seems like it only looks at package.json rather than the final bundle, then outputs it as a table:

Webpack Bundle Size Analyzer will show you a nested list of dependency weights, including the size of the bundle code itself, which is interesting:

package size will show you the weight of a comma-separated list of packages

package size has a simple CLI syntax for that:

You have another favorite way to keep your project in check?

The post How to Worry About npm Package Weight appeared first on CSS-Tricks.

Nobody is quite wrong.

Css Tricks - Mon, 12/17/2018 - 11:57am

There are two opposing views on using non-polyfillable new web features that I find are both equally common in our industry:

  1. Websites don't need to look the same in every browser. The concept of progressive enhancement helps with that. There are tools, even native language features, that help with this.
  2. If browser support isn't where I want it to be, it's just exotic eye candy for demos and not to be used.

I'm not sure I'd say either one of these is more or less correct than the other.

I also imagine it doesn't come as much of surprise that I support the thinking behind #1. It's perfectly possible to design and implement things that behave differently in different browsers and conditions. That's essentially what responsive design is, and that's pretty much the entire internet now.

The backbone of progressive enhancement is starting with a working foundation that works everywhere and layering design and functionality on top of that, when possible. There are even native language features to support the idea. @supports rules allow us to write CSS that can do something if a feature is supported and do something else if it isn't.

This is the entire use case for Modernizr and it has 22,804 stars.

I don't want to argue against progressive enhancement. Remember, I just said I support that thinking. But I do have some empathy for people and teams that choose not to go there, and end up developing more of a #2 attitude.

It is a bit more work to develop and design features that work in different ways. It might be work that is absolutely worth doing. Or it might not. Either way, it does complicate things. It's more code, it requires more attention and testing, and it's a bit harder to reason. It's technical debt.

Let me be preemptively defensive again: technical debt can be fine, and even intentional. We all incur it in everything we build. My point is that it is helpful to be smart about it and take on an amount of technical debt that is feasible for you to look after in perpetuity.

You might argue that building on a progressive enhancement foundation is, in a sense, less technical debt because you're building on such a sturdy foundation that less testing and constant tending to is required. Perhaps!

I do get behaving like a #2. It feels safer. It feels like you're being cautious and responsible. "Hey that's neat," you think. "I'll revisit it in a few years to see if I can use it for real." I might argue that 1) that's no fun and 2) almost counter-intuitively, it means you aren't willing to take a progressive enhancement approach which may make your code ultimately more frail.

It depends, I suppose. It depends on what exactly you're trying to do. It depends on the weight of that techinical debt. It depends on the team and the rate of developer churn. It depends on documentation. It depends on testing and QA.

You do you.

The post Nobody is quite wrong. appeared first on CSS-Tricks.

A CSS Venn Diagram

Css Tricks - Mon, 12/17/2018 - 11:42am

This is pretty wild: Adrian Roselli has made a series of rather complex Venn diagrams using nothing but CSS. With a combination of the Firefox dev inspector, plus a mixture of CSS Grid and the shape-outside property, it’s possible to do this and without a ton of hacks, too.

I also think it’s super cute that Adrian has made the code snippets in this post look like the display from an old monitor, like the one Chris recently broke down.

Direct Link to ArticlePermalink

The post A CSS Venn Diagram appeared first on CSS-Tricks.

Reversing an Easing Curve

Css Tricks - Mon, 12/17/2018 - 5:12am

Let’s take a look at a carousel I worked on where items slide in and out of view with CSS animations. To get each item to slide in and out of view nicely I used a cubic-bezier for the animation-timing-function property, instead of using a standard easing keyword.

See the Pen Carousel with reversed easing curve by Michelle Barker (@michellebarker) on CodePen.

A cubic-bezier can appear confusing at first glance, but when used correctly, it can add a nice touch to the user experience.

While building this carousel, I realized I not only needed a custom animation curve, but had to use it in reverse as well to get the effect right. I figured it was worth sharing what I learned because creating a custom curve and reversing it may seem tricky, but it’s actually pretty straightforward.

First, a primer on easing

Easing is the word used to describe the acceleration and deceleration of an animation’s progress along a timeline. We can plot this as a graph, where x is time and y is the animation’s progress. The graph for a linear animation, which has no acceleration or deceleration (it moves at the same speed all the way through), is a straight line:

Non-linear easing is what gives animations a more natural, life-like feel. We can apply easing to transitions and animations in CSS. The animation-timing-function property allows us to define the easing on an animation. (The same options are available for transition-timing-function.) We have four keywords to choose from:

  • linear – as described above
  • ease-in – the animation starts off slow and accelerates as it progresses
  • ease-out – the animation starts off fast and decelerates towards the end
  • ease-in-out – the animation starts off slowly, accelerates in the middle and slows down towards the end
  • ease – the default value, a variant on ease-in-out
  • Getting to know cubic-bezier

    If none of those options suit our animation, we can create a custom easing curve using the cubic-bezier function. Here’s an example:

    .my-element { animation-name: slide; animation-duration: 3s; animation-timing-function: cubic-bezier(0.45, 0.25, 0.60, 0.95); }

    If we prefer, we can write these properties as shorthand, like this:

    .my-element { animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95); }

    You’ll notice the cubic-bezier function takes four values. These are the two pairs of coordinates needed in order to plot our curve onto the graph. What do those coordinates represent? Well, if you’ve used vector illustration programs, like Illustrator, the idea of vector points and “handles” that control the size and direction of the curve might be familiar to you. This is essentially what we’re plotting with a cubic-bezier curve.

    We don’t need to know about all the maths behind cubic-bezier curves in order to create a nice animation. Luckily there are plenty of online tools, like cubic-bezier.com by Lea Verou, that allow us to visualize an easing curve and copy the values. This is what I did for the above easing curve, which looks like this:

    Here, we can see the two points we need to plot, where the cubic-bezier function is cubic-bezier(x1, y1, x2, y2).

    Applying easing in two directions

    My carousel rotates in both directions — if you click the left arrow, the current item slides out of view to the right, and the next item slides in from the left; and if you click the right arrow, the reverse happens. For the items to slide into or out of view, a class is added to each item, depending on whether the user has clicked the "next” or “previous” button. My initial assumption was that I could simply reverse the animation-direction for items sliding out in the opposite direction, like this:

    .my-element--reversed { animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95) reverse; }

    There’s just one problem: reversing the animation also reversed the easing curve! So, now my animation looks great in one direction, but is completely off in the other direction. Oh no!

    In this demo, the first box shows the initial animation (an item sliding left-to-right) and the second box shows what happens when the animation-direction is reversed.

    See the Pen Reverse animation by Michelle Barker (@michellebarker) on CodePen.

    You can see the two animations don’t have the same feel at all. The first box speeds up early on and slows down gently as it progresses, while the second box starts off quite sluggish, then gains a burst of speed before abruptly slowing down. This wouldn’t feel right at all for a carousel.

    We have a choice between two options to achieve this:

    1. We could create a new keyframe animation to animate the items out, and then apply the same easing as before. That’s not too hard in this example, but what if we have a more complex animation? It would take quite a bit more work to create the same animation in reverse, and we could easily make a mistake.
    2. We could use the same keyframe animation (with the animation-direction: reverse) and invert the easing curve so we get the same easing in both directions. This isn’t too hard to do, either.

    To reverse the easing curve for our reversed animation we need to rotate the curve 180 degrees on its axis and find the new coordinates.

    We can do this with some simple maths — by switching the coordinate pairs and subtracting each value from 1.

    To visualize this, imagine that our original values are:

    x1, y1, x2, y2

    Our reversed values will be:

    (1 - x2), (1 - y2), (1 - x1), (1 - y1)

    In this demo, the third box shows what we want to happen: the item sliding in the opposite direction, but with the easing reversed to give it the same feel.

    See the Pen CSS Variables to reverse easing by Michelle Barker (@michellebarker) on CodePen.

    Let’s walk through how we can calculate the reversed easing curve.

    Calculating the new curve with CSS variables

    We can use CSS variables to calculate the new curve for us! Lets assign each value to a variable:

    :root { --x1: 0.45; --y1: 0.25; --x2: 0.6; --y2: 0.95; --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2)); }

    Then we can use those variables to calculate the new values:

    :root { --reversedCurve: cubic-bezier(calc(1 - var(--x2)), calc(1 - var(--y2)), calc(1 - var(--x1)), calc(1 - var(--y1))); }

    Now, if we make any changes to the first set of variables, the reversed curve will be calculated automatically. To make this a bit easier to scan when examining and debugging our code, I like to break these new values out into their own variables:

    :root { /* Original values */ --x1: 0.45; --y1: 0.25; --x2: 0.6; --y2: 0.95; --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2)); /* Reversed values */ --x1-r: calc(1 - var(--x2)); --y1-r: calc(1 - var(--y2)); --x2-r: calc(1 - var(--x1)); --y2-r: calc(1 - var(--y1)); --reversedCurve: cubic-bezier(var(--x1-r), var(--y1-r), var(--x2-r), var(--y2-r)); }

    Now all that remains is to apply the new curve to our reversed animation:

    .my-element--reversed { animation: slide 3s var(--reversedCurve) reverse; }

    To help visualize this, I’ve built a little tool to calculate the reversed values of a cubic-bezier. Enter the original coordinate values to get the reversed curve:

    See the Pen Reverse cubic-bezier by Michelle Barker (@michellebarker) on CodePen.

    The post Reversing an Easing Curve appeared first on CSS-Tricks.

Annotated Build Processes

Css Tricks - Fri, 12/14/2018 - 5:59am

When you're putting together a build process for a site, it's so dang useful to look at other people's processes. I ran across Andrew Welch's "An Annotated webpack 4 Config for Frontend Web Development" the other day and was glad he blogged it. If I was kicking off a new site where I wanted a webpack build, then I'd almost certainly reference something like this rather than start from scratch. At the same time, it made me realize how build processes all have such different needs and how unique those needs are now from even a few years ago in the hay day of Grunt and Gulp build processes.

I was looking around for an annotated Gulp reference file and came across another one of Andrew's articles — "A Gulp Workflow for Frontend Development Automation" — from just one year earlier! Here's a simplified list of what he was doing with Gulp (which he explains in more detail in the post):

  • Compile Sass
  • Run Autoprefixer
  • Create Sourcemaps
  • Minify
  • Inject critical CSS and bits of scripts
  • Run Babel
  • Uglify
  • Do style injection/reloading
  • Run accessibility audit
  • Generate icon font
  • Optimize images

Speaking of Gulp and annotated build processes, I'm working on a CSS-Tricks redesign and, for various reasons, went with a Gulp build. Against my better judgment, I wrote it from scratch, and this is how far I've gotten. It doesn't feel particularly robust or efficient, so rewrites and suggestions are welcome! And speaking of Gulp, here's a recently-published boilerplate I wish I had seen before starting.

Now, a year later, here's what the build process is being asked to do:

  • Run differently-configured web servers
  • Hot module replacement
  • Dynamic code splitting
  • Lazy loading
  • Make modern and legacy code bundles
  • Cache busting
  • Create service worker
  • Compile PostCSS
  • Optimize images / create .webp
  • Process .vue files
  • Run Tailwind and PurgeCSS

It's funny how quickly things change. We're still essentially asking for help compiling files and optimizing things, but the tools we use change, the code we write changes, the way we talk about development changes, the expectations of development changes, the best practices change... makes ya sweat. &#x1f605;

The post Annotated Build Processes appeared first on CSS-Tricks.

Making SVG icon libraries for React apps

Css Tricks - Fri, 12/14/2018 - 5:20am

Nicolas Gallagher:

At Twitter I used the approach described here to publish the company’s SVG icon library in several different formats: optimized SVGs, plain JavaScript modules, React DOM components, and React Native components.

There is no One True Way© to make an SVG icon system. The only thing that SVG icon systems have in common is that, somehow, some way, SVG is used to show that icon. I gotta find some time to write up a post that goes into all the possibilities there.

One thing different systems tend to share is some kind of build process to turn a folder full of SVG files into a more programmatically digestible format. For example, gulp-svg-sprite takes your folder of SVGs and creates a SVG sprite (chunk of <symbol>s) to use in that type of SVG icon system. Grunticon processes your folder of SVGs into a CSS file, and is capable of enhancing them into inline SVG. Gallagher's script creates React components out of them, and like he said, that's great for delivery to different targets as well as performance optimization, like code splitting.

This speaks to the versatility of SVG. It's just markup, so it's easy to work with.

Direct Link to ArticlePermalink

The post Making SVG icon libraries for React apps appeared first on CSS-Tricks.

Two Ways to Build a Site That Seem Super Different But Weirdly Aren’t That Different

Css Tricks - Fri, 12/14/2018 - 5:16am

Here are two ways to build a site (abstractly) that feel diametrically opposed to me:

  1. Build a site as an SPA (Single Page App). The page loads a skeleton HTML page that executes JavaScript as quickly as it can. The JavaScript calls an API to get data, and then the page renders content. Navigation of the site is more API calls to get the data it needs and re-rendering.
  2. Build a site as statically-generated. A build process runs in which the entire site is built out as static HTML files with all the content baked into them. JavaScript isn't required at all for the site to work.

That feels just about as different as can be. But weirdly, they kinda aren't:

  1. They are both JAMstack. They can be hosted statically as neither of them needs backend languages running on the server they are hosted on.
  2. They are both building content based on an API of data. It's more obvious in the first one, but you can think of a static site generator as hitting an API of data as it runs and builds itself. It's just that the API might be temporarily created from content files it finds on disk. Or it might be the exact same API used for the former site.

That's all.

The post Two Ways to Build a Site That Seem Super Different But Weirdly Aren’t That Different appeared first on CSS-Tricks.

JavaScript to Native (and Back!)

Css Tricks - Thu, 12/13/2018 - 1:17pm

I admit I'm quite intrigued by frameworks that allow you write apps in web frameworks because they do magic to make them into native apps for you. There are loads of players here. You've got NativeScript, Cordova, PhoneGap, Tabris, React Native, and Flutter. For deskop apps, we've got Electron.

What's interesting now is to see what's important to these frameworks by honing in on their focus. Hummingbird is Flutter for the web. (There is a fun series on Flutter over on the Bendworks blog in addition to a post we published earlier this year.) The idea being you get super high performance ,thanks to the framework, and you've theoretically built one app that runs both on the web and natively. I don't know of any real success stories I can point to, but it does seem like an awesome possibility.

Nicolas Gallagher has been a strong proponent of React Native for the web.

The post JavaScript to Native (and Back!) appeared first on CSS-Tricks.

Rendering Lists Using React Virtualized

Css Tricks - Thu, 12/13/2018 - 5:20am

Working with data in React is relatively easy because React is designed to handle data as state. The hassle begins when the amount of data you need to consume becomes massive. For example, say you have to handle a dataset which is between 500-1,000 records. This can result in massive loads and lead performance problems. Well, we’re going to look at how we can make use of virtualized lists in React to seamlessly render a long list of data in your application.

We’re going to use the React Virtualized component to get what we need. It will allow us to take large sets of data, process them on the fly, and render them with little-to-no jank.

The setup

React Virtualized already has a detailed set of instructions to get it up and running, so please check out the repo to get started.

We’re going to want data to work with, so we will set up a function which uses faker to create a large data set.

function createRecord(count) { let records = []; for (let i = 0; i < count; i++) { records.push({ username: faker.internet.userName(), email: faker.internet.email() }); } return records; }

Next, we will pass it the number of data records we want to create, like so:

const records = createRecord(1000);

Alright, now we have what we need to work on rendering a list of those records!

Creating a virtualized list

Here’s the list we want to create, sans styling. We could make use of the few presentational styles that the library includes by importing the included CSS file, but we're going to leave that out in this post.

See the Pen React Virtualized 1 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Go ahead and re-run that demo. Crazy fast, right?

You might wonder what the heck React Virtualized is doing behind the scenes to make that happen. Turns out it's a bunch of crazy and cool sizing, positioning, transforms and transitions that allow the records to scroll in and out of view. The data is already there and rendered. React Virtualized creates a window frame that allows records to slide in and out of view as the user scrolls through it.

To render a virtualized list in React Virtualized, we make use of its List component, which uses a Grid component internally to render the list.

First, we start by setting up rowRenderer, which is responsible for displaying a single row and sets up an index that assigns an ID to each record.

rowRenderer = ({ index, isScrolling, key, style }) => { return ( <div key={key} style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> ); };

As you can see, this returns a single div node that contains two additional divs: one for the username and another for the email. You know, a common list pattern to display users.

rowRenderer accepts several parameters. Here’s what they are and what each one does:

  • index: The numeric ID of a record.
  • isScrolling: Indicates if the scrolling is occurring in the List component.
  • isVisible: Determines if a row is visible or out of view.
  • key: The records position in the array.
  • parent: Defines whether the list is a parent or a child of another list.
  • style: A style object to position the row.

Now that we know more about the rowRenderer function, let’s make put it to use in the List component:

<List rowCount={this.props.data.length} width={width} height={height} rowHeight={rowHeight} rowRenderer={this.rowRenderer} overscanRowCount={3} />

You may have noticed a few new parameters. Here’s what they are:

  • rowCount: This takes the numbers of a row in a list that we pass to calculate the length of our list.
  • width: The width of the list.
  • height: The height of the list.
  • rowHeight: This can be a number or a function that returns a row height given its index.
  • rowRenderer: This is responsible for rendering the row. the list is not supposed to be passed directly, so we pass the rowRenderer function that we created in this tutorial.
  • overscanRowCount: This is used to render additional rows in the direction the user scrolls. It reduces the chances of the user scrolling faster than the virtualized content is rendered.

At the end, your code should look something like this;

const { List } = ReactVirtualized ... const height = 700; const rowHeight = 40; const width = 800; class App extends React.Component { rowRenderer = ({ index, isScrolling, key, style }) => { return ( <div key={key} style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> ); }; render() { return ( <div> <h2>Details</h2> <List rowCount={this.props.data.length} width={width} height={height} rowHeight={rowHeight} rowRenderer={this.rowRenderer} overscanRowCount={3} /> </div> ); } } Cell measurer

According to the documentation, a cell measurer is a higher-order component that is used to temporarily render a list. It’s not yet visible to the user at this point, but the data is held and ready to display.

Why should you care about this? The popular use case is a situation where the value of your rowHeight is dynamic. React Virtualized can render the height of the row on render then cache that height so it no longer needs to calculate as data scrolls out of view — it's always the right height, no matter the content it contains!

First, we create our cache, which can be done in our component’s constructor using CellMeasurerCache:

constructor() { super() this.cache = new CellMeasurerCache({ fixedWidth: true, defaultHeight: 100 }) }

We make use of the cache when we set up the List component;

<List rowCount={this.props.data.length} width={rowWidth} height={listHeight} deferredMeasurementCache={this.cache} rowHeight={this.cache.rowHeight} rowRenderer={this.renderRow} overscanRowCount={3} />

The value passed to deferredMeasurementCache will be used to temporarily rendering the data, then — as the calculated value for rowHeight comes in — additional rows will flow in like they were always there.

Next, though, we will make use of React Virtualized’s CellMeasurer component inside our rowRenderer function instead of the div we initially set up as a placeholder:

rowRenderer = ({ index, parent, key, style }) => { return ( <CellMeasurer key={key} cache={this.cache} parent={parent} columnIndex={0} rowIndex={index} > <div style={style}> <div>{this.props.data[index].username}</div> <div>{this.props.data[index].email}</div> </div> </CellMeasurer> ); };

Now the data is fetched, cached and ready to display in the virtual window at will!

Virtualized table

Yeah, so the main point of this post is to cover lists, but what if we actually want to render data to a table instead? React Virtualized has you covered on that front, too. In this case, we will make use of Table and Column components that come baked into React Virtualized.

Here’s how we would put those components to use in our primary App component:

class App extends React.Component { render() { return ( <div> <h2>Details</h2> <Table width={500} height={300} headerHeight={20} rowHeight={40} rowCount={this.props.data.length} rowGetter={({ index }) => this.props.data[index]} > <Column label='Username' dataKey='username' width={100} /> <Column width={200} label='Email' dataKey='email' /> </Table> </div> ); } }

The Table component accepts the following parameters:

  • width: The width of the table.
  • height: The height of the table.
  • headerHeight: The table header height.
  • rowHeight: The height of a row given its index.
  • rowCount: This is the initial number of rows we want in the table. It’s the same as the way we defined the number of records we wanted to start with in the List component example.
  • rowGetter: This returns the data of a specific row by its index.

If you take a look at the Column component, you will notice that we put a dataKey parameter to use. That passes the data for each column we called in the dataKey, which receives a unique identifier for that data. Remember that in the function where we create our random data, we make use of two keys; username and email. This is why we have the dataKey of one column set as username and the other set as email.

In conclusion

Hopefully, this walkthrough gives you a good idea of what React Virtualized is capable of doing, how it can make rendering large data sets into lists and tables super fast, and how to put it to use in a project.

We've only scratched the surface here. The library is capable of handling a lot of other use cases, like generating placeholders for the data records on scroll, an infinite loading component to fetch and cache data in real-time, a method for allowing arrow keys to navigate through the data, and a slick grid and masonry layouts that we didn't even cover here.

That should give you a lot to play around with!

Plus, the package is highly maintained. In fact, you can join the Slack group to keep up with the project, contribute to it, and generally get to connect with other folks.

It’s also worth noting that React Virtualized has it own tag in StackOverflow and that can be a good resource to find questions other people have asked about it, or even post your own questions.

Oh, and if you’ve put React Virtualized to use on a project, we’d love to know it! Share it with us in the comments with some notes on how you approached it or what you learned from it.

The post Rendering Lists Using React Virtualized appeared first on CSS-Tricks.

Level up your JavaScript error monitoring

Css Tricks - Thu, 12/13/2018 - 5:16am

(This is a sponsored post.)

Automatically detect and diagnose JavaScript errors impacting your users with Bugsnag. Get comprehensive diagnostic reports, know immediately which errors are worth fixing, and debug in a fraction of the time.

Bugsnag detects every single error and prioritizes errors with the greatest impact on your users. Get support for 50+ platforms and integrate with the development and productivity tools your team already uses.

Bugsnag is used by the world's top engineering teams including Airbnb, Slack, Pinterest, Lyft, Square, Yelp, Shopify, Docker, and Cisco. Start your free trial today.

Direct Link to ArticlePermalink

The post Level up your JavaScript error monitoring appeared first on CSS-Tricks.

Keep Math in the CSS

Css Tricks - Wed, 12/12/2018 - 7:22am

There is a sentiment that leaving math calculations in your CSS is a good idea that I agree with. This is for math that you could calculate at authoring time, but specifically chose not to. For instance, if you needed a 7-column float-based grid (don't ask), it's cleaner and more intuitive:

.col { /* groan */ width: 14.2857142857%; /* oh, I get it */ width: calc(100% / 7); }

You could probably prove that the calc() takes the computer 0.0000001% longer, so explicitly defining the width is technically faster for performance reason — but that is about the equivalent of not using punctuation in sentences because it saves HTML weight.

That math can be a little more complicated as you continue. For example, like in our use cases for calc() article, what about columns in that 7-column grid that span?

.column-1-7 { width: calc(100% / 7); } .column-2-7 { width: calc(100% / 7 * 2); } .column-3-7 { width: calc(100% / 7 * 3); }

I'd say that's rather clean to read and manage.

The readability of the math can be enhanced by comments if it gets too complicated. Say you are trying to account for a margin-based gutter with padding inside of an element:

.parent { width: 600px; padding: 18px; } .left { /* base width - 1/2 horizontal padding */ width: calc(400px - 18px); margin-right: 1rem; /* gutter */ } .right { /* base width - 1/2 horizontal padding - gutter */ width: calc(200px - 1rem - 18px); }

Again, I'd say that's pretty readable, but it's also a good amount of repetition. This might call for using variables. We'll do it with CSS custom properties for fun. You have to pick what is worthy of a variable and what isn't. You might need fewer comments as the code becomes somewhat self-documenting:

.parent { --padding: 18px; --gutter: 1rem; width: 600px; padding: var(--padding); } .left { width: calc(400px - var(--padding)); margin-right: var(--gutter); } .right { width: calc(200px - var(--gutter) - var(--padding)); }

That is a decent balance to me. Here's a step further:

.parent { --padding: 18px; --gutter: 1rem; --parentWidth: 600px; --leftSize: 2/3; --rightSize: 1/3; width: var(--parentWidth); padding: var(--padding); } .left { width: calc(calc(var(--parentWidth) * var(--leftSize)) - var(--padding)); margin-right: var(--gutter); } .right { width: calc(calc(var(--parentWidth) * var(--rightSize)) - var(--gutter) - var(--padding)); }

Every single number has been given a variable in there. Too far? Maybe. It certainly makes those width declarations pretty hard to wrap your head around quickly. Ana Tudor does some serious stuff with calc(), as proof that everyone's comfort level with this stuff is different.

One of the things that made me think of all this is a recent article from James Nash — "Hardcore CSS calc()" — where he builds this:

While the solution took a heavily math-y road to get there, it ends up being only sort of medium-level calculation on the ol' complexity meter. And note that not everything gets a variable' only the most re-used bits:

See the Pen Fluid 1 + 2 thumbnail block by James Nash (@cirrus) on CodePen.

The post Keep Math in the CSS appeared first on CSS-Tricks.

Web Designs That Feel Like Ancient History, but Are More Recent Than You Think

Css Tricks - Wed, 12/12/2018 - 5:03am

Flickr announced not long ago that they are limiting free accounts to 1,000 photos. I don't particularly mind that (because it seems like sound business sense), although it is a bit sad that a ton of photos will be nuked from the internet. I imagine the Internet Archive will swoop in and get most of it. And oh hey, the Twitter account @FlickrJubilee is showcasing Flickr users that could really use a gifted pro account so their amazing photos are not lost, if you're feeling generous and want to contribute.

This change doesn't affect pro accounts. I've been pro forever on Flickr, so my photos were never at risk, but the big change has me thinking it's about time to spin down Flickr for myself. I've been keeping all my photos on iCloud/Photos for years now anyway so it seems kind redundant to keep Flickr around.

I went into the Flickr settings and exported all my photos, got a bunch of gigabytes of exported photos, and loaded them into Photos. Sadly, the exported photos have zero metadata, so there will forever be this obnoxious chunk of thousands upon thousands of photos in my Photos collection that all look like they were taken on the same day and with no location.

Anyway, that was way too long of an intro to say: I found a bunch of old website screenshots! Not a ton, but it looks like I used Flickr to store a handful of web designs I found interesting in some way a number of years back. What's interesting today is how dated they look when they were created not that long ago. Shows how fast things change.

Here they are.

It's not terribly surprising to me to hear people push back on the same-ness of web design these days, and to blame things like frameworks, component-driven architecture, and design systems for it. It wasn't long ago when it seemed like we were trying harder to be fancy and unique with our designs — things like shadow treatments, reflective images and skeuomorphic enhancements. I don't mean to make sweeping generalizations here... merely a difference between what we considered to be boring and fancy work back than compared to now, of course.

The post Web Designs That Feel Like Ancient History, but Are More Recent Than You Think appeared first on CSS-Tricks.

Prototypes and production

Css Tricks - Tue, 12/11/2018 - 11:19am

There’s an interesting distinction that Jeremy Keith defines between prototype code and production code in this post and I’ve been thinking about it all week:

...every so often, we use the materials of front-end development—HTML, CSS, and JavaScript—to produce something that isn’t intended for production. I’m talking about prototyping.

What’s interesting is that—when it comes to prototyping—our usual front-end priorities can and should go out the window. The priority now is speed. If that means sacrificing semantics or performance, then so be it. If I’m building a prototype and I find myself thinking “now, what’s the right class name for this component?”, then I know I’m in the wrong mindset. That question might be valid for production code, but it’s a waste of time for prototypes.

I love the way that Jeremy phrases all of this and how he describes that these two environments require entirely separate mindsets. When prototyping, for instance, we can probably overlook optimizing for accessibility or performance and even let our CSS standards slip in order to get something in the browser and test it as quickly as possible.

Earlier this year, I echoed some of the same thoughts when I wrote a little bit about prototyping in the browser:

I reckon that the first time a designer and/or front-end developer writes code, it should never be in a production environment. Having the leeway and freedom to go crazy with the code in a safe environment focuses your attention on the design and making it compatible with a browser’s constraints. After this, you can think about grooming the code from a hot, steaming heap of garbage into lovely, squeaky-clean, production-ready poetry. Translating the static mockups into an interactive prototype is the first step, but it’s vital to have a next step to enforce your code standards.

Direct Link to ArticlePermalink

The post Prototypes and production appeared first on CSS-Tricks.

Creating an Animated Login Form for TouchID

Css Tricks - Tue, 12/11/2018 - 5:07am

I came across this amazing Dribbble shot by Jakub Reis a while back. It caught my eye and I knew that I just had to try recreating it in code. At that moment, I didn’t know how. I tried out a bunch of different things, and about a year later, I finally managed to make this demo.

I learned a couple of things along the way, so let me take you on a little journey of what I did to make this because you may learn a thing or two as well.

See the Pen Opening screen for a banking app by Kirill Kiyutin (@kiyutink) on CodePen.

Step 1: Split the work into parts

I watched the original GIF many times. My goal was to split the animation into small, digestible chunks and I was able to break it down like this:

I know, it looks a lot — but we can do this!

Step 2: Take the original demo apart frame-by-frame

I needed to extract as much info as I could out of the original GIF to have a good understanding of the animation, so I split it up into single frames. There actually are a lot of services that can do this for us. I used one at ezgif.com but it could have just as easily been something else. Either way, this enables us to get details such as the colors, sizes, and proportions of all the different elements we need to create.

Oh, and we still need to turn the fingerprint into an SVG. Again, there are plenty of apps that will help us here. I used Adobe Illustrator to trace the fingerprint with the pen tool to get this set of paths:

See the Pen css-t. paths by Kirill Kiyutin (@kiyutink) on CodePen.

We’ll go through the same process with the line chart that appears towards the end of the animation, so might as well keep that vector editor open. &#x1f642;

Step 3: Implement the animations

I’ll explain how the animations work in the final pen, but you can also find some of the unsuccessful approaches I took along the way in the end of the article.

I’ll focus on the important parts here and you can refer to the demos for the full code.

Filling the fingerprint

Let’s create the HTML structure of the phone screen and the fingerprint.

<div class="demo"> <div class="demo__screen demo__screen--clickable"> <svg class="demo__fprint" viewBox="0 0 180 320"> <!-- removes-forwards and removes-backwards classes will be helpful later on --> <path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M46.1,214.3c0,0-4.7-15.6,4.1-33.3"/> <path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M53.5,176.8c0,0,18.2-30.3,57.5-13.7"/> <path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M115.8,166.5c0,0,19.1,8.7,19.6,38.4"/> <!-- ... and about 20 more paths like this --> </svg>

The styles are quite simple so far. Note that I am using Sass throughout the demo — I find that it helps keep the work clean and helps with some of the heavier lifting we need to do.

// I use a $scale variable to quickly change the scaling of the whole pen, so I can focus on the animation and decide on the size later on. $scale: 1.65; $purplish-color: #8742cc; $pinkish-color: #a94a8c; $bg-color: #372546; // The main container .demo { background: linear-gradient(45deg, lighten($pinkish-color, 10%), lighten($purplish-color, 10%)); min-height: 100vh; display: flex; justify-content: center; align-items: center; font-size: 0; user-select: none; overflow: hidden; position: relative; // The screen that holds the login component &__screen { position: relative; background-color: $bg-color; overflow: hidden; flex-shrink: 0; &--clickable { cursor: pointer; -webkit-tap-highlight-color: transparent; } } // Styles the fingerprint SVG paths &__fprint-path { stroke-width: 2.5px; stroke-linecap: round; fill: none; stroke: white; visibility: hidden; transition: opacity 0.5s ease; &--pinkish { stroke: $pinkish-color; } &--purplish { stroke: $purplish-color; } } // Sizes positions the fingerprint SVG &__fprint { width: 180px * $scale; height: 320px * $scale; position: relative; top: 20px * $scale; overflow: visible; // This is going to serve as background to show "unfilled" paths. we're gonna remove it at the moment where the filling animation is over background-image: url('https://kiyutink.github.io/svg/fprintBackground.svg'); background-size: cover; &--no-bg { background-image: none; } } }

Now the hard part: making the fingerprint interactive. You can read about the animation of SVG lines here. That’s the method we’ll use to fill in each individual path.

Let’s create a class that describes a path element so that it’s easier to manipulate the paths later on.

class Path { constructor(selector, index) { this.index = index; this.querySelection = document.querySelectorAll(selector)[index]; this.length = this.querySelection.getTotalLength(); this.$ = $(selector).eq(index); this.setDasharray(); this.removesForwards = this.$.hasClass('demo__fprint-path--removes-forwards'); } setDasharray() { this.$.css('stroke-dasharray', `${this.length} ${this.length + 2}`); return this; } offset(ratio) { this.$.css('stroke-dashoffset', -this.length * ratio + 1); return this; } makeVisible() { this.$.css('visibility', 'visible'); return this; } }

The general idea is this: Create an instance of this class for each path that we have in the fingerprint, and modify them in every frame. The paths will start with an offset ratio of -1 (fully invisible) and then will increase the offset ratio (which we’ll refer to as “offset” from here on) by a constant value each frame until they get to 0 (fully visible). The filling animation will be over at this point.

If you’ve never animated anything with this frame-by-frame approach, here’s a very simple demo to help understand how this works:

See the Pen 60fps raf animation proof of concept by Kirill Kiyutin (@kiyutink) on CodePen.

We should also handle the case where the user stops tapping or pressing the mouse button. In this case, we will animate in the opposite direction (subtracting a constant value from the offset each frame until it gets to -1 again).

Let’s create the function that calculates the offset increment for every frame — this’ll be useful later on.

function getPropertyIncrement(startValue, endValue, transitionDuration) { // We animate at 60 fps const TICK_TIME = 1000 / 60; const ticksToComplete = transitionDuration / TICK_TIME; return (endValue - startValue) / ticksToComplete; }

Now it’s time to animate! We will keep the fingerprint paths in a single array:

let fprintPaths = []; // We create an instance of Path for every existing path. // We don't want the paths to be visible at first and then // disappear after the JavaScript runs, so we set them to // be invisible in CSS. That way we can offset them first // and then make them visible. for (let i = 0; i < $(fprintPathSelector).length; i++) { fprintPaths.push(new Path(fprintPathSelector, i)); fprintPaths[i].offset(-1).makeVisible(); }

We will go through that array for each frame in the animation, animating the paths one by one:

let fprintTick = getPropertyIncrement(0, 1, TIME_TO_FILL_FPRINT); function fprintFrame(timestamp) { // We don't want to paint if less than 1000 / 65 ms elapsed // since the last frame (because there are faster screens // out there and we want the animation to look the same on // all devices). We use 65 instead of 60 because, even on // 60 Hz screens, `requestAnimationFrame` can sometimes be called // a little sooner, which can result in a skipped frame. if (timestamp - lastRafCallTimestamp >= 1000 / 65) { lastRafCallTimestamp = timestamp; curFprintPathsOffset += fprintTick * fprintProgressionDirection; offsetAllFprintPaths(curFprintPathsOffset); } // Schedule the next frame if the animation isn't over if (curFprintPathsOffset >= -1 && curFprintPathsOffset <= 0) { isFprintAnimationInProgress = true; window.requestAnimationFrame(fprintFrame); } // The animation is over. We can schedule next animation steps else if (curFprintPathsOffset > 0) { curFprintPathsOffset = 0; offsetAllFprintPaths(curFprintPathsOffset); isFprintAnimationInProgress = false; isFprintAnimationOver = true; // Remove the background with grey paths $fprint.addClass('demo__fprint--no-bg'); // Schedule the next animation step - transforming one of the paths into a string // (this function is not implemented at this step yet, but we'll do that soon) startElasticAnimation(); // Schedule the fingerprint removal (removeFprint function will be implemented in the next section) window.requestAnimationFrame(removeFprint); } // The fingerprint is back to the original state (the user has stopped holding the mouse down) else if (curFprintPathsOffset < -1) { curFprintPathsOffset = -1; offsetAllFprintPaths(curFprintPathsOffset); isFprintAnimationInProgress = false; } }

And we’ll attach some event listeners to the demo:

$screen.on('mousedown touchstart', function() { fprintProgressionDirection = 1; // If the animation is already in progress, // we don't schedule the next frame since it's // already scheduled in the `fprintFrame`. Also, // we obviously don't schedule it if the animation // is already over. That's why we have two separate // flags for these conditions. if (!isFprintAnimationInProgress && !isFprintAnimationOver) window.requestAnimationFrame(fprintFrame); }) // On `mouseup` / `touchend` we flip the animation direction $(document).on('mouseup touchend', function() { fprintProgressionDirection = -1; if (!isFprintAnimationInProgress && !isFprintAnimationOver) window.requestAnimationFrame(fprintFrame); })

...and now we should be done with the first step! Here’s how our work looks at this step:

See the Pen css-t. step 1 by Kirill Kiyutin (@kiyutink) on CodePen.

Removing the fingerprint

This part is pretty similar to the first one, only now we have to account for the fact that some of the paths remove in one direction and the rest of them in the other. That’s why we added the --removes-forwards modifier earlier.

First, we’ll have two additional arrays: one for the paths that are removed forwards and another one for the ones that are removed backwards:

const fprintPathsFirstHalf = []; const fprintPathsSecondHalf = []; for (let i = 0; i < $(fprintPathSelector).length; i++) { // ... if (fprintPaths[i].removesForwards) fprintPathsSecondHalf.push(fprintPaths[i]); else fprintPathsFirstHalf.push(fprintPaths[i]); }

...and we’ll write a function that offsets them in the right direction:

function offsetFprintPathsByHalves(ratio) { fprintPathsFirstHalf.forEach(path => path.offset(ratio)); fprintPathsSecondHalf.forEach(path => path.offset(-ratio)); }

We’re also going to need a function that draws the frames:

function removeFprintFrame(timestamp) { // Drop the frame if we're faster than 65 fps if (timestamp - lastRafCallTimestamp >= 1000 / 65) { curFprintPathsOffset += fprintTick * fprintProgressionDirection; offsetFprintPathsByHalves(curFprintPathsOffset); lastRafCallTimestamp = timestamp; } // Schedule the next frame if the animation isn't over if (curFprintPathsOffset >= -1) window.requestAnimationFrame(removeFprintFrame); else { // Due to the floating point errors, the final offset might be // slightly less than -1, so if it exceeds that, we'll just // assign -1 to it and animate one more frame curFprintPathsOffset = -1; offsetAllFprintPaths(curFprintPathsOffset); } } function removeFprint() { fprintProgressionDirection = -1; window.requestAnimationFrame(removeFprintFrame); }

Now all that’s left is to call removeFprint when we’re done filling the fingerprint:

function fprintFrame(timestamp) { // ... else if (curFprintPathsOffset > 0) { // ... window.requestAnimationFrame(removeFprint); } // ... }

Let’s check our work now:

See the Pen css-t. part 2 by Kirill Kiyutin (@kiyutink) on CodePen.

Animating the path ends

You can see that, as the fingerprint is almost removed, some of its paths are longer than they were in the beginning. I moved them into separate paths that start animating at the right moment. I could incorporate them into the existing paths, but it would be much harder and at 60fps would make next-to-no difference.

Let’s create them:

<path class="demo__ending-path demo__ending-path--pinkish" d="M48.4,220c-5.8,4.2-6.9,11.5-7.6,18.1c-0.8,6.7-0.9,14.9-9.9,12.4c-9.1-2.5-14.7-5.4-19.9-13.4c-3.4-5.2-0.4-12.3,2.3-17.2c3.2-5.9,6.8-13,14.5-11.6c3.5,0.6,7.7,3.4,4.5,7.1"/> <!-- and 5 more paths like this -->

...and apply some basic styles:

&__ending-path { fill: none; stroke-width: 2.5px; stroke-dasharray: 60 1000; stroke-dashoffset: 61; stroke-linecap: round; will-change: stroke-dashoffset, stroke-dasharray, opacity; transform: translateZ(0); transition: stroke-dashoffset 1s ease, stroke-dasharray 0.5s linear, opacity 0.75s ease; &--removed { stroke-dashoffset: -130; stroke-dasharray: 5 1000; } &--transparent { opacity: 0; } &--pinkish { stroke: $pinkish-color; } &--purplish { stroke: $purplish-color; } }

Now, we have to add the --removed modifier to flow these paths in at the right moment:

function removeFprint() { $endingPaths.addClass('demo__ending-path--removed'); setTimeout(() => { $endingPaths.addClass('demo__ending-path--transparent'); }, TIME_TO_REMOVE_FPRINT * 0.9); // ... }

Now our work is really starting to take shape:

See the Pen css-t. part 3 by Kirill Kiyutin (@kiyutink) on CodePen.

Morphing the fingerprint

OK, I found this part to be really hard to do on my own, but it’s really easy to implement with GSAP’s morphSVG plugin.

Let’s create the invisible paths (well, a path and a line to be exact &#x1f642;) that will be the keyframes for our string:

<line id='demo__straight-path' x1="0" y1="151.3" x2="180" y2="151.3"/> <path class="demo__hidden-path" id='demo__arc-to-top' d="M0,148.4c62.3-13.5,122.3-13.5,180,0"/>

Then we’ll use morphSVG to transition the path in between the keyframes:

const $elasticPath = $('#demo__elastic-path'); const ELASTIC_TRANSITION_TIME_TO_STRAIGHT = 250; const WOBBLE_TIME = 1000; function startElasticAnimation() { $elasticPath.css('stroke-dasharray', 'none'); const elasticAnimationTimeline = new TimelineLite(); elasticAnimationTimeline .to('#demo__elastic-path', ELASTIC_TRANSITION_TIME_TO_STRAIGHT / 1000, { delay: TIME_TO_REMOVE_FPRINT / 1000 * 0.7, morphSVG: '#demo__arc-to-top' }) .to('#demo__elastic-path', WOBBLE_TIME / 1000, { morphSVG: '#demo__straight-path', // I played with the easing a bit to get that "vibration" effect ease: Elastic.easeOut.config(1, 0.3) }) }

We’ll call this function inside the fprintFrame once the fingerprint is filled:

function fprintFrame(timestamp) { // ... else if (curFprintPathsOffset > 0) { // ... startElasticAnimation(); // ... } // ... }

The outcome is this:

See the Pen css-t. part 4 by Kirill Kiyutin (@kiyutink) on CodePen.

Animating the floating bullet

For this, I used some simple straightforward CSS animations. I chose the timing functions to emulate the gravity. You can play around with the timing functions here or here.

Let’s create a div:

<div class="demo__bullet"></div>

...and apply some styles to it:

&__bullet { position: absolute; width: 4px * $scale; height: 4px * $scale; background-color: white; border-radius: 50%; top: 210px * $scale; left: 88px * $scale; opacity: 0; transition: all 0.7s cubic-bezier(0.455, 0.030, 0.515, 0.955); will-change: transform, opacity; // This will be applied after the bullet has descended, to create a transparent "aura" around it &--with-aura { box-shadow: 0 0 0 3px * $scale rgba(255, 255, 255, 0.3); } // This will be applied to make the bullet go up &--elevated { transform: translate3d(0, -250px * $scale, 0); opacity: 1; } // This will be applied to make the bullet go down &--descended { transform: translate3d(0, 30px * $scale, 0); opacity: 1; transition: all 0.6s cubic-bezier(0.285, 0.210, 0.605, 0.910); } }

Then we tie it together by adding and removing classes based on a user’s interactions:

const DELAY_TO_BULLET_AURA = 300; const ELEVATION_TIME = 700; const DELAY_AFTER_ELEVATION = 700; const $bullet = $('.demo__bullet'); function elevateBullet() { $bullet.addClass('demo__bullet--elevated'); } function descendBullet() { $bullet.addClass('demo__bullet--descended').removeClass('demo__bullet--elevated'); animateBulletAura(); } function animateBulletAura() { setTimeout(() => $bullet.addClass('demo__bullet--with-aura'), DELAY_TO_BULLET_AURA); } function animateBullet() { elevateBullet(); $screen.removeClass('demo__screen--clickable'); setTimeout(descendBullet, ELEVATION_TIME + DELAY_AFTER_ELEVATION); }

Now, we need to call the animateBullet function:

function startElasticAnimation() { // ... animateBullet(); }

Here’s where we are at this point:

See the Pen css-t. part 5 by Kirill Kiyutin (@kiyutink) on CodePen.

Morphing the string into a graph

Now, let’s turn that string into a graph where the bullet can land. We’ll add another keyframe to the morphSVG animation.

<path class="demo__hidden-path" id='demo__curve' d="M0,140.2c13.1-10.5,34.7-17,48.5-4.1c5.5,5.2,7.6,12.1,9.2,19.2c2.4,10.5,4.3,21,7.2,31.4c2.4,8.6,4.3,19.6,10.4,26.7c4.3,5,17.7,13.4,23.1,4.8c5.9-9.4,6.8-22.5,9.7-33c4.9-17.8,13-14.6,15.7-14.6c1.8,0,9,2.3,15.4,5.4c6.2,3,11.9,7.7,17.9,11.2c7,4.1,16.5,9.2,22.8,6.6"/>

We add this keyframe into our timeline like this:

const DELAY_TO_CURVE = 350; const ELASTIC_TRANSITION_TIME_TO_CURVED = 300; function startElasticAnimation() { // ... elasticAnimationTimeline // ... .to('#demo__elastic-path', ELASTIC_TRANSITION_TIME_TO_CURVED / 1000, { delay: DELAY_TO_CURVE / 1000, morphSVG: '#demo__curve' }) // ... }

Here’s what we get:

See the Pen css-t. part 6 by Kirill Kiyutin (@kiyutink) on CodePen.

Exploding the particles

This is a fun animation. First, we’ll create a couple of new divs that contain the particles that explode:

<div class="demo__logo-particles"> <div class="demo__logo-particle"></div> <!-- and several more of these --> </div> <div class="demo__money-particles"> <div class="demo__money-particle"></div> <!-- and several more of these --> </div>

The two explosions are practically the same with the exception of a few parameters. That’s where SCSS mixins will come in handy. We can write the function once and use it on our divs.

@mixin particlesContainer($top) { position: absolute; width: 2px * $scale; height: 2px * $scale; left: 89px * $scale; top: $top * $scale; // We'll hide the whole container to not show the particles initially opacity: 0; &--visible { opacity: 1; } } // The $sweep parameter shows how far from the center (horizontally) the initial positions of the particles can be @mixin particle($sweep, $time) { width: 1.5px * $scale; height: 1.5px * $scale; border-radius: 50%; background-color: white; opacity: 1; transition: all $time ease; position: absolute; will-change: transform; // Phones can't handle the particles very well :( @media (max-width: 400px) { display: none; } @for $i from 1 through 30 { &:nth-child(#{$i}) { left: (random($sweep) - $sweep / 2) * $scale + px; @if random(100) > 50 { background-color: $purplish-color; } @else { background-color: $pinkish-color; } } &--exploded:nth-child(#{$i}) { transform: translate3d((random(110) - 55) * $scale + px, random(35) * $scale + px, 0); opacity: 0; } } }

Note the comment in the code that the particles don’t perform particularly well on less powerful devices such as phones. Perhaps there’s another approach here that would solve this if anyone has ideas and wants to chime in.

Alright, let’s put the mixins to use on the elements:

&__logo-particles { @include particlesContainer(15px); } &__logo-particle { @include particle(50, 1.7s); } &__money-particles { @include particlesContainer(100px); } &__money-particle { @include particle(100, 1.5s); }

Now we add the classes to the divs at the right time in JavaScript:

const DELAY_TO_ANIMATE_MONEY_PARTICLES = 300; const DELAY_TO_ANIMATE_LOGO_PARTICLES = 500; const $moneyParticles = $('.demo__money-particle'); const $moneyParticlesContainer = $('.demo__money-particles'); const $logoParticlesContainer = $('.demo__logo-particles'); const $logoParticles = $('.demo__logo-particle'); function animateMoneyParticles() { setTimeout(() => { $moneyParticlesContainer.addClass('demo__money-particles--visible') $moneyParticles.addClass('demo__money-particle--exploded'); }, DELAY_TO_ANIMATE_MONEY_PARTICLES); } function animateLogoParticles() { setTimeout(() => { $logoParticlesContainer.addClass('demo__logo-particles--visible') $logoParticles.addClass('demo__logo-particle--exploded'); }, DELAY_TO_ANIMATE_LOGO_PARTICLES); } function elevateBullet() { // ... animateMoneyParticles(); animateLogoParticles(); }

Here’s where we’re at:

See the Pen css-t. part 7 by Kirill Kiyutin (@kiyutink) on CodePen.

Animating the account balance

Every digit will have a few random numbers that we’ll scroll through:

<div class="demo__money"> <div class="demo__money-currency">$</div> <!-- every digit will be a div like this one --> <div class="demo__money-digit"> 1 2 3 4 5 6 7 8 1 </div> // ... </div>

We will put different transition times on all of the digits so that the animations are staggered. We can use a SCSS loop for that:

&__money-digit { // ... // we start from 2 because the first child is the currency sign :) @for $i from 2 through 6 { &:nth-child(#{$i}) { transition: transform 0.1s * $i + 0.2s ease; transition-delay: 0.3s; transform: translate3d(0, -26px * $scale * 8, 0); } &--visible:nth-child(#{$i}) { transform: none; } } }

All that’s left is to add the CSS classes at the right time:

const $money = $('.demo__money'); const $moneyDigits = $('.demo__money-digit'); function animateMoney() { $money.addClass('demo__money--visible'); $moneyDigits.addClass('demo__money-digit--visible'); } function descendBullet() { // ... animateMoney(); // ... }

Now sit back and marvel at our work:

See the Pen css-t. part 8 by Kirill Kiyutin (@kiyutink) on CodePen.

The rest of the animations are fairly simple and involve light CSS transitions, so I won’t get into them to keep things brief. You can see all of the final code in the completed demo.

View Demo

Some final words
  • In my early attempts I tried using CSS transitions for all of the animation work. I found it virtually impossible to control the progress and direction of the animation, so shortly I abandoned that idea and waited a month or so before starting again. In reality, if I knew back then that the Web Animations API was a thing, I would have tried to make use of it.
  • I tried making the explosion with Canvas for better performance (using this article as a reference), but I found it difficult to control the frame rate with two separate requestAnimationFrame chains. If you know how to do that, then maybe you can tell me in the comments (or write an article for CSS-Tricks &#x1f642;).
  • After I got a first working prototype, I was really unhappy with its performance. I was hitting around 40-50fps on a PC, not to mention phones at all. I spent a lot of time optimizing the code and this article was a lot of help.
  • You can see that the graph has a gradient. I did that by declaring a gradient directly in the SVG defs block:
<defs> <linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#8742cc"/> <stop offset="100%" stop-color="#a94a8c"/> </linearGradient> </defs>

...and then applied it in the CSS properties:

fill: url(#linear); stroke: url(#linear);

The whole process from start to finish — discovering the Dribbble shot and finishing the work — took me about a year. I was taking month-long breaks here and there either because I didn’t know how to approach a particular aspect or I simply didn’t have enough free time to work on it. The entire process was a really valuable experience and I learned a lot of new things along the way.

That being said, the biggest lesson to take away from this is that there’s no need to shy away from taking on an ambitious task, or feel discouraged if you don’t know how to approach it at first. The web is a big place and there is plenty of space to figure things out as you go along.

The post Creating an Animated Login Form for TouchID appeared first on CSS-Tricks.

What makes someone a good front-end developer?

Css Tricks - Tue, 12/11/2018 - 5:06am

We recently covered this exact same thing, but from the perspective of a bunch of developers.

Chris Ferdinandi weighs in:

The least important skills for a front-end developer to have are technical ones.

The nuances of JavaScript. How to use a particular library, framework, or build tool. How the cascade in CSS works. Semantic HTML. Fizz-buzz.

Chris takes that a little farther than I would. I do think that with an understanding of HTML, CSS, and JavaScript, the deeper the better, and that it is an ingredient in making a good front-end developer. But I also agree it's much more than that. In fact, with solid foundational skills and really good soft skills (e.g. you're great at facilitating a brainstorming meeting), you could and should get a job before they even look at your language skills.

Direct Link to ArticlePermalink

The post What makes someone a good front-end developer? appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.