Developer News

Weekly Platform News: CSS Scroll Snap, Opera GX, PWA Install Icon

Css Tricks - Fri, 06/14/2019 - 3:53am

Šime posts regular content for web developers on webplatform.news.

In this week's roundup, Chrome is adding an install option for Progressive Web Apps, Opera GX comes to Windows, the ECMAScript proposals get an update, and CSS Scroll Snap is coming to a Firefox browser near you.

An install icon is coming to Chrome on desktop

Pete LePage: The next version of Chrome will automatically show an install icon in the address bar on desktop if the site meets Chrome’s PWA "installability" criteria. You can listen for the appinstalled event to detect if the user installed your PWA.

Opera GX is available on Windows

Maciej Kocemba: The preview version of Opera GX for Windows is now available. This is a special version of Opera that lets users limit how much CPU and RAM is available to the browser.

Updated ECMAScript proposals

Azu The JavaScript optional chaining operator (obj?.prop) and null-ish coalescing operator (x ?? y) proposals have been moved to Stage 2 of the TC39 process. (See Web Platform News issue 902 for more information about the TC39 process.)

// BEFORE let text = response.settings && response.settings.headerText; if (text == null) text = "Hello, world!"; // AFTER let text = response.settings?.headerText ?? "Hello, world!"; CSS Scroll Snap is coming to Firefox

Šime Vidas: CSS Scroll Snap is supported in Chrome, Safari, and the next version of Firefox. Scroll snapping works well on touch screen devices but there are some usability issues on desktop platforms.

The post Weekly Platform News: CSS Scroll Snap, Opera GX, PWA Install Icon appeared first on CSS-Tricks.

Drawing Realistic Clouds with SVG and CSS

Css Tricks - Thu, 06/13/2019 - 4:17am

Greek mythology tells the story of Zeus creating the cloud nymph, Nephele. Like other Greek myths, this tale gets pretty bizarre and X-rated. Here’s a very abridged, polite version.

Nephele, we are told, was created by Zeus in the image of his own beautiful wife. A mortal meets Nephele, falls in love with her and, together, they take an adult nap™. Finally, in a strange twist, the cloud gives birth to half-human half-horse Centaur babies.

Weird, right??Personally, I can’t make heads or tails of it. Thankfully, the process for creating clouds in the browser is much more straightforward and far less risqué.

Yuan Chuan’s clouds detail. (Demo)

Recently, I discovered that developer Yuan Chuan has realized code-generated, photorealistic clouds. For me, this notion in the browser had long been the stuff of myth.

With one glance at the code in this pen we can imagine that convincing individual clouds are achievable through the use of CSS box-shadow with a <filter> element containing two SVG filters as its complement.

The photorealism we want is achieved with a delicate mix of feTurbulence and feDisplacementMap. These SVG filters are powerful, complex and offer very exciting features (including an Oscar winning algorithm)! However, under the hood, their complexity can be a bit intimidating.

While the physics of SVG filters is beyond the scope of this article, there is ample documentation available on MDN and w3.org. A very informative page on feTurbulence and feDisplacement is freely available (and offered as a chapter of this amazing book).

For this article, we will focus on learning to use these SVG filters to get spectacular results. We don’t need to delve too deeply into what is happening behind the scenes algorithmically, much in the way an artist isn’t required know the molecular structure of paint to render a stunning landscape.

Instead, let's pay close attention to small handful of SVG attributes that are essential for drawing convincing clouds in the browser. Their use will enable us to bend these powerful filters to our will and learn how to customize them with precision in our own projects.

Let’s start with some basics

The CSS box-shadow property has five values that deserve close attention:

box-shadow: <offsetX> <offsetY> <blurRadius> <spreadRadius> <color>;

