Finger-friendly numerical inputs with `inputmode`

Forms are often a nightmare on mobile. We can make the process as pain-free as possible by reacting to context. Input fields that expect numerical values should have a numerical most) larger screens, number inputs come with an incrementer/decrementer button. It’s a useful piece of UI we get for free by default. It does, however, make this kind of input totally inappropriate for a credit card number, for example.

A default number input that displays the up and down arrows that allow users to increase and decrease numbers in the field.
The default UI for number inputs looks something like this in all desktop browsers

The spec itself makes this clear.

The type=number state is not appropriate for input that happens to only consist of numbers but isn’t strictly speaking a number. For example, it would be inappropriate for credit card numbers or US postal codes. A simple way of determining whether to use type=number is to consider whether it would make sense for the input control to have a spinbox interface (e.g., with “up” and “down” arrows). Getting a credit card number wrong by 1 in the last digit isn’t a minor mistake, it’s as wrong as getting every digit incorrect. So it would not make sense for the user to select a credit card number using “up” and “down” buttons. When a spinbox interface is not appropriate, type=text is probably the right choice (possibly with a pattern attribute).

It’s easy to hide the up and down buttons with CSS:

input[type="number"] { -moz-appearance: textfield;
}
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

It’s important to note that this isn’t the only difference between a number and text input. You should definitely follow the spec on this point! Some older browsers will strip out leading zeros for number inputs which would be a big problem for US ZIP codes. The often-useful maxlength attribute is ignored on number inputs.

Why would anybody dislike such a useful input?

The answer comes down to validation and using the input for the wrong thing. The number input performs input sanitization by default. If a user enters anything that isn’t a valid number, the value will be equal to an empty string — regardless of what the user can see on the screen.

This input sanitization can trip developers up, and there’s no way to turn it off. If you want to allow input that isn’t a valid number, don’t use type="number".

A screenshot showing a number input that is filled with numbers and includes dashes between some of the numbers.
Number input in Chrome. This might be valid input for your use case, but it’s illegitimate in the eyes of the number input.
var numberinput = document.querySelector('input[type="number"]')
numberinput.value // will be ""

This might not be what you would intuitively expect. However, if you follow the spec and only use the number input for what its designed for — actual numbers — this behavior is unproblematic.

Number Input Alternatives

iOS Solution: Use the `pattern` Attribute on a Text Input

On iOS devices, using the pattern attribute with a value of [0-9]* will bring up the numeric keypad. This only works with this exact pattern — you can’t allow any extra characters.

<label for="creditcard">credit card number:</label> <input pattern="[0-9]*" type="text" name="creditcard">
The iOS number keyboard that displays only numbers one through ten and no other special characters.
iOS with pattern attribute

Bear in mind that an iPhone won’t let the user switch keyboard type when this keyboard is displayed. Make sure these are the only keys they need to fill in the input correctly.

If you want to bring up a keypad of large numeric keys on iOS, you need to use the pattern attribute even on number inputs. Otherwise, you’ll get small and finger-friendly buttons:

A screenshot of the iOS keyboard displaying both numbers and letters.
iOS keypad for <input type="number">

A Better Solution: `inputmode`

inputmode has been a WHATWG spec for a couple of years, and has finally been implemented by Chrome as of version 66:

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

Desktop

Chrome Opera Firefox IE Edge Safari
66 No 20 No No No

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
No No No No No No

For the widest support possible, it can be combined with the pattern attribute for iOS:

<label for="creditcard">credit card number:</label> <input inputmode="numeric" pattern="[0-9]*" type="text" name="creditcard">

This gives developers full control of the mobile UI without any extra baggage. It makes the UI finger-friendly while being more versatile than the pattern attribute as we can allow any characters we like. It controls one thing — and one thing only. inputmode is a great solution for those cases when it’s inappropriate to use type="number".

Some people would go further and ditch type="number" altogether once inputmode has better support. I’m not convinced that’s wise, but type="number" can be problematic.

if (numberInput.validity.valueMissing) {
errorMessage.textContent = "field must not be empty"
}
A screenshot of a number input filled with numbers and special characters with an error message below it that informs the user the field is empty.
Contrary to the human eye, the field is empty…

If you want to explicitly warn of empty number inputs, you’ll need to use:

if (numberInput.validity.valueMissing && !numberInput.validity.badInput) {
errorMessage.textContent = "field must not be empty"
}

According to Google, users abandon purchases twice as often on mobile as compared to desktop. Sales on phones account for only one third of all completed online purchases. Clearly people don’t tolerate fumbling through badly designed forms and jabbing at tiny inputs. Data entry needs to be effortless. While browser support is currently low, we’re only really waiting on mobile browsers. Desktop support is largely irrelevant. The input elements introduced by HTML5 are great, but they miss some edge cases. This can fill in some gaps.

