The possibilities of the color-adjust property

The Open Web continues to show up in places we would have never originally expected to find it: our phones, televisions, watches, books, video game consoles, fast food menus, gas pumps, elevators, cars—even our refrigerators.

By not making too many or too strict assumptions about how the web should be used, it remains flexible and adaptable. These qualities have allowed it to outperform closed technologies like Flash and Silverlight.

With the web’s growth comes new features to better accommodate its new form factors and use cases. One feature I’m excited about is the color-adjust property, proposed in CSS Color Module Level 4. It is an acknowledgement that the web will continue to show up on devices that have less-than-stellar displays.

There are two values for color-adjust: economy and exact. A value of exact tells the browser it shouldn’t make adjustments to the colors declared in the stylesheet:

.card { background-color: #98b3c7; border-bottom: 0.25rem solid #7c92a3; color: #f3f3f3; color-adjust: exact; ...
}

The color-adjust: exact; declaration in this example forces the browser to render all colors as accurately as possible on anything with a class of card applied to it. Accurate meaning being as close as possible based on the host device’s best ability.

The description for the economy value in the specification reads as, “The user agent should make adjustments to the page’s styling as it deems necessary and prudent for the output device.” It places trust in the browser’s hands, allowing it to make adjustments to color values as it sees fit.

Best ability

Handing control over to a browser might seem a little scary at first. As an industry, we’re really great at bikeshedding the heck out of color systems. And that’s a great thing! The use of color, including proper contrast ratios, is an incredibly important aspect of design, and can oftentimes make or break a product.

But we need to understand that our platonically ideal design might not be able to be experienced in the real world as intended. Not everyone owns a device that outputs to a Retina display with a luxurious DCI-P3 color space; nor do they always have perfect vision or ideal lighting conditions. In these kinds of circumstances, it’s better to bend, not break.

We now live in a Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First world. Limited color displays aren’t as rare as you think, and are probably only going to get more commonplace as time goes on. I’d especially like to call attention to the rise of internet use by low income populations and emerging markets. With that comes cheaper devices with lower-quality displays.

Browser support

At the time of this article’s publishing, color-adjust has been supported since Firefox 48 (and Android Firefox 60):

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
19* 15* 48 No 18 6*

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
12 No No 67 67 60

Chrome and Safari, both WebKit browsers, require a vendor-prefixed declaration of -webkit-print-color-adjust. Curiously, -webkit-print signals that their implementation of this property is only intended for print. While the W3C documentation does mention use cases for printing, it is phrased in such a way as to not be limited to it.

People still print webpages! Paper doesn’t require a data plan, nor does its connection drop when you go underground. Just yesterday, I saw someone on the train who was using a collection of printed sites to study for their next exam. And here’s your galaxy brain moment: printed pages are just limited color displays.

I’d also be remiss if I didn’t mention situations where print styles are missing or poorly-authored, potentially forcing a printer to waste ink in an attempt to do what the stylesheet asks of it. Printer ink is hideously expensive—minding this does your (or your IT department’s) budget a solid.

Potential uses

Before we get any further, I want to state the following is all personal theorizing based off the phrasing in the W3C specification—targeting, but not limited to printing.

I think color-adjust could be one of those properties that could find a home explicitly declared in the body selector, where it can best take advantage of the Cascade:

body { color-adjust: economy; ...
}

This declaration says, “Every time I declare color in this website, use the values I specify. If you can’t, that’s cool—do what you think is best.” That’s a lot better than the browser trying to literally interpret styling instructions at all cost, potentially rendering the page as completely illegible.

You could declare color-adjust in a more specific way, say nested in a @supports at-rule inside of a print media query, but that’s unnecessary extra work. It would fail to accommodate things like High Contrast Mode and the upcoming color gamut media feature. Better to embrace the unknown and cast a wide net.

I’m also very curious to see how color-adjust could work in conjunction with other browser capabilities, say the Ambient Light Sensor API (RIP Battery Status API). It’d be neat if there were opportunities to experiment with other specialized display modes—macOS’ Night Shift, Increased Contrast, Grayscale, and Reduce Transparency options all come to mind.

A note about accessibility

I’m wondering if software (browser preference toggle or extension, bookmarklet, etc.) could be written to override what the device’s hardware reports itself as being. Much like User Agent spoofing, it could “trick” a browser into thinking it has a limited color display, using economy to force better contrast between text and background color. This would be a lot like some browser’s reading modes, only page layout would be better preserved.

That being said, I don’t think color-adjust is a silver bullet for all color-related accessibility concerns. We can’t always know the device and context our websites and web apps will show up in, including what colors color-adjust would ultimately render as. Because of this, it’s still important to mind your color contrast ratios.

Bending, not breaking

color-adjust feels like a natural extension of Jen Simmons’ Intrinsic Web Design: fluid and squishy UI, proportional sizing, media queries as needed, and simple declarations that do the heavy lifting.

The beauty of the CSS Cascade means you can gracefully create intent, then adjust as needed. color-adjust‘s documentation specifically mentions a situation where it could be useful to ensure a table’s zebra striping is is retained when printed to make it easier to read. Such a tweak can be scoped to a single selector, without having to spend time undoing it for every other component.

body { color-adjust: economy; ...
} tr { color-adjust: exact;
}

The beauty of CSS’ fault tolerance means browsers that don’t understand this declaration will ignore it and continue parsing the rest of of the stylesheet. Browsers that do support it can take advantage of it, without any complicated build tool configuration or dangerous User Agent sniffing.

It is important to make our web sites and web apps design adapt to the user’s environment and circumstances, and not the other way around. Good user experiences meet the user where they are, not where we hope they’ll be.

The post The possibilities of the color-adjust property appeared first on CSS-Tricks.

Browser painting and considerations for web performance

The process of a web browser turning HTML, CSS, and JavaScript into a finished visual representation is quite complex and involves a good bit of magic. Here’s a simplified set of steps the browser goes through:

  1. Browser creates the DOM and CSSOM.
  2. Browser creates the render tree, where the DOM and styles from the CSSOM are taken into account (display: none elements are avoided).
  3. Browser computes the geometry of the layout and its elements based on the render tree.
  4. Browser paints pixel by pixel to create the visual representation we see on the screen.

In this article, I’d like to focus on the last part: painting.

All of those steps combined is a lot of work for a browser to do on load… and actually, not just on load, but any time the DOM (or CSSOM) is changed. That’s why many web developers tend to partially solve this by using some sort of frontend framework, such as React which, apart from many other advantages, can help to highly optimize changes in the DOM to avoid unnecessary recalculating or rendering.

You may have heard terms such as state, component rendering, or immutability. All of those have something to do with optimization of DOM changes, or in other words, to only make changes to the DOM when it’s necessary.

To give an example, the state of a web application may change, and that would lead to a change in UI. However, certain (or many) components are not affected by this change. What React helps to do is limit the writing to the DOM for elements that are actually affected by a change in state and ultimately limit the rendering to the smallest part of the web application possible:

DOM/CSSOM → render tree → layout → painting

However, browser painting is special in its own way, as it can happen even without any changes to the DOM and/or CSSOM.

Example of page performance summary

The diagram above was generated using Chrome’s performance panel in DevTools (more on that later) and it shows how much time was taken by each task in the browser in the recorded time (0-7.12s) after reloading of a page. As you can see, painting takes a significant part, and that’s not automatically a bad thing. In this particular example, the increased painting is caused by a combination of animated GIFs on the page and canvas drawing (at 60fps), where both don’t cause any changes to the DOM or its styles, while still triggering painting.

