Archiwum kategorii: CSS

A Basic WooCommerce Setup to Sell T-Shirts

Post pobrano z: A Basic WooCommerce Setup to Sell T-Shirts

WooCommerce is a powerful eCommerce solution for WordPress sites. If you’re like me, and like working with WordPress and have WordPress-powered sites already, WooCommerce is a no-brainer for helping you sell things online on those sites. But even if you don’t already have a WordPress site, WooCommerce is so good I think it would make sense to spin up a WordPress site so you could use it for your eCommerce solution.

Personally, I’ve used WooCommerce a number of times to sell things. Most recently, I’ve used it to sell T-Shirts (and hats) over on CodePen. We use WordPress already to power our blog, documentation, and podcast. Makes perfect sense to use WordPress for the store as well!

What I think is notable about our WooCommerce installation at CodePen is how painless it was, while doing everything we need it to do. I’d say it was a half-day job with maybe a half-day of maintenance every few months, partially based on us wanting to change something.

The first step is installing the plugin, and immediately you get a Products post type you can use to add new products. We’re selling a T-Shirt, so that looks like this:

Note the variations in use for size. We even track inventory at the size level so our T-Shirt printing company knows when to re-print different sizes.

What is somewhat astounding about WooCommerce is that you might need to do very little else. You could set a price, flip on the basic PayPal integration and enter your email, publish the product, and start taking orders.

Or, you could start customizing things and do as much or as little as you want:

  • You could add as many different payment processors as you like. We like using Stripe for credit card processing at CodePen, but also offer PayPal.
  • You could customize the template of every different page involved, or just use the defaults. At CodePen we have very lightly customized templates for the store homepage and product page.
  • You could get very detailed with calculating shipping costs, or use flat rates. We use a flat rate shipping cost at CodePen almost as marketing: same shipping cost anywhere in the world!
  • You could get into integrations, like connecting it with your MailChimp account for further email marketing or Slack account to notify your team of sales.

If you can dream it, you can do it with WooCommerce.

At CodePen, we work with a company called RealThread that actually prints and ships the T-Shirts.

They work great with WooCommerce of course, and the way we set that up is that we use the ShipStation integration and blast the orders into their account there and they handle all the fulfillment from there. There are all sorts of shipping method plugins though for anything you can think of.

Within WooCommerce, we have a dashboard of all the orders, their status, and even tracking information should we need to look something up.

So essentially:

  1. We use WooCommerce
  2. We use the Stripe plugin to take our credit card payments that way
  3. We use the PayPal plugin to take PayPal payments over Braintree
  4. We use the ShipStation plugin to send orders to that system for our fulfillment company to handle

It was quite easy to set up and works great, and it’s comforting to know that we could do tons more with it if we needed to and support is there to help.

The post A Basic WooCommerce Setup to Sell T-Shirts appeared first on CSS-Tricks.

Using feature detection to write CSS with cross-browser support

Post pobrano z: Using feature detection to write CSS with cross-browser support

In early 2017, I presented a couple of workshops on the topic of CSS feature detection, titled CSS Feature Detection in 2017.

A friend of mine, Justin Slack from New Media Labs, recently sent me a link to the phenomenal Feature Query Manager extension (available for both Chrome and Firefox), by Nigerian developer Ire Aderinokun. This seemed to be a perfect addition to my workshop material on the subject.

However, upon returning to the material, I realized how much my work on the subject has aged in the last 18 months.

The CSS landscape has undergone some tectonic shifts:

The above prompted me to not only revisit my existing material, but also ponder the state of CSS feature detection in the upcoming 18 months.

In short:

  1. ❓ Why do we need CSS feature detection at all?
  2. 🛠️ What are good (and not so good) ways to do feature detection?
  3. 🤖 What does the future hold for CSS feature detection?

Cross-browser compatible CSS

When working with CSS, it seems that one of the top concerns always ends up being inconsistent feature support among browsers. This means that CSS styling might look perfect on my browsers of choice, but might be completely broken on another (perhaps an even more popular) browser.

Luckily, dealing with inconsistent browser support is trivial due to a key feature in the design of the CSS language itself. This behavior, called fault tolerance, means that browsers ignore CSS code they don’t understand. This is in stark contrast to languages like JavaScript or PHP that stop all execution in order to throw an error.

The critical implication here is that if we layer our CSS accordingly, properties will only be applied if the browser understands what they mean. As an example, you can include the following CSS rule and the browser will just ignore it— overriding the initial yellow color, but ignoring the third nonsensical value:

background-color: yellow;
background-color: blue; /* Overrides yellow */
background-color: aqy8godf857wqe6igrf7i6dsgkv; /* Ignored */

To illustrate how this can be used in practice, let me start with a contrived, but straightforward situation:

A client comes to you with a strong desire to include a call-to-action (in the form of a popup) on his homepage. With your amazing front-end skills, you are able to quickly produce the most obnoxious pop-up message known to man:

Unfortunately, it turns out that his wife has an old Windows XP machine running Internet Explorer 8. You’re shocked to learn that what she sees no longer resembles a popup in any shape or form.

But! We remember that by using the magic of CSS fault tolerance, we can remedy the situation. We identify all the mission-critical parts of the styling (e.g., the shadow is nice to have, but does not add anything useful usability-wise) and buffer prepend all core styling with fallbacks.

This means that our CSS now looks something like the following (the overrides are highlighted for clarity):

.overlay {
  background: grey;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid grey;
  border: 1px solid rgba(0, 0, 0, 0.4);
  padding: 64px;
  padding: 4rem;
  display: block;
  display: flex;
  justify-content: center; /* if flex is supported */
  align-items: center; /* if flex is supported */
  height: 100%;
  width: 100%;
}

.popup {
  background: white;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 8px;
  border: 1px solid grey;
  border: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 
    0 7px 8px -4px rgba(0,0, 0, 0.2),
    0 13px 19px 2px rgba(0, 0, 0, 0.14),
    0 5px 24px 4px rgba(0, 0, 0, 0.12);
  padding: 32px;
  padding: 2rem;
  min-width: 240px;
}

button {
  background-color: #e0e1e2;
  background-color: rgba(225, 225, 225, 1);
  border-width: 0;
  border-radius: 4px;
  border-radius: 0.25rem;
  box-shadow: 
    0 1px 3px 0 rgba(0,0,0,.2), 
    0 1px 1px 0 rgba(0,0,0,.14), 
    0 2px 1px -1px rgba(0,0,0,.12);
  color: #5c5c5c;
  color: rgba(95, 95, 95, 1);
  cursor: pointer;
  font-weight: bold;
  font-weight: 700;
  padding: 16px;
  padding: 1rem;
}

button:hover {
  background-color: #c8c8c8;
  background-color: rgb(200,200,200); 
}

The above example generally falls under the broader approach of Progressive Enhancement. If you’re interested in learning more about Progressive Enhancement check out Aaron Gustafson’s second edition of his stellar book on the subject, titled Adaptive Web Design: Crafting Rich Experiences with Progressive Enhancement (2016).

If you’re new to front-end development, you might wonder how on earth does one know the support level of specific CSS properties. The short answer is that the more you work with CSS, the more you will learn these by heart. However, there are a couple of tools that are able to help us along the way:

Even with all the above at our disposal, learning CSS support by heart will help us plan our styling up front and increase our efficiency when writing it.

Limits of CSS fault tolerance

The next week, your client returns with a new request. He wants to gather some feedback from users on the earlier changes that were made to the homepage—again, with a pop-up:

Once again it will look as follows in Internet Explorer 8:

Being more proactive this time, you use your new fallback skills to establish a base level of styling that works on Internet Explorer 8 and progressive styling for everything else. Unfortunately, we still run into a problem…

In order to replace the default radio buttons with ASCII hearts, we use the ::before pseudo-element. However this pseudo-element is not supported in Internet Explorer 8. This means that the heart icon does not render; however the display: none property on the <input type="radio"> element still triggers on Internet Explorer 8. The implication being that neither the replacement behavior nor the default behavior is shown.

Credit to John Faulds for pointing out that it is actually possible to get the ’::before’ pseudo-element to work in Internet Explorer 8 if you replace the official double colon syntax with a single colon.

In short, we have a rule (display: none) whose execution should not be bound to its own support (and thus its own fallback structure), but to the support level of a completely separate CSS feature (::before).

For all intents and purposes, the common approach is to explore whether there are more straightforward solutions that do not rely on ::before. However, for the sake of this example, let’s say that the above solution is non-negotiable (and sometimes they are).

Enter User Agent Detection

A solution might be to determine what browser the user is using and then only apply display: none if their browser supports the ::before pseudo-element.

In fact, this approach is almost as old as the web itself. It is known as User Agent Detection or, more colloquially, browser sniffing.