The post Finger-friendly numerical inputs with `inputmode` appeared first on CSS-Tricks.

Practical Jokes in the Browser

I know April Fool’s Day is at the beginning of this month, but hey, now you’ve got a year to prepare. Not to mention a gool ol’ practical joke can be done anytime.

Fair warning on this stuff… you gotta be tasteful. Putting someone’s stapler in the jello is pretty hilarious unless it’s somehow a family heirloom, or it’s someone who’s been the target of a little too much office prankery to the point it isn’t funny anymore. Do good. Have fun.

setTimeout(function() { var text = new SpeechSynthesisUtterance("LOLOLOLOLOLOLOLOL"); speechSynthesis.speak(text);
}, 600000);

Direct Link to Article — Permalink

The post Practical Jokes in the Browser appeared first on CSS-Tricks.

CSS Blocks

A new entry into the CSS-in-JS landscape! Looks like the idea is that you write an individual CSS file for every component. You have to work in components, that’s how the whole thing works. In the same isle as styled-components, css-modules, and glamorous.

Then you write :scope { } which is the base style for that component. Which I guess means you get out of having to pick a name! But also means you’re pretty locked in (true with just about any style processing setup).

Then both the CSS and component are compiled, and probably optimized with its partner tool OptiCSS. The end result is super optimized styles. Since it’s “template aware”, the styles can be far more optimized than they could be by any system trying to optimize CSS in isolation.

Chris Eppstein:

With CSS Blocks, and OptiCSS running at its core, you get to write ergonomic CSS and let the build take care of making your stylesheets properly scoped, screaming fast, and fantastically small.

Speed, style scoping, and never/rarely having unsued CSS definitely seem like the big benefits to me. A non-trivial thing to move to, but sounds like it could be worth it for plenty of big sites and new sites.

A couple of setup repos to explore to see how it could work: css-blocks-webpack-3 and css-blocks-hello-world.

Direct Link to Article — Permalink

The post CSS Blocks appeared first on CSS-Tricks.

Radial Gradient Recipes

Radial gradients are pretty dang cool. It’s amazing we can paint the background of an element with them so easily. Easily is a relative term though. It’s certainly easier than needing to create a graphic in third-party software to use as the background, and the syntax is highly learnable. But it’s also not that easy to remember if you don’t use it often, and it’s more complicated than linear-gradient().

I figured I’d put together a page of reference examples, so if you know what you need but forget the syntax, it’s easy to find that starter code example here.

Centered Bursts

The simplest possible syntax places the first color in the center of the element and the second color on the outside and that’s that:

See the Pen Radial Gradient – Centered by Chris Coyier (@chriscoyier) on CodePen.

That will stretch the gradient into an ellipse on a non-square element though. If you don’t like that, you can force the shape into a circle, like the second example here demonstrates:

See the Pen Radial Gradient – Circle vs. Ellipse by Chris Coyier (@chriscoyier) on CodePen.

