Web Standards

“Killing the URL”

Css Tricks - Fri, 09/07/2018 - 1:05pm

It was Safari who first started hiding the complete URL. Here's what CSS-Tricks looks like even when you're on an article page by default in Safari:

The full URL path is hidden.

You can only fix it (YES, FIX IT) by checking "Show full website address" in settings.

Preferences > Advanced

We've already damaged the sanctity of URLs in a way with URL shorteners. Thankfully, those are used less and less with social networks, like Twitter, not counting the URL toward the total tweet character count anymore.

Now, Lily Hay Newman reports Chrome sees problems as well:

"People have a really hard time understanding URLs," says Adrienne Porter Felt, Chrome's engineering manager. "They’re hard to read, it’s hard to know which part of them is supposed to be trusted, and in general I don’t think URLs are working as a good way to convey site identity. So we want to move toward a place where web identity is understandable by everyone—they know who they’re talking to when they’re using a website and they can reason about whether they can trust them. But this will mean big changes in how and when Chrome displays URLs. We want to challenge how URLs should be displayed and question it as we’re figuring out the right way to convey identity."

I'm not seeing the same research they are. Anecdotally, I'm not sure I've met anyone who doesn't understand a URL. I wonder if there is something else weird afoot here. URLs are the single greatest feature of the web. I know nobody is arguing about removing them (just visually hiding them by default), but it doesn't feel like a step in the right direction. It also seems slightly at odds with the celebration of the web in Chrome's 10-year anniversary post by Paul Kinlan:

We can thank all the browser vendors for their continued work to create and iterate on specs, using streamlined processes like those defined by the WICG and based on the principles in the Extensible Web Manifesto. We’ll continue our commitment to work with browser vendors and the developer ecosystem to prioritize features that users need, and to ensure that those capabilities arrive in a “webby” way.

I'd say seeing URL's is pretty "webby."

The post “Killing the URL” appeared first on CSS-Tricks.

Shadow DOM in Ionic

Css Tricks - Fri, 09/07/2018 - 1:05pm

Mike Hartington glows about how good and useful the Shadow DOM is:

[Shadow DOM is] actually built on two simple ideas, isolation and location. Need to create a bit of DOM that is isolated from the global scope? Shadow DOM is here to help. Need to specify the exact location of a piece of DOM? Shadow DOMs scope API is what you need!

It can be helpful to think of components that use Shadow DOM as modules for HTML. Markup and styles are isolated to their own DOM tree, and removed from the global context.

Last time we talked about it around here, I showed how Twitter is using it for embedded tweets — which is a pretty awesome use case — and how it can fall back to an iframe. Mike says they polyfill it in unsupported situations.

I suspect isolated styles is the primary selling point for any of the CSS-in-JS approaches, and having wide support for a native implementation of that will eventually take over. But... you have to make use of web components to use this, which means your framework-created components need to be web components. That's totally possible; I just don't see it that often.

Direct Link to ArticlePermalink

The post Shadow DOM in Ionic appeared first on CSS-Tricks.

Working With Events in React

Css Tricks - Fri, 09/07/2018 - 4:01am

Most of the behavior in an application revolves around events. User enters a value in the registration form? Event. User hits the submit button? Another event. Events are triggered a number of ways and we build applications to listen for them in order to do something else in response.

You may already be super comfortable working with events based on your existing JavaScript experience. However, React has a distinct way of handling them. Rather than directly targeting DOM events, React wraps them in their own event wrapper. But we’ll get into that.

Let’s go over how to create, add and listen for events in React.

Creating Events

We’ll start by creating a form that has an input and a button. An event will be triggered when a value is entered. The button is used to call a function which will reverse that value.

Here’s how it'll work:

  • An empty input field allows the user to enter text.
  • An onChange event is triggered when values are entered in the input. This calls a function — handleChange() — that is used to set a new state for the input.
  • When the "Reverse Text" button is clicked, another event is triggered. This calls a function — handleReverse() — to set a new state for reversedText.

Here’s that translated into code:

class App extends React.Component { state = { /* Initial State */ input: "", reversedText: "" }; /* handleChange() function to set a new state for input */ handleChange = event => { const value = event.target.value; this.setState({ input: value }); }; /* handleReverse() function to reverse the input and set that as new state for reversedText */ handleReverse = event => { event.preventDefault(); const text = this.state.input; this.setState({ reversedText: text .split("") .reverse() .join("") }); }; render() { return ( <React.Fragment> { /* handleReverse() is called when the form is submitted */ } <form onSubmit={this.handleReverse}> <div> { /* Render input entered */} <label>Text: {this.state.input}</label> </div> <div> { /* handleChange() is triggered when text is entered */ } <input type="text" value={this.state.input} onChange={this.handleChange} placeholder="Enter a text" /> </div> <div> <button>Reverse Text</button> </div> </form> { /* Render reversed text */} <p>Reversed Text: {this.state.reversedText}</p> </React.Fragment> ); } }}

See the Pen React Event Pen - form by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Listening to component events

Let’s say you have a component like this;

class IncrementButton extends React.Component{ render() { return ( <React.Fragment> <button>+</button> </React.Fragment> ) } }

Will including it in your App component like this work?

class App extends React.Component{ state = { count: 0 } handleIncrement = (event) => { this.setState({ count: this.state.count + 1}) } render() { return( <React.Fragment> <h1>{this.state.count}</h1> <IncrementButton onClick={this.handleIncrement} /> </React.Fragment> ) } }

No, it won’t because you can only listen to events on DOM elements. We touched on this at the beginning of the post, but React components are wrappers for DOM elements. That means we essentially have a layer that we need to pass through to listen for the event.

The way around this is to pass the event handler as a prop to the child component. Then the prop is passed down to the click event as an attribute like so:

class IncrementButton extends React.Component{ render() { return ( <React.Fragment> <button onClick={this.props.increaseButton}>+</button> </React.Fragment> ) } } class App extends React.Component{ state = { count: 0 } handleIncrement = (event) => { this.setState({ count: this.state.count + 1}) } render() { return( <React.Fragment> <h1>{this.state.count}</h1> <IncrementButton increaseButton={this.handleIncrement} /> </React.Fragment> ) } }

See the Pen React Event Pen - Component Events by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

You could make use of a stateless functional component instead:

const IncrementButton = (props) => { return ( <React.Fragment> <button onClick={props.increaseButton}>+</button> </React.Fragment> ) } Adding event listeners

There may be times when you want to make use of certain DOM events that are triggered when the component is mounted. Let’s see this using the resize event — we want to see the width of the window whenever it is resized.

class App extends React.Component{ state = { windowWith: window.innerWidth } handleResize = (event) => { this.setState({ windowWith: window.innerWidth }) } render() { return( <React.Fragment> <h1>Window Width</h1> <h1>{this.state.windowWith}</h1> </React.Fragment> ) } }

If we create a component and try it out like we have below, then the event will not be triggered. We’ll need to add the event listener (handleResize() in this case) and the event type like we have here:

class App extends React.Component{ state = { windowWith: window.innerWidth } handleResize = (event) => { this.setState({ windowWith: window.innerWidth }) } componentDidMount() { window.addEventListener('resize', this.handleResize) } componentDidUnmount() { window.removeEventListener('resize', this.handleResize) } render() { return( <React.Fragment> <h1>Window Width</h1> <h1>{this.state.windowWith}</h1> </React.Fragment> ) } }

See the Pen React Event Pen - addEventListener by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Now, the event listener will be added when the component mounts. That means our component is actively listening to the browser window and will display its width when it updates.

In summary

OK, so we covered quite a bit of ground in a very small amount of space. We learned that React does not connect directly to a DOM event, but rather Synthetic Events that are wrappers for DOM events. We dug into the process for creating event listeners so that they attach to Synthetic Events and, from there, made sure that a component will update when those events are triggered.

Additional resources

The post Working With Events in React appeared first on CSS-Tricks.

The Complete CSS Demo for OpenType Features

Css Tricks - Thu, 09/06/2018 - 8:47am

I'm very glad a guide for these features exists because we already know there are so many weird things that variable fonts can do — well done, Tunghsiao Liu!

There are quite a few possible values for font-feature-settings, like, ya know:

aalt, swsh, cswh, calt, hist, hlig, locl, rand, nalt, cv01-cv99, salt, subs, sups, titl, rvrn, liga, dlig, size, ornm, ccmp, kern, mark, mkmk, smcp, c2sc, pcap, c2pc, unic, cpsp, case, ital, ordn, lnum, onum, pnum, tnum, frac, afrc, dnom, numr, sinf, zero, mgrk, flac, dtls, ssty, ss01-ss20, smpl, trad, tnam, expt, hojo, nlck, jp78, jp83, jp90, jp04, hngl, ljmo, tjmo, vjmo, fwid, hwid, halt, twid, qwid, pwid, palt, pkna, ruby, hkna, vkna, rlig, init, medi, and fina

...to name a few.

Direct Link to ArticlePermalink

The post The Complete CSS Demo for OpenType Features appeared first on CSS-Tricks.

Helping a Beginner Understand Getting a Website Live

Css Tricks - Thu, 09/06/2018 - 4:01am

I got a great email from a fellow named Josh Long the other day. He is, in his words, "relatively new to web design" and was a bit stuck on the concept of getting a site live. I should say that I'm happy to get emails like this an I always read them, but I typically can't offer tech support over email. If I can respond at all, I normally point people to other community resources.

In this case, it struck me what a perfect moment this is for Josh. He's a little confused, but he knows enough to be asking a lot of questions and sorting through all this stuff. I figured this was a wonderful opportunity to dig into his questions, hopefully helping him and just maybe helping others in a similar situation.

Here's one of the original paragraphs Josh sent me, completely unedited:

I’m relatively new to web design, but I’ve taken a few courses on HTML and CSS and I’ve done a Codecademy course on JavaScript. But, (jumping forward probably quite a while here!) after having fully designed and coded a HTML/CSS/JS website or webpage, I don’t fully understand the full process of going from a local site hosted with mamp/wamp to publishing a public site using wordpress(?) or some other host (is WordPress even a host?!) and also finding a server that’s suitable and some way of hosting images/videos or other content. (If that sounded like I didn’t know what half of those meant, it’s because unfortunately I don’t!.. but I’d really like to!)

Can you sense that enthusiasm? I love it.

We worked together a bit to refine many of his questions for this post, but they are still Josh's words. Here we go!

What is a Domain Registrar? I get they are for registering domain names, but what’s the difference between them? How do you know which one is right for you? A quick search for "best domain hosts" on Google gave me 5 ads for companies who are domain registrars/hosts and 9 "Top 10" style pages that look as though they have some sort of affiliation with at least one company they're suggesting. Am I just looking for the cheapest one?

You're exactly right, domain registrants are for registering domain names. If you want joshlongisverycool.com, you're going to have to buy it, and domain registrants are companies that help you do that.

Searching for a domain name