Another good example of a feature that may cause painting without any outside intervention is the CSS animation property, and compared to animated GIF or canvas, it is probably more common on the web. An animation is usually triggered by user input, like hover, but thanks to animation and @keyframes rules, we can even create quite complex animations running constantly on the page without much of an effort, which is pretty amazing.

What some might not realize, is that those animations can easily get out of hand and constantly trigger painting, and that can cost us a lot of processing power. Of course, there are some rules that can be used to avoid painting. Most obvious is limiting manipulation of elements to CSS transform and opacity properties, which by default don’t trigger paint, unless some special circumstances are in place, such as animating an SVG path.

Paint flashing

You likely know that Chrome has DevTools. What you might not know about is a little shortcut (Shift+Cmd+P on Mac or Control+Shift+P on PC) which can be used inside DevTools to bring up a little search bar and command menu.

Command Menu

I’ve started digging around it, and apart from many other useful and incredibly interesting options, a render panel caught my attention.

Render Panel

At the first sight, you can see some interesting options that can be very helpful when it comes to debugging animation on the web, like an transform property, which as we covered, doesn’t cause painting. The painting was present where one would expect it to be, like changes in text color on hover, but that’s not something that should be much of a concern due to its area and presence only on hover of the element. To sum it up, you can always find something to improve, even if you wrote the code yesterday…

But one thing was a slap in the face.

It doesn’t matter how experienced or careful you are, you can — and most likely will — make a mistake. We’re just people and some would argue that fixing your own bugs is most of the job when it comes to development. However, for a bug to be fixable, we need to be aware of it… and that’s exactly where the render panel helps.

Case study

Let’s take a closer look at the actual issue. The design came in with the request for a noisy background. That kind of effect that old TVs had when there was no signal.

It is known that GIFs have many issues, where performance is certainly one of them, so I definitely couldn’t use that for a whole page background. If you’d like to read some more on why to avoid GIFs, here is a good resource with a bunch of reasons.

Using JavaScript is definitely an option in this case. Displaying or hiding elements with a slightly moved background was the first thing that came to my mind, and using canvas could help too. However, all of this seemed a little overkill for simply having a background. I decided to go for a CSS-only approach.

My solution was to take a small “noisy” PNG image as a background-image, enable background-repeat and throw it over a one-color background. How did I achieve the noise effect? With infinite CSS animation! By setting the background-position to different value over the period of 200 milliseconds. Here’s how that turned out:

See the Pen MXoddr by Georgy Marchuk (@gmrchk) on CodePen.

Can you guess the problem? It seemed like a quite an elegant solution to me, and I was excited about my achievement of making it through without a crappy GIF and even not a single line of JavaScript. Just simple CSS that is optimized in browsers these days.

Well, the paint flashing showed something completely different. The layer of the size of the window was constantly repainting, without the user even doing anything. You can see the paint flashing in the demo above if you enable it in the render panel (note that paint flashing doesn’t show up in embedded pen).

Without paint flashing (left) vs. with paint flashing (right)

That certainly doesn’t play well with the performance of the website and drains laptop batteries like there’s no tomorrow.

CPU usage for the animation done with background-position (top) and transform (bottom)

All of this CPU usage could have been avoided by replacing the changes to background-position using transform or opacity.

See the Pen XYOYGm by Georgy Marchuk (@gmrchk) on CodePen.

The problem

I’ve been doing web development for a while and I knew very well that animating a background is never a good idea. This felt like a rookie mistake. People make mistakes… but that’s not the whole story. The website was all laggy and uncomfortable to navigate. How did I miss it?

Something that certainly plays a big role is the fact that I am (and you may be as well) a little spoiled when it comes to development equipment. I have a nice, powerful computer for work and access to speedy internet. Unless we write some really crappy code, anything we write runs quite smoothly in our eyes. But that’s not always the case for our users.

A similar problem applies to many other things — like display size. Using a little exaggeration, while we are developing on 27” display with 4K resolution and getting the designs primarily for 1920×1080, our visitors come in mainly from 1366×768 laptops and have a completely different workflow when it comes to using a computer.

Conclusion

While this article started off as a piece about painting, its main topic is really much more about being mindful of the impact our code has on the painting process or performance in general. While painting serves as a good example of something that can be problematic and easily missed, it’s more of a disconnect between developer and user that is the issue.

The web is a place of many environments, where the developer’s environment is often far different than the user’s. While there is no need to change our ways or switch to lazy computers, it definitely helps to see our work the way it is seen by others from time to time. My suggestion is: when you come home from work and have a little free time, try to pick up your old computer and check your work there, to get a little closer to what your users experience.

If you don’t have this kind of computer around, tools like render panel can turn out to be awfully handy.

The post Browser painting and considerations for web performance appeared first on CSS-Tricks.

Slow Websites

The web has grown bigger. Both in expansiveness and weight. Nick Heer’s “The Bullshit Web”:

The average internet connection in the United States is about six times as fast as it was just ten years ago, but instead of making it faster to browse the same types of websites, we’re simply occupying that extra bandwidth with more stuff.

Nick clearly explains what he means by bullshit, and one can see a connection to Brad Frost’s similarly framed argument. Nick talks about how each incremental interaction is a choice and connects the cruft of the web to the rise and adoption of frameworks like AMP.

Ethan Marcotte paints things in a different light by looking at business incentive:

…ultimately, the web’s performance problem is a problem of profitability. If we’re going to talk about bloated pages, we should do so in context: in the context of a web where digital advertising revenue is cratering for publishers, but is positively flourishing for Facebook and Google. We should look at the underlying structural issues that incentivize a company to include heavy advertising scripts and pesky overlays, or examine the market challenges that force a publisher to adopt something like AMP.

In other words, the way we talk about slow websites needs to be much, much broader. If we can do that, then we’ll have a sharper understanding of where—and how—the web can be faster.

It’s a systemic state of the industry problem that breeds slow websites. The cultural fight to fix it is perhaps just as important as the technical fights. Not that there isn’t a lot to learn and deal with on a technical level.

Addy Osamai wrote up a deep dive (a 20-minute read, according to Medium) that explores the cost of JavaScript to overall web performance. Everyone seems to agree JavaScript is the biggest problem area for slow websites. It’s not preachy but rather a set of well-explained principles to follow in this era where the use of JavaScript is trending up:

  • To stay fast, only load JavaScript needed for the current page.
  • Embrace performance budgets and learn to live within them.
  • Learn how to audit and trim your JavaScript bundles.
  • Every interaction is the start of a new ‘Time-to-Interactive’; consider optimizations in this context.
  • If client-side JavaScript isn’t benefiting the user experience, ask yourself if it’s really necessary.

The post Slow Websites appeared first on CSS-Tricks.

Sticky, Smooth, Active Nav

Just like the title says! Here’s a sidebar navigation bar that…

  1. Uses sticky positioning. It stays on the screen when it can, but won’t overlap the header, footer, or ever make any of it’s links inaccessible.
  2. Scrolls smoothly to the sections you click to.
  3. Activates the current nav based on scroll position (it’s a single page thing).

See the Pen Sticky, Smooth, Active Nav by Chris Coyier (@chriscoyier) on CodePen.

Sticky

It’s easy to toss position: sticky; top: 0; on something. But for it to work, it’s gotta be within a taller parent element. So, the unordered list (<ul>) within the navigation (<nav>) works great here. Thanks to the CSS grid layout, the <nav> is as tall as the <main> content area. However, note that that we also gotta position: -webkit-sticky; for iOS.

I also tossed in a magic number for the vertical media query so that it doesn’t stick in such a way that you can’t get to the lower navigation items:

/* Only stick if you can fit */
@media (min-height: 300px) { nav ul { position: sticky; top: 0; }
}

Smooth

In my first crack at this, I thought about JavaScript-based smooth scrolling. It’s even native these days with no need for frameworks. You can target an element and smoothly scroll to it:

document.querySelector('.hello').scrollIntoView({ behavior: 'smooth' });

Bringing that to an arbitrary set of nav…

let mainNavLinks = document.querySelectorAll("nav ul li a"); mainNavLinks.forEach(link => { link.addEventListener("click", event => { event.preventDefault(); let target = document.querySelector(event.target.hash); target.scrollIntoView({ behavior: "smooth", block: "start" }); });
});

That’s supported in both Chrome and Firefox, but not Edge or Safari.

Then it occurred to me, CSS can do this! There is a scroll-behavior property and you can put it on the document to make everything scroll that way:

html { scroll-behavior: smooth;
}

Since our navigational <a> links are hash/jump/anchor links, that’s literally all we need. Forget the JavaScript. Especially because the browser support for scroll-behavior is the same as the “smooth” version of .scrollIntoView().

Active

This is a bit trickier, particularly because this is a single-page scrolling app rather than individual pages with their own separate documents. If they were separate documents, we’d change an active class somewhere in the navigation or use a body.specific_page class or something.

Instead, we’ll need to look at the scroll position of the page, decide which section is in view and mark it that way. There might be some kinda fancy IntersectionObserver way to handle this, but I couldn’t quite wrap my head around that, so instead I’m just looking at all the relevant sections, doing a little measuring and math, and deciding if the link is active that way.

let mainNavLinks = document.querySelectorAll("nav ul li a");
let mainSections = document.querySelectorAll("main section"); let lastId;
let cur = []; window.addEventListener("scroll", event => { let fromTop = window.scrollY; mainNavLinks.forEach(link => { let section = document.querySelector(link.hash); if ( section.offsetTop <= fromTop && section.offsetTop + section.offsetHeight > fromTop ) { link.classList.add("current"); } else { link.classList.remove("current"); } });
});

The scroll handler there should trigger a little warning flag. That’s the kind of thing that should probably be throttled, like if you have lodash available:

window.addEventListener("scroll", () => { _.throttle(doThatStuff, 100);
});

I just didn’t do that here to keep the demo dependency-free.

Oh! And it largely works fine on mobile (iOS here):

A Free Template for JavaScript Library Homepages

I used all this stuff in this template I made that you’re free to use for whatever.

The post Sticky, Smooth, Active Nav appeared first on CSS-Tricks.

Let’s make a form that puts current location to use in a map!

I love shopping online. I can find what I need and get most things for a decent price. I am Nigerian currently working and studying in India, and two things I dread when shopping online are:

  1. Filling out a credit card form
  2. Filling out shipping and billing address forms

Maybe I’m just lazy, but these things are not without challenges! For the first one, thanks to payment processing services like PayPal and e-wallets, I neither have to type in my 12-digit credit card number for every new e-commerce site I visit, nor have to save my credit card details with them.

For the second, the only time-saving option given by most shopping websites is to save your shipping address, but you still have to fill the form (arrghh!). This is where the challenge is. I’ve had most of my orders returned because my address (which I thought was the right address) could not be located or confirmed by the app for one reason or another.

Address inputs are challenging

Getting a user’s address through an input form is a clean solution but can also be a herculean task to the user. Here’s why:

  • If the user is new in a particular city, they might not know their full address
  • If the user wants to ship to a new address which isn’t saved (e.g shipping to a workplace or a friend’s address instead of the saved home address)
  • If the user resides in a city with very difficult address systems
  • If the user is plain lazy like me

A potential solution: get the address automatically

Getting the user’s address by the tap/click of a button. Yup, that’s easy! The UX is great as it saves the user both the time and effort of filling out some form. It will also save the store owner time, effort, and even money in some cases, as there’ll likely be a reduction in the number of incorrectly placed orders or shipments.

Let’s build a mini app that gets a user’s address and shows it on a Google Map interface using vanilla JavaScript. The concept is as follows:

  1. Get the HTML button and listen for a click event
  2. Get the user’s location (latitude and longitude) on a button click
  3. Show the user’s location on a Google map
  4. Pass the latitude and longitude to the Google Maps Geocode API URL
  5. Display the returned address (or list of addresses) on the UI for the user to select one
  6. Listen for map events and repeat steps 4 and 5
  7. Pre-fill the form with the address data the user selects

Getting started and setting up

To build this app, we’re going to use the Materialize CSS framework to save us some time fussing with styles. Materialize is a modern responsive front-end framework based on Google’s Material Design system. The beta version works with vanilla JavaScript.

A basic setup using Materialize’s CSS and JavaScript files in a document is like this:

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Address Locator</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css"> <link rel="stylesheet" href="css/main.css">
</head>
<body> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script> <script src="js/main.js"></script>
</body>
</html>

We’re also going to use the Google Maps API for displaying the map and getting the user’s human-readable address. We’ll need an API key to do this. Here’s how to get one:

  1. Sign in to your Google Developer’s Console Account
  2. Create a new project or select an existing one
  3. Click on “Enable APIs and Services”
  4. Select the “Maps Javascript API” option
  5. Click “Enable” on the new page that comes up. Go back to the previous page and do a search for “Geocoding API,” click on it and enable it as well
  6. Then, on the right nav of the page, click on Credentials, copy the API key on the page and save it to a file

Now, let’s update our document to show the map and let the user know it can be used to get their current location as the address. Also, we will add a form that’s pre-filled with the address the user selects.

... <body> <div class="container"> <h3>Shipping Address</h3> <p>You can click the button below to use your current location as your shipping address</p> <div id="map"> </div> <button id="showMe" class="btn">Use My Location</button> <form id="shippingAddress"> <div id="locationList"></div> <br> <div class="input-field"> <textarea class="input_fields materialize-textarea" id="address" type="text"></textarea> <label class="active" for="address">Address (Area and Street)</label> </div> <div class="input-field"> <input class="input_fields" id="locality" type="text"> <label class="active" for="locality">Locality</label> </div> <div class="input-field"> <input class="input_fields" id="city" type="text"> <label class="active" for="city">City/District/Town</label> </div> <div class="input-field"> <input class="input_fields" id="postal_code" type="text"> <label class="active" for="pin_code">Pin Code</label> </div> <div class="input-field"> <input class="input_fields" id="landmark" type="text"> <label class="active" for="landmark">Landmark</label> </div> <div class="input-field"> <input class="input_fields" id="state" type="text"> <label class="active" for="State">State</label> </div> </form> <!-- You could add a fallback address gathering form here --> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script> <script src="js/main.js"></script>
</body> </html>

While we are here, let’s style things a bit to make this look a little better:

.container { width: 50%; max-width: 800px;
} #map { height: 50vh; margin-bottom: 10px; display: none;
} #locationList .card { padding: 10px;
} #toast-container { top: 50%; bottom: unset;
} .toast { background-color: rgba(0, 0, 0, 0.8);
} @media only screen and (max-width: 768px) { .container { width: 80%; }
}

This CSS hides the map until we are ready to view it. Our app should look like this:

Let’s plan this out

Our app will be making use of the HTML5 Geolocation API to determine our user’s current location as well as Google’s Geocode API with a technique called Reverse Geocoding. The Geocode API takes a human-readable address and changes it into geographical (latitudinal and longitudinal) coordinates and marks the spot in the map.