You can also control the size by literally saying how large the circle/ellipse should be (the final color will still stretch to cover the element) by:

  • Using a keyword closest-side, farthest-side, closest-corner, farthest-corner
  • Explicitly saying like radial-gradient(circle 100px, ...)
  • Using color stops like radial-gradient(#56ab2f, #a8e063 150px)

See the Pen Radial Gradient – Sizing by Chris Coyier (@chriscoyier) on CodePen.

Here’s some of that stuff in use:

See the Pen Usage of Radial Gradients by Chris Coyier (@chriscoyier) on CodePen.

See the Pen Lit text by Chris Coyier (@chriscoyier) on CodePen.

Positioned

Besides controlling the size and shape of the gradient, the other big trick to know with radial gradients is that you can position the center of them.

This is one of the shortcomings, I find, with gradient generators. They help you pick colors and color stops and stuff, but they usually punt on the positioning stuff.

This is a beautiful gradient tool, but doesn’t help with positioning or sizing. Some of them do help a little with positioning (see “Expert” settings), but don’t expose all the possibilities.

The center of a radial gradient doesn’t have to be in the center! For example, you can position the center in the top left like this:

.element { background: radial-gradient( at top left, var(--light), var(--dark) /* using variables just for fun! */ )
}

Here’s all the four corners:

See the Pen Positioned Radial Gradients by Chris Coyier (@chriscoyier) on CodePen.

You can also be very specifically positioned. Here’s an example of a gradient positioned exactly 195px from the left along the bottom of the element. It also has a specific size, but otherwise does the default ellipse shape:

.element { background: radial-gradient( 150px 40px at 195px bottom, #666, #222 );
}

See the Pen Specifically positioned gradient by Chris Coyier (@chriscoyier) on CodePen.

Another little thing to know is that you can use transparent in the gradients to expose the color behind if that’s needed, or partially transparent colors like rgba(255, 255, 255, 0.5) to do the same at a colorized color stop.

Also, radial gradients can be used with multiple backgrounds, applying multiple of them to a single element, even overlapping!

.element { background: radial-gradient( circle at top left, rgba(255, 255, 255, 0.5), transparent 100px ), radial-gradient( circle at top right, rgba(255, 255, 255, 0.5), transparent 100px ), radial-gradient( at bottom left, rgba(255, 0, 255, 0.5), transparent 400px ), radial-gradient( at bottom right, rgba(255, 100, 100, 0.5), transparent 400px );
}

See the Pen Multiple Gradients by Chris Coyier (@chriscoyier) on CodePen.

To highlight the idea that the center of the gradient can be anywhere, here’s a gradient that follows the mouse:

See the Pen Radial Gradient Move With Mouse by Leo Sammarco (@lsammarco) on CodePen.

Resources

People tend to think about browser support, and rightfully so, but don’t think too hard about it in this case. We’re at pretty much across the board support even without any prefixes.

  • There is also repeating-linear-gradient() and here Ana Tudor gets into some detail and use cases.
  • Need some colors that go nicely togehter in a gradient? uiGradients is nice.
  • MDN on radial-gradient
  • See our complete guide to all gradients here!

OK bye!

See the Pen CSS Sunset Sunrise by Marty Saetre (@msaetre) on CodePen.

The post Radial Gradient Recipes appeared first on CSS-Tricks.

​Level Up Your JavaScript Error Monitoring

(This is a sponsored post.)

Automatically detect and diagnose JavaScript errors impacting your users with Bugsnag without changing your code or adding try/catch blocks. Get comprehensive diagnostic reports, know immediately which errors are worth fixing, and debug in a fraction of the time compared to traditional tools.

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, Lyft, Square, Yelp, Eventbrite, Shopify, MailChimp, and Docker. Start your free trial today.

Direct Link to Article — Permalink

The post ​Level Up Your JavaScript Error Monitoring appeared first on CSS-Tricks.

Understanding React `setState`

React components can, and often do, have state. State can be anything, but think of things like whether a user is logged in or not and displaying the correct username based on which account is active. Or an array of blog posts. Or if a modal is open or not and which tab within it is active.

React components with state render reconciliation. The reconciliation process is the way React updates the DOM, by making changes to the component based on the change in state. When the request to setState() is triggered, React creates a new tree containing the reactive elements in the component (along with the updated state). This tree is used to figure out how the Search component’s setState Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Let’s register the component and define the markup for the Understanding React `setState` appeared first on CSS-Tricks.

Grid to Flex

Una Kravets shows how to make layouts in CSS Grid with flexbox fallbacks for browsers that don’t support those grid properties just yet. Una writes:

CSS grid is AMAZING! However, if you need to support users of IE11 and below, or Edge 15 and below, grid won’t really work as you expect…This site is a solution for you so you can start to progressively enhance without fear!

The site is a provides examples using common layouts and component patterns, including code snippets. For example:

See the Pen Grid To Flex — Example 1 by Una Kravets (@una) on CodePen.

Direct Link to Article — Permalink

The post Grid to Flex appeared first on CSS-Tricks.

JAMstack Comments

JAMstack sites are often seen as being static. A more accurate mental model for them would be that they are sites which have the ability to be hosted statically. The difference might seem semantic, but thanks to the rise of many tools and services which simplify running a build and deploying to static hosting infrastructure, such sites can feel much fresher and dynamic than you might imagine, while still capable of being served from static hosting infrastructure, with all the benefits that brings.

A feature often used as an example of why a site cannot be hosted statically is comments. A comments engine needs to handle submissions, allow for moderation, and is by its very nature, “dynamic”.

Comment systems are generally thought of as quite dynamic content

Thanks to the growing ecosystem of tools available for JAMstack sites, there are solutions to this. Let’s look at an example which you could use on your own site, which:

  • Does not depend on client-side JavaScript
  • Could work with any static site generator
  • Includes moderation
  • Sends notifications when new comments need moderating
  • Bakes the comments into your site, so that they load quickly and appear in searches

This example makes use of some of the features of Netlify, a platform for automating, deploying and hosting web projects, but many of the principles could be used with other platforms.

You can see the example site here.

Stashing our content

We’ll create 2 forms to receive all of our comments at the different stages of their journey from commenter to content. When Netlify sees a <form>, it creates a unique data store for the data the form collects. We’ll make great use of that.

  • Form 1) A queue to hold all of the new comment submissions. In other words, a store to hold all comments awaiting moderation.
  • Form 2) Contains all approved comments.