It's a bummer that web search results are so saturated by ads and affiliate-link-saturated SEO-jacked pages. You'll never get total honesty from that because those pages are full of links promoting whoever will pay them the most to send new customers. Heck, even Google themselves will sell you a domain name.

The truth is that you can't go too wrong here. Domain names are a bit of a commodity and the hundreds of companies that will sell you one largely compete on marketing.

Some things to watch out for:

  • Some companies treat the domain as a loss leader. Like a grocery store selling cheap milk to hope you buy some more stuff while you are there. The check out process at any domain registrant will almost certainly try to sell you a bunch of extra stuff. For example, they might try to sell you additional domain names or email hosting you probably don't need. Just be careful.
  • Web hosts (which we're getting to next) will often sell them to you along with hosting. That's fine I suppose, but I consider it a bit of a conflict of interest. Say you choose to move hosts one day. That hosting company is incentivized in the wrong direction to make that easy for you. If the domain is handled elsewhere, that domain registrant is incentivized the right direction to help you make changes.

I hate to add to the noise for you, but here are some domain registrants that I've used personally and aren't paying for sponsorship here nor are affiliate links:

Our own Sarah Drasner recommends looking at ZEIT domains, which are super interesting in that you buy and manage them entirely over the command line.

I might suggest, if you can see yourself owning several domain names in your life, keeping them consolidated to a single registrant. Managing domains isn't something you'll do very often, so it's easy to lose track of what domains you registered on what registrant, not to mention how/where to change all the settings across different registrants.

I'd also suggest it's OK to experiment here. That's how all of us have learned. Pick one with a UI that you don't hate and a trustable vibe. Maybe your friend also uses that one. Hopefully, it works out fine. If you hate it, it'll be a little work, but you can always switch.

What is a web host and why do I need one? A Google search throws you a mountain of "best web host" articles and ads. These websites all seem to be full of jargon like "shared hosting" and "managed hosting." I see things like "suggested hosts" on some sites. How do you find the right web host? I'm not even sure what my needs are. Should I just find the cheapest one?

Just because you own a domain doesn't mean it will do anything. In fact, right after you buy it, it's likely that the domain registrant slaps up a "coming soon" page for you:

A "coming soon" page you might see immediately after buying a domain name.

To host a website at your new domain, you'll need to configure the DNS of your new domain to point at a server connected to the internet. Here's an interesting tidbit... you could do this right from your house if you wanted to. Your Internet Service Provider (ISP) at home probably gives you an IP address. It's all a bit nerdy, but you could point your domain name at that IP and set up your computer to be a web server that responds to incoming requests and serves up your website. Almost nobody does that though. You don't want your web server to stop working because you closed your laptop or your ISP changed your IP.

Web hosting services give you that server. Like domain registrants, web hosts are almost a commodity. There are lots of them that provide a similar service, so the price is driven fairly low and they find other things to compete on.

Buying web hosting is a little trickier than buying a domain though. You'll need to know a little bit about the website you intend to host when making that choice. Will it be a WordPress site? Or another PHP/MySQL-based CMS site (we'll get to those later)? That means your host will need to support those technologies. Most do, some don't. You might wanna look in their documentation or literally ask them before pulling the trigger if you are unsure. There are lots of technologies for running websites. Say the site will use Ruby on Rails — that's a different set of requirements that not all hosts offer. Or Node... Or Python... same story.

If a web host says they specialize in a particular set of technologies, and that's what you need, that's probably a decent way to go, particularly in your early days. Let's take a very limited gander. Again, these are not affiliate or paid-for links and they are somewhat randomly selected web hosts that come to mind for me:

Now here some other web hosts that are a little less traditional. Forgive the techy terms here — if they don't mean anything to you, just ignore them.

  • Netlify does static site hosting, which is great for things like static site generators and JAMstack sites.
  • Zeit is a host where you interact with it only through the command line.
  • Digital Ocean has their own way of talking about hosting. They call their servers Droplets, which are kind of like virtual machines with extra features.
  • Heroku is great for hosting apps with a ready-to-use backend for things like Node, Ruby, Java, and Python.
  • Amazon Web Services (AWS) is a whole suite of products with specialized hosting focuses, which are for pretty advanced users. Microsoft Azure and Google Cloud are similar.

Again, I'd say it's OK to, in a sense, make some mistakes here. If you aren't hosting something particularly mission-critical, like your personal website, pick a host that seems to fit the bill and give it a go. Hopefully, it works out great — if not, you can move. Moving isn't always super fun, but everybody ends up doing it, and you'll learn as you go.

When you buy web hosting, that host is going to tell you how to use it. One common way is that the host will give you SFTP credentials. Then you'll use software that is built for connecting to servers over SFTP, and that will allow you to upload files to the web server.

This is a magic moment!

Say you've been working on a file that is a single index.html file, that loads a style.css file. Upload those files over SFTP into the folder your host tells you is correct public root directory for that site.

That is the process for taking a site from local to live! There is nothing wrong with it, either. This is referred to as deployment, and this is about as basic and simple as it gets. Even fancier ways of doing deployment sometimes ultimately do just this behind the scenes. We'll get more into deployment later.

Should you bundle your domain registrar and web host into one if a company offers both?

I mentioned this above a little: I'm a fan of not doing that in general. On one hand, it's mighty handy. Things like shared billing and a single checkout flow. The host will also do things like configuring the DNS for you to be all set up for their hosting and you probably don't even have to think about it.

But say the day comes where you just don't like that host anymore. You've found a better deal, outgrown them, were turned off by their support or service, or any other reason. You want to move hosts. The problem is that they aren't just your host, but your domain registrant, too. Do you leave the domain with them and just move hosts? Probably not, you're trying to leave them. Now you need to move two things. That makes that move all the more perilous, but worse, this company isn't exactly incentivized to respond quickly and helpfully to your requests since they know they're losing you as a customer.

What really is a "CMS"? What's its purpose? WordPress, Joomla, and Drupal are the most popular names I’ve found for content management systems, and from their descriptions, all sound very similar. What are the kinds of features that set one apart from another? Is a CMS all you need to get your website from your local computer to the public internet?

CMS (Content Management System) is a pretty generic term. It means literally anything that helps you manage content. There are, as you've seen, some big players like WordPress and CraftCMS. They don't really have anything directly to do with that connection between working locally on a site and getting that site live. But they do rather complicate it.

The reason that you'd use a CMS at all is to make working on your site easier. Consider this site you're looking at right now. There are tens of thousands of pages on this site. It would be untenable for each of them to be a hand-authored file.html file.

Instead, a CMS allows us to craft all those pages by combining data and templates.

Let's consider the technology behind WordPress, a CMS that works pretty good for CSS-Tricks. In order for WordPress to run, it needs:

  1. PHP (the back-end language)
  2. MySQL (the database)
  3. Apache (the web server)

You can do all that locally!

I use Local by Flywheel for that (Mac and Windows), but there are a number of ways to get those technologies running: MAMP, Docker, Vagrant, etc.

That'll get you up and running locally with your CMS. That's a beautiful thing. Having a good local development environment for your site is crucial. But it doesn't help you get that site live.

We'll go over getting all this to a live site a bit later, but you should know this: the web server that you run will need to run these same technologies. Looking at the WordPress example from above, your web server will also need to run PHP, MySQL, and Apache. Then you'll need to set up a system for getting all your files from your local computer to your web server like you would for any other site, but also probably have a system for dealing with the database. The database is a bit tricky as it's not a "flat file" like most of the rest of your site.

A CMS could be built from any set of technologies, not just the ones listed above. For example, see KeystoneJS. Instead of PHP, Keystone is Node.js. Instead of MySQL for the database, it uses MongoDB. Instead of Apache, it uses Express. Just a different set of technologies. Both of which you can get running locally and on a live web server.

A CMS could even have no database at all! Static site generators are like this. You get the site running locally, and they produce a set of flat files which you move to your live server. A different way to do things, but absolutely still a CMS. What I always say is that the best CMS is one that is customized to your needs.

What is "Asset Hosting"? Are assets not content? What is the difference between a CMS and an asset hosting service? What does an asset host do?

Let's define an asset: any "flat" file. As in, not dynamically generated like how a CMS might generate an HTML file. Images are a prime example of an "asset." But it's also things like CSS and JavaScript files, as well as videos and PDFs.

And before we get any further: you probably don't need to worry about this right away. Your web host can host assets and that's plenty fine for your early days on small sites.

One major reason people go with an asset host (probably more commonly referred to as a CDN or Content Delivery Network) is for a speed boost. Asset hosts are also servers, just like your web host's web server, but they are designed for hosting those flat file assets super fast. So, not only do those assets get delivered to people looking at your site super fast, but your web server is relieved of that burden.

You could even think of something like YouTube as an asset host. That 100 MB video of a butterfly in your garden is a heavy load for your little web server, and potentially a problem if your outgoing bandwidth is capped like it often is. Uploading that video to YouTube puts your video into that whole social universe, but a big reason to do it other than the social stuff is that it's hosting that video asset for you.

I’ve heard of "repositories", but don’t really get what they are. I hear stuff like "just upload it to my Git Repository." What the heck does that mean? I feel like a moron for asking this. What is Git? What is it for? Do I need to use it? Is it involved in the "local to live" process at all?

Sorry you got hit with a "just" there. There is an epidemic in technology conversations where people slip that in to make it seem like what they are about to say is easy and obvious when it could be neither depending on who is reading.

But let's get into talking about Git repositories.

Git is a specific form of version control. There are others, but Git is so dominant in the web industry that it's hardly worth mentioning any others.

Let's say you and me are working on a website together. We've purchased a domain and hosting and gotten the site live. We've shared the SFTP credentials so we both have access to change the files on the live site. This could be quite dangerous!

Coda is a code editor that let's you edit files directly on a sever you've connected to over SFTP. Cool, but dangerous!

Say we both edit a file and upload it over SFTP... which change wins? It's whoever uploaded their file last. We have no idea who has done what. We're over-writing each other and have no way of staying in sync with each other's changes, changes immediately affect the live site which could break things and we have no way of undoing changes in case we break things. That's a situation so unacceptable that it's really never done.

Instead, we work with version control, like Git. With Git, when we make changes, we commit them to a repository. A repository can be hosted anywhere, even on your local machine. But to make them really useful, they are hosted on the internet somewhere everyone has access to. You've surely seen GitHub, which hosts these repositories and adds a bunch of other features like issue tracking. Similar are GitLab and Bitbucket.

Now let's say you and me are working on that same site, but we've set up a Git repository for it. When I make a change, I commit it to the repository. If you want to make a change as well, you have to pull my changes down which merges them into your own copy of the code. Then you can push your changes up to the repository. Like anything, it gets more complicated, but that's the gist of it.

But a Git repository isn't the live website. You're on your own for getting the files from a Git repository to a live site. Fortunately, that's a situation that everyone faces, so there are lots of options. Good thing your last question is about this!