It is usually done as follows:

  • All browsers add a JavaScript property on the global window object called navigator and this object contains a userAgent string property.
  • In my case, the userAgent string is: Mozilla/5.0 (Windows NT10.0;Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.9 Safari/537.36.
  • Mozilla Developer Network has a comprehensive list of how the above can be used to determine the browser.
  • If we are using Chrome, then the following should return true: (navigator.userAgent.indexOf("chrome") !== -1).
  • However, under the Internet Explorer section on MDN, we just get Internet Explorer. IE doesn’t put its name in the BrowserName/VersionNumber format.
  • Luckily, Internet Explorer provides its own native detection in the form of Conditional Comments.

This means that adding the following in our HTML should suffice:

<!--[if lt IE 9]>
  <style>
    input {
      display: block;
    }
  </style>
<![endif]-->

This means that the above will be applied, should the browser be a version of Internet Explorer lower than version 9 (IE 9 supports ::before)—effectively overriding the display: none property.
Seems straightforward enough?

Unfortunately, over time, some critical flaws emerged in User Agent Detection. So much so that Internet Explorer stopped supporting Conditional Comments from version 10 onward. You will also notice that in the Mozilla Developer Network link itself, the following is presented in an orange alert:

It’s worth re-iterating: it’s very rarely a good idea to use user agent sniffing. You can almost always find a better, more broadly compatible way to solve your problem!

The biggest drawback of User Agent Detection is that browser vendors started spoofing their user agent strings over time due to the following:

  • Developer adds CSS feature that is not supported in the browser.
  • Developer adds User Agent Detection code to serve fallbacks to the browser.
  • Browser eventually adds support for that specific CSS feature.
  • Original User Agent Detection code is not updated to take this into consideration.
  • Code always displays the fallback, even if the browser now supports the CSS feature.
  • Browser uses a fake user agent string to give users the best experience on the web.

Furthermore, even if we were able to infallibly determine every browser type and version, we would have to actively maintain and update our User Agent Detection to reflect the feature support state of those browsers (notwithstanding browsers that have not even been developed yet).

It is important to note that although there are superficial similarities between feature detection and User Agent Detection, feature detection takes a radically different approach than User Agent Detection. According to the Mozilla Developer Network, when we use feature detection, we are essentially doing the following:

  1. 🔎 Testing whether a browser is actually able to run a specific line (or lines) of HTML, CSS or JavaScript code.
  2. 💪 Taking a specific action based on the outcome of this test.

We can also look to Wikipedia for a more formal definition (emphasis mine):

Feature detection (also feature testing) is a technique used in web development for handling differences between runtime environments (typically web browsers or user agents), by programmatically testing for clues that the environment may or may not offer certain functionality. This information is then used to make the application adapt in some way to suit the environment: to make use of certain APIs, or tailor for a better user experience.

While a bit esoteric, this definition does highlight two important aspects of feature detection:

  • Feature detection is a technique, as opposed to a specific tool or technology. This means that there are various (equally valid) ways to accomplish feature detection.
  • Feature detection programmatically tests code. This means that browsers actually run a piece of code to see what happens, as opposed to merely using inference or comparing it against a theoretical reference/list as done with User Agent Detection.

CSS feature detection with @supports

The core concept is not to ask „What browser is this?” It’s to ask „Does your browser support the feature I want to use?”.

—Rob Larson, The Uncertain Web: Web Development in a Changing Landscape (2014)

Most modern browsers support a set of native CSS rules called CSS conditional rules. These allow us to test for certain conditions within the stylesheet itself. The latest iteration (known as module level 3) is described by the Cascading Style Sheets Working Group as follows:

This module contains the features of CSS for conditional processing of parts of style sheets, conditioned on capabilities of the processor or the document the style sheet is being applied to. It includes and extends the functionality of CSS level 2 [CSS21], which builds on CSS level 1 [CSS1]. The main extensions compared to level 2 are allowing nesting of certain at-rules inside ‘@media’, and the addition of the ‘@supports’ rule for conditional processing.

If you’ve used @media, @document or @import before, then you already have experience working with CSS conditional rules. For example when using CSS media queries we do the following:

  • Wrap a single or multiple CSS declarations in a code block with curly brackets, { }.
  • Prepend the code block with a @media query with additional information.
  • Include an optional media type. This can either be all, print, speech or the commonly used screen type.
  • Chain expressions with and/or to determine the scope. For example, if we use (min-width: 300px) and (max-width: 800px), it will trigger the query if the screen size is wider than 300 pixels and smaller than 800 pixels.

The feature queries spec (editor’s draft) prescribes behavior that is conveniently similar to the above example. Instead of using a query expression to set a condition based on the screen size, we write an expression to scope our code block according to a browser’s CSS support (emphasis mine):

The ‘@supports rule allows CSS to be conditioned on implementation support for CSS properties and values. This rule makes it much easier for authors to use new CSS features and provide good fallback for implementations that do not support those features. This is particularly important for CSS features that provide new layout mechanisms, and for other cases where a set of related styles needs to be conditioned on property support.

In short, feature queries are a small built-in CSS tool that allow us to only execute code (like the display: none example above) when a browser supports a separate CSS feature—and much like media queries, we are able to chain expressions as follows: @supports (display: grid) and ((animation-name: spin) or (transition: transform(rotate(360deg)).

So, theoretically, we should be able to do the following:

@supports (::before) {
  input {
    display: none;
  }
}

Unfortunately, it seems that in our example above the display: none property did not trigger, in spite of the fact that your browser probably supports ::before.

That’s because there are some caveats to using @supports:

  • First and foremost, CSS feature queries only support CSS properties and not CSS pseudo-element, like ::before.
  • Secondly, you will see that in the above example our @supports (transform: scale(2)) and (animation-name: beat) condition fires correctly. However if we were to test it in Internet Explorer 11 (which supports both transform: scale(2) and animation-name: beat) it does not fire. What gives? In short, @supports is a CSS feature, with a support matrix of its own.

CSS feature detection with Modernizr

Luckily, the fix is fairly easy! It comes in the form of an open source JavaScript library named Modernizr, initially developed by Faruk Ateş (although it now has some pretty big names behind it, like Paul Irish from Chrome and Alex Sexton from Stripe).

Before we dig into Modernizr, let’s address a subject of great confusion for many developers (partly due to the name „Modernizr” itself). Modernizr does not transform your code or magically enable unsupported features. In fact, the only change Modernzr makes to your code is appending specific CSS classes to your <html> tag.

This means that you might end up with something like the following:

<html class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">

That is one big HTML tag! However, it allows us do something super powerful: use the CSS descendant selector to conditionally apply CSS rules.

When Modernizr runs, it uses JavaScript to detect what the user’s browser supports, and if it does support that feature, Modernizr injects the name of it as a class to the <html>. Alternatively, if the browser does not support the feature, it prefixes the injected class with no- (e.g., no-generatedcontent in our ::before example). This means that we can write our conditional rule in the stylesheet as follows:

.generatedcontent input {
  display: none
}

In addition, we are able to replicate the chaining of @supports expressions in Modernizr as follows:

/* default */
.generatedcontent input { }

/* 'or' operator */
.generatedcontent input, .csstransforms input { }

/* 'and' operator */
.generatedcontent.csstransformsinput { }

/* 'not' operator */
.no-generatedcontent input { }

Since Modernizr runs in JavaScript (and does not use any native browser APIs), it’s effectively supported on almost all browsers. This means that by leveraging classes like generatedcontent and csstransforms, we are able to cover all our bases for Internet Explorer 8, while still serving bleeding-edge CSS to the latest browsers.

It is important to note that since the release of Modernizr 3.0, we are no longer able to download a stock-standard modernizr.js file with everything except the kitchen sink. Instead, we have to explicitly generate our own custom Modernizr code via their wizard (to copy or download). This is most likely in response to the increasing global focus on web performance over the last couple of years. Checking for more features contributes to more loading, so Modernizr wants us to only check for what we need.

So, I should always use Modernizr?

Given that Modernizr is effectively supported across all browsers, is there any point in even using CSS feature queries? Ironically, I would not only say that we should but that feature queries should still be our first port of call.

First and foremost, the fact that Modernizr does not plug directly into the browser API is it’s greatest strength—it does not rely on the availability of a specific browser API. However, this benefit comes a cost, and that cost is additional overhead to something most browsers support out of the box through @supports—especially when you’re delivering this additional overhead to all users indiscriminately in order to a small amount of edge users. It is important to note that, in our example above, Internet Explorer 8 currently only stands at 0.18% global usage).

Compared to the light touch of @supports, Modernizr has the following drawbacks:

  • The approach underpinning development of Modernizr is driven by the assumption that Modernizr was „meant from day one to eventually become unnecessary.”
  • In the majority of cases, Modernizr needs to be render blocking. This means that Modernizr needs to be downloaded and executed in JavaScript before a web page can even show content on the screen—increasing our page load time (especially on mobile devices)!
  • In order to run tests, Modernizr often has to actually build hidden HTML nodes and test whether it works. For example, in order to test for <canvas> support, Modernizr executes the follow JavaScript code: return !!(document.createElement('canvas').getContext && document.createElement('canvas').getContext('2d'));. This consumes CPU processing power that could be used elsewhere.
  • The CSS descendant selector pattern used by Modernizr increases CSS specificity. (See Harry Roberts’ excellent article on why „specificity is a trait best avoided.”)
  • Although Modernizr covers a lot of tests (150+), it still does not cover the entire spectrum of CSS properties like @support does. The Modernizr team actively maintains a list of these undetectables.

Given that feature queries have already been widely implemented across the browser landscape, (covering about 93.42% of global browsers at the time of writing), it’s been a good while since I’ve used Modernizr. However, it is good to know that it exists as an option should we run into the limitations of @supports or if we need to support users still locked into older browsers or devices for a variety of potential reasons.

Furthermore, when using Modernizr, it is usually in conjunction with @supports as follows:

.generatedcontent input {
  display: none;
}

label:hover::before {
  color: #c6c8c9;
}

input:checked + label::before {
  color: black;
}

@supports (transform: scale(2)) and (animation-name: beat) {
  input:checked + label::before {
    color: #e0e1e2;
    animation-name: beat;
    animation-iteration-count: infinite;
    animation-direction: alternate;
  }
}

This triggers the following to happen:

  • If ::before is not supported, our CSS will fallback to the default HTML radio select.
  • If neither transform(scale(2)) nor animation-name: beat are supported but ::before is, then the heart icon will change to black instead of animate when selected.
  • If transform(scale(2), animation-name: beat and ::before are supported, then the heart icon will animate when selected.

The future of CSS feature detection

Up until this point, I’ve shied away from talking about feature detection in a world being eaten by JavaScript, or possibly even a post-JavaScript world. Perhaps even intentionally so, since current iterations at the intersection between CSS and JavaScript are extremely contentious and divisive.

From that moment on, the web community was split in two by an intense debate between those who see CSS as an untouchable layer in the „separation of concerns” paradigm (content + presentation + behaviour, HTML + CSS + JS) and those who have simply ignored this golden rule and found different ways to style the UI, typically applying CSS styles via JavaScript. This debate has become more and more intense every day, bringing division in a community that used to be immune to this kind of „religion wars”.

—Cristiano Rastelli, Let there be peace on CSS (2017)

However, I think exploring how to apply feature detection in the modern CSS-in-JS toolchain might be of value as follows:

  • It provides an opportunity to explore how CSS feature detection would work in a radically different environment.
  • It showcases feature detection as a technique, as opposed to a specific technology or tool.

With this in mind, let us start by examining an implementation of our pop-up by means of the most widely-used CSS-in-JS library (at least at the time of writing), Styled Components:

This is how it will look in Internet Explorer 8:

In our previous examples, we’ve been able to conditionally execute CSS rules based on the browser support of ::before (via Modernizr) and transform (via @supports). However, by leveraging JavaScript, we are able to take this even further. Since both @supports and Modernizr expose their APIs via JavaScript, we are able to conditionally load entire parts of our pop-up based solely on browser support.

Keep in mind that you will probably need to do a lot of heavy lifting to get React and Styled Components working in a browser that does not even support ::before (checking for display: grid might make more sense in this context), but for the sake of keeping with the above examples, let us assume that we have React and Styled Components running in Internet Explorer 8 or lower.

In the example above, you will notice that we’ve created a component, called ValueSelection. This component returns a clickable button that increments the amount of likes on click. If you are viewing the example on a slightly older browser, you might notice that instead of the button you will see a dropdown with values from 0 to 9.

In order to achieve this, we’re conditionally returning an enhanced version of the component only if the following conditions are met:

if (
  CSS.supports('transform: scale(2)') &&
  CSS.supports('animation-name: beat') &&
  Modernizr.generatedcontent
) {
  return (
    <React.Fragment>
      <Modern type="button" onClick={add}>{string}</Modern> 
      <input type="hidden" name="liked" value={value} />
    </React.Fragment>
  )
}

return (
  <Base value={value} onChange={select}>
    {
      [1,2,3,4,5,6,7,8,9].map(val => (
        <option value={val} key={val}>{val}</option>
      ))
    }
  </Base>
);

What is intriguing about this approach is that the ValueSelection component only exposes two parameters:

  • The current amount of likes
  • The function to run when the amount of likes are updated
<Overlay>
  <Popup>
    <Title>How much do you like popups?</Title>
    <form>
      <ValueInterface value={liked} change={changeLike} />
      <Button type="submit">Submit</Button>
    </form>
  </Popup>
</Overlay>

In other words, the component’s logic is completely separate from its presentation. The component itself will internally decide what presentation works best given a browser’s support matrix. Having the conditional presentation abstracted away inside the component itself opens the door to exciting new ways of building cross-browser compatible interfaces when working in a front-end and/or design team.

Here’s the final product:

…and how it should theoretically look in Internet Explorer 8:

Additional Resources

If you are interested in diving deeper into the above you can visit the following resources:


Schalk is a South African front-end developer/designer passionate about the role technology and the web can play as a force for good in his home country. He works full time with a group of civic tech minded developers at a South African non-profit called OpenUp.

He also helps manage a collaborative space called Codebridge where developers are encouraged to come and experiment with technology as a tool to bridge social divides and solve problems alongside local communities.

The post Using feature detection to write CSS with cross-browser support appeared first on CSS-Tricks.

Using feature detection to write CSS with cross-browser support

Post pobrano z: Using feature detection to write CSS with cross-browser support

In early 2017, I presented a couple of workshops on the topic of CSS feature detection, titled CSS Feature Detection in 2017.

A friend of mine, Justin Slack from New Media Labs, recently sent me a link to the phenomenal Feature Query Manager extension (available for both Chrome and Firefox), by Nigerian developer Ire Aderinokun. This seemed to be a perfect addition to my workshop material on the subject.

However, upon returning to the material, I realized how much my work on the subject has aged in the last 18 months.

The CSS landscape has undergone some tectonic shifts:

The above prompted me to not only revisit my existing material, but also ponder the state of CSS feature detection in the upcoming 18 months.

In short:

  1. ❓ Why do we need CSS feature detection at all?
  2. 🛠️ What are good (and not so good) ways to do feature detection?
  3. 🤖 What does the future hold for CSS feature detection?

Cross-browser compatible CSS

When working with CSS, it seems that one of the top concerns always ends up being inconsistent feature support among browsers. This means that CSS styling might look perfect on my browsers of choice, but might be completely broken on another (perhaps an even more popular) browser.

Luckily, dealing with inconsistent browser support is trivial due to a key feature in the design of the CSS language itself. This behavior, called fault tolerance, means that browsers ignore CSS code they don’t understand. This is in stark contrast to languages like JavaScript or PHP that stop all execution in order to throw an error.

The critical implication here is that if we layer our CSS accordingly, properties will only be applied if the browser understands what they mean. As an example, you can include the following CSS rule and the browser will just ignore it— overriding the initial yellow color, but ignoring the third nonsensical value:

background-color: yellow;
background-color: blue; /* Overrides yellow */
background-color: aqy8godf857wqe6igrf7i6dsgkv; /* Ignored */

To illustrate how this can be used in practice, let me start with a contrived, but straightforward situation:

A client comes to you with a strong desire to include a call-to-action (in the form of a popup) on his homepage. With your amazing front-end skills, you are able to quickly produce the most obnoxious pop-up message known to man:

Unfortunately, it turns out that his wife has an old Windows XP machine running Internet Explorer 8. You’re shocked to learn that what she sees no longer resembles a popup in any shape or form.

But! We remember that by using the magic of CSS fault tolerance, we can remedy the situation. We identify all the mission-critical parts of the styling (e.g., the shadow is nice to have, but does not add anything useful usability-wise) and buffer prepend all core styling with fallbacks.

This means that our CSS now looks something like the following (the overrides are highlighted for clarity):

.overlay {
  background: grey;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid grey;
  border: 1px solid rgba(0, 0, 0, 0.4);
  padding: 64px;
  padding: 4rem;
  display: block;
  display: flex;
  justify-content: center; /* if flex is supported */
  align-items: center; /* if flex is supported */
  height: 100%;
  width: 100%;
}

.popup {
  background: white;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 8px;
  border: 1px solid grey;
  border: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 
    0 7px 8px -4px rgba(0,0, 0, 0.2),
    0 13px 19px 2px rgba(0, 0, 0, 0.14),
    0 5px 24px 4px rgba(0, 0, 0, 0.12);
  padding: 32px;
  padding: 2rem;
  min-width: 240px;
}

button {
  background-color: #e0e1e2;
  background-color: rgba(225, 225, 225, 1);
  border-width: 0;
  border-radius: 4px;
  border-radius: 0.25rem;
  box-shadow: 
    0 1px 3px 0 rgba(0,0,0,.2), 
    0 1px 1px 0 rgba(0,0,0,.14), 
    0 2px 1px -1px rgba(0,0,0,.12);
  color: #5c5c5c;
  color: rgba(95, 95, 95, 1);
  cursor: pointer;
  font-weight: bold;
  font-weight: 700;
  padding: 16px;
  padding: 1rem;
}

button:hover {
  background-color: #c8c8c8;
  background-color: rgb(200,200,200); 
}

The above example generally falls under the broader approach of Progressive Enhancement. If you’re interested in learning more about Progressive Enhancement check out Aaron Gustafson’s second edition of his stellar book on the subject, titled Adaptive Web Design: Crafting Rich Experiences with Progressive Enhancement (2016).

If you’re new to front-end development, you might wonder how on earth does one know the support level of specific CSS properties. The short answer is that the more you work with CSS, the more you will learn these by heart. However, there are a couple of tools that are able to help us along the way:

Even with all the above at our disposal, learning CSS support by heart will help us plan our styling up front and increase our efficiency when writing it.

Limits of CSS fault tolerance

The next week, your client returns with a new request. He wants to gather some feedback from users on the earlier changes that were made to the homepage—again, with a pop-up:

Once again it will look as follows in Internet Explorer 8:

Being more proactive this time, you use your new fallback skills to establish a base level of styling that works on Internet Explorer 8 and progressive styling for everything else. Unfortunately, we still run into a problem…

In order to replace the default radio buttons with ASCII hearts, we use the ::before pseudo-element. However this pseudo-element is not supported in Internet Explorer 8. This means that the heart icon does not render; however the display: none property on the <input type="radio"> element still triggers on Internet Explorer 8. The implication being that neither the replacement behavior nor the default behavior is shown.

Credit to John Faulds for pointing out that it is actually possible to get the ’::before’ pseudo-element to work in Internet Explorer 8 if you replace the official double colon syntax with a single colon.

In short, we have a rule (display: none) whose execution should not be bound to its own support (and thus its own fallback structure), but to the support level of a completely separate CSS feature (::before).

For all intents and purposes, the common approach is to explore whether there are more straightforward solutions that do not rely on ::before. However, for the sake of this example, let’s say that the above solution is non-negotiable (and sometimes they are).

Enter User Agent Detection

A solution might be to determine what browser the user is using and then only apply display: none if their browser supports the ::before pseudo-element.

In fact, this approach is almost as old as the web itself. It is known as User Agent Detection or, more colloquially, browser sniffing.

It is usually done as follows:

  • All browsers add a JavaScript property on the global window object called navigator and this object contains a userAgent string property.
  • In my case, the userAgent string is: Mozilla/5.0 (Windows NT10.0;Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.9 Safari/537.36.
  • Mozilla Developer Network has a comprehensive list of how the above can be used to determine the browser.
  • If we are using Chrome, then the following should return true: (navigator.userAgent.indexOf("chrome") !== -1).
  • However, under the Internet Explorer section on MDN, we just get Internet Explorer. IE doesn’t put its name in the BrowserName/VersionNumber format.
  • Luckily, Internet Explorer provides its own native detection in the form of Conditional Comments.

This means that adding the following in our HTML should suffice:

<!--[if lt IE 9]>
  <style>
    input {
      display: block;
    }
  </style>
<![endif]-->

This means that the above will be applied, should the browser be a version of Internet Explorer lower than version 9 (IE 9 supports ::before)—effectively overriding the display: none property.
Seems straightforward enough?

Unfortunately, over time, some critical flaws emerged in User Agent Detection. So much so that Internet Explorer stopped supporting Conditional Comments from version 10 onward. You will also notice that in the Mozilla Developer Network link itself, the following is presented in an orange alert:

It’s worth re-iterating: it’s very rarely a good idea to use user agent sniffing. You can almost always find a better, more broadly compatible way to solve your problem!

The biggest drawback of User Agent Detection is that browser vendors started spoofing their user agent strings over time due to the following:

  • Developer adds CSS feature that is not supported in the browser.
  • Developer adds User Agent Detection code to serve fallbacks to the browser.
  • Browser eventually adds support for that specific CSS feature.
  • Original User Agent Detection code is not updated to take this into consideration.
  • Code always displays the fallback, even if the browser now supports the CSS feature.
  • Browser uses a fake user agent string to give users the best experience on the web.

Furthermore, even if we were able to infallibly determine every browser type and version, we would have to actively maintain and update our User Agent Detection to reflect the feature support state of those browsers (notwithstanding browsers that have not even been developed yet).

It is important to note that although there are superficial similarities between feature detection and User Agent Detection, feature detection takes a radically different approach than User Agent Detection. According to the Mozilla Developer Network, when we use feature detection, we are essentially doing the following:

  1. 🔎 Testing whether a browser is actually able to run a specific line (or lines) of HTML, CSS or JavaScript code.
  2. 💪 Taking a specific action based on the outcome of this test.

We can also look to Wikipedia for a more formal definition (emphasis mine):

Feature detection (also feature testing) is a technique used in web development for handling differences between runtime environments (typically web browsers or user agents), by programmatically testing for clues that the environment may or may not offer certain functionality. This information is then used to make the application adapt in some way to suit the environment: to make use of certain APIs, or tailor for a better user experience.

While a bit esoteric, this definition does highlight two important aspects of feature detection:

  • Feature detection is a technique, as opposed to a specific tool or technology. This means that there are various (equally valid) ways to accomplish feature detection.
  • Feature detection programmatically tests code. This means that browsers actually run a piece of code to see what happens, as opposed to merely using inference or comparing it against a theoretical reference/list as done with User Agent Detection.

CSS feature detection with @supports

The core concept is not to ask „What browser is this?” It’s to ask „Does your browser support the feature I want to use?”.

—Rob Larson, The Uncertain Web: Web Development in a Changing Landscape (2014)

Most modern browsers support a set of native CSS rules called CSS conditional rules. These allow us to test for certain conditions within the stylesheet itself. The latest iteration (known as module level 3) is described by the Cascading Style Sheets Working Group as follows:

This module contains the features of CSS for conditional processing of parts of style sheets, conditioned on capabilities of the processor or the document the style sheet is being applied to. It includes and extends the functionality of CSS level 2 [CSS21], which builds on CSS level 1 [CSS1]. The main extensions compared to level 2 are allowing nesting of certain at-rules inside ‘@media’, and the addition of the ‘@supports’ rule for conditional processing.

If you’ve used @media, @document or @import before, then you already have experience working with CSS conditional rules. For example when using CSS media queries we do the following:

  • Wrap a single or multiple CSS declarations in a code block with curly brackets, { }.
  • Prepend the code block with a @media query with additional information.
  • Include an optional media type. This can either be all, print, speech or the commonly used screen type.
  • Chain expressions with and/or to determine the scope. For example, if we use (min-width: 300px) and (max-width: 800px), it will trigger the query if the screen size is wider than 300 pixels and smaller than 800 pixels.

The feature queries spec (editor’s draft) prescribes behavior that is conveniently similar to the above example. Instead of using a query expression to set a condition based on the screen size, we write an expression to scope our code block according to a browser’s CSS support (emphasis mine):

The ‘@supports rule allows CSS to be conditioned on implementation support for CSS properties and values. This rule makes it much easier for authors to use new CSS features and provide good fallback for implementations that do not support those features. This is particularly important for CSS features that provide new layout mechanisms, and for other cases where a set of related styles needs to be conditioned on property support.

In short, feature queries are a small built-in CSS tool that allow us to only execute code (like the display: none example above) when a browser supports a separate CSS feature—and much like media queries, we are able to chain expressions as follows: @supports (display: grid) and ((animation-name: spin) or (transition: transform(rotate(360deg)).

So, theoretically, we should be able to do the following:

@supports (::before) {
  input {
    display: none;
  }
}

Unfortunately, it seems that in our example above the display: none property did not trigger, in spite of the fact that your browser probably supports ::before.

That’s because there are some caveats to using @supports:

  • First and foremost, CSS feature queries only support CSS properties and not CSS pseudo-element, like ::before.
  • Secondly, you will see that in the above example our @supports (transform: scale(2)) and (animation-name: beat) condition fires correctly. However if we were to test it in Internet Explorer 11 (which supports both transform: scale(2) and animation-name: beat) it does not fire. What gives? In short, @supports is a CSS feature, with a support matrix of its own.

CSS feature detection with Modernizr

Luckily, the fix is fairly easy! It comes in the form of an open source JavaScript library named Modernizr, initially developed by Faruk Ateş (although it now has some pretty big names behind it, like Paul Irish from Chrome and Alex Sexton from Stripe).

Before we dig into Modernizr, let’s address a subject of great confusion for many developers (partly due to the name „Modernizr” itself). Modernizr does not transform your code or magically enable unsupported features. In fact, the only change Modernzr makes to your code is appending specific CSS classes to your <html> tag.

This means that you might end up with something like the following:

<html class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">

That is one big HTML tag! However, it allows us do something super powerful: use the CSS descendant selector to conditionally apply CSS rules.

When Modernizr runs, it uses JavaScript to detect what the user’s browser supports, and if it does support that feature, Modernizr injects the name of it as a class to the <html>. Alternatively, if the browser does not support the feature, it prefixes the injected class with no- (e.g., no-generatedcontent in our ::before example). This means that we can write our conditional rule in the stylesheet as follows:

.generatedcontent input {
  display: none
}

In addition, we are able to replicate the chaining of @supports expressions in Modernizr as follows:

/* default */
.generatedcontent input { }

/* 'or' operator */
.generatedcontent input, .csstransforms input { }

/* 'and' operator */
.generatedcontent.csstransformsinput { }

/* 'not' operator */
.no-generatedcontent input { }

Since Modernizr runs in JavaScript (and does not use any native browser APIs), it’s effectively supported on almost all browsers. This means that by leveraging classes like generatedcontent and csstransforms, we are able to cover all our bases for Internet Explorer 8, while still serving bleeding-edge CSS to the latest browsers.

It is important to note that since the release of Modernizr 3.0, we are no longer able to download a stock-standard modernizr.js file with everything except the kitchen sink. Instead, we have to explicitly generate our own custom Modernizr code via their wizard (to copy or download). This is most likely in response to the increasing global focus on web performance over the last couple of years. Checking for more features contributes to more loading, so Modernizr wants us to only check for what we need.

So, I should always use Modernizr?

Given that Modernizr is effectively supported across all browsers, is there any point in even using CSS feature queries? Ironically, I would not only say that we should but that feature queries should still be our first port of call.

First and foremost, the fact that Modernizr does not plug directly into the browser API is it’s greatest strength—it does not rely on the availability of a specific browser API. However, this benefit comes a cost, and that cost is additional overhead to something most browsers support out of the box through @supports—especially when you’re delivering this additional overhead to all users indiscriminately in order to a small amount of edge users. It is important to note that, in our example above, Internet Explorer 8 currently only stands at 0.18% global usage).

Compared to the light touch of @supports, Modernizr has the following drawbacks:

  • The approach underpinning development of Modernizr is driven by the assumption that Modernizr was „meant from day one to eventually become unnecessary.”
  • In the majority of cases, Modernizr needs to be render blocking. This means that Modernizr needs to be downloaded and executed in JavaScript before a web page can even show content on the screen—increasing our page load time (especially on mobile devices)!
  • In order to run tests, Modernizr often has to actually build hidden HTML nodes and test whether it works. For example, in order to test for <canvas> support, Modernizr executes the follow JavaScript code: return !!(document.createElement('canvas').getContext && document.createElement('canvas').getContext('2d'));. This consumes CPU processing power that could be used elsewhere.
  • The CSS descendant selector pattern used by Modernizr increases CSS specificity. (See Harry Roberts’ excellent article on why „specificity is a trait best avoided.”)
  • Although Modernizr covers a lot of tests (150+), it still does not cover the entire spectrum of CSS properties like @support does. The Modernizr team actively maintains a list of these undetectables.

Given that feature queries have already been widely implemented across the browser landscape, (covering about 93.42% of global browsers at the time of writing), it’s been a good while since I’ve used Modernizr. However, it is good to know that it exists as an option should we run into the limitations of @supports or if we need to support users still locked into older browsers or devices for a variety of potential reasons.

Furthermore, when using Modernizr, it is usually in conjunction with @supports as follows:

.generatedcontent input {
  display: none;
}

label:hover::before {
  color: #c6c8c9;
}

input:checked + label::before {
  color: black;
}

@supports (transform: scale(2)) and (animation-name: beat) {
  input:checked + label::before {
    color: #e0e1e2;
    animation-name: beat;
    animation-iteration-count: infinite;
    animation-direction: alternate;
  }
}

This triggers the following to happen:

  • If ::before is not supported, our CSS will fallback to the default HTML radio select.
  • If neither transform(scale(2)) nor animation-name: beat are supported but ::before is, then the heart icon will change to black instead of animate when selected.
  • If transform(scale(2), animation-name: beat and ::before are supported, then the heart icon will animate when selected.

The future of CSS feature detection

Up until this point, I’ve shied away from talking about feature detection in a world being eaten by JavaScript, or possibly even a post-JavaScript world. Perhaps even intentionally so, since current iterations at the intersection between CSS and JavaScript are extremely contentious and divisive.

From that moment on, the web community was split in two by an intense debate between those who see CSS as an untouchable layer in the „separation of concerns” paradigm (content + presentation + behaviour, HTML + CSS + JS) and those who have simply ignored this golden rule and found different ways to style the UI, typically applying CSS styles via JavaScript. This debate has become more and more intense every day, bringing division in a community that used to be immune to this kind of „religion wars”.

—Cristiano Rastelli, Let there be peace on CSS (2017)

However, I think exploring how to apply feature detection in the modern CSS-in-JS toolchain might be of value as follows:

  • It provides an opportunity to explore how CSS feature detection would work in a radically different environment.
  • It showcases feature detection as a technique, as opposed to a specific technology or tool.

With this in mind, let us start by examining an implementation of our pop-up by means of the most widely-used CSS-in-JS library (at least at the time of writing), Styled Components:

This is how it will look in Internet Explorer 8:

In our previous examples, we’ve been able to conditionally execute CSS rules based on the browser support of ::before (via Modernizr) and transform (via @supports). However, by leveraging JavaScript, we are able to take this even further. Since both @supports and Modernizr expose their APIs via JavaScript, we are able to conditionally load entire parts of our pop-up based solely on browser support.

Keep in mind that you will probably need to do a lot of heavy lifting to get React and Styled Components working in a browser that does not even support ::before (checking for display: grid might make more sense in this context), but for the sake of keeping with the above examples, let us assume that we have React and Styled Components running in Internet Explorer 8 or lower.

In the example above, you will notice that we’ve created a component, called ValueSelection. This component returns a clickable button that increments the amount of likes on click. If you are viewing the example on a slightly older browser, you might notice that instead of the button you will see a dropdown with values from 0 to 9.

In order to achieve this, we’re conditionally returning an enhanced version of the component only if the following conditions are met:

if (
  CSS.supports('transform: scale(2)') &&
  CSS.supports('animation-name: beat') &&
  Modernizr.generatedcontent
) {
  return (
    <React.Fragment>
      <Modern type="button" onClick={add}>{string}</Modern> 
      <input type="hidden" name="liked" value={value} />
    </React.Fragment>
  )
}

return (
  <Base value={value} onChange={select}>
    {
      [1,2,3,4,5,6,7,8,9].map(val => (
        <option value={val} key={val}>{val}</option>
      ))
    }
  </Base>
);

What is intriguing about this approach is that the ValueSelection component only exposes two parameters:

  • The current amount of likes
  • The function to run when the amount of likes are updated
<Overlay>
  <Popup>
    <Title>How much do you like popups?</Title>
    <form>
      <ValueInterface value={liked} change={changeLike} />
      <Button type="submit">Submit</Button>
    </form>
  </Popup>
</Overlay>

In other words, the component’s logic is completely separate from its presentation. The component itself will internally decide what presentation works best given a browser’s support matrix. Having the conditional presentation abstracted away inside the component itself opens the door to exciting new ways of building cross-browser compatible interfaces when working in a front-end and/or design team.

Here’s the final product:

…and how it should theoretically look in Internet Explorer 8:

Additional Resources

If you are interested in diving deeper into the above you can visit the following resources:


Schalk is a South African front-end developer/designer passionate about the role technology and the web can play as a force for good in his home country. He works full time with a group of civic tech minded developers at a South African non-profit called OpenUp.

He also helps manage a collaborative space called Codebridge where developers are encouraged to come and experiment with technology as a tool to bridge social divides and solve problems alongside local communities.

The post Using feature detection to write CSS with cross-browser support appeared first on CSS-Tricks.

Using CSS Clip Path to Create Interactive Effects, Part II

Post pobrano z: Using CSS Clip Path to Create Interactive Effects, Part II

This is a follow up to my previous post looking into clip paths. Last time around, we dug into the fundamentals of clipping and how to get started. We looked at some ideas to exemplify what we can do with clipping. We’re going to take things a step further in this post and look at different examples, discuss alternative techniques, and consider how to approach our work to be cross-browser compatible.

One of the biggest drawbacks of CSS clipping, at the time of writing, is browser support. Not having 100% browser coverage means different experiences for viewers in different browsers. We, as developers, can’t control what browsers support — browser vendors are the ones who implement the spec and different vendors will have different agendas.

One thing we can do to overcome inconsistencies is use alternative technologies. The feature set of CSS and SVG sometimes overlap. What works in one may work in the other and vice versa. As it happens, the concept of clipping exists in both CSS and SVG. The SVG clipping syntax is quite different, but it works the same. The good thing about SVG clipping compared to CSS is its maturity level. Support is good all the way back to old IE browsers. Most bugs are fixed by now (or at least one hope they are).

This is what the SVG clipping support looks like:

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

Desktop

Chrome Opera Firefox IE Edge Safari
4 9 3 9 12 3.2

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
3.2 10 all 4.4 67 60

Clipping as a transition

A neat use case for clipping is transition effects. Take The Silhouette Slideshow demo on CodePen:

See the Pen Silhouette zoom slideshow by Mikael Ainalem (@ainalem) on CodePen.

A „regular” slideshow cycles though images. Here, to make it a bit more interesting, there’s a clipping effect when switching images. The next image enters the screen through a silhouette of of the previous image. This creates the illusion that the images are connected to one another, even if they are not.

The transitions follow this process:

  1. Identify the focal point (i.e., main subject) of the image
  2. Create a clipping path for that object
  3. Cut the next image with the path
  4. The cut image (silhouette) fades in
  5. Scale the clipping path until it’s bigger than the viewport
  6. Complete the transition to display the next image
  7. Repeat!

Let’s break down the sequence, starting with the first image. We’ll split this up into multiple pens so we can isolate each step.

<p data-height="300" data-theme- data-slug-hash="gzKxwR" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained I”>See the Pen Silhouette zoom slideshow explained I by Mikael Ainalem (@ainalem) on CodePen.

    This is the basic structure of the SVG markup:

    <svg>
      ...
      <image class="..." xlink:href="..." />
      ...
    </svg>

    For this image, we then want to create a mask of the focal point — in this case, the person’s silhouette. If you’re unsure how to go about creating a clip, check out my previous article for more details because, generally speaking, making cuts in CSS and SVG is fundamentally the same:

    1. Import an image into the SVG editor
    2. Draw a path around the object
    3. Convert the path to the syntax for SVG clip path. This is what goes in the SVG’s <defs> block.
    4. Paste the SVG markup into the HTML

    If you’re handy with the editor, you can do most of the above in the editor. Most editors have good support for masks and clip paths. I like to have more control over the markup, so I usually do at least some of the work by hand. I find there’s a balance between working with an SVG editor vs. working with markup. For example, I like to organize the code, rename the classes and clean up any cruft the editor may have dropped in there.

    Mozilla Developer Network does a fine job of documenting SVG clip paths. Here’s a stripped-down version of the markup used by the original demo to give you an idea of how a clip path fits in:

    <svg>
      <defs>
        <clipPath id="clip"> <!-- Clipping defined -->
          <path class="clipPath clipPath2" d="..." />
        </clipPath>
      </defs>
      ...
      <path ... clip-path="url(#clip)"/> <!-- Clipping applied -->
    </svg>

    Let’s use a colored rectangle as a placeholder for the next image in the slideshow. This helps to clearly visualize the shape that part that’s cut out and will give a clearer idea of the shape and its movement.

    <p data-height="422" data-theme- data-slug-hash="bMKrBL" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained II”>See the Pen Silhouette zoom slideshow explained II by Mikael Ainalem (@ainalem) on CodePen.

    Now that we have the silhouette, let’s have a look at the actual transition. In essence, we’re looking at two parts of the transition that work together to create the effect:

    • First, the mask fades into view.
    • After a brief delay (200ms), the clip path scales up in size.

    Note the translate value in the upscaling rule. It’s there to make sure the mask stays in the focal point as things scale up. This is the CSS for those transitions:

    .clipPath {
      transition: transform 1200ms 500ms; /* Delayed transform transition */
      transform-origin: 50%;
    }
    
    .clipPath.active {
      transform: translateX(-30%) scale(15); /* Upscaling and centering mask */
    }
    
    .image {
      transition: opacity 1000ms; /* Fade-in, starts immediately */
      opacity: 0;
    }
    
    .image.active {
      opacity: 1;
    }

    Here’s what we get — an image that transitions to the rectangle!

    <p data-height="425" data-theme- data-slug-hash="bMKrYM" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained III”>See the Pen Silhouette zoom slideshow explained III by Mikael Ainalem (@ainalem) on CodePen.

    Now let’s replace the rectangle with the next image to complete the transition:

    <p data-height="402" data-theme- data-slug-hash="jKqWYX" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained IV”>See the Pen Silhouette zoom slideshow explained IV by Mikael Ainalem (@ainalem) on CodePen.

    Repeating the above procedure for each image is how we get multiple slides.

    The last thing we need is logic to cycle through the images. This is a matter of bookkeeping, determining which is the current image and which is the next, so on and so forth:

    remove = (remove + 1) % images.length;
    current = (current + 1) % images.length

    Note that this examples is not supported by Firefox at the time of writing because is lacks support for scaling clip paths. I hope this is something that will be addressed in the near future.

    Clipping to emerge foreground objects into the background

    Another interesting use for clipping is for revealing and hiding effects. We can create parts of the view where objects are either partly or completely hidden making for a fun way to make background images interact with foreground content. For instance, we could have objects disappear behind elements in the background image, say a building or a mountain. It becomes even more interesting when we pair that idea up with animation or scrolling effects.

    See the Pen Parallax clip by Mikael Ainalem (@ainalem) on CodePen.

    This example uses a clipping path to create an effect where text submerges into the photo — specifically, floating behind mountains as a user scrolls down the page. To make it even more interesting, the text moves with a parallax effect. In other words, the different layers move at different speeds to enhance the perspective.

    We start with a simple div and define a background image for it in the CSS:

    <p data-height="300" data-theme- data-slug-hash="WyVWym" data-default-tab="css,result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained I”>See the Pen Parallax clip Explained I by Mikael Ainalem (@ainalem) on CodePen.

    The key part in the photo is the line that separates the foreground layer from the layers in the background of the photo. Basically, we want to split the photo into two parts — a perfect use-case for clipping!

    Let’s follow the same process we’ve covered before and cut elements out by following a line. In your photo editor, create a clipping path between those two layers. The way I did it was to draw a path following the line in the photo. To close off the path, I connected the line with the top corners.

    Here’s visual highlighting the background layers in blue:

    <p data-height="400" data-theme- data-slug-hash="BVXeab" data-default-tab="result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained II”>See the Pen Parallax clip Explained II by Mikael Ainalem (@ainalem) on CodePen.

    Any SVG content drawn below the blue area will be partly or completely hidden. This creates an illusion that content disappears behind the hill. For example, here’s a circle that’s drawn on top of the blue background when part of it overlaps with the foreground layer:

    <p data-height="400" data-theme- data-slug-hash="MBJzzr" data-default-tab="result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained III”>See the Pen Parallax clip Explained III by Mikael Ainalem (@ainalem) on CodePen.

    Looks kind of like the moon poking out of the mountain top!

    All that’s left to recreate my original demo is to change the circle to text and move it when the user scrolls. One way to do that is through a scroll event listener:

    window.addEventListener('scroll', function() {
      logo.setAttribute('transform',`translate(0 ${html.scrollTop / 10 + 5})`);
      clip.setAttribute('transform',`translate(0 -${html.scrollTop / 10 + 5})`);
    });

    Don’t pay too much attention to the + 5 used when calculating the distance. It’s only there as a sloppy way to offset the element. The important part is where things are divided by 10, which creates the parallax effect. Scrolling a certain amount will proportionally move the element and the clip path. Template literals convert the calculated value to a string which is used for the transform property value as an offset to the SVG nodes.

    Combining clipping and masking

    Clipping and masking are two interesting concepts. One lets you cut out pieces of content whereas the other let’s you do the opposite. Both techniques are useful by themselves but there is no reason why we can’t combine their powers!

    When combining clipping and masking, you can split up objects to create different visual effects on different parts. For example:

    See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

    I created this effect using both clipping and masking on a logo. The text, split into two parts, blends with the background image, which is a beautiful monochromatic image of the New York’s Statue of Liberty. I use different colors and opacities on different parts of the text to make it stand out. This creates an interesting visual effect where the text blends in with the background when it overlaps with the statue — a splash of color to an otherwise grey image. There is, besides clipping and masking, a parallax effect here as well. The text moves in a different speed relative to the image when the user hovers or moves (touch) over the image.

    To illustrate the behavior, here is what we get when the masked part is stripped out:

    <p data-height="500" data-theme- data-slug-hash="djvyyj" data-default-tab="result" data-user="ainalem" data-pen-title="parallax logo blend

  • Explained I”>See the Pen parallax logo blend Explained I by Mikael Ainalem (@ainalem) on CodePen.

    This is actually a neat feature in itself because the text appears to flow behind the statue. That’s a good use of clipping. But, we’re going to mix in some creative masking to let the text blend into the statue.

    Here’s the same demo, but with the mask applied and the clip disabled:

    <p data-height="500" data-theme- data-slug-hash="KBWKpz" data-default-tab="result" data-user="ainalem" data-pen-title="parallax logo blend

  • Explained II”>See the Pen parallax logo blend Explained II by Mikael Ainalem (@ainalem) on CodePen.

    Notice how masking combines the text with the statue and uses the statue as the visual bounds for the text. Clipping allows us to display the full text while maintaining that blending. Again, the final result:

    See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

    Wrapping up

    Clipping is a fun way to create interactions and visual effects. It can enhance slide-shows or make objects stand out of images, among other things. Both SVG and CSS provide the ability to apply clip paths and masks to elements, though with different syntaxes. We can pretty much cut any web content nowadays. It is only your imagination that sets the limit.

    If you happen to create anything cool with the things we covered here, please share them with me in the comments!

    The post Using CSS Clip Path to Create Interactive Effects, Part II appeared first on CSS-Tricks.

  • Using CSS Clip Path to Create Interactive Effects, Part II

    Post pobrano z: Using CSS Clip Path to Create Interactive Effects, Part II

    This is a follow up to my previous post looking into clip paths. Last time around, we dug into the fundamentals of clipping and how to get started. We looked at some ideas to exemplify what we can do with clipping. We’re going to take things a step further in this post and look at different examples, discuss alternative techniques, and consider how to approach our work to be cross-browser compatible.

    One of the biggest drawbacks of CSS clipping, at the time of writing, is browser support. Not having 100% browser coverage means different experiences for viewers in different browsers. We, as developers, can’t control what browsers support — browser vendors are the ones who implement the spec and different vendors will have different agendas.

    One thing we can do to overcome inconsistencies is use alternative technologies. The feature set of CSS and SVG sometimes overlap. What works in one may work in the other and vice versa. As it happens, the concept of clipping exists in both CSS and SVG. The SVG clipping syntax is quite different, but it works the same. The good thing about SVG clipping compared to CSS is its maturity level. Support is good all the way back to old IE browsers. Most bugs are fixed by now (or at least one hope they are).

    This is what the SVG clipping support looks like:

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

    Desktop

    Chrome Opera Firefox IE Edge Safari
    4 9 3 9 12 3.2

    Mobile / Tablet

    iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
    3.2 10 all 4.4 67 60

    Clipping as a transition

    A neat use case for clipping is transition effects. Take The Silhouette Slideshow demo on CodePen:

    See the Pen Silhouette zoom slideshow by Mikael Ainalem (@ainalem) on CodePen.

    A „regular” slideshow cycles though images. Here, to make it a bit more interesting, there’s a clipping effect when switching images. The next image enters the screen through a silhouette of of the previous image. This creates the illusion that the images are connected to one another, even if they are not.

    The transitions follow this process:

    1. Identify the focal point (i.e., main subject) of the image
    2. Create a clipping path for that object
    3. Cut the next image with the path
    4. The cut image (silhouette) fades in
    5. Scale the clipping path until it’s bigger than the viewport
    6. Complete the transition to display the next image
    7. Repeat!

    Let’s break down the sequence, starting with the first image. We’ll split this up into multiple pens so we can isolate each step.

    <p data-height="300" data-theme- data-slug-hash="gzKxwR" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained I”>See the Pen Silhouette zoom slideshow explained I by Mikael Ainalem (@ainalem) on CodePen.

    This is the basic structure of the SVG markup:

    <svg>
      ...
      <image class="..." xlink:href="..." />
      ...
    </svg>

    For this image, we then want to create a mask of the focal point — in this case, the person’s silhouette. If you’re unsure how to go about creating a clip, check out my previous article for more details because, generally speaking, making cuts in CSS and SVG is fundamentally the same:

    1. Import an image into the SVG editor
    2. Draw a path around the object
    3. Convert the path to the syntax for SVG clip path. This is what goes in the SVG’s <defs> block.
    4. Paste the SVG markup into the HTML

    If you’re handy with the editor, you can do most of the above in the editor. Most editors have good support for masks and clip paths. I like to have more control over the markup, so I usually do at least some of the work by hand. I find there’s a balance between working with an SVG editor vs. working with markup. For example, I like to organize the code, rename the classes and clean up any cruft the editor may have dropped in there.

    Mozilla Developer Network does a fine job of documenting SVG clip paths. Here’s a stripped-down version of the markup used by the original demo to give you an idea of how a clip path fits in:

    <svg>
      <defs>
        <clipPath id="clip"> <!-- Clipping defined -->
          <path class="clipPath clipPath2" d="..." />
        </clipPath>
      </defs>
      ...
      <path ... clip-path="url(#clip)"/> <!-- Clipping applied -->
    </svg>

    Let’s use a colored rectangle as a placeholder for the next image in the slideshow. This helps to clearly visualize the shape that part that’s cut out and will give a clearer idea of the shape and its movement.

    <p data-height="422" data-theme- data-slug-hash="bMKrBL" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained II”>See the Pen Silhouette zoom slideshow explained II by Mikael Ainalem (@ainalem) on CodePen.

    Now that we have the silhouette, let’s have a look at the actual transition. In essence, we’re looking at two parts of the transition that work together to create the effect:

    • First, the mask fades into view.
    • After a brief delay (200ms), the clip path scales up in size.

    Note the translate value in the upscaling rule. It’s there to make sure the mask stays in the focal point as things scale up. This is the CSS for those transitions:

    .clipPath {
      transition: transform 1200ms 500ms; /* Delayed transform transition */
      transform-origin: 50%;
    }
    
    .clipPath.active {
      transform: translateX(-30%) scale(15); /* Upscaling and centering mask */
    }
    
    .image {
      transition: opacity 1000ms; /* Fade-in, starts immediately */
      opacity: 0;
    }
    
    .image.active {
      opacity: 1;
    }

    Here’s what we get — an image that transitions to the rectangle!

    <p data-height="425" data-theme- data-slug-hash="bMKrYM" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained III”>See the Pen Silhouette zoom slideshow explained III by Mikael Ainalem (@ainalem) on CodePen.

    Now let’s replace the rectangle with the next image to complete the transition:

    <p data-height="402" data-theme- data-slug-hash="jKqWYX" data-default-tab="html,result" data-user="ainalem" data-pen-title="Silhouette zoom slideshow

  • explained IV”>See the Pen Silhouette zoom slideshow explained IV by Mikael Ainalem (@ainalem) on CodePen.

    Repeating the above procedure for each image is how we get multiple slides.

    The last thing we need is logic to cycle through the images. This is a matter of bookkeeping, determining which is the current image and which is the next, so on and so forth:

    remove = (remove + 1) % images.length;
    current = (current + 1) % images.length

    Note that this examples is not supported by Firefox at the time of writing because is lacks support for scaling clip paths. I hope this is something that will be addressed in the near future.

    Clipping to emerge foreground objects into the background

    Another interesting use for clipping is for revealing and hiding effects. We can create parts of the view where objects are either partly or completely hidden making for a fun way to make background images interact with foreground content. For instance, we could have objects disappear behind elements in the background image, say a building or a mountain. It becomes even more interesting when we pair that idea up with animation or scrolling effects.

    See the Pen Parallax clip by Mikael Ainalem (@ainalem) on CodePen.

    This example uses a clipping path to create an effect where text submerges into the photo — specifically, floating behind mountains as a user scrolls down the page. To make it even more interesting, the text moves with a parallax effect. In other words, the different layers move at different speeds to enhance the perspective.

    We start with a simple div and define a background image for it in the CSS:

    <p data-height="300" data-theme- data-slug-hash="WyVWym" data-default-tab="css,result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained I”>See the Pen Parallax clip Explained I by Mikael Ainalem (@ainalem) on CodePen.

    The key part in the photo is the line that separates the foreground layer from the layers in the background of the photo. Basically, we want to split the photo into two parts — a perfect use-case for clipping!

    Let’s follow the same process we’ve covered before and cut elements out by following a line. In your photo editor, create a clipping path between those two layers. The way I did it was to draw a path following the line in the photo. To close off the path, I connected the line with the top corners.

    Here’s visual highlighting the background layers in blue:

    <p data-height="400" data-theme- data-slug-hash="BVXeab" data-default-tab="result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained II”>See the Pen Parallax clip Explained II by Mikael Ainalem (@ainalem) on CodePen.

    Any SVG content drawn below the blue area will be partly or completely hidden. This creates an illusion that content disappears behind the hill. For example, here’s a circle that’s drawn on top of the blue background when part of it overlaps with the foreground layer:

    <p data-height="400" data-theme- data-slug-hash="MBJzzr" data-default-tab="result" data-user="ainalem" data-pen-title="Parallax clip

  • Explained III”>See the Pen Parallax clip Explained III by Mikael Ainalem (@ainalem) on CodePen.

    Looks kind of like the moon poking out of the mountain top!

    All that’s left to recreate my original demo is to change the circle to text and move it when the user scrolls. One way to do that is through a scroll event listener:

    window.addEventListener('scroll', function() {
      logo.setAttribute('transform',`translate(0 ${html.scrollTop / 10 + 5})`);
      clip.setAttribute('transform',`translate(0 -${html.scrollTop / 10 + 5})`);
    });

    Don’t pay too much attention to the + 5 used when calculating the distance. It’s only there as a sloppy way to offset the element. The important part is where things are divided by 10, which creates the parallax effect. Scrolling a certain amount will proportionally move the element and the clip path. Template literals convert the calculated value to a string which is used for the transform property value as an offset to the SVG nodes.

    Combining clipping and masking

    Clipping and masking are two interesting concepts. One lets you cut out pieces of content whereas the other let’s you do the opposite. Both techniques are useful by themselves but there is no reason why we can’t combine their powers!

    When combining clipping and masking, you can split up objects to create different visual effects on different parts. For example:

    See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

    I created this effect using both clipping and masking on a logo. The text, split into two parts, blends with the background image, which is a beautiful monochromatic image of the New York’s Statue of Liberty. I use different colors and opacities on different parts of the text to make it stand out. This creates an interesting visual effect where the text blends in with the background when it overlaps with the statue — a splash of color to an otherwise grey image. There is, besides clipping and masking, a parallax effect here as well. The text moves in a different speed relative to the image when the user hovers or moves (touch) over the image.

    To illustrate the behavior, here is what we get when the masked part is stripped out:

    <p data-height="500" data-theme- data-slug-hash="djvyyj" data-default-tab="result" data-user="ainalem" data-pen-title="parallax logo blend

  • Explained I”>See the Pen parallax logo blend Explained I by Mikael Ainalem (@ainalem) on CodePen.

    This is actually a neat feature in itself because the text appears to flow behind the statue. That’s a good use of clipping. But, we’re going to mix in some creative masking to let the text blend into the statue.

    Here’s the same demo, but with the mask applied and the clip disabled:

    <p data-height="500" data-theme- data-slug-hash="KBWKpz" data-default-tab="result" data-user="ainalem" data-pen-title="parallax logo blend

  • Explained II”>See the Pen parallax logo blend Explained II by Mikael Ainalem (@ainalem) on CodePen.

    Notice how masking combines the text with the statue and uses the statue as the visual bounds for the text. Clipping allows us to display the full text while maintaining that blending. Again, the final result:

    See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

    Wrapping up

    Clipping is a fun way to create interactions and visual effects. It can enhance slide-shows or make objects stand out of images, among other things. Both SVG and CSS provide the ability to apply clip paths and masks to elements, though with different syntaxes. We can pretty much cut any web content nowadays. It is only your imagination that sets the limit.

    If you happen to create anything cool with the things we covered here, please share them with me in the comments!

    The post Using CSS Clip Path to Create Interactive Effects, Part II appeared first on CSS-Tricks.

  • Firefox Multi-Account Containers

    Post pobrano z: Firefox Multi-Account Containers

    It’s an extension:

    Each Container stores cookies separately, so you can log into the same site with different accounts and online trackers can’t easily connect the browsing.

    A great idea for a feature if you ask me. For example, I have two Buffer accounts and my solution is to use different browsers entirely to stay logged into both of them. I know plenty of folks that prefer the browser version of apps like Notion, Front, and Twitter, and it’s cool to have a way to log into the same site with multiple accounts if you need to — and without weird trickery.

    This is browsers competing on UI/UX features rather than web platform features, which is a good thing. Relevant: Opera Neon and Refresh.

    Direct Link to ArticlePermalink

    The post Firefox Multi-Account Containers appeared first on CSS-Tricks.

    Seriously, though. What is a progressive web app?

    Post pobrano z: Seriously, though. What is a progressive web app?

    Amberley Romo read a ton about PWAs in order to form her own solid understanding.

    “Progressive web app” (PWA) is both a general term for a new philosophy toward building websites and a specific term with an established set of three explicit, testable, baseline requirements.

    As a general term, the PWA approach is characterized by striving to satisfy the following set of attributes:

    1. Responsive
    2. Connectivity independent
    3. App-like-interactions
    4. Fresh
    5. Safe
    6. Discoverable
    7. Re-engageable
    8. Installable
    9. Linkable

    Direct Link to ArticlePermalink

    The post Seriously, though. What is a progressive web app? appeared first on CSS-Tricks.

    Level up your .filter game

    Post pobrano z: Level up your .filter game

    .filter is a built-in array iteration method that accepts a predicate which is called against each of its values, and returns a subset of all values that return a truthy value.

    That is a lot to unpack in one statement! Let’s take a look at that statement piece-by-piece.

    • „Built-in” simply means that it is part of the language—you don’t need to add any libraries to get access to this functionality.
    • „Iteration methods” accept a function that are run against each item of the array. Both .map and .reduce are other examples of iteration methods.
    • A „predicate” is a function that returns a boolean.
    • A „truthy value” is any value that evaluates to true when coerced to a boolean. Almost all values are truthy, with the exceptions of: undefined, null, false, 0, NaN, or "" (empty string).

    To see .filter in action, let’s take a look at this array of restaurants.

    const restaurants = [
        {
            name: "Dan's Hamburgers",
            price: 'Cheap',
            cuisine: 'Burger',
        },
        {
            name: "Austin's Pizza",
            price: 'Cheap',
            cuisine: 'Pizza',
        },
        {
            name: "Via 313",
            price: 'Moderate',
            cuisine: 'Pizza',
        },
        {
            name: "Bufalina",
            price: 'Expensive',
            cuisine: 'Pizza',
        },
        {
            name: "P. Terry's",
            price: 'Cheap',
            cuisine: 'Burger',
        },
        {
            name: "Hopdoddy",
            price: 'Expensive',
            cuisine: 'Burger',
        },
        {
            name: "Whataburger",
            price: 'Moderate',
            cuisine: 'Burger',
        },
        {
            name: "Chuy's",
            cuisine: 'Tex-Mex',
            price: 'Moderate',
        },
        {
            name: "Taquerias Arandina",
            cuisine: 'Tex-Mex',
            price: 'Cheap',
        },
        {
            name: "El Alma",
            cuisine: 'Tex-Mex',
            price: 'Expensive',
        },
        {
            name: "Maudie's",
            cuisine: 'Tex-Mex',
            price: 'Moderate',
        },
    ];

    That’s a lot of information. I’m currently in the mood for a burger, so let’s filter that array down a bit.

    const isBurger = ({cuisine}) => cuisine === 'burger';
    const burgerJoints = restaurants.filter(isBurger);

    isBurger is the predicate, and burgerJoints is a new array which is a subset of restaurants. It is important to note that restaurants remained unchanged from the .filter.

    Here is a simple example of two lists being rendered—one of the original restaurants array, and one of the filtered burgerJoints array.

    See the Pen .filter – isBurger by Adam Giese (@AdamGiese) on CodePen.

    Negating Predicates

    For every predicate there is an equal and opposite negated predicate.

    A predicate is a function that returns a boolean. Since there are only two possible boolean values, that means it is easy to „flip” the value of a predicate.

    A few hours have passed since I’ve eaten my burger, and now I’m hungry again. This time, I want to filter out burgers to try something new. One option is to write a new isNotBurger predicate from scratch.

    const isBurger = ({cuisine}) => cuisine === 'burger';
    const isNotBurger = ({cuisine}) => cuisine !== 'burger';

    However, look at the amount of similarities between the two predicates. This is not very DRY code. Another option is to call the isBurger predicate and flip the result.

    const isBurger = ({cuisine}) => cuisine === 'burger';
    const isNotBurger = ({cuisine}) => !isBurger(cuisine);

    This is better! If the definition of a burger changes, you will only need to change the logic in one place. However, what if we have a number of predicates that we’d like to negate? Since this is something that we’d likely want to do often, it may be a good idea to write a negate function.

    const negate = predicate => function() {
      return !predicate.apply(null, arguments);
    }
    
    const isBurger = ({cuisine}) => cuisine === 'burger';
    const isNotBurger = negate(isBurger);
    
    const isPizza = ({cuisine}) => cuisine === 'pizza';
    const isNotPizza = negate(isPizza);

    You may have some questions.

    What is .apply?

    MDN:

    apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

    What is arguments?

    MDN:

    The arguments object is a local variable available within all (non-arrow) functions. You can refer to a function’s arguments within the function by using the arguments object.

    Why return an old-school function instead of a newer, cooler arrow function?

    In this case, returning a traditional function is necessary because the arguments object is only available on traditional functions.

    Returning Predicates

    As we saw with our negate function, it is easy for a function to return a new function in JavaScript. This can be useful for writing „predicate creators.” For example, let’s look back at our isBurger and isPizza predicates.

    const isBurger = ({cuisine}) => cuisine === 'burger';
    const isPizza  = ({cuisine}) => cuisine === 'pizza';

    These two predicates share the same logic; they only differ in comparisons. So, we can wrap the shared logic in an isCuisine function.

    const isCuisine = comparison => ({cuisine}) => cuisine === comparison;
    const isBurger  = isCuisine('burger');
    const isPizza   = isCuisine('pizza');

    This is great! Now, what if we want to start checking the price?

    const isPrice = comparison => ({price}) => price === comparison;
    const isCheap = isPrice('cheap');
    const isExpensive = isPrice('expensive');

    Now the isCheap and isExpensive are DRY, and isPizza and isBurger are DRY—but isPrice and isCuisine share their logic! Luckily, there are no rules for how many functions deep you can return.

    const isKeyEqualToValue = key => value => object => object[key] === value;
    
    // these can be rewritten
    const isCuisine = isKeyEqualToValue('cuisine');
    const isPrice = isKeyEqualToValue('price');
    
    // these don't need to change
    const isBurger = isCuisine('burger');
    const isPizza = isCuisine('pizza');
    const isCheap = isPrice('cheap');
    const isExpensive = isPrice('expensive');

    This, to me, is the beauty of arrow functions. In a single line, you can elegantly create a third-order function. isKeyEqualToValue is a function that returns the function isPrice which returns the function isCheap.

    See how easy it is to create multiple filtered lists from the original restaurants array?

    See the Pen .filter – returning predicates by Adam Giese (@AdamGiese) on CodePen.

    Composing Predicates

    We can now filter our array by burgers or by a cheap price… but what if you want cheap burgers? One option is to simply chain to filters together.

    const cheapBurgers = restaurants.filter(isCheap).filter(isBurger);

    Another option is to „compose” the two predicates into a single one.

    const isCheapBurger = restaurant => isCheap(restaurant) && isBurger(restaurant);
    const isCheapPizza = restaurant => isCheap(restaurant) && isPizza(restaurant);

    Look at all of that repeated code. We can definitely wrap this into a new function!

    const both = (predicate1, predicate2) => value =>
      predicate1(value) && predicate2(value);
    
    const isCheapBurger = both(isCheap, isBurger);
    const isCheapPizza = both(isCheap, isPizza);
    
    const cheapBurgers = restaurants.filter(isCheapBurger);
    const cheapPizza = restaurants.filter(isCheapPizza);

    What if you are fine with either pizza or burgers?

    const either = (predicate1, predicate2) => value =>
      predicate1(value) || predicate2(value);
    
    const isDelicious = either(isBurger, isPizza);
    const deliciousFood = restaurants.filter(isDelicious);

    This is a step in the right direction, but what if you have more than two foods you’d like to include? This isn’t a very scalable approach. There are two built-in array methods that come in handy here. .every and .some are both predicate methods that also accept predicates. .every checks if each member of an array passes a predicate, while .some checks to see if any member of an array passes a predicate.

    const isDelicious = restaurant =>
      [isPizza, isBurger, isBbq].some(predicate => predicate(restaurant));
    
    const isCheapAndDelicious = restaurant =>
      [isDelicious, isCheap].every(predicate => predicate(restaurant));

    And, as always, let’s wrap them up into some useful abstraction.

    const isEvery = predicates => value =>
      predicates.every(predicate => predicate(value));
    
    const isAny = predicates => value =>
      predicates.some(predicate => predicate(value));
    
    const isDelicious = isAny([isBurger, isPizza, isBbq]);
    const isCheapAndDelicious = isEvery([isCheap, isDelicious]);

    isEvery and isAny both accept an array of predicates and return a single predicate.

    Since all of these predicates are easily created by higher order functions, it isn’t too difficult to create and apply these predicates based on a user’s interaction. Taking all of the lessons we have learned, here is an example of an app that searches restaurants by applying filters based on button clicks.

    See the Pen .filter – dynamic filters by Adam Giese (@AdamGiese) on CodePen.

    Wrapping up

    Filters are an essential part of JavaScript development. Whether you’re sorting out bad data from an API response or responding to user interactions, there are countless times when you would want a subset of an array’s values. I hope this overview helped with ways that you can manipulate predicates to write more readable and maintainable code.

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

    Working with refs in React

    Post pobrano z: Working with refs in React

    Refs make it possible to access DOM nodes directly within React. This comes in handy in situations where, just as one example, you want to change the child of a component. Let’s say you want to change the value of an <input> element, but without using props or re-rendering the whole component.

    That’s the sort of thing refs are good for and what we’ll be digging into in this post.

    How to create a ref

    createRef() is a new API that shipped with React 16.3. You can create a ref by calling React.createRef() and attaching a React element to it using the ref attribute on the element.

    class Example extends React.Component {
      constructor(props) {
        super(props)
    
        // Create the ref
        this.exampleRef = React.createRef()
      }
    
      render() {
        return (
          <div>
            // Call the ref with the `ref` attribute
            <input type="text" ref={this.exampleRef} />
          </div>
        )
      }
    }

    We can „refer” to the node of the ref created in the render method with access to the current attribute of the ref. From the example above, that would be this.exampleRef.current.

    Here’s an example:

    See the Pen React Ref – createRef by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    class App extends React.Component {
      constructor(props) {
        super(props)
        
        // Create the ref
        this.textInput = React.createRef();
        this.state = {
          value: ''
        }
      }
      
      // Set the state for the ref
      handleSubmit = e => {
        e.preventDefault();
        this.setState({ value: this.textInput.current.value})
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - createRef</h1>
            // This is what will update
            <h3>Value: {this.state.value}</h3>
            <form onSubmit={this.handleSubmit}>
              // Call the ref on <input> so we can use it to update the <h3> value
              <input type="text" ref={this.textInput} />
              <button>Submit</button>
            </form>
          </div>
        );
      }
    }
    How a conversation between a child component and an element containing the ref might go down.

    This is a component that renders some text, an input field and a button. The ref is created in the constructor and then attached to the input element when it renders. When the button is clicked, the value submitted from the input element (which has the ref attached) is used to update the state of the text (contained in an H3 tag). We make use of this.textInput.current.value to access the value and the new state is then rendered to the screen.

    Passing a callback function to ref

    React allows you to create a ref by passing a callback function to the ref attribute of a component. Here is how it looks:

    <input type="text" ref={element => this.textInput = element} />

    The callback is used to store a reference to the DOM node in an instance property. When we want to make use of this reference, we access it using:

    this.textInput.value

    Let’s see how that looks in the same example we used before.

    See the Pen React Ref – Callback Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    class App extends React.Component {
        state = {
        value: ''
      }
      
      handleSubmit = e => {
        e.preventDefault();
        this.setState({ value: this.textInput.value})
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - Callback Ref</h1>
            <h3>Value: {this.state.value}</h3>
            <form onSubmit={this.handleSubmit}>
              <input type="text" ref={element => this.textInput = element} />
              <button>Submit</button>
            </form>
          </div>
        );
      }
    }

    When you make use of callback like we did above, React will call the ref callback with the DOM node when the component mounts, when the component un-mounts, it will call it with null.

    It is also possible to pass ref from a parent component to a child component using callbacks.

    See the Pen React Ref – Callback Ref 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    Let’s create our „dumb” component that will render a simple input:

    const Input = props => {
      return (
        <div>
          <input type="text" ref={props.inputRef} />
        </div>
      );
    };

    This component is expecting inputRef props from its parent component which is then used to create a ref to the DOM node.

    Here’s the parent component:

    class App extends React.Component {
      state = {
        value: ''
      };
    
      handleSubmit = event => {
        this.setState({ value: this.inputElement.value });
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - Callback Ref</h1>
            <h3>Value: {this.state.value}</h3>
            <Input inputRef={el => (this.inputElement = el)} />
            <button onClick={this.handleSubmit}>Submit</button>
          </div>
        );
      }
    }

    In the App component, we want to obtain the text that is entered in the input field (which is in the child component) so we can render it. The ref is created using a callback like we did in the first example of this section. The key lies in how we access the DOM of the input element in the Input component from the App component. If you look closely, we access it using this.inputElement. So, when updating the state of value in the App component, we get the text that was entered in the input field using this.inputElement.value.

    The ref attribute as a string

    This is the old way of creating a ref and it will likely be removed in a future release because of some issues associated with it. The React team advises against using it, going so far as to label it as „legacy” in the documentation. We’re including it here anyway because there’s a chance you could come across it in a codebase.

    See the Pen React Ref – String Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    Going back to our example of an input whose value is used to update text value on submit:

    class App extends React.Component {
        state = {
        value: ''
      }
      
      handleSubmit = e => {
        e.preventDefault();
        this.setState({ value: this.refs.textInput.value})
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - String Ref</h1>
            <h3>Value: {this.state.value}</h3>
            <form onSubmit={this.handleSubmit}>
              <input type="text" ref="textInput" />
              <button>Submit</button>
            </form>
          </div>
        );
      }
    }

    The component is initialized and we start with a default state value set to an empty string (value='’). The component renders the text and form, as usual and, like before, the H3 text updates its state when the form is submitted with the contents entered in the input field.

    We created a ref by setting the ref prop of the input field to textInput. That gives us access to the value of the input in the handleSubmit() method using this.refs.textInput.value.

    Forwarding a ref from one component to another

    **Ref forwarding is the technique of passing a ref from a component to a child component by making use of the React.forwardRef() method.

    See the Pen React Ref – forward Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    Back to our running example of a input field that updates the value of text when submitted:

    class App extends React.Component {
        constructor(props) {
          super(props)
          this.inputRef = React.createRef();
          this.state = {
            value: ''
          }
        }
      
      handleSubmit = e => {
        e.preventDefault();
        this.setState({ value: this.inputRef.current.value})
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - createRef</h1>
            <h3>Value: {this.state.value}</h3>
            <form onSubmit={this.handleSubmit}>
              <Input ref={this.inputRef} />
              <button>Submit</button>
            </form>
          </div>
        );
      }
    }

    We’ve created the ref in this example with inputRef, which we want to pass to the child component as a ref attribute that we can use to update the state of our text.

    const Input = React.forwardRef((props, ref) => (
      <input type="text" ref={ref} />
    ));

    Here is an alternative way to do it by defining the ref outside of the App component:

    const Input = React.forwardRef((props, ref) => (
      <input type="text" ref={ref} />
    ));
    
    const inputRef = React.createRef();
    
    class App extends React.Component {
        constructor(props) {
          super(props)
          
          this.state = {
            value: ''
          }
        }
      
      handleSubmit = e => {
        e.preventDefault();
        this.setState({ value: inputRef.current.value})
      };
    
      render() {
        return (
          <div>
            <h1>React Ref - createRef</h1>
            <h3>Value: {this.state.value}</h3>
            <form onSubmit={this.handleSubmit}>
              <Input ref={inputRef} />
              <button>Submit</button>
            </form>
          </div>
        );
      }
    }

    Using ref for form validation

    We all know that form validation is super difficult but something React is well-suited for. You know, things like making sure a form cannot be submitted with an empty input value. Or requiring a password with at least six characters. Refs can come in handy for these types of situations.

    See the Pen React ref Pen – validation by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.username = React.createRef();
        this.password = React.createRef();
        this.state = {
          errors: []
        };
      }
    
      handleSubmit = (event) => {
        event.preventDefault();
        const username = this.username.current.value;
        const password = this.password.current.value;
        const errors = this.handleValidation(username, password);
    
        if (errors.length > 0) {
          this.setState({ errors });
          return;
        }
        // Submit data
      };
    
      handleValidation = (username, password) => {
        const errors = [];
        // Require username to have a value on submit
        if (username.length === 0) {
          errors.push("Username cannot be empty");
        }
        
        // Require at least six characters for the password
        if (password.length < 6) {
          errors.push("Password should be at least 6 characters long");
        }
        
        // If those conditions are met, then return error messaging
        return errors;
      };
    
      render() {
        const { errors } = this.state;
        return (
          <div>
            <h1>React Ref Example</h1>
            <form onSubmit={this.handleSubmit}>
              // If requirements are not met, then display errors
              {errors.map(error => <p key={error}>{error}</p>)}
              <div>
                <label>Username:</label>
                // Input for username containing the ref
                <input type="text" ref={this.username} />
              </div>
              <div>
                <label>Password:</label>
                // Input for password containing the ref
                <input type="text" ref={this.password} />
              </div>
              <div>
                <button>Submit</button>
              </div>
            </form>
          </div>
        );
      }
    }

    We used the createRef() to create refs for the inputs which we then passed as parameters to the validation method. We populate the errors array when either of the input has an error, which we then display to the user.

    That’s a ref… er, a wrap!

    Hopefully this walkthrough gives you a good understanding of how powerful refs can be. They’re an excellent way to update part of a component without the need to re-render the entire thing. That’s convenient for writing leaner code and getting better performance.

    At the same time, it’s worth heeding the advice of the React docs themselves and avoid using ref too much:

    Your first inclination may be to use refs to „make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to „own” that state is at a higher level in the hierarchy.

    Get it? Got it? Good.

    The post Working with refs in React appeared first on CSS-Tricks.

    Using data in React with the Fetch API and axios

    Post pobrano z: Using data in React with the Fetch API and axios

    If you are new to React, and perhaps have only played with building to-do and counter apps, you may not yet have run across a need to pull in data for your app. There will likely come a time when you’ll need to do this, as React apps are most well suited for situations where you’re handling both data and state.

    The first set of data you may need to handle might be hard-coded into your React application, like we did for this demo from our Error Boundary tutorial:

    See the Pen error boundary 0 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    What if you want to handle data from an API? That’s the purpose of this tutorial. Specifically, we’ll make use of the Fetch API and axios as examples for how to request and use data.

    The Fetch API

    The Fetch API provides an interface for fetching resources. We’ll use it to fetch data from a third-party API and see how to use it when fetching data from an API built in-house.

    Using Fetch with a third-party API

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

    We will be fetching random users from JSONPlaceholder, a fake online REST API for testing. Let’s start by creating our component and declaring some default state.

    class App extends React.Component {
      state = {
        isLoading: true,
        users: [],
        error: null
      }
    
      render() {
        <React.Fragment>
        </React.Fragment>
      }
    }

    There is bound to be a delay when data is being requested by the network. It could be a few seconds or maybe a few milliseconds. Either way, during this delay, it’s good practice to let users know that something is happening while the request is processing.

    To do that we’ll make use of isLoading to either display the loading message or the requested data. The data will be displayed when isLoading is false, else a loading message will be shown on the screen. So the render() method will look like this:

    render() {
      const { isLoading, users, error } = this.state;
      return (
        <React.Fragment>
          <h1>Random User</h1>
          // Display a message if we encounter an error
          {error ? <p>{error.message}</p> : null}
          // Here's our data check
          {!isLoading ? (
            users.map(user => {
              const { username, name, email } = user;
              return (
                <div key={username}>
                  <p>Name: {name}</p>
                  <p>Email Address: {email}</p>
                  <hr />
                </div>
              );
            })
          // If there is a delay in data, let's let the user know it's loading
          ) : (
            <h3>Loading...</h3>
          )}
        </React.Fragment>
      );
    }

    The code is basically doing this:

    1. De-structures isLoading, users and error from the application state so we don’t have to keep typing this.state.
    2. Prints a message if the application encounters an error establishing a connection
    3. Checks to see if data is loading
    4. If loading is not happening, then we must have the data, so we display it
    5. If loading is happening, then we must still be working on it and display „Loading…” while the app is working

    For Steps 3-5 to work, we need to make the request to fetch data from an API. This is where the JSONplaceholder API will come in handy for our example.

    fetchUsers() {
      // Where we're fetching data from
      fetch(`https://jsonplaceholder.typicode.com/users`)
        // We get the API response and receive data in JSON format...
        .then(response => response.json())
        // ...then we update the users state
        .then(data =>
          this.setState({
            users: data,
            isLoading: false,
          })
        )
        // Catch any errors we hit and update the app
        .catch(error => this.setState({ error, isLoading: false }));
    }

    We create a method called fetchUser() and use it to do exactly what you might think: request user data from the API endpoint and fetch it for our app. Fetch is a promise-based API which returns a response object. So, we make use of the json() method to get the response object which is stored in data and used to update the state of users in our application. We also need to change the state of isLoading to false so that our application knows that loading has completed and all is clear to render the data.

    The fact that Fetch is promise-based means we can also catch errors using the .catch() method. Any error encountered is used a value to update our error’s state. Handy!

    The first time the application renders, the data won’t have been received — it can take seconds. We want to trigger the method to fetch the users when the application state can be accessed for an update and the application re-rendered. React’s componentDidMount() is the best place for this, so we’ll place the fetchUsers() method in it.

    componentDidMount() {
      this.fetchUsers();
    }

    Using Fetch With Self-Owned API

    So far, we’ve looked at how to put someone else’s data to use in an application. But what if we’re working with our own data in our own API? That’s what we’re going to cover right now.

    See the Pen React Fetch API Pen 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

    I built an API which is available on GitHub. The JSON response you get has been placed on AWS — that’s what we will use for this tutorial.

    As we did before, let’s create our component and set up some default state.

    class App extends React.Component {
      state = {
        isLoading: true,
        posts: [],
        error: null
      }
    
      render() {
        <React.Fragment>
        </React.Fragment>
      }
    }

    Our method for looping through the data will be different from the one we used before but only because of the data’s structure, which is going to be different. You can see the difference between our data structure here and the one we obtained from JSONPlaceholder.

    Here is how the render() method will look like for our API:

    render() {
      const { isLoading, posts, error } = this.state;
      return (
        <React.Fragment>
          <h1>React Fetch - Blog</h1>
          <hr />
          {!isLoading ? Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) : <h3>Loading...</h3>}
        </React.Fragment>
      );
    }

    Let’s break down the logic

    {
      !isLoading ? 
      Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) 
      : <h3>Loading...</h3>
    }

    When isLoading is not true, we return an array, map through it and pass the information to the Post component as props. Otherwise, we display a „Loading…” message while the application is at work. Very similar to before.

    The method to fetch posts will look like the one used in the first part.

    fetchPosts() {
      // The API where we're fetching data from
      fetch(`https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json`)
        // We get a response and receive the data in JSON format...
        .then(response => response.json())
        // ...then we update the state of our application
        .then(
          data =>
            this.setState({
              posts: data,
              isLoading: false,
            })
        )
        // If we catch errors instead of a response, let's update the app
        .catch(error => this.setState({ error, isLoading: false }));
    }

    Now we can call the fetchPosts method inside a componentDidMount() method

    componentDidMount() {
      this.fetchPosts();
    }

    In the Post component, we map through the props we received and render the title and content for each post:

    const Post = ({ body }) => {
      return (
        <div>
          {body.map(post => {
            const { _id, title, content } = post;
            return (
              <div key={_id}>
                <h2>Using data in React with the Fetch API and axios</h2>
                <p>{content}</p>
                <hr />
              </div>
            );
          })}
        </div>
      );
    };

    There we have it! Now we know how to use the Fetch API to request data from different sources and put it to use in an application. High fives. ✋

    axios

    OK, so we’ve spent a good amount of time looking at the Fetch API and now we’re going to turn our attention to axios.

    Like the Fetch API, axios is a way we can make a request for data to use in our application. Where axios shines is how it allows you to send an asynchronous request to REST endpoints. This comes in handy when working with the REST API in a React project, say a headless WordPress CMS.

    There’s ongoing debate about whether Fetch is better than axios and vice versa. We’re not going to dive into that here because, well, you can pick the right tool for the right job. If you’re curious about the points from each side, you can read here and here.

    Using axios with a third-party API

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

    Like we did with the Fetch API, let’s start by requesting data from an API. For this one, we’ll fetch random users from the Random User API.

    First, we create the App component like we’ve done it each time before:

    class App extends React.Component {
      state = {
        users: [],
        isLoading: true,
        errors: null
      };
    
      render() {
        return (
          <React.Fragment>
          </React.Fragment>
        );
      }
    }

    The idea is still the same: check to see if loading is in process and either render the data we get back or let the user know things are still loading.

    To make the request to the API, we’ll need to create a function. We’ll call the function getUsers(). Inside it, we’ll make the request to the API using axios. Let’s see how that looks like before explaining further.

    getUsers() {
      // We're using axios instead of Fetch
      axios
        // The API we're requesting data from
        .get("https://randomuser.me/api/?results=5")
        // Once we get a response, we'll map the API endpoints to our props
        .then(response =>
          response.data.results.map(user => ({
            name: `${user.name.first} ${user.name.last}`,
            username: `${user.login.username}`,
            email: `${user.email}`,
            image: `${user.picture.thumbnail}`
          }))
        )
        // Let's make sure to change the loading state to display the data
        .then(users => {
          this.setState({
            users,
            isLoading: false
          });
        })
        // We can still use the `.catch()` method since axios is promise-based
        .catch(error => this.setState({ error, isLoading: false }));
    }

    Quite different from the Fetch examples, right? The basic structure is actually pretty similar, but now we’re in the business of mapping data between endpoints.

    The GET request is passed from the API URL as a parameter. The response we get from the API contains an object called data and that contains other objects. The information we want is available in data.results, which is an array of objects containing the data of individual users.

    Here we go again with calling our method inside of the componentDidMount() method:

    componentDidMount() {
      this.getUsers();
    }

    Alternatively, you can do this instead and basically combine these first two steps:

    componentDidMount() {
      axios
        .get("https://randomuser.me/api/?results=5")
        .then(response =>
          response.data.results.map(user => ({
            name: `${user.name.first} ${user.name.last}`,
            username: `${user.login.username}`,
            email: `${user.email}`,
            image: `${user.picture.thumbnail}`
          }))
        )
        .then(users => {
          this.setState({
            users,
            isLoading: false
          });
        })
        .catch(error => this.setState({ error, isLoading: false }));
    }

    If you are coding locally from your machine, you can temporarily edit the getUsers() function to look like this:

    getUsers() {
      axios
        .get("https://randomuser.me/api/?results=5")
        .then(response => console.log(response))
        .catch(error => this.setState({ error, isLoading: false }));
    }

    Your console should get something similar to this:

    We map through the results array to obtain the information we need for each user. The array of users is then used to set a new value for our users state. With that done, we can then change the value of isLoading.

    By default, isLoading is set to true. When the state of users is updated, we want to change the value of isLoading to false since this is the cue our app is looking for to make the switch from „Loading…” to rendered data.

    render() {
      const { isLoading, users } = this.state;
      return (
        <React.Fragment>
          <h2>Random User</h2>
          <div>
            {!isLoading ? (
              users.map(user => {
                const { username, name, email, image } = user;
                return (
                  <div key={username}>
                    <p>{name}</p>
                    <div>
                      <img src={image} alt={name} />
                    </div>
                    <p>{email}</p>
                    <hr />
                  </div>
                );
              })
            ) : (
              <p>Loading...</p>
            )}
          </div>
        </React.Fragment>
      );
    }

    If you log the users state to the console, you will see that it is an array of objects:

    The empty array shows the value before the data was obtained. The returned data contains only the name, username, email address and image of individual users because those are the endpoints we mapped out. There is a lot more data available from the API, of course, but we’d have to add those to our getUsers method.

    Using axios with your own API

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

    You have seen how to use axios with a third-party API but we can look at what it’s like to request data from our own API, just like we did with the Fetch API. In fact, let’s use same JSON file we used for Fetch so we can see the difference between the two approaches.

    Here is everything put together:

    class App extends React.Component {
      // State will apply to the posts object which is set to loading by default
      state = {
        posts: [],
        isLoading: true,
        errors: null
      };
      // Now we're going to make a request for data using axios
      getPosts() {
        axios
          // This is where the data is hosted
          .get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json")
          // Once we get a response and store data, let's change the loading state
          .then(response => {
            this.setState({
              posts: response.data.posts,
              isLoading: false
            });
          })
          // If we catch any errors connecting, let's update accordingly
          .catch(error => this.setState({ error, isLoading: false }));
      }
      // Let's our app know we're ready to render the data
      componentDidMount() {
        this.getPosts();
      }
      // Putting that data to use
      render() {
        const { isLoading, posts } = this.state;
        return (
          <React.Fragment>
            <h2>Random Post</h2>
            <div>
              {!isLoading ? (
                posts.map(post => {
                  const { _id, title, content } = post;
                  return (
                    <div key={_id}>
                      <h2>Using data in React with the Fetch API and axios</h2>
                      <p>{content}</p>
                      <hr />
                    </div>
                  );
                })
              ) : (
                <p>Loading...</p>
              )}
            </div>
          </React.Fragment>
        );
      }
    }

    The main difference between this method and using axios to fetch from a third-party is how the data is formatted. We’re getting straight-up JSON this way rather than mapping endpoints.

    The posts data we get from the API is used to update the value of the component’s posts state. With this, we can map through the array of posts in render(). We then obtain the id, title and content of each post using ES6 de-structuring, which is then rendered to the user.

    Like we did before, what is displayed depends on the value of isLoading. When we set a new state for posts using the data obtained from the API, we had to set a new state for isLoading, too. Then we can finally let the user know data is loading or render the data we’ve received.

    async and await

    Another thing the promise-based nate of axios allows us to do is take advantage of is async and await . Using this, the getPosts() function will look like this.

    async getPosts() {
      const response = await axios.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json");
      try {
        this.setState({
          posts: response.data.posts,
          isLoading: false
        });
      } catch (error) {
        this.setState({ error, isLoading: false });
      }
    }

    Base instance

    With axios, it’s possible to create a base instance where we drop in the URL for our API like so:

    const api = axios.create({
      baseURL: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json"
    });

    …then make use of it like this:

    async getPosts() {
      const response = await api.get();
      try {
        this.setState({
          posts: response.data.posts,
          isLoading: false
        });
      } catch (error) {
        this.setState({ error, isLoading: false });
      }
    }

    Simply a nice way of abstracting the API URL.

    Now, data all the things!

    As you build React applications, you will run into lots of scenarios where you want to handle data from an API. Hopefully you know feel armed and ready to roll with data from a variety of sources with options for how to request it.

    Want to play with more data? Sarah recently wrote up the steps for creating your own serverless API from a list of public APIs.

    The post Using data in React with the Fetch API and axios appeared first on CSS-Tricks.