The act of moderation will be somebody looking at each new submission and deciding, “yep!” or “nope!”. Those that get nope-d will be deleted from the queue. Those that are approved will be posted over to the approved comments form.

All of the comments in the approved comments form are used by our static site generator in subsequent site builds thanks to the API access Netlify gives to the submissions in our forms.

The comment form

Each page includes an HTML <form>. By adding the boolean attribute of netlify to any HTML form element in your site, Netlify will automatically generate an API for your form, and gathers all of the submissions to it for you. You’ll also be able to access the submissions via that API later. Handy!

The comments <form> on each page will look a lot like this (some classes and extra copy omitted for clarity):

<form netlify name="comments-queue" action="/thanks"> <input name="path" type="hidden" value="{{ page.url }}"> <p> <label for="name">Your name</label> <input type="text" name="name" id="name"> </p> <p> <label for="email">Your email</label> <input type="email" name="email" id="email"> </p> <p> <label for="comment">Your comment</label> <textarea name="comment" id="comment"></textarea> </p> <p> <button type="submit">Post your comment</button> </p>
</form>

You’ll may notice that the form also includes a type="hidden" field to let us know which page on the site this comment is for. Our static site generator populates that for us when the site is generated, and well use it later when deciding which comments should be shown on which page.

Submissions and notifications

When a new comment is posted via the comment form, Netlify not only stashes that for us, but can also send a notification. That could be:

  • an email
  • a Slack notification
  • a webhook of our choosing.

These give us the chance to automate things a little.

New submissions result in a notification being posted to Slack. We’ll get to see what was submitted and to which page right there in our Slack client.

To make things extra slick, we can massage that notification a little to include some action buttons. One button to delete the comment, one to approve it. Approving a new comment from a Slack notification on your phone while riding the bus feels good.

We can’t make those buttons work without running a little bit of logic which, we can do in a Lambda function. Netlify recently added support for Lambda functions too, making the process of writing and deploying Lambdas part of the same deployment process. You’ll not need to go rummaging around in Amazon’s AWS configuration settings.

We’ll use one Lambda function to add some buttons to our Slack notification, and another Lambda function to handle the actions of clicking either of those buttons.

Bring the comments into the site

With a freshly approved comment being posted to our approved comments form, we are back to using the submission event triggers that Netlify provides. Every time something is posted to the approved comments form, we’ll want to include it in the site, so we have Netlify automatically rebuild and deploy our site.

Most static site generators have some notion of data files. Jekyll uses files in a [_data] directory, Hugo has a similar data directory. This example is using Eleventy as its static site generator which has a similar concept. We’ll make use of this.

Each time we run our site build, whether in our local development environment or within Netlify through their automated builds, the first step is to pull all of our external data into local data files which our a Gulp task.

Armed with a `comments.json` file which we have populated from a call to Netlify’s form submission API which grabbed all of our approved comments, our The example site and all of its code are available to explore. You can try submitting comments if you like (although poor old Phil will need to moderate any comments on this example site before they appear, but that will just make him feel loved).

Better still, you can clone this example and deploy your own version to Netlify with just a few clicks. The example site explains how.

Just show me behind the scenes right now!

If you’d want to take a look at how things behave for the moderator of a site using this system without grabbing a copy of your own, this short video will walk through a comment being made, moderated and incorporated into the site.

The post JAMstack Comments appeared first on CSS-Tricks.

Server-Side Visualization With Nightmare

This is an extract from chapter 11 of Ashley Davis’s book Data Wrangling with JavaScript now available on the Manning Early Access Program. I absolutely love this idea as there is so much data visualization stuff on the web that relies on fully functioning client side JavaScript and potentially more API calls. It’s not nearly as robust, accessible, or syndicatable as it could be. If you bring that data visualization back to the server, you can bring progressive enhancement to the party. All example code and data can be found on GitHub.

When doing exploratory coding or data analysis in Node.js it is very useful to be able to render a visualization from our data. If we were working in browser-based JavaScript we could choose any one of the many charting, graphics, and visualization libraries. Unfortunately, under Node.js, we don’t have any viable options, so how otherwise can we achieve this?

We could try something like faking the DOM under Node.js, but I found a better way. We can make our browser-based visualization libraries work for us under Node.js using a headless browser. This is a browser that has no user interface. You can think of it as a browser that is invisible.

I use Nightmare under Node.js to capture visualizations to PNG and PDF files and it works really well!

The headless browser

When we think of a web-browser we usually think of the graphical software that we interact with on a day to day basis when browsing the web. Normally we interact with such a browser directly, viewing it with our eyes and controlling it with our mouse and keyboard as shown in Figure 1.

Figure 1: The normal state of affairs: our visualization renders in a browser and the user interacts directly with the browser