OK. So now with all that straight... where do you start with going from local to live? Where do you "upload" your HTML, CSS and JavaScript files? How do you link your shiny new domain name to those files and see it out in the wild? Which service is in charge of adding new content to your site, or updating it? Does it get really confusing if you have different companies for each service?

Let's start with a very simple website on what I'd consider typical web hosting. Say you have just index.html, style.css, and script.js files on your local computer which is your entire website. You've purchased a domain name and pointed the DNS settings at a web host. That host has given you SFTP credentials. You'll use those credentials in an app that allows SFTP connections to log in:

Your host will also tell you which folder is the "public root" of your website. The files there will be out on the public internet for the world to see!

You might hear people refer to the "live" website as a "production" site. When someone asks something like, Did that bug make it to production?" they mean whether the bug is on the live website. "Development" is your local computer. You might also have a "Staging" site, which is a clone of the live website on the same hardware/software of the live site for testing.

Remember earlier when we talked about Git repositories? While the repositories themselves don't directly help you get the files in them to your web server, most systems that help you with the local-to-live process work with your repositories.

The phrase "local-to-live" refers to deployment. When you have changes that you want to go out to your production website, you deploy them. That's the process of moving your work from "development" to "production."

One service that helps with this idea of deployment is Beanstalk. Beanstalk hosts your Git repository, plus you give it the SFTP credentials for your server — that way it can move the files to your web server when you make commits. Cool right? Say you wanted to host that Git repo elsewhere though, like GitHub, Bitbucket, or Gitlab. Check out DeployBoy, which does the same thing, only it can connect to those sites as well. It probably comes as no surprise by now that there are lots of options here, ranging in price and complexity.

Let's go back to our WordPress example.

  1. You've got it running locally (on your computer) just perfectly and now want to go live with it.
  2. You've bought a domain name from a registrar.
  3. You've purchased hosting that meets WordPress requirements.
  4. You've pointed the DNS of the domain name at the web host.
  5. You've verified it's all working (easy way: upload an index.html file in the public root via SFTP and verify that it loads when you type you type the domain name into a browser.)

Now, you've still got some work to do:

  1. Set up a Git repository for the site.
  2. Set up a deployment service to move the files from the repository to the live site.
  3. Configure/Set up the live site as needed. For example, you'll need a database on the live site. You'll have to create that (your host will have instructions) and do things like run the WordPress installer and update configuration files.
  4. If you have things in your local database that you want to move to the live site, you might be exporting/importing things. That can happen at the raw MySQL level using WordPress' native import/export features, or a fancy plugin like WP DB Migrate Pro.

It's a non-trivial amount of work! Sorry. This process is pretty similar for any site though. It's a matter of configuring and setting up your production web server exactly how it should be, then deploying files to it. Every site is a bit different, but you'll get the hang of this whole dance.

It really is a big dance. I've only painted one picture for you here. I tried to pick one that was generic and broad enough that it shows the landscape of what needs to be done. But, at every step in this dance, there are different ways you can do things, different services you can pick, companies trying to help you at different pain points... it's an ever-changing world.

Right now, Netlify is enjoying a lot of popularity because they are one of the only web hosts that actually helps you with deployment. They'll watch your Git repositories and do deployment for you! Netlify is for static sites only, but that can be a whole world onto itself. ZEIT also is massively innovative in how it helps with deploying and hosting web projects, including directly connecting with GitHub.

Good luck!

I hope this was helpful. Remember, you aren't alone in all this. Zillions of other developers have done this before you and there is help to be found on the internet.

Oh, and remember: the best way to learn anything at all is to...


The post Helping a Beginner Understand Getting a Website Live appeared first on CSS-Tricks.

Level up your hosting. Get started on DigitalOcean with $100.

Css Tricks - Thu, 09/06/2018 - 3:58am

(This is a sponsored post.)

Tired of slow, unreliable web hosting? See how easy it is to self-host your next project on DigitalOcean's cloud platform. Build and manage ultra-fast websites, blogs, and other static web pages using our user-friendly control panel or simple API, all with a 99.99% uptime SLA. Save time using our One-Click install apps for WordPress, Ghost and Discourse. Never worry about running out of storage space again with Spaces — highly scalable, affordable object storage.

Sign up today with a free $100 credit for CSS-Tricks readers.

Direct Link to ArticlePermalink

The post Level up your hosting. Get started on DigitalOcean with $100. appeared first on CSS-Tricks.

What do we call browser’s native development tools?

Css Tricks - Wed, 09/05/2018 - 12:03pm

You know, that panel of tools that allows you to do stuff like inspect the DOM and see network requests. How do the companies that make them refer to them?

I think it's somewhat safe to generically refer to them as DevTools. Safari is the only browser that doesn't use that term, but I imagine even die-hard Safari users will know what you mean.

The post What do we call browser’s native development tools? appeared first on CSS-Tricks.

Design Is The New Black [Sponsored]

Usability Geek - Wed, 09/05/2018 - 8:42am
It’s hard to escape discussions around design these days. Design thinking is being broadly embraced by large (and small) organizations across industries, and not just by their design...
Categories: Web Standards

Designing With Code

Css Tricks - Wed, 09/05/2018 - 8:20am

Wall Street Journal design director Matthew Ström on something near and dear to me: the link between code and design tools:

We’re in the middle of a design tool renaissance. In the 8 years since Sketch 1.0 was released, there’s been a wave of competition among traditional design tools. And as the number of tools available to designers grows exponentially, ideas that were once considered fringe are finding a broader audience.

One of these ideas will significantly change the way digital products are designed: integrating design and code at a deep level. Figma can update a React code base in real time; InVision, Abstract, and Zeplin have done away with design-developer handoff documents; Framer’s new Framer X can render interactive React components directly into its workspace. These examples are just a hint of what’s to come.

Matthew then looks at how this combination of code and design has been improving his own design process, specifically on the “story cards” that appear on the homepage of the WSJ:

A tiny bit of NodeJS fills in the cards with live data from the WSJ.com home page. I can make small changes to parts of the component and see how the system reacts in a matter of seconds. This multiplicative process means that small changes have a huge output, making my designs much more comprehensive in the process.

I really can’t wait to see how our design tools are evolve. It’s a thoroughly exciting time to be a designer that’s interested in code.

Direct Link to ArticlePermalink

The post Designing With Code appeared first on CSS-Tricks.

Flutter: Google’s take on cross platform

Css Tricks - Wed, 09/05/2018 - 4:01am

Flutter is a mobile SDK that, at its core, is about empowering everyone to build beautiful mobile apps. Whether you come from the world of web development or native mobile development, Flutter makes it easier to create mobile apps in a familiar, simplified way, without ever giving up control to the framework.

As of this writing, Google AdWords and Alibaba are both using Flutter in production. You can see more examples of who’s using Flutter (including the app I’ve worked on) on Flutter’s website on the showcase page.

Right now, there’s a lot of buzz about Flutter. The question I see most often is, "Flutter or React Native...which one should I use?" Like all things in programming, its all about the tradeoffs you’re willing to make.

I’m going to try to convince you that Flutter is the best option for mobile app development. I believe it’s better than any other cross platform framework, and it’s possibly better than native development — but more on that in a bit.

Before that though, let me walk (quickly) through what Flutter is, and what it is not, starting with the Dart programming language.

What’s Dart?

Dart is a programming language created by Google and was used to write Flutter. Dart was created, more or less, because Google wanted a language that was "better" than JavaScript to write server side and front-end code. From what I understand, the main issue they had with JavaScript is how slowly it updates with new features since it relies on a huge committee for approvals and several browser vendors to implement it.

After a series of decisions about whether to take on JavaScript directly or not, Google decided to make a language that semantically fit inside of JavaScript. In other words, every single thing you write in Dart can compile to JavaScript. This is why they didn’t just use Java — it’s semantically huge.

Here’s a leaked email chain from Google from 2010. It’s the "coming to Jesus" moment that they decided they needed to do something about JavaScript.

The fundamentals of Dart are similar to all high-level languages. That said, programming languages are, as it turns out, hard to learn.

There’s good news, though. Dart excels at being a "safe" language to learn. Google didn't set out to create anything innovative with Dart. They were seeking to make a language that was simple, productive and could be compiled into JavaScript.

There is nothing particularly exciting about its syntax, and no special operators that will throw you through a loop. In Dart (unlike JavaScript), there is one way to say true: True. There is one way to say false: False.

In JavaScript, this coerces to True:

if (3) { ... }

In Dart, that would blow up your program. Dart is, at its core, a productive, predictable, and simple language.

This is important, because writing an app in Flutter is simply writing Dart. Flutter is, underneath it all, a library of Dart classes. There is no markup language involved or JSX-style hybrid language. Every bit of front-end code is written in Dart. No HTML. No CSS.

Why does Flutter use Dart?

If you’re coming from literally any other background (and you’re like me), you’ve probably complained about the fact that Flutter uses Dart, and not JavaScript. (Developers are, believe it or not, opinionated.)

And there are reasons to be skeptical of this choice. It's not one of the hot languages of today. It's not even one of the top 25 most used languages. What gives? Is Google just using it because it’s their language? I'd imagine that played a role, but there are practical reasons, too.

  • Dart supports both Just In Time (JIT) compiling and Ahead of Time (AOT) compiling.
    • The AOT compiler changes Dart into efficient native code. This makes Flutter fast (a win for the user and the developer), but it also means that almost all of the framework is written in Dart. For you, the developer, that means you customize everything.
    • Dart’s optional JIT compiling allows hot-reloading to exist. Fast development and iteration is a key to the joy of using Flutter. When you save code in your text editor, your app is updated in your simulator in less than a second.
  • Dart is Object Oriented. This makes it easy to write visual user-experiences exclusively with Dart, with no need for a markup language.

  • Dart is a productive and predictable language. It’s easy to learn and it feels familiar. Whether you come from a dynamic language or a static language, you can get up and running with ease.
  • And yes, I’d image that it is extremely appealing to use a language made by the same company, because the Flutter team could work closely with the Dart team to implement new needed features.
Flutter vs. React Native (and other options)

Before I offer up my unsolicited opinions on your other options, I want to make this crystal clear: Flutter is not the answer 100% of the time. It’s a tool and we should choose the right tool for the job at hand. That said, I’d only argue that it’s something you should strongly consider in the future.

Native development (iOS and Android)

Your first choice is to write native apps for iOS and Android. This gives you maximum control, debugging tools, and (potentially) a very performant app. At a company, this likely means you have to write everything twice; once for each platform. You likely need different developers on different teams with different skillsets that can’t easily help each other.

React Native, WebViews, and other cross-platform JavaScript options

Your second option: cross-platform, JavaScript-based tools such as WebViews and React Native. These aren’t bad options. The problems you experience with native development disappear. Every front-end web developer on your team can chip in and help — all they need are some modern JavaScript skills. This is precisely why large companies such as AirBnb, Facebook, and Twitter have used React Native on core products. (AirBnb recently announced that it would stop using React Native, because of some of the issues I’ll describe below.)