Reverse Geocoding does the reverse. It takes the latitude and longitude and converts them to human-readable addresses. Geocoding and Reverse Geocoding are well documented.

Here’s how our app will work:

  1. The user clicks on the “Use My Location” button
  2. The user is located with the HTML5 Geolocation API (navigator.geolocation)
  3. We get the user’s geographic coordinates
  4. We pass the coordinates to the geocode request API
  5. We display the resulting addresses to the user

Most times, the geocode returns more than one address, so we would have to show the user all the returned addresses and let them choose the most accurate one.

Phew! Finally, we can get to the fun part of actually writing the JavaScript. Let’s go through each of the steps we outlined.

Step 1: Clicking the button

In our main.js file, let’s get a reference to the HTML button. While we are at it, we’ll set up some other variables we’ll need, like our API key.

//This div will display Google map
const mapArea = document.getElementById('map'); //This button will set everything into motion when clicked
const actionBtn = document.getElementById('showMe'); //This will display all the available addresses returned by Google's Geocode Api
const locationsAvailable = document.getElementById('locationList'); //Let's bring in our API_KEY
const __KEY = 'YOUR_API_KEY'; //Let's declare our Gmap and Gmarker variables that will hold the Map and Marker Objects later on
let Gmap;
let Gmarker; //Now we listen for a click event on our button
actionBtn.addEventListener('click', e => { // hide the button actionBtn.style.display = "none"; // call Materialize toast to update user M.toast({ html: 'fetching your current location', classes: 'rounded' }); // get the user's position getLocation();
});

When the click handler for our button runs, it:

  1. Hides the button
  2. Alerts the user that we are getting their current location (a “toast” in Materialize is like a popup notification)
  3. Calls the getLocation function

Step 2: Get the user’s location (latitude and longitude)

When our getLocation function is invoked, we need to do some more work. First, let’s check if we can even use the Geolocation API:

getLocation = () => { // check if user's browser supports Navigator.geolocation if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(displayLocation, showError, options); } else { M.toast({ html: "Sorry, your browser does not support this feature... Please Update your Browser to enjoy it", classes: "rounded" }); }
}

When we have support, it calls geolocation’s getCurrentPosition method. If it doesn’t have support, then the user is alerted that there’s no browser support.

If there is support, then the getCurrentLocation method is used to get the current location of the device. The syntax is like this:

navigator.geolocation.getCurrentPosition(*success, error, [options]*)
  • success : This is a callback function that takes a position as its only parameter. For us, our success callback function is the displayLocation function.
  • error : [optional] This is a callback function that takes a PositionError as its sole input parameter. You can read more about this here. Our error callback function is the showError function.
  • options : [optional] This is an object which describes the options property to be passed to the getCurrentPosition method. You can read more about this here. Our options parameter is the options object.

Before writing our displayLocation function, let’s handle the showError function and options object:

// Displays the different error messages
showError = (error) => { mapArea.style.display = "block" switch (error.code) { case error.PERMISSION_DENIED: mapArea.innerHTML = "You denied the request for your location." break; case error.POSITION_UNAVAILABLE: mapArea.innerHTML = "Your Location information is unavailable." break; case error.TIMEOUT: mapArea.innerHTML = "Your request timed out. Please try again" break; case error.UNKNOWN_ERROR: mapArea.innerHTML = "An unknown error occurred please try again after some time." break; }
}
//Makes sure location accuracy is high
const options = { enableHighAccuracy: true
}

Now, let’s write the code for our displayLocation function inside our main.js file:

displayLocation = (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude;
}

We now have our user’s latitude and longitude and we can view them in the console by writing the code below inside displayLocation:

console.log( `Current Latitude is ${lat} and your longitude is ${lng}` );

Step 3: Show the user’s current location on a Google Map

To do this, we will be adding these lines of code to our displayLocation function.

const latlng = {lat, lng}
showMap(latlng);
createMarker(latlng);
mapArea.style.display = "block";

The first line takes our lat and lng values and encapsulates it in the latlng object literal. This makes it easy for us to use in our app.

The second line of code calls a showMap function which accepts a latlng argument. In here, we get to instantiate our Google map and render it in our UI.

The third line invokes a createMarker function which also accepts our object literal (latlng) as its argument and uses it to create a Google Maps Marker for us.

The fourth line makes the mapArea visible so that our user can now see the location.

displayLocation = (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; const latlng = { lat, lng } showMap(latlng); createMarker(latlng); mapArea.style.display = "block";
}

Now, let’s get to creating our functions. We will start with the showMap function.

showMap = (latlng) => { let mapOptions = { center: latlng, zoom: 17 }; Gmap = new google.maps.Map(mapArea, mapOptions);
}

The showMap function creates a mapOptions objects that contain the map center (which is the lat and lng coordinates we got from displayLocation) and the zoom level of the map. Finally, we create an instance of the Google Maps class and pass it on to our map. In fewer words, we instantiate the Google Maps class.

To create a map instance, we specify two parameters in the constructor: the div the map will be displayed and the mapOptions. In our case, our div is called mapArea and our mapOptions is called mapOptions. After this, our created map will show up, but without a marker. We need a marker so the user can identify their current position on the map.

Let’s create our marker using the createMarker function:

createMarker = (latlng) => { let markerOptions = { position: latlng, map: Gmap, animation: google.maps.Animation.BOUNCE, clickable: true }; Gmarker = new google.maps.Marker(markerOptions);
}

A few things to note in this code:

  1. The position property positions the marker at the specified latlng
  2. The map property specifies the map instance where the marker should be rendered (in our case, it’s Gmap)
  3. The animation property adds a little BOUNCE to our marker
  4. The clickable property set to true means our marker can be clicked
  5. Finally, we instantiate the Marker class in our Gmarker instance variable

So far, our user’s location has been fetched, the map has rendered and the user can see their current location on the map. Things are looking good! 🕺

Step 4: Pass the latitude and longitude to the Geocode API

Google’s Geocoding API will be used to convert our user’s numeric geographical coordinates to a formatted, human-readable address using the reverse geocoding process we covered earlier.

The URL takes this form:

https://maps.googleapis.com/maps/api/geocode/outputFormat?parameters

…where the outputFormat may either be a json or xml which determines the the format used to deliver the data. The parameters part is a list of parameters needed for the request.

Our request URL will look like this:

https://maps.googleapis.com/maps/api/geocode/json?latlng=${latlng}&key=${__KEY}

Let’s go ahead and connect to the API. We would do this in a function called getGeolocation.

getGeolocation = (lat, lng) => { const latlng = lat + "," + lng; fetch( `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latlng}&key=${__KEY}` ) .then(res => res.json()) .then(data => console.log(data.results));
}

The getGeolocation function takes two arguments ( lat and lng } concatenates them to form a new latlng variable that is passed to the URL.

Using the Fetch API (more on this here), we add the new latlng and __KEY into the Geocode request URL. Then, on the response object we get back, we pass the .json method to resolve the promise with JSON. Finally, we log the response in our console.

To make use of our newly created function, we have to call it in the displayLocation function. So let’s update our displayLocation function to contain the getGeolocation function call:

displayLocation = (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; const latlng = { lat, lng } showMap(latlng); createMarker(latlng); mapArea.style.display = "block"; getGeolocation(lat, lng)// our new function call
}

The returned data should look something like this:

{ "results" : { "address_components": { "long_name": "1600", "short_name": "1600", "types": ["street_number"] }, { "long_name": "Amphitheatre Pkwy", "short_name": "Amphitheatre Pkwy", "types": ["route"] }, { "long_name": "Mountain View", "short_name": "Mountain View", "types": ["locality", "political"] }, { "long_name": "Santa Clara County", "short_name": "Santa Clara County", "types": ["administrative_area_level_2", "political"] }, { "long_name": "California", "short_name": "CA", "types": ["administrative_area_level_1", "political"] }, { "long_name": "United States", "short_name": "US", "types": ["country", "political"] }, { "long_name": "94043", "short_name": "94043", "types": ["postal_code"] } ], "formatted_address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", "geometry": { "location": { "lat": 37.4224764, "lng": -122.0842499 }, "location_type": "ROOFTOP", "viewport": { "northeast": { "lat": 37.4238253802915, "lng": -122.0829009197085 }, "southwest": { "lat": 37.4211274197085, "lng": -122.0855988802915 } } }, "place_id": "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", "types": ["street_address"] } ], "status" : "OK"
}

Step 5: Display the returned address(es) for the user to select

At this stage, we have made a request to Google’s Geocoding API and have gotten our result logged in the console. Now, we have to display the results in a UI for our user. This requires two things:

  1. Create a new function that handles creating HTML elements
  2. Update our getGeolocation function to make the function call

Let’s create the function that would take care of creating the HTML elements and updating the DOM.

populateCard = (geoResults) => { geoResults.map(geoResult => { // first create the input div container const addressCard = document.createElement('div'); // then create the input and label elements const input = document.createElement('input'); const label = document.createElement('label'); // then add materialize classes to the div and input addressCard.classList.add("card"); input.classList.add("with-gap"); // add attributes to them label.setAttribute("for", geoResult.place_id); label.innerHTML = geoResult.formatted_address; input.setAttribute("name", "address"); input.setAttribute("type", "radio"); input.setAttribute("value", geoResult.formatted_address); input.setAttribute("id", geoResult.place_id); addressCard.appendChild(input); addressCard.appendChild(label) return ( // append the created div to the locationsAvailable div locationsAvailable.appendChild(addressCard) ); })
}

In this function, we iterate through our results and create some HTML elements (div , input and a label), append the input and the label to the div and finally append the new div to a parent div (which is locationsAvailable). Once we get the result from our API call, our DOM will be created and displayed to the user.

Next, we update our getGeolocation function to call our populateCard function by replacing the last line of getGeolocation with this:

.then(data => populateCard(data.results));

…which means our updated function should look this:

getGeolocation = (lat, lng) => { const latlng = lat + "," + lng; fetch( `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latlng}&key=${__KEY}` ) .then(res => res.json()) .then(data => populateCard(data.results));
}

At this point, everything should be working fine. Our user clicks a button, gets a location displayed on the map along with a list of addresses that match the current location.

Step 6: Listen for map events and repeat steps 4 and 5

If our user decides to move the map or marker, nothing happens to the UI — new addresses aren’t not displayed and everything remains static. We’ve got to fix this, so let’s make our app dynamic by listening for map events. You can read all about Google Map Events here.

There are three events we want to listen for:

  1. drag: This is fired once the user starts dragging and continues to drag the map
  2. dragend: This is fired once the user stops dragging the map
  3. idle: This is fired once every event has been fired and the map is idle

Quick Question: Why are these events best suited for our app?

Quick Answer: The first two events will make sure that our map marker stays in the center of the map during the drag event while the idle event will make a geocoding request with the new coordinates.

To listen for these events we have to update the showMap function with the following:

Gmap.addListener('drag', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center
});
Gmap.addListener('dragend', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center
});
Gmap.addListener('idle', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center if (Gmarker.getPosition().lat() !== lat || Gmarker.getPosition().lng() !== lng) { setTimeout(() => { updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display }, 2000); }
});

As explained above, the first two event listeners simply ensure that the marker remains in the center of our map. Pay closer attention to the idle event listener because that is where the action is.

Once the idle event is fired, the marker goes to the center, then a check is done to find out if the current position of the marker is the same with the lat or lng values received by the displayLocation function. If it is not the same, then we call the updatePosition function after two seconds of idleness.

Having said that, we have to make a few updates to the showMap function. First, on the function header, we have to include more parameters and on the showMap function call. We need to add the new arguments there, too. Our showMap function should look like this:

showMap = (latlng, lat, lng) => { let mapOptions = { center: latlng, zoom: 17 }; Gmap = new google.maps.Map(mapArea, mapOptions); Gmap.addListener('drag', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center }); Gmap.addListener('dragend', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center }); Gmap.addListener('idle', function () { Gmarker.setPosition(this.getCenter()); // set marker position to map center if (Gmarker.getPosition().lat() !== lat || Gmarker.getPosition().lng() !== lng) { setTimeout(() => { updatePosition(this.getCenter().lat(), this.getCenter().lng()); // update position display }, 2000); } });
}

And our displayLocation function should look like this:

displayLocation = (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; const latlng = { lat, lng } showMap(latlng, lat, lng); //passed lat and lng as the new arguments to the function createMarker(latlng); mapArea.style.display = "block"; getGeolocation(lat, lng);
}

Having listened for the map events, let’s repeat Step 4 and Step 5.

We start by writing our updatePosition function. This function will perform only one action for now, which is to pass the new lat and lng values to the getGeolocation function:

updatePosition = (lat, lng) => { getGeolocation(lat, lng);
}

After getting the new position and fetching addresses, our DOM should re-render for the user, right? Well, it doesn’t. And to fix that, we create a function that will force the DOM to re-render:

// check if the container has a child node to force re-render of dom
function removeAddressCards(){ if (locationsAvailable.hasChildNodes()) { while (locationsAvailable.firstChild) { locationsAvailable.removeChild(locationsAvailable.firstChild); } }
}

It checks if the locationsAvailable div has any childNodes, and if it does, it deletes them before creating new address cards. The populateCard function is now updated to this:

populateCard = (geoResults) => { // check if a the container has a child node to force re-render of dom removeAddressCards(); geoResults.map(geoResult => { // first create the input div container const addressCard = document.createElement('div'); // then create the input and label elements const input = document.createElement('input'); const label = document.createElement('label'); // then add materialize classes to the div and input addressCard.classList.add("card"); input.classList.add("with-gap"); // add attributes to them label.setAttribute("for", geoResult.place_id); label.innerHTML = geoResult.formatted_address; input.setAttribute("name", "address"); input.setAttribute("type", "radio"); input.setAttribute("value", geoResult.formatted_address); input.setAttribute("id", geoResult.place_id); addressCard.appendChild(input); addressCard.appendChild(label); return ( locationsAvailable.appendChild(addressCard); ); })
}

We are done and are now able to fully get and display the user’s address!

Step 7: Pre-fill the form with the address data the user selects

The final step is to fill the form with the address the user selects. We need to add a click event listener to the address card and pass the address as argument to the callback function.

Here’s how we add the event listener in the populateCard function:

input.addEventListener('click', () => inputClicked(geoResult));

You should note that the geoResult argument in the above callback is the selected address object from the results array. That said, update the populateCard function to accommodate our new line of code.

The inputClicked function uses a series of if statements to assign values to our form elements. so before working on it, let’s bring our form elements into the equation:

const inputAddress = document.getElementById('address'), inputLocality = document.getElementById('locality'), inputPostalCode = document.getElementById('postal_code'), inputLandmark = document.getElementById('landmark'), inputCity = document.getElementById('city'), inputState = document.getElementById('state');

Having done this, let us now work on pre-filling the form with the address_components in the inputClicked function.

inputClicked = result => { result.address_components.map(component => { const types = component.types if (types.includes('postal_code')) { inputPostalCode.value = component.long_name } if (types.includes('locality')) { inputLocality.value = component.long_name } if (types.includes('administrative_area_level_2')) { inputCity.value = component.long_name } if (types.includes('administrative_area_level_1')) { inputState.value = component.long_name } if (types.includes('point_of_interest')) { inputLandmark.value = component.long_name } }); inputAddress.value = result.formatted_address; // to avoid labels overlapping pre-filled input contents M.updateTextFields(); // removes the address cards from the UI removeAddressCards();
}

The above block of code iterates over the clicked (or selected) address component, checks the types of components and finally assigns them to the input fields if they match.

M.updateTextFields() function is from Materialize and it ensures that the label does not overlap with the input fields values and the removeAddressCards() function removes the address cards from the UI.

With this, we are done with our app and have saved our users lots of typing and headaches! Surely they will thank us for implementing such a hassle free solution.

This whole UX experiment can be seen as a shortcut that will help the user pre-fill the shipping address form. We should clearly state here that the returned addresses isn’t always 100% accurate. But that’s why we allow the address to be manually edited in the UI.

Demo!

See the Pen Prefill Address Form with Geolocation and Google Maps by CSS-Tricks (@css-tricks) on CodePen.

The post Let’s make a form that puts current location to use in a map! appeared first on CSS-Tricks.

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>{title}</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>{title}</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.

VS Code extensions for the discerning developer palate

I am a VS Code extension snob. I like to hunt down the most obscure extensions for VS Code — the ones that nobody knows about — and impress people at parties with my knowledge of finely aged and little-known VS Code capabilities… then watch as they look around desperately for someone else to talk to. It’s like the “Sideways” of VS Code.

In my endless pursuit of the perfect VS Code setup, I reached out to my colleagues here on the Azure team and asked them to share their favorite extension in their own words. So clear your pallet and breathe in the aromatic flavors of productivity; I am your VS Code Extension Sommelier.


Christina Warren – Settings Sync

I cannot live without this extension. If you use multiple machines (especially on multiple platforms, where a sym-linked Dropbox folder won’t really work), this extension is for you. It syncs your extensions, settings file, keybinding file, launch file, snippets folder, extension settings, and workspaces folder. This means that when you login to a new machine, you can quickly get back to work with your own settings and workflow tools in just a few minutes.

👉 Get Settings SyncExtension


Shayne Boyer – Paste JSON as Code

Consuming an endpoint that produces JSON is like breathing, but no one wants to choke on the hand cranking of an object by looking back and forth between JSON and the target language. This is a long loved feature in Visual Studio for .NET developers, but now you too can copy the JSON and paste that class into the editor as your target language and save a ton of time. Currently supports C#, Go, C++, Java, TypeScript, Swift, Elm, and JSON Schema.

👉 Get Paste JSON as Code Extension


Jeremy Likness – Spell Right

I find myself authoring blog posts, articles, and documentation almost every day. After embracing the power of Markdown (it is, after all, what is used to drive our own https://docs.com), I began writing my content in Visual Studio Code. It has a built-in preview window so I can edit the Markdown source and see the rendered result side-by-side. As much as I’ve written over the years, mastering the fine art of spelling still eludes me. Maybe it’s because I’m lazy, and this extension doesn’t help at all. With Spell Right, I get to reunite with my same favorite red squiggly lines that I first met in Word. It does a great job of catching spelling mistakes in real time, then illuminates my mistakes with a handy light bulb with alternative suggestions that give me single-click corrections. It enables me to be highly productive and look like I know what I’m doing. I recommend this for anyone who uses Code to write.

👉 Get Spell Right Extension


Aaron Wislang – Go

I live in VS Code and use it for everything from code and content to its integrated terminal. This extension enables first-class support for IntelliSense, testing, refactoring and more, making Code the best place to me to write Go. And it turns out I’m not the only one who thinks so; it helped to make Code the most popular editor amongst Gophers, just ahead of vim-go, as of the Go 2017 Survey!

👉 Get Go Extension


Cecil Phillip – C# Extensions

This extension was created by one of our community members, and it’s a great companion to the official C# extension from Microsoft. The “New Class|Interface” actions make it easy to add new types, and takes some of the hassle out of fixing up the namespaces. It also comes with a few interesting refactorings like “Initialize fields from constructors,” which I use pretty often. Whenever I’m teaching a C# course, I always have my students that are using Visual Studio Code install this extension.

👉 Get C# Extension


Brian Clark – VS Live Share

Pair programming just got way better. Gone are the days where I need to set up screen sharing to review code with coworkers. Instead I fire up a live share session, invite the other party and we can all view and edit code directly from our editors. I’ve used it in a situations where I review someone else’s C# code on my machine while it runs on THEIR machine! I didn’t have anything installed on my Mac for C# and yet I could debug their code!

👉 Get VS Live Share Extension


David Smith – Rewrap

I write a lot of text, and sometimes I just want (or need) to write in a plain-text environment. Easy reflowing of text is essential. (Surprised this isn’t built in, in fact.)

👉 Get Rewrap Extension


Anthony Chu – Git Lens

At a glance, GitLens shows me contextual information from Git about the line of code and the file I’m working in. It adds some useful commands to view history and diffs, search commits, and browse local and remote branches… all without leaving VS Code.

👉 Get Git Lens Extension


Asim Hussain – AsciiDoc

I used to write with Markdown, we all make mistakes. The solution to my Markdown mistake is AsciiDoc, especially if you write a lot of code snippets as I do. Out of the box it let’s you add line numbers, annotate and highlight lines and provides an incredible amount of customization. Plus, as a bonus it also can convert your blog posts into PDFs, ePubs, Mobis which is perfect for ebooks.

Once you start with AsciiDoc it’s hard to go back to Markdown and this plugin lets you preview your AsciiDoc right inside the editor.

👉 Get AsciiDoctor Extension


Seth Juarez) – VS Code Tools For AI

With Visual Studio Code Tools for AI, I can finally use machines I need but might never have access to in order to build the next Skynet — all within the comfort of my favorite lightweight editor. We live in amazing times, friends…

👉 Get VS Code Tools For AI Extension


Alena Hall – Ionide

Ionide is an awesome Visual Studio Code extension for cross-platform F# development. It’s open-source and it was created by the F# Community. I use it every day on multiple machines I have. It runs perfectly on both my Mac and Linux machines. Ionide conveniently integrates with Paket, Project Scaffold, and you can experiment away as much as you want in F# Interactive!

👉 Get Ionide Extension


Matt Soucoup – VSCodeVim

There’s an old joke that goes: “How do you know if a developer uses vim? They’ll tell you.” Well, I use vim! But… I want more. I want to tell everybody I use vim and I want to use all the great features and extensions that VS Code offers. (I mean, look at the list here!) So that’s where VSCodeVim saves the day for me. It puts a full-featured vim emulator into my VS Code editor, letting me edit files super fast by typing esoteric commands like h, 10 k, i, and u (lots and lots of u) and I still get to use all the awesome features of VS Code.

👉 Get VSCodeVim Extension


John Papa – Docker

If you like it put a container on it. Yeah, containers are the latest craze, but in a constantly evolving containerization world, it’s nice to have great tooling make it easy to use containers. Enter the Docker extension for VS Code. It handles the complete container development and deployment lifecycle! Start by generating docker files to your project, create an image, run it, and even push it to a container registry. If you’re like me, you like to make sure you still have complete control over your code and your app, even when they are inside of containers. Accessing the files, showing logs, and debugging the running container are all essential tools for development. This extension puts all of this within your reach without having to learn the docker command line!

👉 Get Docker Extension


Suz Hinton – Arduino

My favorite extension for VS Code is Arduino. I’m pretty sure anyone who knows me wouldn’t be surprised about that. Traditionally, developing programs for Arduino-compatible micro-controller boards has been done in the Arduino IDE. It’s a powerful program which smooths over the compilation and uploading experiences for dozens of boards. It is, however, not a full code IDE. It’s missing some of the features you love, such as autocomplete, a file tree, and fine-grained tuning of the editor itself.

The good news is that the Arduino extension allows you to finally develop freely for all of your favorite micro-controller boards without leaving VS Code!

Here are some of my favorite things about the extension:

  1. It’s open source! So reporting bugs and contributing improvements is a straightforward experience.
  2. The Command Palette integration is so handy. Compile and upload your code to an Arduino with one simple shortcut.
  3. Access all the great tools from the Arduino IDE right in VS Code. Yes, that even means board / library management and the serial monitor!
  4. Scaffolding brand new Arduino projects is a command away. No more copy + pasting older project directories to get set up.

👉 Get Arduino Extension


Burke Holland – Azure Functions

Serverless is like Hansel — so hot right now. But Serverless shouldn’t be a black box. The Azure Functions extensions for VS Code puts Serverless right inside of the editor. I love it because it lets me create new Serverless projects, new functions for all of the available trigger types (http, timer, blob storage, etc.), and most importantly, I can run them locally and debug them. Not that I would ever need to debug. My code is always perfect.

👉 Get Azure Functions Extension

The post VS Code extensions for the discerning developer palate appeared first on CSS-Tricks.

On Switching Code Editors

I’m sure a lot of you are like me and have switched code editors a number of times. I think my first major editor was Coda. Then I moved to TextMate when I started working primarily on local. Then Sublime Text. And, most recently, VS Code. I bet your journey was different. I know lots of folks that quite love Atom, Brackets, WebStorm, and even BBedit. You do you!

For me, that’s four changes in a dozen years, or a change every three years. Moving isn’t something I do quickly. Here’s a collection of thoughts around the idea of changing editors.

When moving, I have to take time to make sure it works pretty much like the old one.

Otherwise, I’ll just end up disliking it to the point that I switch back a day or two later. It’s happened to me every time I switch. I have little false-starts after a switch where I go back to the old editor because something bugged me too much or it affected my productivity and I gave up. (Now that I know I do this, I don’t let a single false-start make me feel like the editor I’m trying is never a possibility.)

My latest switch was from Sublime Text to VS Code. I’d become become very used to the key bindings (e.g. CMD+Shift+d to duplicate a line) in Sublime Text, so thankfully VS Code has that covered.

I was amazed to find even my VIM friends happy and comfortable in VS Code. (Fun fact: we have key bindings choices in CodePen, too.)

Nothing can be too obnoxious.

In one of my first attempts at switching, I found the UI in VS code to be too cluttered and the find-in-project feature to be a little slow and awkward. Those things bugged me to the point they caused false-starts and I went back to Sublime Text.

On this last switch attempt (my 3rd or 4th maybe?) I finally have a theme I quite like (customized a smidge), found some settings to clean up the UI (I removed the whitespace indicators which were overwhelming to me, and overrode that intense blue footer with something more chill).

In working with find-in-project a bit more, I’ve grown to get used to it. I finally might even like it more than Sublime, as the sidebar approach is more consistent than opening a new tab of results. I find the jump-to-line feature works more consistently and search feels more the first-class citizen it should be.

Another factor would be Emmet. I’m quite sure that I’d be too annoyed writing HTML and CSS in an editor without Emmet, and I’d just give up and use something else that had it. Emmet isn’t even an extension in VS Code, it’s built in.

I’m cool with making small changes after a successful switch.

Once I’ve actually done it, and made the switch to full-time use, then I can make some changes. Maybe I’ll learn some new key commands. Maybe I’ll add an extension that adds functionality I’ve never had before. Maybe the editor affects some workflow thing in a way I’m now willing to try.

The new editor better have some killer feature that incentivizes me to switch.

If it’s exactly the same, why bother?

The new editor needs to be faster (or feel just as fast). Or should look better. Or it should have some awesome package that is only available on it. Ideally all of that.

In this recent switch for me, it was GitLens.

How cool is that?

It ought to have a plugin architecture.

Meaning that anyone can write code to extend the editor. I’m fairly certain that having a plugin architecture (plus a healthy amount of community momentum) is what is key to any editor’s success. Sublime’s package manager, and the subsequent built-in packages feature of VS Code, seem crucial. Not only for functionality but even just for the look of the editor. I wouldn’t use an editor with a look I hate, but I’d be tempted to if the functionality was awesome. That’s a non-issue with a plugin-based editor. Open source seems smart as well.

Careful for those GOTCHAs.

One of those was spell-checking for me. In Sublime Text, it was an option under the View menu. I had it checked all the time, and it spell-checked all the time.

This is not a thing in VS Code. That was dangerous after switching because, who knows, I may have been committing typos all over the place. Fortunately, this extension seems to be doing the trick. Thank jeepers for extensions!

Your thoughts!

I thought it might be interesting to ask what y’all think about when switching code editors. There were lots of responses. I picked out as many as I could here and focused on one thing that you mentioned.

  • Jani Hartikainen cares about VIM key bindings.
  • Morgon wants version control integration.
  • Stu Robson wants it to not crash when you open huge files.
  • Gabriel Vaquer doesn’t want it to be Electron.
  • gryzzly wants it to start up fast.
  • Josh Betz wants a human-readable config file.
  • Dan Finlay wants it to be mouse-free.
  • Frank Spin cares about GitHub stars.
  • Elijah Manor wants it to support extensions.
  • Max Sandelin wants visual git controls.
  • Matt Obee wants speed.
  • Kuldar wants less UI.
  • Devon wants something that his old editor doesn’t have.
  • Brett Jankord wants it to be actively developed.
  • Jordan Koschei wants it to be used by people he trusts.
  • PaulMDev wants night mode.
  • Brad Frost wants reliability.
  • Will Browar wants multiple cursors.
  • Umar Taufiq wants code hinting.
  • Thomas Faller wants community and support.
  • code witch sam wants community engagement.
  • Steve Gardner wants speed.
  • Nathan Knowler is concerned about screen real estate.
  • hearsay wants a live preview.
  • Keith Grant cares about syntax highlighting themes.
  • Mike Reithmuller cares about speed.
  • Nori Code cares about RAM usage.
  • droan cares about ligatures.

The post On Switching Code Editors appeared first on CSS-Tricks.

The peculiar magic of flexbox and auto margins

In front-end development, there are often times when I know that I don’t know something. I might know enough to know what CSS to search for, but I have absolutely no idea how to use it or what the right syntax is. Somehow, in my head, there appears to be a filing cabinet that’s entirely empty, and when I try to look something up, all I find is an almost illegible sticky note instead.

One topic like this (which is an area I’ve sort of always known about but never really understood) is how auto margins and flexbox interact with one another.

Take this example for instance:

.parent { display: flex
} .child { margin: auto;
}

What does this do again? I seem to recall there’s a bunch of nifty things you can do with it, and earlier this week, I half-remembered them after reading a great post by Sam Provenza from a while back that shows how auto-margins and flexbox work together. But I still didn’t quite get the concept even after reading that post, and it wasn’t until I started making demos of my own that it started to click.

In that post, Sam describes how margin: auto impacts flex items like so:

If you apply auto margins to a flex item, that item will automatically extend its specified margin to occupy the extra space in the flex container, depending on the direction in which the auto-margin is applied.

Let’s pick that apart a bit and say we have a simple parent div with a child div inside it:

<div class="parent"> <div class="child"></div>
</div>

And let’s assume we’re using the following CSS to style those divs:

.parent { display: flex; height: 400px; background-color: #222;
} .child { background-color: red; width: 100px; height: 100px;
}

The result is something like this:

See the Pen margin-auto: #1 by Robin Rendle (@robinrendle) on CodePen.

When we add margin-left: auto to the .child element like so:

.child { background-color: red; width: 100px; height: 100px; margin-left: auto;
}

…then we’ll see this instead:

See the Pen margin-auto: #2 by Robin Rendle (@robinrendle) on CodePen.

Weird, huh? The left-hand margin is pushing the parent so that the child is nestled up in the far right-hand corner. But it gets a little weirder when we set all margins to auto:

.child { background-color: red; width: 100px; height: 100px; margin: auto;
}

See the Pen margin-auto: #3 by Robin Rendle (@robinrendle) on CodePen.

It’s like we’re using a popular centering trick by setting justify-content and align-items to center because the child decides to rest in the center of the parent, both horizontally and vertically. Likewise, if we set margin-left and margin-top to auto, then we can let the flex item push itself into the bottom-right of the parent:

See the Pen margin-auto: #4 by Robin Rendle (@robinrendle) on CodePen.

When Sam says, “that item will automatically extend its specified margin to occupy the extra space in the flex container,” the way my empty filing cabinet brain interprets that is like so:

Setting the margin property on a flex child will push the child away from that direction. Set margin-left to auto, the child will push left. Set margin-top to auto and the child will push to the top.

After I write that down, it sounds so obvious to me now that it’s almost foolish but sometimes that’s what it takes to get a new concept to stick in my big dumb spongey noggin.

Why is this useful to know? Well, I think there are a few moments where justify-self or align-self might not get you exactly what you want in a layout where using auto margins gives you that extra flexibility to fine-tune things. A lot of demos I’ve seen out there, including the ones Sam made for her original post, mostly appear to be for aligning navigation items in a menu. So, pushing one item in that menu to the bottom or far right of a flex parent is certainly useful in those scenarios.

Anyway, I think this weird trick is important to remember, just in case.

The post The peculiar magic of flexbox and auto margins appeared first on CSS-Tricks.

Sometimes `sizes` is quite important.

Paraphrased question from email:

I just read your article Responsive Images: If you’re just changing resolutions, use srcset. In the age of “responsive websites,” srcset does not help in certain situations. For example, I have a popular products slider. On mobile, I have one image per slide where the images are 320px wide. On desktop, I have six images per slide where each is 160px wide. So the desktop images are smaller on desktop, not bigger.

How do I handle this situation with srcset?

I tried to be careful with that post title: “If you’re just changing resolutions, use srcset.” In this case, we’re changing the size of the images not just at certain resolutions, but at specific breakpoints as well, which means we’re also going to need to use the sizes attribute to get the most out of responsive images. The entire job of the sizes attribute is to tell the browser what size the image will be shown at, as per our CSS.

A demo! Resize the width to see it alternate between the “Desktop” and “Mobile” views.

See the Pen Responsive Images Slider by Chris Coyier (@chriscoyier) on CodePen.

As the email mentioned, the “Desktop” version actually renders the images smaller (160px) than the “Mobile” version (320px).

Let’s also account for 2x displays. To prepare ourselves, let’s have three versions of each image:

  • 160px (for 1x desktop displays)
  • 320px (for 2x desktop displays, or 1x mobile displays)
  • 640px (for 2x mobile displays)

With srcset, that looks like this:

<img srcset=" food-big.jpg 640w, foot-medium.jpg 320w, food-small.jpg 160w"
/>

Notice we’re not yet using the sizes attribute. Browsers will assume you’re probably going to render this image at 100vw wide. That’s unfortunate because the browser may download a larger image than it needs, which is what we’re trying to fight against with responsive images in the first place.

On my 2x desktop display, I can tell it’s downloading the 640px version, but it really only needs the 320px version.

It’s our CSS that controls how big these images render. In fact, we have a media query in this demo that says, “Hey browser, only render the images at 160px wide on Desktop displays.”

@media (min-width: 600px) { .slider img { width: 160px; }
}

You’d think the browser would know that, and it does — it just needs to download and parse the CSS first. The browser wants to make a decision about what to download faster than that. So, let’s tell it with the sizes attribute.

<img srcset=" food-big.jpg 640w, foot-medium.jpg 320w, food-small.jpg 160w" sizes="(min-width: 600px) 160px, 320px"
/>

That’s saying, “OK, we’ll be rendering this image 160px wide on Desktop. Otherwise, let’s go with 320px wide.” With that in place, we can see the browser is making the right choice:

The browser is now only choosing to download the 320px version, which is correct on a 2x display where the images are being rendered at 160px.

And just to be sure, here’s a narrow viewport (like “mobile” would be):

We’re back to downloading the 640px version, which is correct, since at this viewport size, the sizes attribute is telling the browser we intend to render at 320px and we’re on a 2x display.

There is even more nuance here

I showed this demo to Eric “Sizes Master” Portis, who confirmed all this, but had some browser-specific things to add. I’ll summarize (but note the date of this blog post because these things tend to change):

  • Firefox does exactly as described above.
  • Chrome does too, except that it will always use the larger version if it has that version in cache. So, if it has a 640px version in cache, it knows it really only needs a 320px version, but since it doesn’t have a 320px version in cache, it’ll use the 640px version instead.
  • Safari does too, except that after it has made its choice, it never changes (like if you resize the browser window).
  • An interesting part about srcset is that the spec allows it to make choices however it wants, perhaps using stuff like network conditions to decide. Most browsers don’t do anything like this yet, except Chrome which downloads the smallest resource should it get a Save-Data header on the HTML document.
  • Joe McGill also noted: “For older iOS devices that don’t support w descriptors in srcset, the first source item in the list will be used, so you may want to lead with your preferred default size if you’re supporting legacy iOS devices.” In other words, those older iOS devices may have supported earlier syntaxes of responsive images, but only with x descriptor (like big-image.jpg 2x), so perhaps specify a good default image as the first in your srcset.

It might be helpful to look at Eric’s fork to more easily see what gets downloaded:

See the Pen Responsive Images Slider by Eric Portis (@eeeps) on CodePen.

Random notes

  • I snagged those food photos from Unsplash.
  • I uploaded them to Cloudinary so that I could use URL params to resize them instead of having to deal with that myself.
  • They are all squares, not because I downloaded them like that, but because I sized them that way in CSS and prevented squishing with object-fit. That means image data is being downloaded that isn’t needed, so I either should have cropped them myself or used Cloudinary URL params to do that.
  • I used the Pug HTML preprocessor for my demo just to reduce code repetition.

This is easier to look at:

img(srcset=` ${img_base}w_640${img_1} 640w, ${img_base}w_320${img_1} 320w, ${img_base}w_160${img_1} 160w,
` sizes=sizes)

…than the output:

<img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/robin-stickel-82145-unsplash_qnexwz.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/><img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/cel-lisboa-60315-unsplash_qsji9j.jpg.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/><img srcset=" https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_640/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg 640w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_320/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg 320w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,f_auto,q_auto,w_160/v1531407936/charles-deluvio-466056-unsplash_ocd3dh.jpg.jpg 160w, " sizes="(min-width: 600px) 160px, 320px"/>

The post Sometimes `sizes` is quite important. appeared first on CSS-Tricks.