Let’s crank these values up (probably higher than what any sane developer would so that this shadow becomes a player on the stage in its own right.

(Demo) #cloud-square { background: turquoise; box-shadow: 200px 200px 50px 0px #000; width: 180px; height: 180px; } #cloud-circle { background: coral; border-radius: 50%; box-shadow: 200px 200px 50px 0px #000; width: 180px; height: 180px; }

You’ve either made or seen shadow puppets, right?

Credit: Double-M

In the same way that a hand changes shape to alter the shadow, a "source shape" in the our HTML can move and morph to move and alter the shape of a shadow rendered in the browser. box-shadow duplicates the "morphing" features on the original size and border-radius. SVG filters get applied to both the element and its shadow.

<svg width="0" height="0"> <filter id="filter"> <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="10" /> <feDisplacementMap in="SourceGraphic" scale="10" /> </filter> </svg>

This is the markup for our SVG so far. It won’t render because we haven’t defined anything visual (not to mention the zero width and height). It’s sole purpose is to hold a filter that we feed our SourceGraphic (aka our <div>). Our source <div> and its shadow are both being distorted independently by the filter.

We’ll add the essential CSS rule linking the HTML element (`#cloud-circle`) to the SVG filter using its ID:

#cloud-circle { filter: url(#filter); box-shadow: 200px 200px 50px 0px #fff; } Et Voilà!

OK, so admittedly, adding the SVG filter is pretty underwhelming.

(Demo)

No worries! We have only just scratched the surface and have a lot more good stuff to look at.

Experimenting with the feDisplacementMap scale attribute

A few un-scientific experiments with this one attribute can yield dramatic results. For the moment, let’s keep the all values in feTurbulence constant and simply adjust the scale attribute of DisplacementMap.

As scale increases (by increments of 30) our source <div> becomes distorted and casts a shadow to mirror the stochastic form in which clouds appear in the sky.

<feDisplacementMap in="SourceGraphic" scale="180"/> The scale attribute incremented by values of 30. (Demo)

OK, we’re getting somewhere! Let’s change the colors a bit to produce a more convincing cloud and to "sell" the effect.

body { background: linear-gradient(165deg, #527785 0%, #7FB4C7 100%); } #cloud-circle { width: 180px; height: 180px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 200px 200px 50px 0px #fff; }

Now we’re getting closer to a realistic cloud effect!

Modifying the box-shadow blur value

The following suite of images shows the influence that the blur value has on box-shadow. Here, blur is increased by 10 pixels incrementally.

The cloud becomes "softer" as the blur value increases.

To give our cloud a bit of a cumulus-like effect, we can widen our source <div> a bit.

#cloud-circle { width: 500px; height: 275px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 200px 200px 60px 0px #fff; } Great, now the source element is getting in the way. &#x1f62b;

Wait! We’ve widened the source element and now it’s in the way of our of the white shadow we’re calling a cloud. Let’s "re-cast" the shadow at a greater distance so that our cloud is no longer obscured by the source image. (Think of this as moving your hand away further from the wall so it doesn’t block the view of your shadow puppet.)

This is nicely achieved with a bit of CSS positioning. The <body> is the parent element for our cloud, which is statically positioned by default. Let’s "tuck" our source <div> up and out of the way with some absolute positioning. Initially, that will reposition our shadow as well, so we’ll also need to increase the distance of the shadow from the element and nudge the element a bit more.

#cloud-circle { width: 500px; height: 275px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 400px 400px 60px 0px #fff; /* Increase shadow offset */ position: absolute; /* Take the parent out of the document flow */ top: -320px; /* Move a little down */ left: -320px; /* Move a little right */ }

Yes! We've arrived at a pretty persuasive cloud.

See the Pen
by Beau Haus (@beauhaus)
on CodePen.

What is painted to the browser is a pretty decent depiction of a cloud–But, I’m not sure…does this cloud really do justice the cloud nymph, Nephele? I'm sure we can do better!

Conveying depth with layers

Here’s what we want:

Credit: pcdazero

From the look of the depth, texture and richness of the clouds in this photograph, one thing is clear: Zeus went to art school. At the very least, he must have read the The Universal Principles of Design which illustrates a powerful–yet, deceptively ordinary–concept:

[...] lighting bias plays a significant role in the interpretation of depth and naturalness, and can be manipulated in a variety of ways by designers...Use the level of contrast between light and dark areas to vary the appearance of depth.

This passage provides for us a hint as to how to we can vastly improve our own code-generated cloud. We can render our cloud with a good deal of fidelity to the clouds in our reference image by stacking layers of differing form, size and color on top of each other. All that takes is calling our filter as many times as we want layers.

<svg width="0" height="0"> <!-- Back Layer --> <filter id="filter-back"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" /> <feDisplacementMap in="SourceGraphic" scale="170" /> </filter> <!-- Middle Layer --> <filter id="filter-mid"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" scale="150" /> </filter> <!-- Front Layer --> <filter id="filter-front"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" scale="100" /> </filter> </svg>

Applying our layers will afford us an opportunity to explore feTurbulence and realize its versatility. We’ll choose the smoother type available to us: fractalNoise with numOctaves cranked up to 6.

<feTurbulence type="fractalNoise" baseFrequency="n" numOctaves="6"/>

What does all that mean? For now, let’s focus specifically on the baseFrequency attribute. Here’s what we get as we increase the value of n:

The lower the value, the rounder and fuzzier we get. The higher the value, the rounder and more rigid we get.

Words like turbulence, noise, frequency, and octave may seem odd and even confusing. But fear not! It’s actually perfectly accurate to analogize this filter’s effects to sound waves. We may equate a low frequency (baseFrequency=0.001) with a low, muffled noise and a rising frequency (baseFrequency=0.1) with a higher, crisper pitch.

We can see that our sweet spot for a cumulus-like effect may lie comfortably around the ~0.005 and ~0.01 range for the baseFrequency.

Adding detail with numOctaves

Incrementing numOctaves allows us to render our image in extremely granular detail. This requires a great deal of calculation, so be warned: high values are a significant performance hit. Try to resist the temptation to pump up this value unless your browser is wearing a helmet and knee-pads.

The higher the value we put into numOctaves the more granular detail give to our cloud.

The good news is that we don’t have to crank this value too high in order to produce detail and delicacy. As the array of images above shows, we can satisfy ourselves with a numOctavesvalue of 4 or 5.

Here’s the result

See the Pen
by Beau Haus (@beauhaus)
on CodePen.

Infinite variety with the seed attribute

There is much to say about the seed attribute as it offers a hint into the magic happening behind the scenes. But, for our purposes, the utility of seed can be reduced to four words: "different value, different shape."

The Perlin Noise function (mentioned earlier) uses this value as the starting point for its random number generator. Choosing not to include this attribute will default seed to zero. When included, however, whatever value we give seed, we don’t need to worry about a performance hit.

Different seed values produce different shapes.

The GIF above represents some of what seed has to offer. Keep in mind that each of those clouds is a layered, composite cloud. (While I have tweaked attributes for each layer, I have kept their respective seed values uniform.)

Credit: Brockenhexe

Here, with a close look at the reference image, I've layered 3 cloud-<div>s (of differing in opacity) onto a single base div. Through trial and error and punching in arbitrary seed values, I eventually arrived at a shape resembling the shape of the cloud in the photograph.

See the Pen
Nephele Reference Image study
by BEAU.HAUS (@beauhaus)
on CodePen.

Sky’s the limit

Of course, it would be hubris to think that the <div>s that we paint to the browser could be superior to Zeus’s, Nephele.

However, the more mystery we are able to tease out of CSS and SVG filters, the more we are empowered create something visually stunning with a high degree of fidelity to the Thunder God’s original creation. We can, then, can go on experiment further!

Reflecting Mist

Animated Reflecting mist

Alto-Cirrus Clouds

Alto-Cirrus clouds

In this article, we have just dipped our toe in an ocean of power and complexity. SVG filters can often seem overwhelming and unapproachable.

However, much like the examples found in the A Single Div project project or Diana Smith's painting techniques, a playful and experimental approach will always rewarded with spectacular results!

I hope this gets you excited about creating a bit of photorealism on the web. I developed a little tool to help put them all to use and experiment a bit. Any questions, suggestions or advice? Ping me in the twitterverse drop a comment here.

Many thanks to Amelia Bellamy-Royds for her kind advice on this article.

The post Drawing Realistic Clouds with SVG and CSS appeared first on CSS-Tricks.

A11Y with Lindsey

Css Tricks - Thu, 06/13/2019 - 4:16am

Lindsey Kopacz has a wonderful blog about accessibility. I've seen a number of her articles making the rounds lately and I was like, dang I better make sure I'm subscribed. For example:

Regarding that last one, I remember learning from Sara Soueidan that a good tip for this to position them over the new custom checkboxes and hide them via opacity instead of hiding the native checkboxes by clipping them away. That covers the scenario of people exploring a touch screen for native interactive elements.

The post A11Y with Lindsey appeared first on CSS-Tricks.

Grid, content re-ordering and accessibility

Css Tricks - Wed, 06/12/2019 - 4:13pm

Take this:

<ol> <li>Get hungry</li> <li>Order pizza</li> <li>Eat pizza</li> </ol>

That HTML ends up in the DOM that way (and thus how it is is exposed to assistive technology), and by default, those list items are also visually shown in that order. In most layout situations, the visual order will match that DOM order. Do nothing, and the list items will flow in the block direction of the document. Apply flexbox, and it will flow in the inline direction of the document.

But flexbox and grid also allow you to muck it up. Now take this:

ol { display: flex; flex-direction: row-reverse; }

In this case, the DOM order still makes sense, but the visual order is all wrong. It's not just row-reverse. There are a number of flexbox and grid properties that can get involved and confuse things: the order property, flowing items into columns instead of rows, and positioning items specifically in unusual orders, among others. Even absolute positioning could cause the same trouble.

Manuel Matuzovic says:

If the visual order and the DOM order don’t match, it can irritate and confuse users up to a point where the experience is so bad that the site is unusable.

Rachel Andrew highlights this issue (including things we've published) as a big issue, and hopes we can get tools at the CSS level to help.

I think this is something we sorely need to address at a CSS level. We need to provide a way to allow the tab and reading order to follow the visual order. Source order is a good default, if you are taking advantage of normal flow, a lot of the time following the source is exactly what you want. However not always, not at every breakpoint. If we don’t give people a solution for this, we will end up with a mess. We’ve given people these great tools, and now I feel as if I’m having to tell people not to use them.

Direct Link to ArticlePermalink

The post Grid, content re-ordering and accessibility appeared first on CSS-Tricks.

Using Cypress to Write Tests for a React Application

Css Tricks - Wed, 06/12/2019 - 4:07am

End-to-end tests are written to assert the flow of an application from start to finish. Instead of handling the tests yourself — you know, manually clicking all over the application — you can write a test that runs as you build the application. That’s what we call continuous integration and it’s a beautiful thing. Write some code, save it, and let tooling do the dirty work of making sure it doesn’t break anything.

>Cypress is just one end-to-end testing framework that does all that clicking work for us and that’s what we’re going to look at in this post. It’s really for any modern JavaScript library, but we’re going to integrate it with React in the examples.

Let’s set up an app to test

In this tutorial, we will write tests to cover a todo application I’ve built. You can clone the repository to follow along as we plug it into Cypress.

git clone git@github.com:kinsomicrote/cypress-react-tutorial.git

Navigate into the application, and install the dependencies:

cd cypress-react-tutorial yarn install

Cypress isn’t part of the dependencies, but you can install it by running this:

yarn add cypress --dev

Now, run this command to open Cypress:

node_modules/.bin/cypress open

Typing that command to the terminal over and over can get exhausting, but you can add this script to the package.json file in the project root:

"cypress": "cypress open"

Now, all you have to do is do npm run cypress once and Cypress will be standing by at all times. To have a feel of what the application we’ll be testing looks like, you can start the React application by running yarn start.

We will start by writing a test to confirm that Cypress works. In the cypress/integration folder, create a new file called init.spec.js. The test asserts that true is equal to true. We only need it to confirm that’s working to ensure that Cypress is up and running for the entire application.

describe('Cypress', () => { it('is working', () => { expect(true).to.equal(true) }) })

You should have a list of tests open. Go there and select init.spec.js.

That should cause the test to run and pop up a screen that shows the test passing.

While we’re still in init.spec.js, let’s add a test to assert that we can visit the app by hitting http://localhost:3000 in the browser. This’ll make sure the app itself is running.

it('visits the app', () => { cy.visit('http://localhost:3000') })

We call the method visit() and we pass it the URL of the app. We have access to a global object called cy for calling the methods available to us on Cypress.

To avoid having to write the URL time and again, we can set a base URL that can be used throughout the tests we write. Open the cypress.json file in the home directory of the application and add define the URL there:

{ "baseUrl": "http://localhost:3000" }

You can change the test block to look like this:

it('visits the app', () => { cy.visit('/') })

...and the test should continue to pass. &#x1f91e;

Testing form controls and inputs

The test we’ll be writing will cover how users interact with the todo application. For example, we want to ensure the input is in focus when the app loads so users can start entering tasks immediately. We also want to ensure that there’s a default task in there so the list is not empty by default. When there are no tasks, we want to show text that tells the user as much.

To get started, go ahead and create a new file in the integration folder called form.spec.js. The name of the file isn’t all that important. We’re prepending "form" because what we’re testing is ultimately a form input. You may want to call it something different depending on how you plan on organizing tests.

We’re going to add a describe block to the file:

describe('Form', () => { beforeEach(() => { cy.visit('/') }) it('it focuses the input', () => { cy.focused().should('have.class', 'form-control') }) })

The beforeEach block is used to avoid unnecessary repetition. For each block of test, we need to visit the application. It would be redundant to repeat that line each time beforeEach ensures Cypress visits the application in each case.

For the test, let’s check that the DOM element in focus when application first loads has a class of form-control. If you check the source file, you will see that the input element has a class called form-control set to it, and we have autoFocus as one of the element attributes:

<input type="text" autoFocus value={this.state.item} onChange={this.handleInputChange} placeholder="Enter a task" className="form-control" />

When you save that, go back to the test screen and select form.spec.js to run the test.

The next thing we’ll do is test whether a user can successfully enter a value into the input field.

it('accepts input', () => { const input = "Learn about Cypress" cy.get('.form-control') .type(input) .should('have.value', input) })

We’ve added some text ("Learn about Cypress") to the input. Then we make use of cy.get to obtain the DOM element with the form-control class name. We could also do something like cy.get('input') and get the same result. After getting the element, cy.type() is used to enter the value we assigned to the input, then we assert that the DOM element with class form-control has a value that matches the value of input.

In other words:

Our application should also have two todos that have been created by default when the app runs. It’s important we have a test that checks that they are indeed listed.

What do we want? In our code, we are making use of the list item (<li>) element to display tasks as items in a list. Since we have two items listed by default, it means that the list should have a length of two at start. So, the test will look something like this:

it('displays list of todo', () => { cy.get('li') .should('have.length', 2) })

Oh! And what would this app be if a user was unable to add a new task to the list? We’d better test that as well.

it('adds a new todo', () => { const input = "Learn about cypress" cy.get('.form-control') .type(input) .type('{enter}') .get('li') .should('have.length', 3) })

This looks similar to what we wrote in the last two tests. We obtain the input and simulate typing a value into it. Then, we simulate submitting a task that should update the state of the application, thereby increasing the length from 2 to 3. So, really, we can build off of what we already have!

Changing the value from three to two will cause the test to fail — that’s what we’d expect because the list should have two tasks by default and submitting once should produce a total of three.

You might be wondering what would happen if the user deletes either (or both) of the default tasks before attempting to submit a new task. Well, we could write a test for that as well, but we’re not making that assumption in this example since we only want to confirm that tasks can be submitted. This is an easy way for us to test the basic submitting functionality as we develop and we can account for advanced/edge cases later.

The last feature we need to test is the deleting tasks. First, we want to delete one of the default task items and then see if there is one remaining once the deletion happens. It’s the same sort of deal as before, but we should expect one item left in the list instead of the three we expected when adding a new task to the list.

it('deletes a todo', () => { cy.get('li') .first() .find('.btn-danger') .click() .get('li') .should('have.length', 1) })

OK, so what happens if we delete both of the default tasks in the list and the list is completely empty? Let’s say we want to display this text when no more items are in the list: "All of your tasks are complete. Nicely done!"

This isn’t too different from what we have done before. You can try it out first then come back to see the code for it.

it.only('deletes all todo', () => { cy.get('li') .first() .find('.btn-danger') .click() .get('li') .first() .find('.btn-danger') .click() .get('.no-task') .should('have.text', 'All of your tasks are complete. Nicely done!') })

Both tests look similar: we get the list item element, target the first one, and make use of cy.find() to look for the DOM element with a btn-danger class name (which, again, is a totally arbitrary class name for the delete button in this example app). We simulate a click event on the element to delete the task item.

I’m checking for "No task!" in this particular test. Testing network requests

Network requests are kind of a big deal because that’s often the source of data used in an application. Say we have a component in our app that makes a request to the server to obtain data which will be displayed to user. Let’s say the component markup looks like this:

class App extends React.Component { state = { isLoading: true, users: [], error: null }; fetchUsers() { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => this.setState({ users: data, isLoading: false, }) ) .catch(error => this.setState({ error, isLoading: false })); } componentDidMount() { this.fetchUsers(); } render() { const { isLoading, users, error } = this.state; return ( <React.Fragment> <h1>Random User</h1> {error ? <p>{error.message}</p> : null} {!isLoading ? ( users.map(user => { const { username, name, email } = user; return ( <div key={username}> <p>Name: {name}</p> <p>Email Address: {email}</p> <hr /> </div> ); }) ) : ( <h3>Loading...</h3> )} </React.Fragment> ); } }

Here, we are making use of the JSON Placeholder API as an example. We can have a test like this to test the response we get from the server:

describe('Request', () => { it('displays random users from API', () => { cy.request('https://jsonplaceholder.typicode.com/users') .should((response) => { expect(response.status).to.eq(200) expect(response.body).to.have.length(10) expect(response).to.have.property('headers') expect(response).to.have.property('duration') }) }) })

The benefit of testing the server (as opposed to stubbing it) is that we are certain the response we get is the same as that which a user will get. To learn more about network requests and how you can stub network requests, see this page in the Cypress documentation.

Running tests from the command line

Cypress tests can run from the terminal without the provided UI:

./node_modules/.bin/cypress run

...or

npx cypress run

Let’s run the form tests we wrote:

npx cypress run --record --spec "cypress/integration/form.spec.js"

Terminal should output the results right there with a summary of what was tested.

There’s a lot more about using Cypress with the command line in the documentation.

That’s a wrap!

Tests are something that either gets people excited or scared, depending on who you talk to. Hopefully what we’ve looked at in this post gets everyone excited about implementing tests in an application and shows how relatively straightforward it can be. Cypress is an excellent tool and one I’ve found myself reaching for in my own work, but there are others as well. Regardless of what tool you use (and how you feel about tests), hopefully you see the benefits of testing and are more compelled to give them a try.

Related resources

The post Using Cypress to Write Tests for a React Application appeared first on CSS-Tricks.

Everything You Need to Know About Date in JavaScript

Css Tricks - Tue, 06/11/2019 - 4:27am

Date is weird in JavaScript. It gets on our nerves so much that we reach for libraries (like Date-fns and Moment) the moment (ha!) we need to work with date and time.

But we don't always need to use libraries. Date can actually be quite simple if you know what to watch out for. In this article, I'll walk you through everything you need to know about the Date object.

First, let's acknowledge the existence of timezones.

Timezones

There are hundreds of timezones in our world. In JavaScript, we only care about two—Local Time and Coordinated Universal Time (UTC).

  • Local time refers to the timezone your computer is in.
  • UTC is synonymous with Greenwich Mean Time (GMT) in practice.

By default, almost every date method in JavaScript (except one) gives you a date/time in local time. You only get UTC if you specify UTC.

With this, we can talk about creating dates.

Creating a date

You can create a date with new Date(). There are four possible ways to use new Date():

  1. With a date-string
  2. With date arguments
  3. With a timestamp
  4. With no arguments
The date-string method

In the date-string method, you create a date by passing a date-string into new Date.

new Date('1988-03-21')

We tend towards the date-string method when we write dates. This is natural because we've been using date strings all our lives.

If I write 21-03-1988, you have no problems deducing it's 21st of March, 1988. Yeah? But if you write 21-03-1988 in JavaScript, you get Invalid Date.

new Date('21-03-1988') returns Invalid Date.

There's a good reason for this.

We interpret date strings differently in different parts of the world. For example 11-06-2019 is either 11th June, 2019 or 6th November 2019. But you can't be sure which one I'm referring to, unless you know the date system I'm using.

In JavaScript, if you want to use a date string, you need to use a format that's accepted worldwide. One of these formats is the ISO 8601 Extended format.

// ISO 8601 Extended format `YYYY-MM-DDTHH:mm:ss:sssZ`

Here's what the values mean:

  • YYYY: 4-digit year
  • MM: 2-digit month (where January is 01 and December is 12)
  • DD: 2-digit date (0 to 31)
  • -: Date delimiters
  • T: Indicates the start of time
  • HH: 24-digit hour (0 to 23)
  • mm: Minutes (0 to 59)
  • ss: Seconds (0 to 59)
  • sss: Milliseconds (0 to 999)
  • :: Time delimiters
  • Z: If Z is present, date will be set to UTC. If Z is not present, it'll be Local Time. (This only applies if time is provided.)

Hours, minutes, seconds and milliseconds are optional if you're creating a date. So, if you want to create a date for 11th June 2019, you can write this:

new Date('2019-06-11')

Pay special attention here. There's a huge problem with creating dates with date strings. You can spot the problem if you console.log this date.

If you live in an area that's behind GMT, you'll get a date that says 10th June.

new Date('2019-06-11') produces 10th June if you're in a place behind GMT.

If you live in an area that's ahead of GMT, you'll get a date that says 11th June.

new Date('2019-06-11') produces 11th June if you're in a place after GMT.

This happens because the date-string method has a peculiar behavior: If you create a date (without specifying time), you get a date set in UTC.

In the above scenario, when you write new Date('2019-06-11'), you actually create a date that says 11th June, 2019, 12am UTC. This is why people who live in areas behind GMT get a 10th June instead of 11th June.

If you want to create a date in Local Time with the date-string method, you need to include the time. When you include time, you need to write the HH and mm at a minimum (or Google Chrome returns an invalid date).

new Date('2019-06-11T00:00') Date created in Local Time vsl. Date created in UTC.

The whole Local Time vs. UTC thing with date-strings can be a possible source of error that's hard to catch. So, I recommend you don't create dates with date strings.

(By the way, MDN warns against the date-string approach since browsers may parse date strings differently).

MDN recommends against creating date with date strings.

If you want to create dates, use arguments or timestamps.

Creating dates with arguments

You can pass in up to seven arguments to create a date/time.

  1. Year: 4-digit year.
  2. Month: Month of the year (0-11). Month is zero-indexed. Defaults to 0 if omitted.
  3. Day: Day of the month (1-31). Defaults to 1 if omitted.
  4. Hour: Hour of the day (0-23). Defaults to 0 if omitted.
  5. Minutes: Minutes (0-59). Defaults to 0 if omitted.
  6. Seconds: Seconds (0-59). Defaults to 0 if omitted.
  7. Milliseconds: Milliseconds (0-999). Defaults to 0 if omitted.
// 11th June 2019, 5:23:59am, Local Time new Date(2019, 5, 11, 5, 23, 59)

Many developers (myself included) avoid the the arguments approach because it looks complicated. But it's actually quite simple.

Try reading numbers from left to right. As you go left to right, you insert values in decreasing magnitude: year, month, day, hours, minutes, seconds, and milliseconds.

new Date(2017, 3, 22, 5, 23, 50) // This date can be easily read if you follow the left-right formula. // Year: 2017, // Month: April (because month is zero-indexed) // Date: 22 // Hours: 05 // Minutes: 23 // Seconds: 50

The most problematic part with Date is that the Month value is zero-indexed, as in, January === 0, February === 1, March === 2 and so on.

We have no idea why month in JavaScript is zero-indexed, but it is. Rather than argue about why January should be 1 (and not 0), it's better to accept that month is zero-indexed in JavaScript. Once you accept this fact, dates become much easier to work with.

Here are some more examples for you to familiarize yourself:

// 21st March 1988, 12am, Local Time. new Date(1988, 2, 21) // 25th December 2019, 8am, Local Time. new Date(2019, 11, 25, 8) // 6th November 2023, 2:20am, Local Time new Date(2023, 10, 6, 2, 20) // 11th June 2019, 5:23:59am, Local Time new Date(2019, 5, 11, 5, 23, 59)

Notice dates created with arguments are all in Local Time?

That's one of the perks of using arguments—you won't get confused between Local Time and UTC. If you ever need UTC, you create a date in UTC this way:

// 11th June 2019, 12am, UTC. new Date(Date.UTC(2019, 5, 11)) Creating dates with timestamps

In JavaScript, a timestamp is the amount of milliseconds elapsed since 1 January 1970 (1 January 1970 is also known as Unix epoch time). From my experience, you rarely use timestamps to create dates. You only use timestamps to compare between different dates (more on this later).

// 11th June 2019, 8am (in my Local Time, Singapore) new Date(1560211200000) With no arguments

If you create a date without any arguments, you get a date set to the current time (in Local Time).

new Date() The time now.

You can tell from the image that it's 25th May, 11:10am in Singapore when I wrote this article.

Summary about creating dates
  1. You can create date with new Date().
  2. There are four possible syntaxes:
    1. With a date string
    2. With arguments
    3. With timestamp
    4. With no arguments
  3. Never create a date with the date string method.
  4. It's best to create dates with the arguments method.
  5. Remember (and accept) that month is zero-indexed in JavaScript.

Next, let's talk about converting a date into a readable string.

Formatting a date

Most programming languages give you a formatting tool to create any Date format you want. For example, in PHP, you can write date("d M Y") to a date like 23 Jan 2019.

But there's no easy way to format a date in JavaScript.

The native Date object comes with seven formatting methods. Each of these seven methods give you a specific value (and they're quite useless).

const date = new Date(2019, 0, 23, 17, 23, 42)
  1. toString gives you Wed Jan 23 2019 17:23:42 GMT+0800 (Singapore Standard Time)
  2. toDateString gives you Wed Jan 23 2019
  3. toLocaleString gives you 23/01/2019, 17:23:42
  4. toLocaleDateString gives you 23/01/2019
  5. toGMTString gives you Wed, 23 Jan 2019 09:23:42 GMT
  6. toUTCString gives you Wed, 23 Jan 2019 09:23:42 GMT
  7. toISOString gives you 2019-01-23T09:23:42.079Z

If you need a custom format, you need to create it yourself.

Writing a custom date format

Let's say you want something like Thu, 23 January 2019. To create this value, you need to know (and use) the date methods that comes with the Date object.

To get dates, you can use these four methods:

  1. getFullYear: Gets 4-digit year according to local time
  2. getMonth: Gets month of the year (0-11) according to local time. Month is zero-indexed.
  3. getDate: Gets day of the month (1-31) according to local time.
  4. getDay: Gets day of the week (0-6) according to local time. Day of the week begins with Sunday (0) and ends with Saturday (6).

It's simple to create 23 and 2019 for Thu, 23 January 2019. We can use getFullYear and getDate to get them.

const d = new Date(2019, 0, 23) const year = d.getFullYear() // 2019 const date = d.getDate() // 23

It's harder to get Thu and January.

To get January, you need to create an object that maps the value of all twelve months to their respective names.

const months = { 0: 'January', 1: 'February', 2: 'March', 3: 'April', 4: 'May', 5: 'June', 6: 'July', 7: 'August', 8: 'September', 9: 'October', 10: 'November', 11: 'December' }

Since Month is zero-indexed, we can use an array instead of an object. It produces the same results.

const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]

To get January, you need to:

  1. Use getMonth to get the zero-indexed month from the date.
  2. Get the month name from months
const monthIndex = d.getMonth() const monthName = months[monthIndex] console.log(monthName) // January

The condensed version:

const monthName = months(d.getMonth()) console.log(monthName) // January

You do the same thing to get Thu. This time, you need an array that contains seven days of the week.

const days = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]

Then you:

  1. Get dayIndex with getDay
  2. Use dayIndex to get dayName
const dayIndex = d.getDay() const dayName = days[dayIndex] // Thu

Short version:

const dayName = days[d.getDay()] // Thu

Then, you combine all the variables you created to get the formatted string.

const formatted = `${dayName}, ${date} ${monthName} ${year}` console.log(formatted) // Thu, 23 January 2019

Yes, it tedious. But it's not impossible once you get the hang of it.

If you ever need to create a custom-formatted time, you can use the following methods:

  1. getHours: Gets hours (0-23) according to local time.
  2. getMinutes: Gets minutes (0-59) according to local time.
  3. getSeconds: Gets seconds (0-59) according to local time.
  4. getMilliseconds: Gets milliseconds (0-999) according to local time.

Next, let's talk about comparing dates.

Comparing dates

If you want to know whether a date comes before or after another date, you can compare them directly with >, <, >= and <=.

const earlier = new Date(2019, 0, 26) const later = new Date(2019, 0, 27) console.log(earlier < later) // true

It's more difficult if you want to check if two dates fall exactly at the same time. You can't compared them with == or ===.

const a = new Date(2019, 0, 26) const b = new Date(2019, 0, 26) console.log(a == b) // false console.log(a === b) // false

To check whether two dates fall exactly at the same time, you can check their timestamps with getTime.

const isSameTime = (a, b) => { return a.getTime() === b.getTime() } const a = new Date(2019, 0, 26) const b = new Date(2019, 0, 26) console.log(isSameTime(a, b)) // true

If you want to check whether two dates fall on the same day, you can check their getFullYear, getMonth and getDate values.

const isSameDay = (a, b) => { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate()=== b.getDate() } const a = new Date(2019, 0, 26, 10) // 26 Jan 2019, 10am const b = new Date(2019, 0, 26, 12) // 26 Jan 2019, 12pm console.log(isSameDay(a, b)) // true

There's one final thing we have to cover.

Getting a date from another date

There are two possible scenarios where you want to get a date from another date.

  1. Set a specific date/time value from another date.
  2. Add/subtract a delta from another date.
Setting a specific date/time

You can use these methods to set a date/time from another date:

  1. setFullYear: Set 4-digit year in Local Time.
  2. setMonth: Set month of the year in Local Time.
  3. setDate: Set day of the month in Local Time.
  4. setHours: Set hours in Local Time.
  5. setMinutes: Set minutes in Local Time.
  6. setSeconds: Set seconds in Local Time.
  7. setMilliseconds: Set milliseconds in Local Time.

For example, if you want to set a date to the 15th of the month, you can use setDate(15).

const d = new Date(2019, 0, 10) d.setDate(15) console.log(d) // 15 January 2019

If you want to set the month to June, you can use setMonth. (Remember, month in JavaScript is zero-indexed!)

const d = new Date(2019, 0, 10) d.setMonth(5) console.log(d) // 10 June 2019

Note: The setter methods above mutate the original date object. In practice, we should not mutate objects (more on why here). We should perform these operations on a new date object instead.

const d = new Date(2019, 0, 10) const newDate = new Date(d) newDate.setMonth(5) console.log(d) // 10 January 2019 console.log(newDate) // 10 June 2019 Adding/Subtracting delta from another date

A delta is a change. By adding/subtracting delta from another date, I mean this: You want to get a date that's X from another date. It can be X year, X month, X day, etc.

To get a delta, you need to know the current date's value. You can get it using these methods:

  1. getFullYear: Gets 4-digit year according to local time
  2. getMonth: Gets month of the year (0-11) according to local time.
  3. getDate: Gets day of the month (1-31) according to local time.
  4. getHours: Gets hours (0-23) according to local time.
  5. getMinutes: Gets minutes (0-59) according to local time.
  6. getSeconds: Gets seconds (0-59) according to local time.
  7. getMilliseconds: Gets milliseconds (0-999) according to local time.

There are two general approaches to add/subtract a delta. The first approach is more popular on Stack Overflow. It's concise, but harder to grasp. The second approach is more verbose, but easier to understand.

Let's go through both approaches.

Say you want to get a date that's three days from today. For this example, let's also assume today is 28 March 2019. (It's easier to explain when we're working with a fixed date).

The first approach (the set approach) // Assumes today is 28 March 2019 const today = new Date(2019, 2, 28)

First, we create a new Date object (so we don't mutate the original date)

const finalDate = new Date(today)

Next, we need to know the value we want to change. Since we're changing days, we can get the day with getDate.

const currentDate = today.getDate()

We want a date that's three days from today. We'll use add the delta (3) to the current date.

finalDate.setDate(currentDate + 3)

Full code for the set approach:

const today = new Date(2019, 2, 28) const finalDate = new Date(today) finalDate.setDate(today.getDate() + 3) console.log(finalDate) // 31 March 2019 The second approach (the new Date approach)

Here, we use getFullYear, getMonth, getDate and other getter methods until we hit the type of value we want to change. Then, we use create the final date with new Date.

const today = new Date(2019, 2, 28) // Getting required values const year = today.getFullYear() const month = today.getMonh() const day = today.getDate() // Creating a new Date (with the delta) const finalDate = new Date(year, month, day + 3) console.log(finalDate) // 31 March 2019

Both approaches work. Choose one and stick with it.

Automatic date correction

If you provide Date with a value that's outside of its acceptable range, JavaScript recalculates the date for you automatically.

Here's an example. Let's say we set date to 33rd March 2019. (There's no 33rd March on the calendar). In this case, JavaScript adjusts 33rd March to 2nd April automatically.

// 33rd March => 2nd April new Date(2019, 2, 33) 33rd March gets converted to 2nd April automatically.

This means you don't need to worry about calculating minutes, hours, days, months, etc. when creating a delta. JavaScript handles it for you automatically.

// 33rd March => 2nd April new Date(2019, 2, 30 + 3) 30 + 3 = 33. 33rd March gets converted to 2nd April automatically.

And that's everything you need to know about JavaScript's native Date object.

Interested to learn more JavaScript?

If you found this intro to Date useful, you might love Learn JavaScript, a course I created to teach people everything they need to know about JavaScript.

In the course, I cover the basic concepts of what you need to know, then I show you how to use the concepts you learned to build real-world components.

Have a look. You might find it helpful.

In the meantime, if you have any JavaScript questions, feel free to contact me. I'll do by best to create free articles to answer your questions.

The post Everything You Need to Know About Date in JavaScript appeared first on CSS-Tricks.

Level up your .sort game

Css Tricks - Mon, 06/10/2019 - 2:45am

Sorting is a super handy JavaScript method that can display the values of an array in a certain order. Whether that’s real estate listings by price, burger joints by distance, or best nearby happy hours by rating, sorting arrays of information is a common need.

If you’re already doing this with JavaScript on a project, you are will likely using the built-in array .sort method, which is in the same family of array methods that includes .filter, .map and .reduce.

Let's take a look at how to do that!

A quick note about side effects

Before going into the details of how to use .sort, there is a very important detail that needs to be addressed. While many of the ES5 array methods such as .filter, .map, and .reduce will return a new array and leave the original untouched, .sort will sort the array in place. If this is unwanted, an ES6 technique to avoid this is using the spread operator to concisely create a new array.

const foo = ['c','b','a']; const bar = ['x','z','y']; const fooSorted = foo.sort(); const barSorted = [...bar].sort(); console.log({foo, fooSorted, bar, barSorted}); /* { "foo": [ "a", "b", "c" ], "fooSorted": [ "a", "b", "c" ], "bar": [ "x", "z", "y" ], "barSorted": [ "x", "y", "z" ] } */

foo and fooSorted both reference the same array, but bar and barSorted are now individual arrays.

General overview

The only parameter of the .sort method is a function. The spec refers to this as the compareFn — I will refer to it as the "comparison function" for the rest of the post. This comparison function accepts two parameters, which I will refer to as a and b. a and b are the two elements that we will be comparing. If you do not provide a comparison function, the array will coerce each element into a string and sort according to Unicode points.

If you would like the a to be ordered first in the array, the comparison function should return a negative integer; for b, a positive integer. If you would like the two to maintain their current order, return a 0.

If you don't understand, don't worry! Hopefully it will become much more clear with a few examples.

Comparing numbers

One of the simplest callbacks to write is a number comparison.

const numbers = [13,8,2,21,5,1,3,1]; const byValue = (a,b) => a - b; const sorted = [...numbers].sort(byValue); console.log(sorted); // [1,1,2,3,5,8,13,21]

If a is greater than b, a - b will return a positive number, so b will be sorted first.

Comparing strings

When comparing strings, the > and < operators will compare values based on each string’s Unicode value. This means that all uppercase letters will be “less” than all lowercase letters, which can lead to unexpected behavior.

JavaScript does have a method to help with comparing strings: the String.prototype.localeCompare method. This method accepts a comparison string, a locale, and an options object. The options object accepts a few properties (all of which you can view here), but I find that the most useful is "sensitivity." This will affect how comparisons work between letter variations such as case and accent.

const strings = ['Über', 'alpha', 'Zeal', 'über', 'uber', 'Uber', 'Alpha', 'zeal']; const sortBySensitivity = sensitivity => (a, b) => a.localeCompare( b, undefined, // locale string -- undefined means to use browser default { sensitivity } ); const byAccent = sortBySensitivity('accent'); const byBase = sortBySensitivity('base'); const byCase = sortBySensitivity('case'); const byVariant = sortBySensitivity('variant'); // default const accentSorted = [...strings].sort(byAccent); const baseSorted = [...strings].sort(byBase); const caseSorted = [...strings].sort(byCase); const variantSorted = [...strings].sort(byVariant); console.log({accentSorted, baseSorted, caseSorted, variantSorted}); /* { "accentSorted": [ "alpha", "Alpha", "uber", "Uber", "Über", "über", "Zeal", "zeal" ], "baseSorted": [ "alpha", "Alpha", "Über", "über", "uber", "Uber", "Zeal", "zeal" ], "caseSorted": [ "alpha", "Alpha", "über", "uber", "Über", "Uber", "zeal", "Zeal" ], "variantSorted": [ "alpha", "Alpha", "uber", "Uber", "über", "Über", "zeal", "Zeal" ] } */

To me, baseSorted seems to be the most logical for most alphabetical sorting — ‘ü’, ‘u’, ‘Ü’, and ‘U’ are equivalent, so they remain in the order of the original array.

Running functions before comparing values

You may want to run a comparison function on a value that is derived from each array’s element. First, let’s write a comparison function factory that will "map" over the element before calling the comparison function.

const sortByMapped = (map,compareFn) => (a,b) => compareFn(map(a),map(b));

One use case for this is sorting based on the attribute of an object.

const purchases = [ { name: 'Popcorn', price: 5.75 }, { name: 'Movie Ticket', price: 12 }, { name: 'Soda', price: 3.75 }, { name: 'Candy', price: 5 }, ]; const sortByMapped = (map,compareFn) => (a,b) => compareFn(map(a),map(b)); const byValue = (a,b) => a - b; const toPrice = e => e.price; const byPrice = sortByMapped(toPrice,byValue); console.log([...purchases].sort(byPrice)); /* [ { name: "Soda", price: 3.75 }, { name: "Candy", price: 5 }, { name: "Popcorn", price: 5.75 }, { name: "Movie Ticket", price: 12 } ] */

Another case might be to compare an array of dates.

const dates = ['2018-12-10', '1991-02-10', '2015-10-07', '1990-01-11']; const sortByMapped = (map,compareFn) => (a,b) => compareFn(map(a),map(b)); const toDate = e => new Date(e).getTime(); const byValue = (a,b) => a - b; const byDate = sortByMapped(toDate,byValue); console.log([...dates].sort(byDate)); // ["1990-01-11", "1991-02-10", "2015-10-07", "2018-12-10"] Reversing a sort

There are some cases where you may want to reverse the outcome of a comparison function. This is subtly different than doing a sort and then reversing the result in the way ties are handled: if you reverse the outcome, ties will also be reversed in order.

To write a higher order function that accepts a comparison function and returns a new one, you will need to flip the sign of the comparison’s return value.

const flipComparison = fn => (a,b) => -fn(a,b); const byAlpha = (a,b) => a.localeCompare(b, null, { sensitivity: 'base' }); const byReverseAlpha = flipComparison(byAlpha); console.log(['A', 'B', 'C'].sort(byReverseAlpha)); // ['C','B','A'] Running a tiebreaker sort

There are times when you may want to have a "tie-breaker" sort — that is, another comparison function that is used in the case of a tie.

By using [].reduce, you can flatten an array of comparison functions into a single one.

const sortByMapped = map => compareFn => (a,b) => compareFn(map(a),map(b)); const flipComparison = fn => (a,b) => -fn(a,b); const byValue = (a,b) => a - b; const byPrice = sortByMapped(e => e.price)(byValue); const byRating = sortByMapped(e => e.rating)(flipComparison(byValue)); const sortByFlattened = fns => (a,b) => fns.reduce((acc, fn) => acc || fn(a,b), 0); const byPriceRating = sortByFlattened([byPrice,byRating]); const restaurants = [ { name: "Foo's Burger Stand", price: 1, rating: 3 }, { name: "The Tapas Bar", price: 3, rating: 4 }, { name: "Baz Pizza", price: 3, rating: 2 }, { name: "Amazing Deal", price: 1, rating: 5 }, { name: "Overpriced", price: 5, rating: 1 }, ]; console.log(restaurants.sort(byPriceRating)); /* {name: "Amazing Deal", price: 1, rating: 5} {name: "Foo's Burger Stand", price: 1, rating: 3} {name: "The Tapas Bar", price: 3, rating: 4} {name: "Baz Pizza", price: 3, rating: 2} {name: "Overpriced", price: 5, rating: 1} */ Writing a random sort

You might want to sort an array "randomly." One technique that I have seen is to use the following function as the comparison function.

const byRandom = () => Math.random() - .5;

Since Math.random() returns a "random" number between 0 and 1, the byRandom function should return a positive number half of the time and a negative number the other half. This seems like it would be a good solution, but unfortunately, since the comparison function is not "consistent" — meaning it may not return the same value when called multiple times with the same values — it may result in some unexpected results.

For example, let's take an array of numbers between 0 and 4. If this byRandom function was truly random, it would be expected that the new index of each number would be spread out equally over enough iterations. The original 0 value would be just as likely to be in index 4 as index 0 in the new array. However, in practice, this function will bias each number to its original position.

See the Pen
Array.sort() Random &#x1f44e;
by Adam Giese (@AdamGiese)
on CodePen.

The "diagonal" from the top-left will statistically have the greatest value. In an ideal and truly random sort, each table cell would hover around 20%.

The fix for this is to find a way to ensure that the comparison function remains consistent. One way to do this is to map the random value to each array element before the comparison, then map it away after.

const sortByMapped = map => compareFn => (a,b) => compareFn(map(a),map(b)); const values = [0,1,2,3,4,5,6,7,8,9]; const withRandom = (e) => ({ random: Math.random(), original: e }); const toOriginal = ({original}) => original; const toRandom = ({random}) => random; const byValue = (a,b) => a - b; const byRandom = sortByMapped(toRandom)(byValue); const shuffleArray = array => array .map(withRandom) .sort(byRandom) .map(toOriginal);

This ensures that each element has a single random value that is only calculated once per element rather than once per comparison. This removes the sorting bias towards the original position.

See the Pen
Array.sort() Random &#x1f44d;
by Adam Giese (@AdamGiese)
on CodePen.

The post Level up your .sort game appeared first on CSS-Tricks.

Designing with Motifs

Css Tricks - Mon, 06/10/2019 - 2:43am

I love the way Erik Kennedy talks about digital design. Very practical and understandable. Have a listen to a chat with him we had on ShopTalk.

One of his latest blog posts is titled "The #1 Way to Spice Up Your Designs (And Create a More Cohesive Brand)" and it's about something he pegs as more of an intermediate (beyond the basics) level design tip about the idea of motifs.

In music, that might be a bit of a melody that asserts itself periodically and kinda informs the rest of the song. It's equally interesting in design, where a theme — perhaps a geometric element — is sprinkled in tastefully that helps the gestalt. Ties the room together, as they say.

Anyway, if you're serious about getting better at design, his course is where it's at and opens up in mid-June. So, now's the time to think about it.

Direct Link to ArticlePermalink

The post Designing with Motifs appeared first on CSS-Tricks.

Using DevTools to Improve the UX Design to Development Process

Css Tricks - Fri, 06/07/2019 - 8:31am

I’d like to tell you how I see code and design intersect and support one another. Specifically, I want to cover how designers can use code in their everyday work. I suggest this not because it’s a required skill, but because even a baseline understanding of coding can make designs better and the hand-off from design to development smoother.

As a UX Designer, I am always looking for good ways to both explore my UX design problems and communicate the final designs to others. Over the past 30 years, my work has always involved working alongside developers, but generally there has been a great divide between what I do and what developers do.

I can code at a basic level. For example, I’ve helped teach C to undergraduates back when I was a post-graduate student. I’ve worked on the usability of JDeveloper Oracle’s Integrated Development Environment (IDE) for Java. I also worked for a very short while on simplifying the UX of a WordPress content management environment to make it accessible to less technical users. This required a good understanding of HTML and CSS. I also volunteered on the design of the PHP website and had to develop some understanding of the server side of web development.

But even given these experiences, I am not a developer in any true sense of the word. If I happen to be looking at code, it’s in a “just in time” learning model — I look up what I need and then hack it until it works. Learning this way has often been frowned upon, a bit like learning to drive without lessons. You pick up bad development habits but maybe that's OK for the work I do.

So, no I don’t develop or write code. My day-to-day work is mostly been spent drawing, talking and gathering requirements. As far as design goes, I’ll start by sketching concepts in a notebook or using Balsamiq. Then I draw up UX wireframes and prototypes using tools like Axure, Adobe XD, InVision Studio, Figma and Sketch. By the time I'm ready to hand off my deliverables to development, all the visual assets and documentation have been defined and communicated. But I don’t step over the line into code development. That is just not my area of expertise.

So, why should designers know code?

We’ve already established that I’m no developer, but I have recently become an advocate for designers getting a good feel for how design and code interact.

In fact, I’d call it “playing with code.” I am definitely not suggesting that UX designers become developers, but at the very least, I think designers would benefit by becoming comfortable with a basic understanding of what is currently possible with CSS and best practices in HTML.

Being experimental is a huge part of doing design. Code is just another medium with which we can experiment and build beautiful solutions. So, we're going to look at a couple of ways designers can experiment with code, even with a light understanding of it. What we're covering here may be obvious to developers, but there are plenty of designers out there who have never experimented with code and will be seeing these for the first time.

So, it's for them (and maybe a refresher for you) that we look at the following browser tools.

DevTools: The ultimate code playground

One of the concerns a UX designer might have is knowing how a design holds up once it’s in the browser. Are the colors accurate? Are fonts legible throughout? How do the elements respond on various devices? Will my grey hover state work with the white/grey zebra striping on my application grids in practice? These are some of the styling and interaction issues designers are thinking about when we hand our work off for development.

This is where DevTools can be a designer’s best friend. Every browser has its own version of it. You may have already played with such tools before. It’s that little “Inspect” option when right clicking on the screen.

Entering the wonderful world of DevTools can be done from any webpage.

What makes DevTools such a wonderful resource is that it provides a way to manipulate the code of a live website or web application without having to set up a development environment. And it’s disposable. Any edits you make are for your eyes only and are washed away the very moment the browser refreshes.

Editing code in DevTools makes changes to the page on the fly.

Further, DevTools can mimic other devices.

Need to see how a page or changes to it look on other devices? DevTools can give you an idea.

And, if you haven’t seen it yet, Firefox released a wonderful new shape path editor that's very valuable for exploring interesting designs.

Over the past few months, I have been working on a complex web client for an enterprise-level application. Last sprint, my UX design story was to explore the look of the entry page of the web application and how to introduce a new color scheme. It was hard to envision how the changes I was making were going to impact the tool as a whole as some of the components I was changing are used throughout the product.

One day, when discussing a design decision, one of the developers tested out my suggested change to a component using the latest DevTools in his browser. I was amazed by how much DevTools has grown and expanded since I last remember it. I could immediately see the impact of that change across our whole web application and how different design decisions interacted with the existing design. I started to experiment with DevTools myself and was able to preview and experiment with how my own simple CSS changes to components would impact the whole web application. Super helpful!

However, it was also a little frustrating to not be able store my experiments and changes for future reference. So, I went exploring to see what else was out there to support my design process.

Chrome browser extensions

DevTools is are amazing right out of the box, but experimenting with code gets even more awesome when browser extensions are added to the mix. Chrome, in particular, has a couple that I really like.

Chrome Extension 1: User CSS

User CSS is a Chrome browser extension that allows you to save the changes you make in DevTools in an editable CSS code tab. These CSS changes are automatically executed on that page if User CSS is enabled. This means that you can set up CSS overrides for any page on the web, view them later, and share them with others. This can be an incredible tool when, say, doing a design review of a staging site prior to release, or really any design exploration for a web application or website that is viewable in a browser.

The first thing I do with User CSS is make the changes in the Chrome elements panel. Then, I simply cut and paste the CSS changes from Chrome’s DevTools to the User CSS code tab as I am going along. This video shows in detail the different ways to edit CSS, HTML and Javascript in Chrome DevTools and how I use UserCSS.

User CSS has a nice built-in code editor, so my code is always well formatted and includes syntax highlighting so I don't have to worry about that sort of thing. I particularly like the fact that overrides are executed immediately so you can see changes on the fly. It also has a useful switch that allows you to turn your overrides on and off. This makes it very simple to demonstrate a set of changes to a team. This extension has allowed me to easily present a comparison between an existing page design and proposed changes. I’ve even used it to make a simple video demonstrating the proposed design changes.

In this video I make some simple edits to my web page and then show how I can turn on and off the edits by simply clicking the on/off button on User CSS:

This extension is a perfect if you all you need to do is edit CSS, particularly if you have some very simple design changes to make want to those changes to persist. However, the complexity of a design increases, I have found myself wanting to save more than one snippet of code at a time. Copying and pasting code in and out of the User CSS editor was becoming a pain. I wanted something with more flexibility and freedom to experiment. I also wanted to be able to look at simple changes to the HTML of my web application and even play with a bit of JavaScript.

That's where the next extension comes into play.

Chrome Extension 2: Web Overrides

The second Chrome extension I found is called Web Override and it provides a way to override HTML, CSS and JavaScript. All of them! This is presented as three tabs, much the same way CodePen does, which makes it a very powerful tool for creating rough working design prototypes.

Web Overrides also allows you to save multiple files so that you can switch different parts of a design on or off in different combinations. It also quickly switches between the different options to show off different design concepts.

This video shows how I added an HTML element into a page and edited the new element with some basic CSS:

Using the HTML tab makes it possible to edit any element on the page, like swap out a logo, remove unnecessary elements, or add new ones. The JavaScript tab is similar in that I can do simple changes, like inject additional text into the website title so that I can test how dynamic changes might affect the layout — this can be useful for testing different scenarios, such as differences with internationalization.

These edits may be trivial from a coding perspective, but they allow me to explore hundreds of alternative designs in a much shorter time and with a lot less risk than scooting pixels around in a design application. I literally could not explore as many ideas as quickly using my traditional UX prototyping tools as I can with this one extension.

And, what is more, both me and my team have confidence in the design deliverables because we tested them early on in the browser. Even the most pixel-perfect Photoshop file can get lost in translation when the design is in the browser because it's really just a snapshot of a design in a static state. Testing designs first in the browser using these extensions prove that what we have designed is possible.

On the flip side of this, you might want to check out how Jon Kantner used similar browser extensions to disable CSS as a means to audit the semantic markup various sites. It's not exactly design-related, but interesting to see how these tools can have different use cases.

What I’ve learned so far

I am excited about what I have learned since leaning into DevTools and browser extensions. I believe my designs are so much better as a result. I also find myself able to have more productive conversations with developers because we now have a way to communicate well. The common ground between design and code in rapid prototypes really helps facilitate discussion. And, because I am playing around with actual code, I have a much better sense about how the underlying code will eventually be written and can empathize a lot more with the work developers do — and perhaps how I can make their jobs easier in the process.

It has also created a culture of collaborative rapid prototyping on my team which is a whole other story.

Playing with code has opened up new ideas and encouraged me to adapt my work to the context of the web. It’s been said that getting into the browser earlier in the design process is ideal and these are the types of tools that allow me (and you) to do just that!

Do you have other tools or processes that you use to facilitate the collaboration between design and code? Please share them in the comments!

The post Using DevTools to Improve the UX Design to Development Process appeared first on CSS-Tricks.

Weekly Platform News: Feature Policy, ECMAScript i18n API, Packaged PWAs

Css Tricks - Fri, 06/07/2019 - 4:27am

Šime posts regular content for web developers on webplatform.news.

New Feature Policy API in Chrome

Pete LePage: You can use the document.featurePolicy.allowedFeatures method in Chrome to get a list of all Feature Policy-controlled features that are allowed on the current page.

This API can be useful when implementing a feature policy (and updating an existing feature policy) on your website.

  1. Open your site in Chrome and run the API in the JavaScript console to check which Feature Policy-controlled features are allowed on your site.
  2. Read about individual features on featurepolicy.info and decide which features should be disabled ('none' value), and which features should be disabled only in cross-origin <iframe> elements ('self' value).
  3. Add the Feature-Policy header to your site’s HTTP responses (policies are separated by semicolons).
  4. Feature-Policy: geolocation 'self';sync-xhr 'none'
  5. Repeat Step 1 to confirm that your new feature policy is in effect. You can also scan your site on securityheaders.com.
In other news...
  • Dave Camp: Firefox now blocks cookies from known trackers by default (when the cookie is used in a third-party context). This change is currently in effect only for new Firefox users; existing users will be automatically updated to the new policy "in the coming months."
  • Pete LePage: Chrome for Android now allows websites to share images (and other file types) via the navigator.share method. See Web Platform News Issue 1014 for more information about the Web Share API. Ayooluwa Isaiah's post from yesterday is also a good reference on how to use it.
  • Valerie Young: The ECMAScript Internationalization APIs for date and time formatting (Intl.DateTimeFormat constructor), and number formatting (Intl.NumberFormat constructor) are widely supported in browsers.
  • Alan Jeffrey: Patrick Walton from Mozilla is working on a vector graphics renderer that can render text smoothly at all angles when viewed with an Augmented Reality (AR) headset. We plan to use it in our browsers for AR headsets (Firefox Reality).
  • Pinterest Engineering: Our progressive web app is now available as a standalone desktop application on Windows 10. It can be installed via the Microsoft Store, which "treats the packaged PWA as a first class citizen with access to Windows 10 feature APIs."
  • Jonathan Davis: The flow-root value for the CSS display property has landed in Safari Technology Preview. This value is already supported in Chrome and Firefox. See Web Platform News Issue 871 for a use case.

The post Weekly Platform News: Feature Policy, ECMAScript i18n API, Packaged PWAs appeared first on CSS-Tricks.

Your first performance budget with Lighthouse

Css Tricks - Fri, 06/07/2019 - 4:26am

Ire Aderinokun writes about a new way to set a performance budget (and stick to it) with Lighthouse, Google’s suite of tools that help developers see how performant and accessible their websites are:

Until recently, I also hadn't setup an official performance budget and enforced it. This isn’t to say that I never did performance audits. I frequently use tools like PageSpeed Insights and take the feedback to make improvements. But what I had never done was set a list of metrics that I needed the site to meet, and enforce them using some automated tool.

The reasons for this were a combination of not knowing what exact numbers I should use for budgets as well as there being a disconnect between setting a budget and testing/enforcing it. This is why I was really excited when, at Google I/O this year, the Lighthouse team announced support for performance budgets that can be integrated with Lighthouse. We can now define a simple performance budget in a JSON file, which will be tested as part of the lighthouse audit!

I completely agree with Ire, and much in the same way I’ve tended to neglect sticking to a performance budget simply because the process of testing was so manual and tedious. But no more! As Ire shows in this post, you can even set Lighthouse up to test your budget with every PR in GitHub. That tool is called lighthousebot and it’s just what I’ve been looking for – an automated and predictable way to integrate a performance budget into every change that I make to a codebase.

Today lighthousebot will comment on your PR after a test is complete and it will show you the before and after score:

How neat is that? This reminds me of Gareth Clubb’s recent post about improving web performance and building a culture around budgets in an organization. What better way to remind everyone about performance than right in GitHub after each and every change that they make?

Direct Link to ArticlePermalink

The post Your first performance budget with Lighthouse appeared first on CSS-Tricks.

What if we got aspect-ratio sized images by doing almost nothing?

Css Tricks - Thu, 06/06/2019 - 12:00pm

Say you have an image you're using in an <img> that is 800x600 pixels. Will it actually display as 800px wide on your site? It's very likely that it will not. We tend to put images into flexible container elements, and the image inside is set to width: 100%;. So perhaps that image ends up as 721px wide, or 381px wide, or whatever. What doesn't change is that image's aspect ratio, lest you squish it awkwardly (ignoring the special use-case object-fit scenario).

The main point is that we don't know how much vertical space an image is going to occupy until that image loads. This is the cause of jank! Terrible jank! It's everywhere and it's awful.

There are ways to create aspect-ratio sized boxes in HTML/CSS today. None of the options are particularly elegant because they rely on the "hack" of setting a zero height and pushing the boxes height with padding. Wouldn't it be nicer to have a platform feature to help us here? The first crack at fixing this problem that I know about is an intrinsicsize attribute. Eric Portis wrote about how this works wonderfully in Jank-Free Image Loads.

We'd get this:

<img src="image.jpg" intrinsicsize="800x600" />

This is currently behind a flag in Chrome 71+, and it really does help solve this problem.

But...

The intrinsicsize property is brand new. It will only help on sites where the developers know about it and take the care to implement it. And it's tricky! Images tend to be sized arbitrarily, and the intrinsicsize attribute will need to be custom on every image to be accurate and do its job. That is, if it makes it out of standards at all.

There is another possibility! Eric also talked about the aspect-ratio property in CSS as a potential solution. It's also still just a draft spec. You might say, but how is this helpful? It needs to be just as bespoke as intrinsicsize does, meaning you'd have to do it as inline styles to be helpful. Maybe that's not so bad if it solves a big problem, but inline styles are such a pain to override and it seems like the HTML attribute approach is more inline with the spirit of images. Think of how srcset is a hint to browsers for what images are available to download, allowing the browser to pick the best one for the scenario. Telling the browser about the aspect-ratio upfront is similarly useful.

I heard from Jen Simmons about an absolutely fantastic way to handle this: put a default aspect ratio into the UA stylesheet based on the elements existing width and height attributes. Like this:

img, video { aspect-ratio: attr(width) / attr(height); }

Let that soak in.

Now if you already have:

<img src="image.jpg" width="800" height="600" />

It automatically has the correct aspect ratio as the page loads. That's awesome.

  1. It's easy to understand.
  2. A ton of the internet already has these attributes sitting on their images.
  3. New developers will have no trouble understanding this, and old developers will be grateful there is little (if any) work to do here.

I like the idea of the CSS feature. But I like 100 times more the idea of putting it into the UAUA stylesheet is no small thing to consider — and I'm not qualified to understand all the implications of that — but it feels like a very awesome thing at first consideration.

Jen has a ticket open for people to voice their thoughts and links to the bug ticket where Firefox is going to test this out to see how it goes.

The post What if we got aspect-ratio sized images by doing almost nothing? appeared first on CSS-Tricks.

How to Use the Web Share API

Css Tricks - Thu, 06/06/2019 - 4:21am

The Web Share API is one that has seemingly gone under the radar since it was first introduced in Chrome 61 for Android. In essence, it provides a way to trigger the native share dialog of a device (or desktop, if using Safari) when sharing content — say a link or a contact card — directly from a website or web application.

While it’s already possible for a user to share content from a webpage via native means, they have to locate the option in the browser menu, and even then, there’s no control over what gets shared. The introduction of this API allows developers to add sharing functionality into apps or websites by taking advantage of the native content sharing capabilities on a user’s device.

iOS offers a number of native sharing options.

This approach provides a number of advantages over conventional methods:

  • The user is presented with a wide range of options for sharing content compared to the limited number you might have in your DIY implementation.
  • You can improve your page load times by doing away with third-party scripts from individual social platforms.
  • You don’t need to add a series of buttons for different social media sites and email. A single button is sufficient to trigger the device’s native sharing options.
  • Users can customize their preferred share targets on their own device instead of being limited to just the predefined options.
A note on browser support

Before we get into the details of how the API works, let’s get the issue of browser support out of the way. To be honest, browser support isn’t great at this time. It’s only available for Chrome for Android, and Safari (desktop and iOS).

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

DesktopChromeOperaFirefoxIEEdgeSafariNoNoNoNoNo12.1Mobile / TabletiOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox12.2NoNoNo74No

But don’t let that discourage you from adopting this API on your website. It’s pretty easy to implement a fallback for supporting browsers that don’t offer support for it, as you’ll see.

A few requirements for using it

Before you can adopt this API on your own web project, there are two major things to note:

  • Your website has to be served over HTTPS. To facilitate local development, the API also works when your site is running over localhost.
  • To prevent abuse, the API can only be triggered in response to some user action (such as a click event).
Here's an example

To demonstrate how to use this API, I’ve prepared a demo that works essentially the same as it does on my site. Here’s how it looks like:

See the Pen
WebShare API Demo - Start
by Ayooluwa (@ayoisaiah)
on CodePen.

At this moment, once you click the share button, a dialog pops out and shows a few options for sharing the content. Here’s the part of the code that helps us achieve that:

shareButton.addEventListener('click', event => { shareDialog.classList.add('is-open'); });

Let’s go ahead and convert this example to use the Web Share API instead. The first thing to do is check if the API is indeed supported on the user’s browser as shown below:

if (navigator.share) { // Web Share API is supported } else { // Fallback }

Using the Web Share API is as simple as calling the navigator.share() method and passing an object that contains at least one of the following fields:

  • url: A string representing the URL to be shared. This will usually be the document URL, but it doesn’t have to be. You share any URL via the Web Share API.
  • title: A string representing the title to be shared, usually document.title.
  • text: Any text you want to include.

Here’s how that looks in practice:

shareButton.addEventListener('click', event => { if (navigator.share) { navigator.share({ title: 'WebShare API Demo', url: 'https://codepen.io/ayoisaiah/pen/YbNazJ' }).then(() => { console.log('Thanks for sharing!'); }) .catch(console.error); } else { // fallback } });

At this point, once the share button is clicked in a supported browser, the native picker will pop out with all the possible targets that the user can share the data with. Targets can be social media apps, email, instant messaging, SMS or other registered share targets.

The API is promised-based, so you can attach a .then() method to perhaps display a success message if the share was successful, and handle errors with .catch(). In a real-world scenario, you might want to grab the page’s title and URL using this snippet:

const title = document.title; const url = document.querySelector('link[rel=canonical]') ? document.querySelector('link[rel=canonical]').href : document.location.href;

For the URL, we first check if the page has a canonical URL and, if so, use that. Otherwise, we grab the href off document.location.

Providing a fallback is a good idea

In browsers where the Web Share API isn’t supported, we need to provide a fallback mechanism so that users on those browsers still get some sharing options.

In our case, we have a dialog that pops out with a few options for sharing the content and the buttons in our demo do not actually link to anywhere since, well, it’s a demo. But if you want to learn about how you can create your own links to share web pages without third-party scripts, Adam Coti's article is a good place to start.

What we want to do is display the fallback dialog for users on browsers without support for the Web Share API. This is as simple as moving the code that opens the share dialog into the else block:

shareButton.addEventListener('click', event => { if (navigator.share) { navigator.share({ title: 'WebShare API Demo', url: 'https://codepen.io/ayoisaiah/pen/YbNazJ' }).then(() => { console.log('Thanks for sharing!'); }) .catch(console.error); } else { shareDialog.classList.add('is-open'); } });

Now, all users are covered regardless of what browser they’re on. Here's a comparison of how the share button behaves on two mobile browsers, one with Web Share API support, and the other without:

Try it out! Use a browser that supports Web Share, and one that doesn't. It should work similarly to the above demonstration.

See the Pen
WebShare API Demo - End
by Ayooluwa (@ayoisaiah)
on CodePen.

Wrapping up

This covers pretty much the baseline for what you need to know about the Web Share API. By implementing it on your website, visitors can share your content more easily across a wider variety of social networks, with contacts and other native apps.

It’s also worth noting that you’re able to add your web application as a share target if it meets the Progressive Web App installation criteria and is added to a user’s home screen. This a feature of the Web Share Target API which you can read about at Google Developers.

Although browser support is spotty, a fallback is easily implemented, so I see no reason why more websites shouldn’t adopt this. If you want to learn more about this API, you can read the specification here.

Have you used the Web Share API? Please share it in the comments.

The post How to Use the Web Share API appeared first on CSS-Tricks.

Snag Resources from An Event Apart Boston 2019 and Save on Washington D.C. Registration

Css Tricks - Thu, 06/06/2019 - 4:10am

(This is a sponsored post.)

Hey, so we talked a little bit about An Event Apart Boston 2019 leading up to the event and now there are a ton of resources available from it. I stopped counting the number of links after 50 because there's way more than that. Seriously, there's stuff in there on subgrid, working with CSS Regions, design systems, using prefers-reduced-motion... and much, much more, so check it out.

And, while you're at it, you should consider attending the next installment of An Event Apart. It takes place July 29-31 in Washington D.C. and seating — as you might expect — is limited. Like Boston, you can expect to get a treasure trove of useful information, educational content, and valuable training on topics that will help you sharpen your front-end chops and grow your career. Plus, the best part is getting to meet the rest of the great folks at the event — that's where your network grows and real conversations take place.

Register Today

Can't make it to Washington D.C.? No worries, because An Event Apart is also slated to take place in Chicago (August 26-28), Denver (October 28-30) and San Francisco (December 9-11). Now's the time to start planning your trip and begging your boss for a well-deserved self-investment in leveling up.

And if you're wondering whether we have a discount code for you... of course we do! Enter the AEACP at checkout to knock $100 off the price. &#x1f911;

Direct Link to ArticlePermalink

The post Snag Resources from An Event Apart Boston 2019 and Save on Washington D.C. Registration appeared first on CSS-Tricks.

A Course About CSS Layout and Animations

Css Tricks - Wed, 06/05/2019 - 1:17pm

Christina Gorton just released a new course called CSS Layout and Animations as a part of Design+Code, which is a $9/month. That includes a ton of video training on everything from stuff like this to React to Sketch to iOS development... and beyond!

Christina approaches the course with my favorite way to learn this stuff: by starting from a lovely design and then pulling it off with code.

That's Figma as the design tool, which is another tool I love.

Of course, what I really love is that:

  • The course is full of CSS trickery and modern HTML & CSS features, like using flexbox and grid in practical ways.
  • She uses CodePen to prototype everything — the perfect place to get started with a project like this, in my humble opinion.

Direct Link to ArticlePermalink

The post A Course About CSS Layout and Animations appeared first on CSS-Tricks.

JAMstack? More like SHAMstack.

Css Tricks - Wed, 06/05/2019 - 5:30am

I'm a fan of the whole JAMstack thing. It seems like a healthy web movement. I'm looking forward to both of the upcoming conferences.

Of any web trend, #jamstack seems like it will be the least regrettable.

— Chris Coyier (@chriscoyier) May 22, 2019

I feel like the acronym might not be quite doing it justice though. Not that I suggest we change it. Once a thing like that has legs, I find it's best to roll with it. Same deal with serverless. Heck, the name of this website is pretty... not great.

To me, the most important part of JAMstack is rooted in the concept of static file hosting. Static file hosting is the foundation of all the power. It opens up a bunch of doors, like:

  • Everything can be CDN-hosted. "The edge," as they say. Even the HTML (the M in JAMStack also refers to Markup) can be CDN-hosted, which you otherwise can't do. That gives you an amazing base of speed that encourages you to keep that speed as you build.
  • The project feels easier to work with. Git clone, npm install, build. Deployments are git pushes of a dist folder. It's so cool, for example, Netlify gives you a URL for every build, even on branches you're working on. This is made possible by deploys being kind of immutable. A set of files at a particular point in time.
  • Cloud functions are awesome. Because you don't have a traditional server-side language to reach for, you build it with cloud functions when you do need server-side code — which is a cool way to architect things anyway and is very spiritually connected to all this.

Don't think, "Oh, JAMstack is just for Jekyll blogs," or whatever. True, static site generators are extremely JAMstack-y, and JAMstack highly encourages as much prebuilt markup as possible (which is good for speed and SEO and all that), but pre-built markup isn't a requirement.

I'd go so far as to say that a client-side JavaScript-powered app that ships a <div id="root"></div> and a bundle of JavaScript that hits APIs and builds out the site is still a JAMstack site. It's still statically hosted (probably) with cloud functions serving up data.

I’d say “yes”.

Perhaps a little more SSR would be good for all the reasons but meh, not required for a jamstack merit badge.

— Chris Coyier (@chriscoyier) May 22, 2019

But as long as you're JAMStack anyway, that encourages you to put more in those static files. In that way, it encourages static content as well, when possible. I'd say "server-side rendered" (SSR) as that's the common term, but it's beyond that. It's not a server side language generating the markup on request; it's built in a build step ahead of time, before deployment. Again it's not required, just encouraged.

So, we've got static-hosted HTML, and all our other files (e.g. CSS, images, etc.) are also static. Then:

  • The J of JAMstack is JavaScript.
  • The A of JAMstack is APIs.

They are sorta kinda the same thing. Your JavaScript files are statically hosted. They run, and they talk to APIs if they need to. A common example might be a GraphQL endpoint coughing up some content.

An interesting twist here is that you can half-and-half this stuff. In other words, you can pre-build some of the markup, and wait for JavaScript and API calls for other parts. Imagine an e-commerce site with a homepage and a dozen other pages you can pre-build entirely, but then a catalog of thousands of products that would be too impractical to statically generate (too slow). They are just a single scaffolded template that flesh themselves out with client-side API calls.

So, if we were to make a new acronym, perhaps we'd include Static Hosting in there and combine the JavaScript and APIs into just APIs, leaving us with...

Static Hosting, APIs, and Markup, or the SHAMstack. Errrrr &#x1f62c; maybe not.

The post JAMstack? More like SHAMstack. appeared first on CSS-Tricks.

Self-Host Your Static Assets

Css Tricks - Wed, 06/05/2019 - 5:30am

Harry Roberts digs into why hosting assets on someone else’s servers (including CDNs) is not such a great idea if we want our websites to be lightning fast.

Harry writes:

One of the quickest wins—and one of the first things I recommend my clients do—to make websites faster can at first seem counter-intuitive: you should self-host all of your static assets, forgoing others’ CDNs/infrastructure.

I think perhaps the most shocking example Harry shows is this one:

...on a reasonably fast connection, hosting these static assets off-site is 311ms, or 1.65×, slower than hosting them ourselves.

By linking to three different origins in order to serve static assets, we cumulatively lose a needless 805ms to network negotiation. Full test. Okay, so not exactly terrifying, but Trainline, a client of mine, found that by reducing latency by 300ms, customers spent an extra £8m a year. This is a pretty quick way to make eight mill.

It’s clear from Harry’s example (as well as the rest of the examples on WPO stats) every millisecond counts when it comes to performance. And, if we can alleviate even a third of a second of latency by moving our assets around, we should probably go do that.

Direct Link to ArticlePermalink

The post Self-Host Your Static Assets appeared first on CSS-Tricks.

Movin’ Modals Along a Path

Css Tricks - Tue, 06/04/2019 - 10:07am

Modals always be just appearin'. You might see one once in a while that slides in from one of the edges, or uses some kind of scale/opacity thing to appear from "above" or "below." But we can get weirder than that. Why not have them come in on an offset-path?

Just a swoopy arc is kinda fun.

See the Pen
Move Modal In on Path
by Chris Coyier (@chriscoyier)
on CodePen.

Or we could Mary Poppins it and have it come floating in from afar.

See the Pen
Move Modal In on Path: Mary Poppins Edition
by Chris Coyier (@chriscoyier)
on CodePen.

Or get straight up wiggly woggly.

See the Pen
Move Modal In on Path: Wackadoo
by Chris Coyier (@chriscoyier)
on CodePen.

That's all. I figured you were here for the CSS tricks, anyway. ;)

The post Movin’ Modals Along a Path appeared first on CSS-Tricks.

Creating Animations Using React Spring

Css Tricks - Tue, 06/04/2019 - 4:17am

Have you ever needed animation in your React application? Traditionally, implementing animation has not an easy feat to accomplish. But now, thanks to Paul Henschel, we there’s a new React tool just for that. react-spring inherits from animated and react-motion for interpolations, optimized performance, and a clean API.

In this tutorial, we will be looking at two of the five hooks included in react-spring, specifically useSpring and useTrail. The examples we’ll implement make use of both APIs.

If you want to follow along, install react-spring to kick things off:

## yarn yarn add react-spring ## npm npm install react-spring --save Spring

The Spring prop can be used for moving data from one state to another. We are provided with a from and to prop to help us define the animation’s starting and ending states. The from prop determines the initial state of the data during render, while we use to in stating where it should to be after the animation completes.

In the first example, we will make use of the render prop version of creating spring animation.

See the Pen
react spring 1
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

On initial render, we want to hide a box, and slide it down to the center of the page when a button is clicked. It’s possible to do this without making use of react-spring, of course, but we want to animate the entrance of the box in to view and only when the button is clicked.

class App extends React.Component { state = { content: false } displayContent = (e) => { e.preventDefault() this.setState({ content: !this.state.content }) } render() { return ( <div className="container"> // The button that toggles the animation <div className="button-container"> <button onClick={this.displayContent} className="button"> Toggle Content </button> </div> { !this.state.content ? ( // Content in the main container <div> No Content </div> ) : ( // We call Spring and define the from and to props <Spring from={{ // Start invisible and offscreen opacity: 0, marginTop: -1000, }} to={{ // End fully visible and in the middle of the screen opacity: 1, marginTop: 0, }} > { props => ( // The actual box that slides down <div className="box" style={ props }> <h1> This content slid down. Thanks to React Spring </h1> </div> )} </Spring> ) } </div> ) } }

Most of the code is basic React that you might already be used to seeing. We make use of react-spring in the section where we want to conditionally render the content after the value of content has been changed to true. In this example, we want the content to slide in from the top to the center of the page, so we make use of marginTop and set it to a value of -1000 to position it offscreen, then define an opacity of 0 as our values for the from prop. This means the box will initially come from the top of the page and be invisible.

Clicking the button after the component renders updates the state of the component and causes the content to slide down from the top of the page.

We can also implement the above example using the hooks API. For this, we’ll be making use of the useSpring and animated hooks, alongside React’s built-in hooks.

const App = () => { const [contentStatus, displayContent] = React.useState(false); // Here's our useSpring Hook to define start and end states const contentProps = useSpring({ opacity: contentStatus ? 1 : 0, marginTop: contentStatus ? 0 : -1000 }) return ( <div className="container"> <div className="button-container"> <button onClick={() => displayContent(a => !a)} className="button">Toggle Content</button> </div> { !contentStatus ? ( <div> No Content </div> ) : ( // Here's where the animated hook comes into play <animated.div className="box" style={ contentProps }> <h1> This content slid down. Thanks to React Spring </h1> </animated.div> ) } </div> ) }

First, we set up the state for the component. Then we make use of useSpring to set up the animations we need. When contentStatus is true, we want the values of marginTop and opacity to be 0 and 1, respectively. Else, they should be -1000 and 0. These values are assigned to contentProps which we then pass as props to animated.div.

When the value of contentStatus changes, as a result of clicking the button, the values of opacity and marginTop changes alongside. This cause the content to slide down.

See the Pen
react spring 2
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Trail

The Trail prop animates a list of items. The animation is applied to the first item, then the siblings follow suit. To see how that works out, we’ll build a component that makes a GET request to fetch a list of users, then we will animate how they render. Like we did with Spring, we’ll see how to do this using both the render props and hooks API separately.

First, the render props.

class App extends React.Component { state = { isLoading: true, users: [], error: null }; // We're using the Fetch <abbr>API</abbr> to grab user data // https://css-tricks.com/using-data-in-react-with-the-fetch-api-and-axios/ fetchUsers() { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => // More on setState: https://css-tricks.com/understanding-react-setstate/ this.setState({ users: data, isLoading: false, }) ) .catch(error => this.setState({ error, isLoading: false })); } componentDidMount() { this.fetchUsers(); } render() { const { isLoading, users, error } = this.state; return ( <div> <h1>Random User</h1> {error ? <p>{error.message}</p> : null} {!isLoading ? ( // Let's define the items, keys and states using Trail <Trail items={users} keys={user => user.id} from={{ marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }} to={{ marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' }} > {user => props => ( <div style={props} className="box"> {user.username} </div> )} </Trail> ) : ( <h3>Loading...</h3> )} </div> ); } }

When the component mounts, we make a request to fetch some random users from a third-party API service. Then, we update this.state.users using the data the API returns. We could list the users without animation, and that will look like this:

users.map(user => { const { username, name, email } = user; return ( <div key={username}> <p>{username}</p> </div> ); })

But since we want to animate the list, we have to pass the items as props to the Trail component:

<Trail items={users} keys={user => user.id} from={{ marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }} to={{ marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' }} > {user => props => ( <div style={props} className="box"> {user.username} </div> )} </Trail>

We set the keys to the ID of each user. You can see we are also making use of the from and to props to determine where the animation should start and end.

Now our list of users slides in with a subtle animation:

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

The hooks API gives us access to useTrail hook. Since we are not making use of a class component, we can make use of the useEffect hook (which is similar to componentDidMount and componentDidUpdate lifecycle methods) to fetch the users when the component mounts.

const App = () => { const [users, setUsers] = useState([]); useEffect(() => { fetch(`https://jsonplaceholder.typicode.com/users`) .then(response => response.json()) .then(data => setUsers(data) ) }, []) const trail = useTrail(users.length, { from: { marginLeft: -20, opacity: 0, transform: 'translate3d(0,-40px,0)' }, to: { marginLeft: 20, opacity: 1, transform: 'translate3d(0,0px,0)' } }) return ( <React.Fragment> <h1>Random User</h1> {trail.map((props, index) => { return ( <animated.div key={users[index]} style={props} className="box" > {users[index].username} </animated.div> ) })} </React.Fragment> ); }

We have the initial state of users set to an empty array. Using useEffect, we fetch the users from the API and set a new state using the setUsers method we created with help from the useState hook.

Using the useTrail hook, we create the animated style passing it values for from and to, and we also pass in the length of the items we want to animate. In the part where we want to render the list of users, we return the array containing the animated props.

See the Pen
React Spring -Trail 2
by Kingsley Silas Chijioke (@kinsomicrote)
on CodePen.

Go, spring into action!

Now you have a new and relatively easy way to work with animations in React. Try animating different aspects of your application where you see the need. Of course, be mindful of user preferences when it comes to animations because they can be detrimental to accessibility.

While you’re at it, ensure you check out the official website of react-spring because there are tons of demo to get your creative juices flowing with animation ideas.

The post Creating Animations Using React Spring appeared first on CSS-Tricks.

Do you need an ICON ONLY button without screwing up the accessibility?

Css Tricks - Mon, 06/03/2019 - 11:42am

The first consideration is: do you really? If you can, having text next to your icons is proven over and over again to be the most accessible and clearest UX (see Apple's latest blunder). But if you need to (and I get it, sometimes you need to), Sara Soueidan and Scott O'Hara have a pair of articles that nicely lay out all the options and present actual research on this topic.

If you just want to be told what to do, I'd go for the just use some text in the button approach:

<button aria-expanded="false" id="menu-trigger"> <svg viewBox="0 0 32 32" width="32px" height="32px" aria-hidden="true" focusable="false"> <!-- svg content --> </svg> Menu </button>

Sara says There is no One Way to Rule Them All, but it does seem like you really need to use actual text inside that button and either hide it or override it somehow. SVG alone has no rock solid way to provide an accessible name to a button or link.

Funny how long this has been a tricky pattern to get right.

The post Do you need an ICON ONLY button without screwing up the accessibility? appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.