A headless browser on the other hand is a web-browser that has no graphical user interface and no direct means for us to control it. You might ask what is the use of a browser that we can’t directly see or interact with.

Well, as developers we would typically use a headless browser for automating and testing web sites. Let’s say that you have created a web page and you want to run a suite of automated tests against it to prove that it works as expected. The test suite is automated, which means it is controlled from code and this means that we need to drive the browser from code.

We use a headless browser for automated testing because we don’t need to directly see or interact with the web page that is being tested. Viewing such an automated test in progress is unnecessary, all we need to know is if the test passed or failed — and if it failed we would like to know why. Indeed, having a GUI for the browser under test would actually be a hindrance for a continuous-integration or continuous-deployment server, where many such tests can run in parallel.

So headless browsers are often used for automated testing of our web pages, but they are also incredibly useful for capturing browser-based visualizations and outputting them to PNG images or PDF files. To make this work we need a web server and a visualization, we must then write code to instance a headless browser and point it at our web server. Our code then instructs the headless browser to take a screenshot of the web page and save it to our file system as a PNG or PDF file.

Figure 2: We can use a headless browser under Node.js to capture our visualization to a static image file

Nightmare is my headless browser of choice. It is a Node.js library (installed via npm) that is built on Electron. Electron is a framework normally used for building cross-platform desktop apps that are based on web-technologies.

Why Nightmare?

It’s called Nightmare, but it’s definitely not a Nightmare to use. In fact, it’s the simplest and most convenient headless browser that I’ve used. It automatically includes Electron, so to get started we simply install Nightmare into our Node.js project as follows:

npm install --save nightmare

That’s all we need to install Nightmare and we can start using it immediately from JavaScript!

Nightmare comes with almost everything we need: A scripting library with an embedded headless browser. It also includes the communication mechanism to control the headless browser from Node.js. For the most part it’s seamless and well-integrated to Node.js.

Electron is built on Node.js and Chromium and maintained by GitHub and is the basis for a number of popular desktop applications.

Here are the reasons that I choose to use Nightmare over any other headless browser:

  • Electron is very stable.
  • Electron has good performance.
  • The API is simple and easy to learn.
  • There is no complicated configuration (just start using it).
  • It is very well integrated with Node.js.

Nightmare and Electron

When you install Nightmare via npm it automatically comes with an embedded version of Electron. So, we can say that Nightmare is not just a library for controlling a headless browser, it effectively is the headless browser. This is another reason I like Nightmare. With some of the other headless browsers, the control library is separate, or it’s worse than that and they don’t have a Node.js control library at all. In the worst case, you have to roll your own communication mechanism to control the headless browser.

Nightmare creates an instance of the Electron process using the Node.js child_process module. It then uses inter-process communication and a custom protocol to control the Electron instance. The relationship is shown in Figure 3.

Figure 3: Nightmare allows us to control Electron running as a headless browser

Our process: Capturing visualizations with Nightmare

So what is the process of capturing a visualization to an image file? This is what we are aiming at:

  1. Acquire data.
  2. Start a local web server to host our visualization
  3. Inject our data into the web server
  4. Instance a headless browser and point it at our local web server
  5. Wait for the visualization to be displayed
  6. Capture a screenshot of the visualization to an image file
  7. Shutdown the headless browser
  8. Shutdown the local web server

Prepare a visualization to render

The first thing we need is to have a visualization. Figure 4 shows the chart we’ll work with. This a chart of New York City yearly average temperature for the past 200 years.

Figure 4: Average yearly temperature in New York City for the past 200 years

To run this code you need Node.js installed. For this first example we’ll also use live-server (any web server will do) to test the visualization (because we haven’t created our Node.js web server yet), install live server as follows:

npm install -g live-server

Then you can clone the example code repo for this blog post:

git clone https://github.com/Data-Wrangling-with-JavaScript/nodejs-visualization-example

Now go into the repo, install dependencies and run the example using live-server

cd nodejs-visualization-example/basic-visualization
bower install
live-server

When you run live-server your browser should automatically open and you should see the chart from Figure 4.

It’s a good idea to check that your visualization works directly in a browser before you try and capture it in a headless browser; there could easily be something wrong with it and problems are much easier to troubleshoot in a real browser than in the headless browser. live-server has live reload built-in, so now you have a nice little setup here when you can edit and improve the chart interactively before you try to capture it under Node.js.

This simple line chart was constructed with C3. Please take a look over the example code and maybe look at some of the examples in the C3 gallery to learn more about C3.

Starting the web server

To host our visualization, we need a web server. It’s not quite enough that we have a web server, we also need to be able to dynamically start and stop it. Listing 1 shows the code for our web server.

Listing 1 – Code for a simple web server that can be started and stopped