The first "mobile apps" to be built cross platform are simply WebViews that run on WebKit (a browser rendering engine). These are literally just embedded web pages. The problem with this is basically that manipulating the DOM is very expensive and doesn't perform well enough to make a great mobile experience.

Some platforms have solved this problem by building the "JavaScript bridge." This bridge lets JavaScript talk directly to native widgets.

This is much more performant than WebViews, because you eliminate the DOM from the equation, but it's still not ideal. Every time your app needs to talk directly to the rendering engine, it has to be compiled to native code to "cross the bridge." On a single interaction, the bridge must be crossed twice: once from platform to app, and then back from app to platform.

Flutter differs because it uses its own rendering engine, Skia, which is the same rendering engine used in Chrome. Skia can communicate with Flutter apps. As a result, Flutter accepts local events directly, rather than having to first compile them into JavaScript. This is essentially possible because Flutter compiles to native ARM code. This is the secret to its success. When your app is fired up on a user’s device, it’s entirely running in the language that the device’s operating system expects.

The JavaScript bridge is a marvel of modern programming, to be sure, but it presents three big problems.

The first problem is that debugging is hard. When there’s an error in the runtime compiler, that error has to be traced back across the JavaScript bridge and found in the JavaScript code. It may be in markup or CSS-like syntax as well. The debugger itself may not work as well as we'd like it to.

A second bigger issue, though, is performance. The JavaScript bridge is very expensive. Every time something in the app is tapped, that event must be sent across the bridge to your JavaScript app. The result, for lack of better term, is jank.

The third big problem, according to AirBnb, is that they found themselves having to dip down into the native code more often than they wanted to, which was a problem for their teams comprised mostly of JavaScript developers. (The jury is still out on this issue with Flutter, but I can say that I’ve never once had to try and write native code at my job. Some members of my team have created plugins in Objective-C and Java.)

The immediate benefits of Flutter

It’s likely, since you’re reading this article, that you’re interested in Flutter... but you might be skeptical. I admire how thorough you are in vetting technology.

Your reasons for being skeptical are fair. It’s a new technology. That means breaking changes in the API. It means missing support for important features (such as Google Maps). It seems possible that Google could abandon it altogether one day.

And, despite the fact that you believe Dart is great language, that doesn’t change the fact that Dart isn’t widely used, and many third-party libraries that you want may not exist.

I would argue against all those points, though. The API unlikely to change, as the Google uses Flutter internally on major revenue-generating apps, including Google AdWords. Dart has recently moved into version 2, which means it will likely be a while until it changes much. It will likely be years until breaking changes are introduced which, in a computer world, is practically forever.

Yes, there are indeed missing features, but Flutter gives you the complete control to add your own native plugins. In fact, many of the most important operating system plugins already exist, such as a map plugin, camera, location services, and device storage. The Dart and Flutter ecosystem and community already exists. It’s much smaller than the JavaScript community, of course, but I would argue that it’s concise. I see people every day contributing to existing packages, rather than creating new ones.

Now, let’s talk about Flutter’s specific benefits.

No JavaScript bridge

This is a major bottleneck in development and in your application’s performance. Again, it leads to jank. Scrolling isn’t smooth, it’s not always performant, and it’s hard to debug.

Flutter compiles to actual native code and is rendered using Skia. The app itself is running in native, so there's no reason to convert Dart to native. This means that it doesn’t lose any of the performance or productivity when it’s running on a user’s device.

Compile time

If you’re coming from native development, one of your major pains is the development cycle. iOS is infamous for its insane compile times. In Flutter, a full compile generally takes less than 30 seconds, and incremental compiles are sub-seconds, thanks to hot-reload. At my day job, we develop features for our mobile client first because Flutter’s development cycle allows us to move so quickly. Only when we’re sure of our implementation do we go write those features in the web client.

Write once, test once, deploy everywhere

Not only do you get to write your app one time and deploy to iOS and Android, you also only have to write your tests once. Dart unit testing is quite easy, and Flutter includes a library for testing Widgets.

Code sharing

I’m going to be fair here: I suppose this is technically possible in JavaScript as well. But, it’s certainly not possible in native development. With Flutter and Dart, your web and mobile apps can share all the code, except each client’s views. (Of course, only if you’re using Dart for your web apps.) You can quite easily use dependency injection to run an AngularDart app and Flutter app with the same models and controllers.

And of course, even if you don’t want to share code between your web app and your mobile app, you’re sharing all your code between the iOS and Android apps.

In practical terms, this means that you are super productive. I mentioned that we develop our mobile features first at my day job. Because we share business logic between web and mobile, once the mobile feature is implemented, we only have to write views that expect that same controller data.

Productivity and collaboration

Gone are the days of separate teams for iOS and Android. In fact, whether your use Dart or JavaScript in your web apps, Flutter development is familiar enough that all your teams will be unified. It’s not a stretch by any means to expect a JavaScript web developer to also effectively develop in Flutter and Dart. If you believe me here, then it follows that your new unified team will be three times more productive.

Code maintenance

Nothing is more satisfying then fixing a bug once and having it corrected on all your clients. Only in very specific cases is there a bug in a iOS app produced with Flutter that is not also in the Android version (and vice versa). In 100% of these cases, these bugs aren’t bugs, but cosmetic issues because Flutter follows the device OS design systems in it’s built-in widgets. Because these are issues like text sizing or alignment, they are trivial in the context of using engineering time to fix.

Flutter for JavaScript developers

Since you’re reading CSS-Tricks, I’d be willing to bet you’re a web developer. If you’ve used any of today’s hottest frameworks (e.g. React, Angular, Vue, etc.), then you’ll be happy to know that picking up Flutter is easy.

Flutter is completely reactive, so the same mindset and paradigm that you’re used to with React carries over to Flutter. You’re essentially building a ton of small, reusable components (called Widgets in Flutter) just like React. These widgets are complete with lifecycle methods, and they’re written in classes. If you’ve used this syntax in React:

const MyComponent extends React.Component { //... render(){} }

...then you’ll pick up Flutter with no problem. This is how you do the same in Flutter:

class MyWidget extends StatelessWidget { //... build(){} }

And, just like React, Flutter favors composition over inheritance. For example, if you want to make a special AddToCartButton in React, you’d build a button with special functions and styles in JSX. That’s exactly how you do it in Flutter (minus the JSX).

Finally, the layout system in Flutter is similar to CSS rules we’re familiar with, like flexbox and absolute positioning.

This is also where a big difference in making views in Flutter comes in, though. In Flutter, literally everything is a Widget. There are some obvious, concrete Widgets, like Text, Button, and AppBar. But Animations and Layout declarations are also Widgets. To center text, you wrap a Text Widget in a Center Widget. To add padding, there’s a Padding Widget.

Imagine breaking down a React app to the smallest possible reusable components you could make. For example, what if you made a higher-order React component that simply took a prop "padding" and all it did was add that amount of padding to whatever was nested within it. That’s how Flutter works, because there is no CSS or markup.

In this sample picture, here are a few layout widgets that you might use, but you can’t ‘see’ as the user:

That may seem like a ton of monotonous work, but Flutter comes with many, many Widgets built right in (such as Padding and Center) so you don’t have to waste time doing that yourself.

These are some of the most common widgets:

Final note

TL;DR: should you try Flutter?

If you want to make buttery smooth mobile apps in a familiar style, then yes! The performance and developer experience are both completely held in tact in Flutter. Its animations tick at 60fps, and it has a bundle of built-in Cupertino-style and Material Design-style Widgets. Or, long story short: it’s incredible how quick you can be productive in Flutter, without sacrificing native performance.

If you want to try Flutter today, here are a couple great places to start:

The Flutter docs are truly some of the best I’ve ever seen, and they’ll teach you everything you need to know.

The post Flutter: Google’s take on cross platform appeared first on CSS-Tricks.

Render Caching for React

Css Tricks - Tue, 09/04/2018 - 3:51am

Server Side Rendering (SSR) is a very useful technique that makes web apps appear faster. The initial HTML is displayed before the JavaScript is parsed and, while the user is deciding what to tap on, our handlers are ready.

Server side rendering in React requires additional work to setup and has server costs. Furthermore, if your server team cannot have JavaScript running on your servers, you are stuck. It significantly complicates the CDN setup especially if you have pages that require login and where the user’s information is managed.

I want to walk through a new concept called Render Caching. This is a cool trick that can give users an instant performance boost just like that of SSR without having to resort to writing code on the server.

What is Render Caching?

The migration from static HTML pages to Single Page Apps (SPAs) has left a gaping hole in the entire concept of caching that the web has traditionally relied on. While browsers optimize delivery and rendering of the initial HTML, an SPA leaves them blank to be filled in later.

Render Caching optimizes the SPA render and can significantly improve the perceptible load time of web pages. It does that by caching the rendered HTML in the browser for next load and can provide that display without the JavaScript parsing that eats up our display time.

Enabling Render Caching

We mentioned earlier that setting up SSR for React requires additional setup and server costs. Render Caching avoids those burdens.

It takes a few steps to set it up. Let’s break it down into digestible pieces.

Step 1: Determine the correct caching state

Figure out the conditions for the current page where it would render the same when a user opens it on the next visit.

For example, you could create a JSON object with the current build number or a user ID. The key is to ensures that the state is encapsulated in the URL, local storage or cookies and do not need a server call for.

Step 2: Setup API calls

Ensure all API calls happen before the render call to react. This makes sense in regular use cases as well where we want to prevent the page from changing under the user which causes flickers.

Step 3: Cache locally in the unload handler

Now add a unload event handler to the document. Store the current DOM in localStorage/indexDB.

That looks something like this, using a build number and a user ID to determine the caching state covered in Step 1:

window.addEventListener('beforeunload', () => { // Production code would also be considerate of localStorage size limitations // and would do a LRU cache eviction to maintain sanity on storage. // There should also be a way to clear this data when the user signs out window.localStorage.setItem(`lastKnown_${window.location.href}`, JSON.stringify({ condition: { userId: "<User ID>", buildNo: "<Build No.>" } data: document.getElementById('content').innerHTML })); // If you want to store data per user, you can add user ID to the key instead of the condition. Step 4: Restore the last known state on load

Next up, we want to pull the last known state from the browser’s local storage so we can use it on future visits. We do this by adding the following to the HTML file (e.g. index.html below the document’s the body tag.

<!-- ... --> </body> <script> const lastKnownState = window.localStorage.getItem(`lastKnown_${window.location.href}`); lastKnownState = lastKnownState && JSON.parse(lastKnownState); if (lastKnownState && lastKnownState.conditions.userId === "<User ID>" && lastKnownState.conditions.buildNo === "<Build No.>") { document.getElementById('content').innerHTML = lastKnownState.data; window.hasRestoredState = true; } </script> Step 5: Render the last known state in React

This is where the rubber meets the road. Now that we have the user’s last known state visible in the DOM, we can fetch the full content and render our app in that state by updating the top level of React's render with hydrate conditionally. Event handlers will become functional once this code hits but the DOM should not change.

import {render, hydrate} from "react-dom" if (window.hasRestoredState) { hydrate(<MyPage />, document.getElementById('content')); } else { render(<MyPage />, document.getElementById('content')); } Step 6: Go Async all the way

Turn your script tags from sync to async/defer for loading the JavaScript files. This is another key step to ensure a smooth loading and rendering experience on the front end.

That's it! Reload the page to see the boost in performance.

Measuring improvement

OK, so you did all that work and now you want to know just how performant your site is. You’re going to want to benchmark the improvements.

Render Caching shines in situations where you have multiple server calls before you know what to render. On script-heavy pages, JavaScript can actually take a lot of time to parse.

You can measure the load performance in the Performance tab in Chrome’s DevTools.

Measuring rendering in the Performance tab of Chrome’s DevTools

Ideally, you’d use a guest profile so that your browser extensions won’t interfere with the measurements. You should see a significant improvement on reload. In the screenshot above, we a sample app with an async data.json fetch call that is performed before calling ReactDOM.hydrate. With Render Caching, the render is complete even before the data is loaded!

Wrapping up

Render Caching is a clever technique to ensure that the perceived speed of re-fetches of the same web page is faster by adding a caching layer to the final HTML and showing them back to the user. Users who visit your site frequently are the ones who stand to benefit the most.

As you can see, we accomplished this with very little code and the performance gains we get in return are huge. Do try this out on your website and post your comments. I’d love to hear whether your site performance sees the same significant boosts that I’ve experienced.

The post Render Caching for React appeared first on CSS-Tricks.

The Pareto Principle And UX – Why Should You Care?

Usability Geek - Mon, 09/03/2018 - 1:06pm
The Pareto Principle, or the 80/20 rule as its also known, is a productivity hack of sorts. The idea behind it is: 80% of the effects of any given process come from 20% of the effort put into it. To...
Categories: Web Standards

New mobile Chrome feature would disable scripts on slow connections

Css Tricks - Fri, 08/31/2018 - 1:10pm

This is a possible upcoming feature for mobile Chrome:

If a Data Saver user is on a 2G-speed or slower network according to the NetInfo API, Chrome disables scripts and sends an intervention header on every resource request. Users are shown a UI at the bottom of the screen indicating the page has been modified to save data. Users can enable scripts on the page by tapping “Show original” in the UI.

And the people shout: progressive enhancement!

Jeremy Keith:

An excellent idea for people in low-bandwidth situations: automatically disable JavaScript. As long as the site is built with progressive enhancement, there’s no problem (and if not, the user is presented with the choice to enable scripts).

Power to the people!

This reminds me of the importance of a very useful building strategy called “Progressive Enhancement” &#x1f440;

&#x1f64c;&#x1f3fb; https://t.co/H4KHu9AzZC

— Sara Soueidan (@SaraSoueidan) August 27, 2018

Did you bet on JavaScript or are you gambling with JavaScript?https://t.co/uYULr5F9oj

— Zach Leatherman (@zachleat) August 27, 2018

George Burduli reports:

This is huge news for developing countries where mobile data packets may cost a lot and are not be affordable to all. Enabling NoScript by default will make sure that users don’t burn through their data without knowledge. The feature will probably be available in the Chrome 69, which will also come with the new Material Design refresh.

The post New mobile Chrome feature would disable scripts on slow connections appeared first on CSS-Tricks.


Css Tricks - Fri, 08/31/2018 - 4:29am

I love a good conference that exists because there is a rising tide in technology. JAMstack_conf:

Static site generators, serverless architectures, and powerful APIs are giving front-end teams fullstack capabilities — without the pain of owning infrastructure. It’s a new approach called the JAMstack.

I'll be speaking at it! I've been pretty interested in all this and trying to learn and document as much as I can.

Save $100 with csstricks100.

Direct Link to ArticlePermalink

The post JAMstack_conf appeared first on CSS-Tricks.

Props and PropTypes in React

Css Tricks - Fri, 08/31/2018 - 4:00am

React encourages developers to build by breaking a UI up into components. This means there will always be a need to pass data from one component to another — more specifically, from parent to child component — since we’re stitching them together and they rely on one another.

React calls the data passed between components props and we’re going to look into those in great detail. And, since we’re talking about props, any post on the topic would be incomplete without looking at PropTypes because they ensure that components are passing the right data needed for the job.

With that, let’s unpack these essential but loaded terms together.

Props: The data being passed around

Basically, props are what make React the tool that it is. React was designed to break things down into pieces that are served when they are needed. Props are defining characteristics stored by those pieces and they are accessed and sent when they’re requested. The result is a screen that renders only what it needs and nothing more, speeding up page loads and boosting overall performance.

These data can come in different forms: namely, strings, array and functions. The ability to pass data between components, so let’s break down specifically how to access and pass data.

Passing and accessing props

Let’s say we are working on an application that shows a list of interesting demos pulled from CodePen:

See the Pen Props Pen by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

We can illustrate the app as a collection of components:

The list of pens is going to require data, notably the title, URL and author for each demo that the app displays. We can construct that data like so:

const pensList = [ { title: "Elastic Input[Google Chrome]", url: "https://codepen.io/andreasstorm/pen/JBGWBa", author: "Andreas Storm" }, { title: "Phenomenon instances!", url: "https://codepen.io/cvaneenige/pen/ajNjaN", author: "Colin van Eenige" }, { title: "cpc-forms experiment with css variables", url: "https://codepen.io/terabaud/pen/YjwYKv", author: "Lea Rosema" }, { title: "Nuotron Logo Animation with Hover Effect", url: "https://codepen.io/YahiaRefaiea/pen/YjyZLm", author: "Yahia Refaiea" } ];

The App component will pull the data. Here’s the basic structure for that component:

const App = () => { return ( <div> <PenList pens={pensList} /> </div> ); }

We are passing an array of pens as a prop to the PenList (which we’ll create in just a bit). The parent component (PenList) accesses the data (penList), which gets passed as pens props to the child component (Pen).

const PenList = props => { return ( <React.Fragment> <h2>Interesting Pens on CodePen</h2> <ul> {props.pens.map(pen => { return ( <li key={pen.url}> <Pen {...pen} /> </li> ); })} </ul> </React.Fragment> ); };

The PenList component loops through the pens props (props.pens) to return each item as a Pen component. If this was a class component, we would prefix the pens props with this, like this:

class PenList extends React.Component { render() { return ( <React.Fragment> <h2>Interesting Pens on CodePen</h2> <ul> { this.props.pens.map(pen => { return ( <li key={pen.url}> <Pen {...pen} /> </li> ) }) } </ul> </React.Fragment> ) } }

The next thing to note is the use of key in the example. A key is a unique identifier we can assign to each item in our list to make sure we can distinguish between items. In this case, we’re mapping the key to the URL of each pen. There’s no chance of two items being the same, so it’s a good piece of data to use for this purpose.

The remaining properties are passed as props to the Pen component. Here’s the Pen component making use of those props:

const Pen = props => { return ( <div> <p> [{props.title}] </p> <p>Made by: {props.author}</p> </div> ); };

Note that we are constructing the Pen component (const Pen) rather than defining it as a class (class PenList) like we did for the PenList component. As such, we can access the values using props. That’s a handy little shorthand we can use instead of re-mapping Pen to the data. The parent already has it, so let’s just pass it along!

Passing functions using props

We just looked at passing an array of data as props from one component to another, but what if we’re working with functions instead? React allows us to pass functions between components, but it’s quite technical. Still, it’s something you’d want to do for specific use cases and worth us looking into.

Let’s use a simple example, say an app that allows you to create a list of tasks. You know, a to-do list, like for chores, projects or what have you. In this app, the list of tasks is contained in the App component, which is the parent component. The Todo component will be the child in this scenario, and its sole job will be to list each task that gets created.

In true to-do list form, we don’t just want to create tasks, but be able to remove them once a task has been created. Since the to-do list is contained in the App component, we have to be able to identify the specific item the user wants to remove from the list by obtaining the id and then remove the item in the App component.

Sound complex? Here’s what we’re going for:

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

Broken down into code:

let todoCounter = 1; class App extends React.Component { state = { list: [], item: "" }; handleInputChange = event => { this.setState({ item: event.target.value }); }; handleSubmit = event => { event.preventDefault(); const item = { id: todoCounter++, value: this.state.item.slice() }; this.setState({ list: this.state.list.concat(item), item: "" }); }; handleRemove = id => { this.setState({ list: this.state.list.filter(c => c.id !== id) }); }; render() { return ( <React.Fragment> <h2>Add Todo</h2> <div> <input type="text" value={this.state.item} onChange={this.handleInputChange} /> </div> <div> <button type="submit" onClick={this.handleSubmit}> Add </button> </div> <div> <h3>Lists</h3> <ul> {this.state.list.map(item => { return ( <li key={item.id}> <Todo {...item} removeTodo={this.handleRemove} /> </li> ); })} </ul> </div> </React.Fragment> ); } }

Notice that we defined todoCounter at the top and set it to 1. We created this so we can have unique keys for the to-do items just like we did when we used URLs for the list of pens in our previous example.

The method for deleting tasks is created in the App component. In the render() function, we pass the to-do properties as props to the Todo component. We also pass the handleRemove() function as a prop named removeTodo(). We will use this in the Todo component which looks like this.

class Todo extends React.Component { deleteTodo = id => { this.props.removeTodo(id); }; render() { return ( <div> {this.props.value} <button onClick={() => this.deleteTodo(this.props.id)}>X</button> </div> ); } }

We have to pass the id of the to-do item to removeTodo() in the Todo component because we cannot update the state of the App component without it. This is essentially how we are able to pass a function between components using props — pretty similar to how we did it with an array, the difference being we’re passing functionality around instead of raw data.


PropTypes ensure that the right type of props is passed to a component — and, conversely, that the receiving component is receiving the right type of props.

We can think about them like a football quarterback passing the ball to a receiver. The quarterback only wants his players to receive the ball. And, for that matter, the quarterback wants the receiver to catch a ball — not a cat, pickle or taxi. PropTypes would ensure that the correct object (a ball) is being passed and that it is passed to the correct receiver (player on the team).

(If only football had PropTypes in real life!)

To make use of PropTypes, you have to add the package as a dependency to your application by running yarn add prop-types in the command line.

We can use PropTypes in our app that displays interesting pens. Here is how we will use it for the Pen component:

Pen.propTypes = { title: PropTypes.string, url: PropTypes.string, author: PropTypes.string };

We’re declaring that the props for title, url and author should be strings. Not numbers. Not functions. Strings and strings alone.

If we happened to the props of author to a number instead of a string like this:

author: PropTypes.number

...we will get an error:

Warning: Failed prop type: Invalid prop `author` of type `string` supplied to `Pen`, expected `number`.

So, PropTypes are useful in catching bugs. We can also enforce passing props by using isRequired:

Pen.propTypes = { title: PropTypes.string.isRequired, url: PropTypes.string.isRequired, author: PropTypes.string.isRequired };

The basic data types you will need include string, number, boolean, function, etc.

Person.propTypes = { email: PropTypes.string, age: PropTypes.number, availability: PropTypes.bool, handleSubmit: PropTypes.func }

There are more types available and tons of documentation on them.

In cases where a prop is optional (i.e. not using isRequired), you can set a default value to make sure something gets passed:

Developer.defaultProps = { language: 'JavaScript' }

With this, the language prop will always have a value when it used — even if one isn’t provided.

Wrap Up

Well, that’s a broad look at props in React. It’s pretty much a guarantee that you will use both props and propTypes in a React application. Hopefully this post shows just how important they are to React as a whole because, without them, we have nothing to pass between components when interactions happen. They’re very much a core part of the component-driven and state management architecture that React is designed around.

And propTypes are an added bonus — like a built-in quality assurance checker for catching bugs and letting us know about them. Nice to know that they’ve got our back as we work.

The post Props and PropTypes in React appeared first on CSS-Tricks.

CSS Shape Editors

Css Tricks - Thu, 08/30/2018 - 4:39pm

Firefox 62 is shipping out of beta on September 5th. The big notable thing for CSS developers is that it will now support the shape-outside property with polygon(), circle(), and ellipse(), joining Chrome and Safari.

What will be nice about the Firefox release (well, it's kinda already nice if you use something like Firefox Developer Edition which is already on 62), is that it has a shape editor built right into DevTools.

Chrome supports shape-outside as well, but there is no native DevTools helper for working with them. Thankfully, Razvan Caliman has a Chrome Plugin that does a great job. (Razvan contributed to the Firefox version as well, I hear.)

I enjoy using shape-outside as it can add real visual interest to a page that isn't nearly overdone or trendy just yet. Plus, in a lot of cases, it doesn't matter whether it's supported because the float behaves as a rectangle. If it causes major issues, you can wrap things in an @supports block and do something different.

@supports (shape-outside: circle(50%)) { img { /* Only round the image if we can float around it too, otherwise leave it square. */ shape-outside: circle(50%); border-radius: 50%; } }

I do have a few gripes with both the Firefox DevTools and the Chrome plugin though...

  • I wish it was easier to add a new shape-outside to an existing element. You can do it, but you have to manually add something like shape-outside: polygon(0 0, 10px 0, 20px 0); or something to the element to kick off the tool, then start using it.
  • I wish they worked with % by default instead of px units.

That second one particularly. It's so common we size things flexibly these days that hard pixel values are sometimes useless and difficult to convert to flexible percentages.

You're probably better off starting with Bennett Feely's Clippy (it's technically for clip-path, but it includes polygon() it works works for either. It works with percentages, so great, moving on from there.

"The frustrations of using CSS Shapes and CSS Exclusions"

That's what Ben Frain recently blogged and it has some good points about all this. One key point is that using shape-outside doesn't necessarily mean that you're clipping the background. Personally, I find that I'm cutting a shape on backgrounds that are transparent anyway, but I take the point.

To fix this you'll need a clip-path as well.

The other big one is there is no shape-inside() property (yet), so if you're hoping to put some text inside a shape rather than have it wrap around the outside of a shape, no luck yet.

The post CSS Shape Editors appeared first on CSS-Tricks.

The Ecological Impact of Browser Diversity

Css Tricks - Thu, 08/30/2018 - 4:01am

Early in my career when I worked at agencies and later at Microsoft on Edge, I heard the same lament over and over: "Argh, why doesn’t Edge just run on Blink? Then I would have access to ALL THE APIs I want to use and would only have to test in one browser!"

Let me be clear: an Internet that runs only on Chrome’s engine, Blink, and its offspring, is not the paradise we like to imagine it to be.

As a Google Developer Expert who has worked on Microsoft Edge, with Firefox, and with the W3C as an Invited Expert, I have some opinions (and a number of facts) to drop on this topic. Let’s get to it.

What is a browser, even?

Let’s clear up some terminology.

Popular browsers you know today include Google Chrome, Apple Safari, Mozilla Firefox, and Microsoft Edge, but in the past we’ve also had such greats as NCSA Mosaic and Netscape Navigator. Whichever browser you use daily (I use Firefox, thanks for asking) is only an interface layer wrapped around a browser engine. All your bookmarks, the forward and backward arrows, that URL bar thingy—those aren’t the browser. Those are the browser’s interface. Often the people who build the browser’s engine never even touch the interface!

Browser engines are the things that actually read all the HTML and CSS and JavaScript that come down across the Internet, interpret them, and display a pretty picture of a web page for you. They have their own names. Chrome’s engine is Blink. Safari runs on WebKit. Firefox uses Gecko. Edge sits on top of EdgeHTML. (I like this naming convention. Good job, Edge.)

Except for Edge, all of these engines are open source, meaning anybody could grab one, wrap it in a new interface, and boom, release their own browser—maybe with a different (perhaps better) user experience—and that’s just what some browsers are! Apple only allows webKit-based browsers in its iOS app store, so the Chrome, Firefox, and even Edge browsers on iPads and iPhones work more like Safari than their desktop counterparts. Oculus Browser, Brave, Vivaldi, Samsung Internet, Amazon’s Silk, and Opera all run on Blink. We call them “Chromium-based browsers”—Chromium is Google’s open source project from which Chrome and its engine emerged.

But what’s inside a browser engine? MOAR ENGINES! Every browser engine is comprised of several other engines:

  • A layout and rendering engine (often so tightly coupled that there’s no distinction) that calculates how the page should look and handles any paints, renders, and even animations.
  • A JavaScript engine, which is its own thing and can even run independently of the browser altogether. For instance, you can use Chrome’s V8 engine or Microsoft Edge’s Chakra to run Node on a server.

I like to compare browser engines to biological cells. Where a cell contains many organelles to perform different functions, so too do browsers. One can think of the nucleus as the rendering engine, containing the blueprints for how the page should display, and the mitochondria as the JavaScript engine, powering our everyday interactions. (Fun fact: mitochondria used to be standalone cells at one point, too, and they even carry their own DNA!)

And you know what? Another way browsers are like living things is that they evolve.

Browser evolution

Back when the first browsers came out, it was a simpler time. CSS was considered the hot new thing when it first appeared in Microsoft Internet Explorer 3 in 1996! There were far fewer JavaScript APIs and CSS specifications to implement than there are today. Over the years, browser codebases have grown to support the number of new features users and developers require to build modern web experiences. It is a delicate evolution between user needs, browser engineering effort, and specification standardization processes.

We have three major lineages of engines right now:

  • WebKit and Blink (Blink originally being a fork of WebKit) running Safari, Chrome, and Opera
  • Gecko running Firefox
  • EdgeHTML (a fork of Trident, aka MSHTML) running Microsoft Edge

Each is very different and has different strengths and weaknesses. Each could pull the Web in a different direction alone: Firefox’s engine has Servo's multithreaded processing for rendering blazing fast graphics. Edge’s engine has the least abstraction from the operating system, giving it more direct access to system resources—but making it a Windows-only browser engine as a result. And Chrome’s Blink has the most web developers testing for it. (I'll get back to why this is a "feature" in a little bit.)

Remember all those Chromium-based browsers we talked about? Well, none of these browsers have to build their rendering engine or JavaScript engines from scratch: they just piggy-back off of Blink. And if there are new features they need? They can develop those features and keep them to themselves, or they can share those features back “upstream” to become a part of the core engine for other browsers to use. (This process is often fraught with politics and logistics—"contributing back" is easier said than done!)

It is hard to imagine any one entity justifying the hours and expense it would take to spin up a browser engine from scratch today. Even the current three engine families are evolutions of engines that were there from the very start of the Internet. They’ve evolved piecemeal alongside us, growing to meet our needs.

Right now, the vast majority of traffic on the Web is happening on Chrome, iOS Safari, or some other permutation of Blink or WebKit.

Branches, renovations, and gut jobs

Some developers would say that WebKit and Blink were forked so long ago that the two are practically completely different browser engines now, no longer able to share contributions. That may be true to a point. But while a common chimney swift and a ruby-throated hummingbird are completely different animals in comparison to each other, when compared to the other animal families, they are still very much birds. Neither’s immediate offspring are likely to manifest teeth, hands, or tails in the near future. Neither WebKit nor Blink have the processing features that Gecko and EdgeHTML have been building up to for years.

Other developers might point out that Microsoft Edge is supposedly a "complete rewrite" of Internet Explorer. But the difference between a "complete gut job" and a mere "renovation" can be a matter of perspective. EdgeHTML is a fork of Internet Explorer's Trident engine, and it still carries much of Trident's backlog with it.

Browser extinction

So these are the three browser engines we have: WebKit/Blink, Gecko, and EdgeHTML. We are unlikely to get any brand new bloodlines in the foreseeable future. This is it.

If we lose one of those browser engines, we lose its lineage, every permutation of that engine that would follow, and the unique takes on the Web it could allow for.

And it’s not likely to be replaced.

Imagine a planet populated only by hummingbirds, dolphins, and horses. Say all the dolphins died out. In the far, far future, hummingbirds or horses could evolve into something that could swim in the ocean like a dolphin. Indeed, ichthyosaurs in the era of dinosaurs looked much like dolphins. But that creature would be very different from a true dolphin: even ichthyosaurs never developed echolocation. We would wait a very long time (possibly forever) for a bloodline to evolve the traits we already have present in other bloodlines today. So, why is it ok to stand by or even encourage the extinction of one of these valuable, unique lineages?

We have already lost one.

We used to have four major rendering engines, but Opera halted development of its own rendering engine Presto before adopting Blink.

Three left. Spend them wisely.

By our powers combined...

Some folks feel that if a browser like Microsoft Edge ran on Blink, then Microsoft's engineers could help build a better Blink, contributing new features upstream for all other Chromium browsers to benefit from. This sounds sensible, right?

But remember Blink was forked from WebKit. Now there are WebKit contributors and Blink contributors, and their contributions don't port one to one. It's not unlikely that a company like Microsoft would, much like Samsung and Occulus, want to do things with the engine differently from Google. And if those differences are not aligned, the company will work on a parallel codebase and not contribute that work upstream. We end up with a WebKit and a Blink—but without the deep differentiation that comes from having a codebase that has been growing with the Internet for decades.

It’s is a nice idea in theory. But in practice, we end up in a similar pickle—and with less "genetic variety" in our ecosystem of browser engines.

Competition is about growing, not "winning"

I'm a fan of competition. Competing with other cartoonists to make better comics and reach a larger audience got me to where I am today. (True story: got my start building websites as a cartoonist building her own community site, newsletter, and shopping cart.) I like to remind people that competition isn't about annihilating your competitors. If you did, you'd stagnate and lose your audience: see also Internet Explorer 6.

Internet Explorer 6 was an amazing browser when it came out: performant enough to really deliver on features previous versions of Internet Explorer introduced like the DOM, data-binding, and asynchronous JavaScript. Its rival, Netscape Navigator, couldn't compete and crumbled into dust (only to have its engine, Gecko, rewritten from scratch—it was that small!—by the Mozilla Foundation to be reborn as Firefox later).

Thinking it had Won the Internet, Microsoft turned its attention to other fronts, and Internet Explorer didn't advance much. This allowed Firefox to get a toehold—by giving users a better experience with features like pop-up up blocking and a better UI. (That interface layer really does matter!) Firefox also collaborated with Opera to advanced Web standards, which weren't really a thing in the IE vs Netscape days. People using and building for the Internet loved it, and Firefox spread like fire (</dad-joke>) through word of mouth and grass roots promotional campaigns.

When the iPhone came, Apple focused on its profitable apps marketplace and cut efforts to support Flash—the Web’s most app-like interaction platform. Apps gave content creators a way to monetize their efforts with something other than an advertising model. Advertising being Google's bread and butter, the Big G grew concerned as the threat of a walled garden of apps only using the Internet for data plumbing loomed. Microsoft, meanwhile, was preoccupied with building its own mobile OS. So Google did two things: Android and Chrome.

Chrome promised a better, faster browsing experience. It was barebones, but Google even went all out and got famous (in my circles at least) cartoonist Scott McCloud to make a comic explaining the browser's mission to users. With Chrome's omnipresence on every operating system and Android phone, its dev tools modeled off Firefox's beloved Firebug extension, and increasing involvement in specs, Chrome not only shook Internet Explorer out of its slumber, it was damn near threatening to kill off every other browser engine on the planet!

Pruning the great family tree of browsers (or collection of bushes as it were) down to a single branch smacks of fragile monoculture. Monocultures are easily disrupted by environmental and ecological challenges—by market and demographic changes. What happens when the next threat to the Web rears its head, but we don't have Firefox's multithreading? Or Microsoft Edge's system integration? Will we be able to iterate fast enough without them? Or will we look to the Chrome developers to do something and pray that they have not grown stagnant as Google turned, like Microsoft did, to attend to other matters after "winning the Web."

It is ironic that the browser Google built to keep the Web from losing to the apps model is itself monopolizing web development much the same way Internet Explorer 6 did.

It's good to be king (of the jungle)

I promised I'd get back to "user base size as a feature." Having the vast majority of the web development community building and testing for your platform is a major competitive advantage. First off, you're guaranteed that most sites are going to work perfectly in your browser—you won't have to spend so much time and effort tapping Fortune 500 sites on the shoulder about this One Weird Bug that is causing all their internal users to switch to your competitor browser and never come back. A downward spiral of fewer users leading to less developer testing leading to fewer users begins that is hard to shake.

It also makes it much easier to propose new specifications that serve your parent company's goals (which may or may not serve the web community's goals) and have that large community of developers build to your implementation first without having to wait for other browsers to catch up. If a smaller browser proposes a spec that no one notices and you pick it up when you need it, people will remember it as being your effort, continuing to build your mindshare whether intentionally or not.

This creates downward pressure on the competition, which simply doesn’t have or cannot use the same resources the biggest browser team has at its disposal. It’s a brutally efficient method, whether by design or accident.

Is it virtuous? At the individual contributor level, yes. Is it a vicious cycle by which companies have driven their competition to extinction by forcing them to spend limited resources to catch up? Also yes. And having legions of people building for just your platform helps.

All the awesome, well-meaning, genuinely good-hearted people involved—from the Chrome team to web developers—can throw their hands up and legitimately say, “I was just trying to build the Web forward!” while contributing to further a corporate monopoly.

Chrome has the most resources and leads the pack in building the Web forward to the point that we can’t be sure if we’re building the Web we want... or the Web Google wants.

Speculative biology

There was a time when Microsoft bailed out Apple as it was about to sink. This was not because Bill Gates and Steve Jobs were friends—no, Microsoft needed Apple to succeed so there would still be operating system competition. (No business wants to be seen as a monopoly!)

But consider, for a moment, that Apple had died. What would personal computers be like today if we’d only had Linux and Windows left standing? What would mobile computing look like if Apple hadn't been around to work on the iPhone?

Yes, it's easier to develop and test in only one browser. I'm sure IT professionals would have loved to only support one kind of machine. But variety creates opportunity for us as developers in the long run. Microsoft saving Apple lead to apps which challenged the Web which gave us Chrome and the myriad of APIs Google is charging ahead with. If at any point in this chain of events someone had said, "Meh, it's so much easier if we all use the same thing," we wouldn't have the careers—or the world—that we have now.

Develop in more than one browser. Test in more than one browser. Use more than one browser.

You are both consumer and producer. You have a say in how the future plays out.

Update: I updated this post to expand just a little bit on WebKit on iOS, the role of Firefox during the era of IE6, and to explicitly call attention to Servo, which is probably the most exciting thing happening in browsers right now.

The post The Ecological Impact of Browser Diversity appeared first on CSS-Tricks.

?The Ultimate Guide to Headless CMS

Css Tricks - Thu, 08/30/2018 - 3:58am

(This is a sponsored post.)

Struggling to engage your customers with seamless omnichannel digital experiences?

Then headless CMS is the technology you’ve been waiting for. But with all the buzz around this new technology, you might be feeling a bit lost.

Download our free headless CMS guide and get all the information you need to understand headless CMS architecture and multichannel content management, learn how to future-proof your content against any upcoming technology, and see the benefits of being programming-language agnostic.

Grab your complimentary The Ultimate Guide to Headless CMS eBook.

Direct Link to ArticlePermalink

The post ?The Ultimate Guide to Headless CMS appeared first on CSS-Tricks.

“View Source” in DevTools

Css Tricks - Wed, 08/29/2018 - 1:07pm

When the conversation about the value of "View Source" rolls around, the #1 response I hear is along these lines:

No way, Jose! I use View Source all the time! It's very useful when you want to look at the raw HTML, not the DOM.

Yes, that is useful, and yes, there is a difference. But just because you are looking at DevTools doesn't mean the DOM is the only thing you can see.

This is Chrome DevTools. Safari has a Resources tab

There is also a Network tab in DevTools for every browser. That's where you find a way to look at the document.

Firefox's Network tab

So, if your concern about losing View Source is that you'd have no possible way to see the document instead of just the DOM, that's just not true. You can rest assured that you have the same affordance in DevTools.

If your concern is that it's handier to see the source as a full-window tab with an easy keyboard shortcut, then sure, OK, that's a reasonable argument to make.

The post “View Source” in DevTools appeared first on CSS-Tricks.

An Intro to Web Site Testing with Cypress

Css Tricks - Wed, 08/29/2018 - 3:52am

End-to-end testing is awesome because it mirrors the user’s experience. Where you might need a ton of unit tests to get good coverage (the kind where you test that a function returns a value you expect), you can write a single end-to-end test that acts like a real human as it tests several pieces of your app at once. It’s a very economical way of testing your app.

Cypress is a new-ish test runner with some features that take some of the friction out of end-to-end testing. It sports the ability to automatically wait for elements (if you try to grab onto an element it can’t find), wait for Ajax requests, great visibility into your test outcomes, and an easy-to-use API.

Note: Cypress is both a test runner and a paid service that records your tests, allowing you to play them back later. This post focuses on the test runner which you can use for free.

Installing Cypress

Cypress.io installs easily with npm. Type this into your terminal to install it for your project:

npm install --save-dev cypress

If everything works, you should see output that looks like this in your terminal:

Now, let’s write some tests to see how this thing works!

Setting up tests for CSS-Tricks

We’ll write some tests for CSS-Tricks since it’s something we’re all familiar with… and maybe this will help Chris avoid any regressions (that’s where changing one thing on your site breaks another) when he adds a feature or refactors something. &#x1f61c;

I’ll start inside my directory for this project. I created a new directory called testing-css-tricks inside my projects directory. Typically, your Cypress tests will go inside the directory structure of the project you want to test.

By default, Cypress expects integration tests to be in cypress/integration from the project root, so I’ll create that folder to hold my test files. Here’s how I’d do that in the terminal:

mkdir cypress mkdir cypress/integration

You don’t have to use this default location though. You can change this by creating a cypress.json configuration file in your project root and setting the integrationFolder key to whatever path you want.

Test: Checking the Page Title

Let’s start with something really simple: I want to make sure the name of the site is in the page title.

A Chrome browser window with an open tab containing the CSS-Tricks page title. The describe function

I’ve created a file inside cypress/integration called sample-spec.js. Inside that file, I’ll kick off a test with a call to describe.

describe('CSS-Tricks home page', function() { });

describe takes two arguments: a string which I think of as the "subject" of your testing sentence and a callback function which can run any code you want. The callback function should probably also call it which tells us what we expect to happen in this test and checks for that outcome.

The it function describe('CSS-Tricks home page', function() { it('contains "CSS-Tricks" in the title', function() { }); });

The it function has the same signature: it takes a string and a callback function. This time, the string is the "verb" of our testing sentence. The code we run inside the it callback should ultimately check our assertion (our desired result) for this test against reality.

This describe callback can contain multiple calls to it. Best practice says each it callback should test one assertion.

Setting up tests

We’re getting slightly ahead of ourselves, though. In our describe call, we’ve made it clear that we intend to test the homepage, but we’re not on the homepage. Since all the tests inside this describe callback should be testing the homepage (or else they belong somewhere else), we can just go ahead and navigate to that page in a beforeEach inside the describe callback.

describe('CSS-Tricks home page', function() { beforeEach(function() { cy.visit('https://css-tricks.com/'); }); it('contains "CSS-Tricks" in the title', function() { }); });

beforeEach reads just like what it does. Whatever code is in the callback function passed to it gets executed before each of the tests in the same scope (in this case, just the single it call under it). You have access to a few others like before, afterEach, and after.

You may wonder why not use before here since we’re going to test the same page with each of our assertions in this block. The reason beforeEach and afterEach are used more frequently than their one-time counterparts is that you want to ensure a consistent state at the start of each test.

Imagine you write a test that confirms you can type into the search field. Great! Imagine you follow it with a test that ensures the search field is empty. Fail! Since you just typed into the search field in the previous test without cleaning up, your second test will fail even though the site functions exactly as you wanted: when it’s first loaded, the search field is empty. If you had loaded the page before each of your assertions, you wouldn’t have had a problem since you’d have a fresh state each time.

Driving the browser

cy.visit() in the example above is the equivalent to our user clicking in the address bar, typing https://css-tricks.com/, and pressing return. It will load up this page in the web browser. Now, we’re ready to write out an assertion.

describe('CSS-Tricks home page', function() { beforeEach(function() { cy.visit('https://css-tricks.com/'); }); it('contains "CSS-Tricks" in the title', function() { cy.title().should('contain', 'CSS-Tricks'); }); }); Title Assertion

cy.title() yields the page title. We chain it with should() which creates an assertion. In this example, we pass should() two arguments: a chainer and a value. For your chainer, you can draw from the assertions in a few different JavaScript testing libraries. contains comes from Chai. (The Cypress docs has a handy list of all the assertions it supports.)

Sometimes, you’ll find multiple assertions that accomplish the same thing. Your goal should be for your entire test to read as close to an English sentence as possible. Use the one that makes the most sense in context.

In our case, our assertion reads as: The title should contain "CSS-Tricks."

Running our first test

Now, we have everything we need in place to run our test. Use this command from the project root:

$(npm bin)/cypress open

Since Cypress isn’t installed globally, we have to run it from this project’s npm binaries. $(npm bin) gets replaced with the npm binary path for this project. We’re running the cypress open command from there. You’ll see this output in the terminal if everything worked:

...and you’ll get a web browser with the test runner GUI:

Click that "Run all specs" button to start running your tests. This will spawn a new browser window with your test results. On the left, you have your tests and their steps. On the right, you have the test "browser."

This brings us to another cool feature of Cypress. One problem with end-to-end tests is visibility into your test outcomes. Every test runner gives you a "pass" or "fail," but they do a terrible job of showing you what happened to cause a failure. You know what didn’t happen (your test assertion), but it’s harder to find out what did happen. In the past, I have resorted to taking a screenshot of the test browser at various points throughout the test which rarely gave me the answers I needed. It’s the automated test equivalent to spamming your code with console.log to debug a problem.

With Cypress, I can click on each step of the test on the left to see the state of the page at that point on the right.

Test: Checking for an element on the page

Next, we’ll check for an element we want to be sure is on the page. The page should always include the logo, and it should be visible.

Since we’re testing the same page, we’ll add a new it call to our describe callback.

it('has a visible star logo', function() { cy.get('.icon-logo-star').should('be.visible'); });

We’re still testing from the home page like before since the cy.visit() call happens before each of these tests. This test is using cy.get() to grab the element we want to check for. It works kinda like jQuery: you pass it a CSS selector string. Then, I chain a should() call and check for visibility.

Two things to note here: first, if this element had loaded asynchronously, cy.get() will automatically wait the defaultCommandTimeout to see if the element shows up. (The default value for that is four seconds, which can be changed in cypress.json.) Second, if you add that test and save the file, your tests will automatically re-run with the new test. This makes it really quick and easy to iterate your tests.

Here’s the result:

Test: Making sure navigation is responsive

We’ll try something slightly fancier with this test. I want to be sure the responsive menu is available on smaller viewports. Otherwise, users might not be able to navigate the site properly.

We’re still testing the home page, so I’ll write this test inside the same describe callback. I’m testing a slightly different scenario though, so I’ll nest another describe call to indicate the specific circumstances of my test and to set up those circumstances.

describe('CSS-Tricks home page', function() { // Our existing tests and the beforeEach are here describe('with a 320x568 viewport', function() { }); }); Testing at 320px width

Here, I’ve decided to test for the responsive navigation menu at 320px width, but it would be useful to know about the default testing viewport. You can click on any of your tests in the test runner and see the viewport width above the browser pane.

1000×660 is the default viewport size. You can change this in your cypress.json configuration file. We’ll start by writing the test to run at 320px width. Then, we’ll duplicate that test for a few different viewports.

To change the viewport for this test only, we can call cy.viewport().

describe('with a 320x568 viewport', function() { beforeEach(function() { cy.viewport(320, 568); }); });

Now, we’ll drop an it call inside the nested describe callback. Now that we have the viewport set, this test will look very similar to the logo test.

it('has a visible mobile menu toggle', function() { cy.get('#mobile-menu-toggle').should('be.visible'); }); Testing at 1100px width

I’m going to run the same test at 1100px to make sure the responsive menu is still there. I think this is the maximum width that should have the menu, so I want to make sure it does.

describe('with a 1100x660 viewport', function() { beforeEach(function() { cy.viewport(1100, 660); }); it('has a visible mobile menu toggle', function() { cy.get('#mobile-menu-toggle').should('be.visible'); }); });

Oh crap! What happened here?

Since the test only tested for a single thing, we have a good idea what happened: the responsive menu wasn’t visible at 1100px viewport width. The feedback from the test give us some good information, too.

"Timed out retrying: expected '' to be 'visible'

This element <button#mobile-menu-toggle.button.button-header.mobile-menu-toggle> is not visible because its parent <div.menu-toggle-area> has CSS property display: none.

Cypress waited the defaultCommandTimeout for the mobile menu toggle to be visible, and it wasn’t. It wasn’t considered visible because a parent element had display: none. Makes sense.

Here’s something Cypress gives us that other test runners don’t: the opportunity to inspect the failure state.

When I click on one of the test steps, I see the state of the page at the time that step ran in the browser on the right, but I also get the output in the console. (Bring up Chrome Developer Tools and check the console to see that.)

In this case, that’s not even necessary. It’s easy to see that the page doesn’t have the responsive menu at this width.

In an idealized, real-world scenario, I would first write tests to reflect what I want (in this case, a responsive menu at 1100px viewport width). Then, I would go back and make changes in the code to fix my test failures. In other words, I would make sure the responsive menu is displayed at 1100px. This is called test-driven development.

In this case, though, since I’m testing a live site, I’ll just rewrite the test to fit what the site already does. If you’re adding tests to an existing site to prevent regressions, you might use a method more like this one where you write tests to reflect the existing functionality.

The responsive menu is visible at widths up to 1086px, so we’ll change this test’s viewport width to 1085px. We want to make sure we change the string we’re passing to describe to properly reflect the new width, too.

describe('with a 1085 viewport', function() { beforeEach(function() { cy.viewport(1085, 660); }); it('has a visible mobile menu toggle', function() { cy.get('#mobile-menu-toggle').should('be.visible'); }); })

Now, we have a passing test!

Test: Search

Functioning search is critical for a site with as much content as CSS-Tricks. We’ll divide up testing it into two parts: first, ensuring the request goes out and, second, ensuring the results get displayed on the page.

Before we can do either of those, though, we have to trigger a search.

Let’s add a describe call inside the home page describe callback to indicate we are testing search.

describe('site search', function() { });

We need to call beforeEach with a callback that will trigger the search. To trigger a search, we’ll use the Cypress API to interact with the page the same way a user would. We’ll first type into the search field. Then, we’ll press the keyboard Enter key.

beforeEach(function() { cy.get('.search-field').type('flexbox{enter}'); });

If you look at the documentation for the type method, you can see that {enter} is a special sequence that triggers a press of the enter key. That should submit our search.

Time for the actual testing!

Checking the URL

Our search should load a new page at https://css-tricks.com/?s=<search-term>. Let’s call it:

it('requests the results', function() { });

To make sure the page was requested, we’ll check the URL for the search term now that we’ve triggered the search.

cy.url().should('include', '?s=flexbox');

The question mark kicks off a query string in a URL. Since CSS-Tricks always puts the search parameter first in the query string, we can look for a substring that starts with ?. The site’s search term parameter is s. By confirming that parameter is in the URL with the value we searched, we know the search request was made.

Confirming we have results

To confirm results, we’re not actually testing the home page. We’re testing the results page instead. Since the page is our top-level describe call, we’ll create a new top-level describe call to test the search results page.

describe('Search results page', function() { });

In the real world, we might break this out into a separate files. This makes it easier to find tests, but it also makes our development cycle more efficient. Cypress will re-run tests when you save changes to your tests. If you’re working with a single page and you have your tests split into different files, you can run only that file’s tests. Since tests take some time to run, this can make your iterations tighter as you make changes or add new tests.

Now, we need to get to this page. We’ll use visit inside a beforeEach just inside the new describe call’s callback to navigate there before the test.

beforeEach(function() { cy.visit('https://css-tricks.com/?s=flexbox'); });

This would work, but, since all the pages we’re going to test are on CSS-Tricks, it would be nice if we didn’t have to repeat the protocol (https) and the domain (css-tricks.com) in every test. That would make our tests DRYer.

Fortunately, we can do this with configuration in cypress.json with the baseUrl property. Here’s what the cypress.json file looks like with baseUrl set.

{ "baseUrl": "https://css-tricks.com/" }

Make sure this file is in the root of your project. Any settings will override the Cypress defaults.

With this configuration in place, we can remove this portion of the URL from any visit calls.

describe('CSS-Tricks home page', function() { beforeEach(function() { cy.visit('/'); }); // ... shortened for brevity }); describe('Search results page', function() { beforeEach(function() { cy.visit('/?s=flexbox'); }); });

We’re ready to check if the page has results. Here’s the it call:

it('displays search results', function() { });

By inspecting the page, I can see that each search result is an li element inside an element with the class search-grid-list. I’ll use this as the basis of the selector for the test.

it('displays search results', function() { cy.get('.search-grid-list li').should('exist'); });

This test will tell us we have at least one result on the search results page. It’s good enough for the purposes of this demo, but, in a real-world test, we’d want some way to control the results that come back from the search. It would be easier because we’d be testing against a local copy of the site instead of a live one. We can’t control the content on the live CSS-Tricks site, and, as a result, we can’t accurately predict what will come back for any search term. For this demo, I’ve made the assumption that the search term flexbox will always return at least one result on the site.

Let’s check the results:

What’s next...

Now, we have a good baseline for implementing some testing with Cypress. We learned:

  • how to organize tests
  • how to visit pages in the test browser
  • how to check the title
  • how to test at different viewport sizes
  • how to check the URL in the browser
  • how to grab on to elements and test them
  • how to interact with forms

We didn’t get to touch on one of the coolest aspects of Cypress: the way it allows you to deal with Ajax requests. This is great for single-page apps. Cypress can sit between the server and your app. This allows it to wait for responses to come back when you make a request.

You can also control the responses. I mentioned before that it would be nicer if we had control over the results coming back from the search. If the CSS-Tricks search had used Ajax to load the results, we could have easily delivered a static set of results and tested that they were properly rendered on the page.

Cypress has really good documentation. If you’re ready to try some of the Ajax stuff, check out Cypress’s guide on network requests.

Wherever you go from here, take what you know now and use it to implement some automated testing in your current project. As your app or site becomes more complex, the chance you’ll introduce regressions increases dramatically. You don’t want to get so wrapped up in introducing new features that you end up breaking the old ones. Automated testing is a great way to help you avoid this but without forcing you to manually test each feature every time.

Are you at CSS-Tricks because you want to become a web developer? If so, I want to help. I write technical tutorials like this one, but I also cover other skills you need to make the transition. You’ll miss these if your learning diet is exclusively technical.

Right now, I’m giving away four free mentoring sessions each week to CSS-Tricksters who sign up for my list. Everyone will get great articles and resources to help you become a web developer, and as many people as I can fit into my schedule will get live personalized advice on how to take the next steps in your career transition.

The post An Intro to Web Site Testing with Cypress appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.