const express = require('express');
const path = require('path'); module.exports = { start: () => { // Export a start function so we can start the web server on demand. return new Promise((resolve, reject) => { const app = express(); const staticFilesPath = path.join(__dirname, "public"); // Make our 'public' sub-directory accessible via HTTP. const staticFilesMiddleWare = express.static(staticFilesPath); app.use('/', staticFilesMiddleWare); const server = app.listen(3000, err => { // Start the web server! if (err) { reject(err); // Error occurred while starting web server. } else { resolve(server); // Web server started ok. } }); }); }
}

The code module in listing 1 exports a start function that we can call to kickstart our web server. This technique, being able to start and stop our web server, is also very useful for doing automated integration testing on a web site. Imagine that you want to start your web server, run some tests against it and then stop it at the end.

So now we have our browser-based visualization and we have a web server that can be started and stopped on demand. These are the raw ingredients we need for capturing server-side visualizations. Let’s mix it up with Nightmare!

Rendering the web page to an image

Now let’s flesh out the code to capture a screenshot of the visualization with Nightmare. Listing 2 shows the code that instances Nightmare, points it at our web server and then takes the screenshot.

Listing 2 – Capturing our chart to an image file using Nightmare

const webServer = require('./web-server.js');
const Nightmare = require('nightmare'); webServer.start() // Start the web server.
.then(server => { const outputImagePath = "./output/nyc-temperatures.png"; const nightmare = new Nightmare(); // Create the Nightmare instance. return nightmare.goto("http://localhost:3000") // Point the browser at the web server we just started. .wait("svg") // Wait until the chart appears on screen. .screenshot(outputImagePath) // Capture a screenshot to an image file. .end() // End the Nightmare session. Any queued operations are completed and the headless browser is terminated. .then(() => server.close()); // Stop the web server when we are done.
})
.then(() => { console.log("All done :)");
})
.catch(err => { console.error("Something went wrong :("); console.error(err);
});

Note the use of the goto function, this is what actually directs the browser to load our visualization.

Web pages usually take some time to load. That’s probably not going to be very long, especially as we are running a local web server, but still we face the danger of taking a screenshot of the headless browser before or during its initial paint. That’s why we must call the wait function to wait until the chart’s <svg> element appears in the browser’s DOM before we call the screenshot function.

Eventually, the end function is called. Up until now we have effectively built a list of commands to send to the headless browser. The end function actually sends the commands to the browser, which takes the screenshot and outputs the file nyc-temperatures.png. After the image file has been captured we finish up by shutting down the web server.

You can find the completed code under the capture-visualization sub-directory in the repo. Go into the sub-directory and install dependencies:

cd nodejs-visualization-example/capture-visualization
cd public bower install
cd ..
npm install
live-server

Now you can try the code for yourself:

node index.js

This has been an extract from chapter 11 of Data Wrangling with JavaScript now available on the Manning Early Access Program. Please use this discount code fccdavis3 for a 37% discount. Please check The Data Wrangler for new updates on the book.

The post Server-Side Visualization With Nightmare appeared first on CSS-Tricks.

Native-Like Animations for Page Transitions on the Web

Some of the most inspiring examples I’ve seen of front-end development have involved some sort of page transitions that look slick like they do in mobile apps. However, even though the imagination for these types of interactions seem to abound, their presence on actual sites that I visit do not. There are a number of ways to accomplish these types of movement!

Here’s what we’ll be building:

Demo Site

GitHub Repo

We’ll build out the simplest possible distillation of these concepts so that you can apply them to any application, and then I’ll also provide the code for this more complex app if you’d like to dive in.

Today we’ll be discussing how to create them with Vue and Nuxt. There are a lot of moving parts in page transitions and animations (lol I kill me), but don’t worry! Anything we don’t have time to cover in the article, we’ll link off to with other resources.

Why?

The web has come under critique in recent years for appearing “dated” in comparison to native iOS and Android app experiences. Transitioning between two states can reduce cognitive load for your user, as when someone is scanning a page, they have to create a mental map of everything that’s contained on it. When we move from page to page, the user has to remap that entire space. If an element is repeated on several pages but altered slightly, it mimics the experience we’ve been biologically trained to expect — no one just pops into a room or changes suddenly; they transition from another room into this one. Your eyes see someone that’s smaller relative to you. As they get closer in proximity to you, they get bigger. Without these transitions, changes can be startling. They force the user to remap placement and even their understanding of the same element. It is for this reason that these effects become critical in an experience that helps the user feel at home and gather information quickly on the web.

The good news is, implementing these kind of transitions is completely doable. Let’s dig in!

Prerequisite Knowledge

If you’re unfamiliar with Nuxt and how to work with it to create Vue.js applications, there’s another article I wrote on the subject here. If you’re familiar with React and Next.js, Nuxt.js is the Vue equivalent. It offers server-side rendering, code splitting, and most importantly, hooks for page transitions. Even though the page transition hooks it offers are excellent, that’s not how we’re going to accomplish the bulk of our animations in this tutorial.

In order to understand how the transitions we’re working with today do work, you’ll also need to have basic knowledge around the <transition /> component and the difference between CSS animations and transitions. I’ve covered both in more detail here. You’ll also need basic knowledge of the <transition-group /> component and this Snipcart post is a great resource to learn more about it.

Even though you’ll understand everything in more detail if you read these articles, I’ll give you the basic gist of what’s going on as we encounter things throughout the post.

Getting Started

First, we want to kick off our project by using the Vue CLI to create a new Nuxt project:

# if you haven’t installed vue cli before, do this first, globally:
npm install -g @vue/cli
# or
yarn global add @vue/cli # then
vue init nuxt/starter my-transitions-project
npm i
# or
yarn # and
npm i vuex node-sass sass-loader
# or
yarn add vuex node-sass sass-loader

Great! Now the first thing you’ll notice is that we have a pages directory. Nuxt will take any .vue files in that directory and automatically set up routing for us. Pretty awesome. We can make some pages to work with here, in our case: about.vue, and users.vue.

Setting Up Our Hooks

As mentioned earlier, Nuxt offers some page hooks which are really nice for page to page transitions. In other words, we have hooks for a page entering and leaving. So if we wanted to create an animation that would allow us to have a nice fade from page to page, we could do it because the class hooks are already available to us. We can even name new transitions per page and use JavaScript hooks for more advanced effects.

But what if we have some elements that we don’t want to leave and re-enter, but rather transition positions? In mobile applications, things don’t always leave when they move from state to state. Sometimes they transition seamlessly from one point to another and it makes the whole application feel very fluid.

Step One: Vuex Store

The first thing we’ll have to do is set up a centralized state management store with Vuex because we’re going to need to hold what page we’re currrently on.

Nuxt will assume this file will be in the store directory and called index.js:

import Vuex from 'vuex' const createStore = () => { return new Vuex.Store({ state: { page: 'index' }, mutations: { updatePage(state, pageName) { state.page = pageName } } })
} export default createStore

We’re storing both the page and we create a mutation that allows us to update the page.

Step Two: Middleware

Then, in our middleware, we’ll need a script that I’ve called pages.js. This will give us access to the route that’s changing and being updated before any of the other components, so it will be very efficient.

export default function(context) { // go tell the store to update the page context.store.commit('updatePage', context.route.name)
}

We’ll also need to register the middleware in our nuxt.config.js file:

module.exports = { ... router: { middleware: 'pages' }, ...
}

Step Three: Register Our Navigation

Now, we’ll go into our layouts/default.vue file. This directory allows you to set different layouts for different page structures. In our case, we’re not going to make a new layout, but alter the one that we’re reusing for every page. Our template will look like this at first:

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

And that nuxt/ tag will insert anything that’s in the templates in our different pages. But rather than reusing a nav component on every page, we can add it in here and it will be presented consistently on every page:

<template> <div> <app-navigation /> <nuxt/> </div>
</template>
<script>
import AppNavigation from '~/components/AppNavigation.vue' export default { components: { AppNavigation }
}
</script>

This is also great for us because it won’t rerender every time the page is re-routed. It will be consistent on every page and, because of this, we cannot plug into our page transition hooks but instead we can build our own with what we built between Vuex and the Middleware.

Step Four: Create our Transitions in the Navigation Component

Now we can build out the navigation, but I’m also going to use this SVG here to do a small demo of basic functionality we’re going to implement for a larger application

<template> <nav> <h2>Simple Transition Group For Layout: {{ page }}</h2> <!--simple navigation, we use nuxt-link for routing links--> <ul> <nuxt-link exact to="/"><li>index</li></nuxt-link> <nuxt-link to="/about"><li>about</li></nuxt-link> <nuxt-link to="/users"><li>users</li></nuxt-link> </ul> <br> <!--we use the page to update the class with a conditional--> <svg :class="{ 'active' : (page === 'about') }" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 447 442"> <!-- we use the transition group component, we need a g tag because it’s SVG--> <transition-group name="list" tag="g"> <rect class="items rect" ref="rect" key="rect" width="171" height="171"/> <circle class="items circ" key="circ" id="profile" cx="382" cy="203" r="65"/> <g class="items text" id="text" key="text"> <rect x="56" y="225" width="226" height="16"/> <rect x="56" y="252" width="226" height="16"/> <rect x="56" y="280" width="226" height="16"/> </g> <rect class="items footer" key="footer" id="footer" y="423" width="155" height="19" rx="9.5" ry="9.5"/> </transition-group> </svg> </nav>
</template>
<script>
import { mapState } from 'vuex' export default { computed: mapState(['page'])
}
</script>

We’re doing a few things here. In the script, we bring in the page name from the store as a computed value. mapState will let us bring in anything else from the store, which will handy later when we deal with a lot of user information.

In the template, we have a regular nav with nuxt-links, which is what we use for routing links in Nuxt. We also have class that will be updated on a conditional based on the page (it will change to .active when it’s the about page.

We’re also using the <transition-group> component around a number of elements that will change positions. The <transition-group> component is a bit magical because it applies the concepts of FLIP under the hood. If you’ve heard of FLIP before, you’re going to be super excited to hear this because it’s a really performant way of animating on the web but usually takes a lot of calculations to implement. If you haven’t heard of FLIP before, it’s definitely good to read up to understand how it works, and maybe more importantly, all of the stuff you no longer have to do to make this kind of effect work! Can I get a “Hell yeah!”

Here is the CSS that makes this work. We basically state how we’d like all of the elements to be positioned on that “active” hook that we made. Then we tell the elements to have a transition applied if something changes. You’ll notice I’m using 3D transforms even if I’m just moving something along one X or Y axis because transforms are better for performance than top/left/margin for reducing paint and I want to enable hardware acceleration.

.items,
.list-move { transition: all 0.4s ease;
} .active { fill: #e63946; .rect { transform: translate3d(0, 30px, 0); } .circ { transform: translate3d(30px, 0, 0) scale(0.5); } .text { transform: rotate(90deg) scaleX(0.08) translate3d(-300px, -35px, 0); } .footer { transform: translateX(100px, 0, 0); }
}

Here is a reduced codepen without the page transitions, but just to show the movement:

See the Pen layout transition-group by Sarah Drasner (@sdras) on CodePen.

I want to point out that any implementations I use here are choices that I’ve made for placement and movement- you can really create any effect you like! I am choosing SVG here because it communicates the concept of layout in a small amount of code, but you don’t need to use SVG. I’m also using transitions instead of animation because of how declarative they are by nature- you are in essence stating: “I want this to be repositioned here when this class is toggled in Vue”, and then the transition’s only job is to describe the movement as anything changes. This is great for this use-case because it’s very flexible. I can then decide to change it to any other conditional placement and it will still work.

Great! This will now give us the effect, smooth as butter between pages, and we can still give the content of the page a nice little transition as well:

.page-enter-active { transition: opacity 0.25s ease-out;
} .page-leave-active { transition: opacity 0.25s ease-in;
} .page-enter,
.page-leave-active { opacity: 0;
}

I’ve also added in one of the examples from the Nuxt site to show that you can still do internal animations within the page as well:

View GitHub Repo

Ok, that works for a small demo, but now let’s apply it to something more real-world, like our example from before. Again, the demo site is here and the repo with all of the code is here.

It’s the same concept:

  • We store the name of the page in the Vuex store.
  • Middleware commits a mutation to let the store know the page has changed.
  • We apply a special class per page, and nest transitions for each page.
  • The navigation stays consistent on each page but we have different positions and apply some transitions.
  • The content of the page has a subtle transition and we build in some interactions based on user events

The only difference is that this is a slightly more involved implementation. The CSS that’s applied to the elements will stay the same in the navigation component. We can tell the browser what position we want all the elements to be in, and since there’s a transition applied to the element itself, that transition will be applied and it will move to the new position every time the page has changed.

// animations
.place { .follow { transform: translate3d(-215px, -80px, 0); } .profile-photo { transform: translate3d(-20px, -100px, 0) scale(0.75); } .profile-name { transform: translate3d(140px, -125px, 0) scale(0.75); color: white; } .side-icon { transform: translate3d(0, -40px, 0); background: rgba(255, 255, 255, 0.9); } .calendar { opacity: 1; }
}

That’s it! We keep it nice and simple and use flexbox, grid and absolute positioning in a relative container to make sure everything translates easily across all devices and we have very few media queries through this project. I’m mainly using CSS for the nav changes because I can declaratively state the placement of the elements and their transitions. For the micro-interactions of any user-driven event, I’m using JavaScript and GreenSock, because it allows me to coordinate a lot of movement very seamlessly and stabilizes transform-origin across browsers, but there are so many ways you could implement this. There are a million ways I could improve this demo application, or build on these animations, it’s a quick project to show some possibilities in a real-life context.

Remember to hardware accelerate and use transforms, and you can achieve some beautiful, native-like effects. I’m excited to see what you make! The web has so much potential for beautiful movement, placement, and interaction that reduces cognitive load for the user.

The post Native-Like Animations for Page Transitions on the Web appeared first on CSS-Tricks.