CSS and Network Performance

JavaScript and images tend to get the bulk of the blame for slow websites, but Harry explains very clearly why CSS is equally to blame and harder to deal with:

  1. A browser can’t render a page until it has built the Render Tree;
  2. the Render Tree is the combined result of the DOM and the CSSOM;
  3. the DOM is HTML plus any blocking JavaScript that needs to act upon it;
  4. the CSSOM is all CSS rules applied against the DOM;
  5. it’s easy to make JavaScript non-blocking with async and defer
    attributes;
  6. making CSS asynchronous is much more difficult;
  7. so a good rule of thumb to remember is that your page will only render as quickly as your slowest stylesheet.

There are lots of options to do better with this, including some interesting things that HTTP/2 unlocks.

Check out Šime Vidas’s takeaways as well. It’s all fascinating, but the progressive rendering stuff is particularly cool. I suspect many CSS-in-JS libraries could/should help with doing things this way.

Direct Link to ArticlePermalink

The post CSS and Network Performance appeared first on CSS-Tricks.

Why Browsers Download Stylesheets with Non-Matching Media Queries

Say you have a stylesheet linked up like this:

<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">

But as the page loads, you’re on a desktop browser where the screen is 1753px wide. The browser should just skip loading that stylesheet entirely, right? It doesn’t. Thomas Steiner explains:

it turns out that the CSS spec writers and browser implementors are actually pretty darn smart about this:

The thing is, the user could always decide to resize their window (impacting width, height, aspect ratio), to print the document, etc., and even things that at first sight seem static (like the resolution) can change when a user with a multi-screen setup moves a window from say a Retina laptop screen to a bigger desktop monitor, or the user can unplug their mouse, and so on.

What browsers do do (heh, 💩) is apply a Lowest download priority.

Direct Link to ArticlePermalink

The post Why Browsers Download Stylesheets with Non-Matching Media Queries appeared first on CSS-Tricks.

How we made Carousell’s mobile web experience 3x faster

Both a sobering and interesting read from Stacey Tay on how the team at Carousell gathered the metrics to define a performance budget and, in turn, developed a better experience for their customers:

Our new PWA listing page loads 3x faster than our old listing page. After releasing this new page, we’ve had a 63% increase in organic traffic from Indonesia, compared to our our all time-high week. Over a 3 week period, we also saw a 3x increase in ads click-through-rates and a 46% increase in anonymous users who initiated a chat on the listing page.

The team inlined critical CSS, reduced the number of resources the app was loading, and implemented a lazy loading strategy, among many other things. I think it’s interesting to note that they also changed the design of the app in certain ways to make things more performant, too. I reckon it’s easy to fall into the trap of thinking that performance is solely a task for developers and posts like this prove that it’s more collaborative than that.

Direct Link to ArticlePermalink

The post How we made Carousell’s mobile web experience 3x faster appeared first on CSS-Tricks.

The “Developer Experience” Bait-and-Switch

Alex Russell describes his thoughts on the current state of JavaScript and how we might sometimes put a ton of focus on the ease-of-use of development at the expense of user experience. So, for example, we might pick a massive framework to make development easier and faster but then that might have an enormous impact on the user.

Alex describes it as substituting “developer value for user value.”

The “developer experience” bait-and-switch works by appealing to the listener’s parochial interests as developers or managers, claiming supremacy in one category in order to remove others from the conversation. The swap is executed by implying that by making things better for developers, users will eventually benefit equivalently. The unstated agreement is that developers share all of the same goals with the same intensity as end users and even managers. This is not true.

Here’s the kicker, though:

JavaScript is the web’s CO2. We need some of it, but too much puts the entire ecosystem at risk. Those who emit the most are furthest from suffering the consequences — until the ecosystem collapses. The web will not succeed in the markets and form-factors where computing is headed unless we get JS emissions under control.

By that standard, it could also stand to reason that the work we put into “design systems” falls into this trap. But there is something to be said about achieving ease of use on this front: a more consistent codebase is probably a very good thing for accessibility, UX consistency, etc. etc.

So, although I agree with Alex’s premise here, I’m not entirely sure I agree wholeheartedly on this subject.

Direct Link to Article — Permalink

The post The “Developer Experience” Bait-and-Switch appeared first on CSS-Tricks.

The Complete Guide to Lazy Loading Images

Images are critical. Whether it is marketing banners, product images or logos, it is impossible to imagine a website without images. Sadly though, images are often heavy files making them the single biggest contributor to the page bloat. According the HTTP Archive’s State of Images report, the median page size on desktops is 1511 KB and images account for nearly 45% (650 KB) of that total.

That said, it’s not like we can simply do away with images. They’re too important to the overall user experience. Instead, we need to make our web pages load really fast with them. In this guide, we will cover all of the ins and outs of lazy loading images, a technique that helps improve the time it takes for a web page to load by deferring image loads until they are needed.

Before we dive right in, here is a sample video that demonstrates the concept. In short, a gray placeholder box is rendered on the page until it scrolls into view—at which point the actual image loads in place of the box.

Chapter 1: What is Lazy Loading?

We often associate the word “lazy” with avoiding work as long as possible, or the sheer act of wanting to do nothing at all.

Similarly, lazy loading defers the loading of resources on the page as long as they are not needed. Instead of loading them right away, which is what normally happens, we allow them to load later.

Lazy Loading is a set of techniques in web and application development that defers the loading of resources on a page to a later point in time—when those resources are actually needed instead of loading them up front. These techniques help in improving performance, better utilization of the device’s resources and reducing associated costs.

The technique of lazy loading can be applied to just about any resources on a page. For example, even a JavaScript file can be held back if it is best not to load it initially. Same deal for an image—load it when we need it.

We will stick to lazy loading images in this guide, but it’s good to know it can be applied to other assets.

Chapter 2: Why Lazy Load at All?

If the user never scrolls to the point of the page that contains the image, then the user will never see that image. It also never loads in the first place because, hey, it was never needed.

You may already start to see how this benefits both you and the user. Here are two of the advantages we get with lazy loading.

Performance Gains

The obvious benefit is that we get smaller web pages that load faster. Lazy loading reduces the number of images that need to be loaded on a page up front. Fewer image requests mean fewer bytes to download. And fewer bytes to download means the page renders faster than if those bytes and requests were being made.

This ensures that any device on any network is able to download and process the remaining resources much faster. Hence, the time from request to render becomes smaller and the page becomes usable much earlier. Win-win!

Cost reduction

The second benefit is for you as a website administrator. Cloud hosting services, like Content Delivery Networks (CDNs) or web servers or storages, deliver images (or any asset for that matter) at a cost based on the number of bytes transferred. A lazy loaded image may never get loaded if the user never reaches it. Thus, you may reduce the total bytes delivered on the page and ultimately save yourself a few pennies in the process. This is especially true for users that instantly bounce off a page or interact only with the top portion of the content.

The reduction in bytes transferred from your delivery network or server reduces delivery costs. This will become more apparent as we explore lazy loading in the coming sections.

Just how much will you save? You can find out which images are a candidate for lazy loading and how many bytes you can save on the initial page load by using the Google Lighthouse audit tool. This has a section dedicated for offscreen images. You can also use ImageKit’s website analyzer to identify if your website uses lazy loading or not apart from other critical image related optimizations on your page.

Lazy loading is critical not only to good performance but also to deliver a good user experience. Since combining performance and user experience with lazy loading is important and challenging, we will continue to address this topic in more detail throughout this guide after we have looked at different ways to lazy load images.

Chapter 3: Lazy Loading Techniques for Images

There are two common ways that we load images to a page: the <img> tag and the CSS background-image property. We will first look at the more common of the two, the <img> tag and then move to CSS background images.

Lazy loading images in an image tag

Let’s start with the typical HTML markup for an image:

<img src="/path/to/some/image.jpg" />

The markup for lazy loading images is pretty similar.

Step one is to prevent the image load up front. The browser uses the src attribute of the tag to trigger the image load. It doesn’t matter if it is the first or the 1,000th image in your HTML. If the browser gets the src attribute, it will trigger the image to be downloaded, regardless of whether it is in or out of current view.

To defer the load, put the image URL in an attribute other than src. Let’s say we specify the image URL in the data-src attribute of the image tag. Now that src is empty and the browser won’t trigger the image load:

<img data-src="https://ik.imagekit.io/demo/default-image.jpg" />

Now that we’re preventing the image from loading, we need to tell the browser when to load it. Otherwise, it will never happen. For this, we check that as soon as the image (i.e. its placeholder) enters the viewport, we trigger the load.

There are two ways to check when an image enters the viewport. Let’s look at both of them with working code samples.

Method 1: Trigger the image load using Javascript events

This technique uses event listeners on the scroll, resize and orientationChange events in the browser. The scroll event is pretty clear cut because it watches where the user is on a page as scrolling occurs. The resize and orientationChange events are equally important. The resize event occurs when the browser window size changes, whereas orientationChange gets triggered when the device is rotated from landscape to portrait, or vice versa.

We can use these three events to recognize a change in the screen and determine the number of images that become visible on the screen and trigger them to load accordingly.

When any of these events occur, we find all the images on the page that are deferred and, from these images, we check which ones are currently in the viewport. This is done using an image’s top offset, the current document top position, and window height. If an image has entered the viewport, we pick the URL from the data-src attribute and move it to the src attribute and the image will load as a result.

Note that we will ask JavaScript to select images that contain a lazy class. Once the image has loaded, we’ll remove the class because it no longer needs to trigger an event. And, once all the images are loaded, we remove the event listeners as well.

When we scroll, the scroll event triggers multiple times rapidly. Thus, for performance, we are adding a small timeout to our script that throttles the lazy loading function execution so it doesn’t block other tasks running in the same thread in the browser.

Here is a working example of this approach.

See the Pen Lazy loading images using event handlers – example code by ImageKit.io (@imagekit_io) on CodePen.

Note that the first three images in this example are loaded up front. The URL is present directly in the src attribute instead of the data-src attribute. This is essential for a good user experience. Since these images are at the top of the page, they should be made visible as soon as possible. There’s no need to wait for JavaScript to load them.

Method 2: Trigger the image load using the Intersection Observer API

The Intersection Observer API is relatively new. It makes it simple to detect when an element enters the viewport and take an action when it does. In the previous method, we had to bind events, keep performance in mind and implement a way to calculate if the element was in the viewport or not. The Intersection Observer API removes all that overhead by avoiding the math and delivering great performance out of the box.

Below is an example using the API to lazy load images. We attach the observer on all the images to be lazy loaded. Once the API detects that the element has entered the viewport, using the isIntersecting property, we pick the URL from the data-src attribute and move it to the src attribute for the browser to trigger the image load. Once this is done, we remove the lazy class from the image and also remove the observer from that image.

See the Pen Lazy loading images using IntersectionObserver – example code by ImageKit.io (@imagekit_io) on CodePen.

If you compare the image loading times for the two methods (event listeners vs. Intersection Observer), you will find that images load much faster using the Intersection Observer API and that the action is triggered quicker as well— and yet the site doesn’t appear sluggish at all, even in the process of scrolling. In the method involving event listeners, we had to add a timeout to make it performant, which has a slightly negative impact on the user experience as the image load is triggered with a slight delay.

However, like any new feature, the support for Intersection Observer API is not available across all browsers.

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
58 45 55 No 16 No

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
No 46 No 67 69 62

So, we need to fall back to the event listener method in browsers where the Intersection Observer API is not supported. We have taken this into account in the example above.

Chapter 4: Lazy Loading CSS Background Images

A common background image in CSS:

.my-class { background-image: url('/path/to/some/image.jpg'); /* more styles */
}

CSS background images are not as straightforward as the image tag. To load them, the browser needs to build the Lazy Loading background images in CSS by ImageKit.io (@imagekit_io) on CodePen.

One thing to note here is that the JavaScript code for lazy loading is still the same. We are still using the Intersection Observer API method with a fallback to the event listeners. The “trick” lies in the CSS.

We have an element with ID bg-image that has a background-image. However, when we add the lazy class to the element, we can override the background-image property by setting the value of it to none in the CSS.

Since an element with an ID and a class has higher specificity in CSS than an ID alone, the browser applies the property background-image: none to the element initially. When we scroll down, the Intersection Observer API (or event listeners, depending on which method you choose) detects that the image is in the viewport, it removes the lazy class from the element. This changes the applicable CSS and applies the actual background-image property to the element, triggering the load of the background image.

Chapter 5: Creating a Better User Experience With Lazy Loading

Lazy loading presents a great performance benefit. For an e-commerce company that loads hundreds of product images on a page, lazy loading can provide a significant improvement in initial page loads while decreasing bandwidth consumption.

However, a lot of companies do not opt for lazy loading because they believe it goes against delivering a great user experience (i.e. the initial placeholder is ugly, the load times are slow etc.).

In this section, we will try to solve some concerns around user experience with lazy loading of images.

Tip 1. Use the Right Placeholder

A placeholder is what appears in the container until the actual image is loaded. Normally, we see developers using a solid color placeholder for images or a single image as a placeholder for all images.

The examples we’ve looked at so far have used a similar approach: a box with a solid light gray background. However, we can do better to provide a more pleasing user experience. Below are some two examples of using better placeholders for our images.

Dominant Color Placeholder

Instead of using a fixed color for the image placeholder, we find the dominant color from the original image and use that as a placeholder. This technique has been used for quite some time by Google in its image search results as well as by Pinterest in its grid design.

Pinterest uses the dominant color of the image as the background color for image placeholders. (Source)

This might look complex to achieve, but Manuel Wieser has an elegant solution to accomplishing this by scaling down the image to down to a 1×1 pixel and then scale it up to the size of the placeholder—a very rough approximation but a simple, no-fuss way to get a single dominant color. Using ImageKit, the dominant color placeholder can be obtained using a chained transform in ImageKit as shown below.

<!-- Original image at 400x300 -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" alt="original image" /> <!-- Dominant color image with same dimensions -->
<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-1,h-1:w-400,h-300" alt="dominant color placeholder" />

The placeholder image is just 661 bytes in size compared to the original image that is 12700 bytes—19x smaller. And it provides a nicer transition experience from placeholder to the actual image.

Here is a video demonstrating how this effect works for the user.

See the Pen Dominant color placeholder – Lazy loading images using IntersectionObserver – example code by ImageKit.io (@imagekit_io) on CodePen.

Low Quality Image Placeholder (LQIP)

We can extend the above idea of using a dominant color placeholder further. Instead of using a single color, we use a very low-quality, blurred version of the original image as the placeholder. Not only does it look good, but it also gives the user some idea about what the actual image looks like and the perception that the image load is in progress. This is great for improving the perceived loading experience. This technique has been utilized by the likes of Facebook and Medium.

LQIP image URL example using ImageKit:

<!-- Original image at 400x300 --> <img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300" alt="original image" /> <!-- Low quality image placeholder with same dimensions --> <img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300,bl-30,q-50" alt="dominant color placeholder" />

The LQIP is 1300 bytes in size, still almost 10x smaller than the original image and a significant improvement in terms of visual experience over any other placeholder technique.

Here is a video demonstrating how this effect works for the user.

See the Pen LQIP placeholder – Lazy loading images using IntersectionObserver – example code by ImageKit.io (@imagekit_io) on CodePen.


It is clear that using either dominant color or LQIP placeholders provides a smoother transition from the placeholder to the actual image, gives the user an idea of what is to come in place of that placeholder, and improves loading perception.

Tip 2: Add Buffer Time for Images to Load

When we discussed different methods to trigger image loads, we checked for the point of time where the image enters the viewport, i.e. the image load is triggered when the top edge of the image placeholder coincides with the bottom edge of the viewport.

The problem with this is that users might scroll really fast through the page and the image will need some time to load and appear on the screen. Combined with throttling possibly further delaying the load, the user may wind up waiting a few milliseconds longer for the image to show up. Not great for user experience!

While we can get a pretty good user experience using the Intersection Observer API for performance and LQIP for smoother transitions, there is another simple trick that you can use to ensure that the images are always loaded completely when they enter the viewport : introduce a margin to the trigger point for images.

Instead of loading the image exactly when it enters the viewport, load it when it’s, let’s say, 500px before it enters the viewport. This provides additional time, between the load trigger and the actual entry in the viewport, for the images to load.

With the Intersection Observer API, you can use the root parameter along with the rootMargin parameter (works as standard CSS margin rule), to increase the effective bounding box that is considered to find the intersection. With the event listener method, instead of checking for the difference between the image edge and the viewport edge to be 0, we can use a positive number to add some threshold.

See the Pen Lazy loading images with additional threshold – example code by ImageKit.io (@imagekit_io) on CodePen.

If you watch the following screencast closely, you’ll notice that the fifth image in the sequence is loaded when the third image is in view. Similarly, the sixth image is loaded when the fourth is in view, and so on. This way, we are giving sufficient time for the images to load completely and, in most cases, the user won’t see the placeholder at all.

If you didn’t notice earlier, in all our examples, the third image (image3.jpg) is always loaded up front, even though it is outside the viewport. This was also done following the same principal:  load slightly in advance instead of loading exactly at the threshold for better user experience.

Tip 3: Avoid Content Reflow

This is another trivial point, which if solved, can help maintain a good user experience.

When there is no image, the browser doesn’t know the size it will take up. And if we do not specify it using CSS, then the enclosing container would have no dimensions, i.e. it will be read as 0x0 pixels.

When the image loads, the browser will drop it into the screen and reflow the content to fit it. This sudden change in the layout causes other elements to move around and it is called content reflow, or shifting. Michael Scharnagl goes into great depth explaining how this creates an unpleasant user experience.

This can be avoided by specifying a height and/or width for the enclosing container so that the browser can paint the image container with a known height and width. Later, when the image loads, since the container size is already specified and the image fits into that perfectly, the rest of the content around that container does not move.

Tip 4: Avoid Lazy Loading Every Image

This is a mistake that developers often make because it’s super tempting to think that deferring image loads is good all the time. But, like life itself, it is possible to have too much of a good thing. Lazy loading might reduce the initial page load, but it also might result in a bad user experience if some images are deferred when they should not be.

We can follow some general principles to identify which images should be lazy loaded. For example, any image that is present in the viewport, or at the beginning of the webpage, should probably not be lazy loaded. This applies to any header image, marketing banner, logos, or really anything that the user would see when initially landing on a page. Also, remember that mobile and desktop devices will have different screen sizes and hence a different number of images that will be visible on the screen initially. You’ll want to take the device that’s being used into account and decide which resources to load up front and which to lazy load.

Another example is any image that is even slightly off the viewport in the initial load should not probably not be lazy loaded. This is going by the principle discussed above—load slightly in advance. So, let’s say any image that is 500px or a single scroll from the bottom of the viewport can be loaded up front as well.

One more example is if the page is short. It may be just a single scroll or a couple of scrolls, or perhaps there are less than five images outside the viewport. In these cases, you can probably leave lazy loading out altogether. It would not provide any significant benefit to the end user in terms of performance and the additional JavaScript that you load on the page to enable lazy loading will offset any potential gain you get from it.

Chapter 5: Lazy Loading’s Dependency on JavaScript

The entire idea of lazy loading is dependent on JavaScript being enabled and available in the user’s browser. While most of your users will likely have JavaScript enabled, it is essential to plan for cases where it is not.

You could either show a message telling users why the images won’t load and encourage them to either use a modern browser or enable JavaScript.

Another route is to use the noscript tag. However, this approach comes with some gotchas. This question thread on Stack Overflow does a great job addressing these concerns and is a recommended read for anyone looking to address this set of users.

Chapter 6: Popular JavaScript Libraries for Lazy Loading

Since environments and implementation details can vary across browsers and devices, you might want to consider a tried and tested library for lazy loading rather than spinning something up from scratch.

Here is a list of popular libraries and platform specific plugins that will allow you to implement lazy loading with minimal effort:

  • Yet Another Lazy Loader: This library uses the Intersection Observer API and falls back to event-based lazy loading for browsers that do not yet support it. This is great for just about any HTML element but unfortunately does not work on background images in CSS. The good news is that it supports IE back to version 11.
  • lazysizes: This is a very popular library with extensive functionality. It includes support for responsive image srcset and sizes attributes and provides superb performance even though it does not make use of the Intersection Observer API.
  • WordPress A3 Lazy Load: There are plenty of lazy loading WordPress plugins out there, but this one comes with a robust set of features, including a fallback when JavaScript is unavailable.
  • jQuery Lazy: A simple library that uses a jQuery implementation.
  • WeltPixel Lazy Loading Enhanced: A Magento 2 extension.
  • Magento Lazy Image Loader: Another Magento extension, for 1.x.
  • Shopify Lazy Image Plugin (paid): Enable lazy loading on a Shopify site.

Chapter 7: Testing Lazy Load

Once you have implemented lazy loading, you will likely want to check that it’s working as intended. The simplest way would be to open up the developer tools in your browser.

From there, go to Network > Images. When you refresh the page for the first time, you should only see loaded images in the list.

Then, as you start scrolling down the page, other image load requests would get triggered and loaded. You can also notice the timings for image load in the waterfall column in this view. It would help you identify image loading issues if any or issues in triggering the image load.

Another way would be to run the Google Chrome Lighthouse audit report on your page after you have implemented the changes and look for suggestions under the “Offscreen images” section.

Conclusion

We have covered a lot of ground about lazy loading images! Lazy loading—if implemented well—can have significant benefits on your site’s performance the loading performance while reducing the overall page size and delivery costs, thanks to deferring unnecessary resources up front.

So, what are you waiting for? Get started with lazy loading images now!

The post The Complete Guide to Lazy Loading Images appeared first on CSS-Tricks.

The Low Hanging Fruit of Web Performance

I kicked off a really poppin’ Twitter thread the other day:

So, I decided to round up all the ideas (both my own and yours) around that in a post over on the Media Temple blog.

These are the things we dive into in that post:

  1. Reduce Requests
  2. Optimize Assets
  3. Make sure you’re gzipping
  4. Make sure you’re browser caching
  5. Use a CDN
  6. Lazy Load and Defer Loading of Things
  7. Use responsive images (or at least use reasonable sizes)
  8. Mind Your Fonts
  9. Good Hosting / HTTP2 / PHP7
  10. Turbolinks

Direct Link to Article — Permalink

The post The Low Hanging Fruit of Web Performance 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.

The web can be anything we want it to be

I really enjoyed this chat between Bruce Lawson and Mustafa Kurtuldu where they talked about browser support and the health of the web. Bruce expands upon a lot of the thoughts in a post he wrote last year called World Wide Web, Not Wealthy Western Web where he writes:

…across the world, regardless of disposable income, regardless of hardware or network speed, people want to consume the same kinds of goods and services. And if your websites are made for the whole world, not just the wealthy Western world, then the next 4 billion people might consume the stuff that your organization makes.

Another highlight is where Bruce also mentions that, as web developers, we might think that we’ve all moved on from jQuery as a community, and yet there are still millions of websites that depend upon jQuery to function properly. It’s an interesting anecdote and relevant to recent discussions about React making a run at being the next thing to replace jQuery:

However! The most interesting part of this particular discussion, for me at least, is where they talk about Flash and the impact it had on the design of CSS3 and HTML5. They both argue that despite Flash’s shortcomings and accessibility issues, it happened to show us all that the web can be much more than just a place to store some hypertext and that ultimately it can be anything we want it to be.

Direct Link to Article — Permalink

The post The web can be anything we want it to be appeared first on CSS-Tricks.

Hey hey `font-display`

Y’all know about font-display? It’s pretty great. It’s a CSS property that you can use within @font-face blocks to control how, visually, that font loads. Font loading is really pretty damn complicated. Here’s a guide from Zach Leatherman to prove it, which includes over 10 font loading strategies, including strategies that involve critical inline CSS of subsets of fonts combined with loading the rest of the fonts later through JavaScript. It ain’t no walk in the park.

Using font-display is kinda like a walk in the park though. It’s just a single line of CSS. It doesn’t solve everything that Zach’s more exotic demos do, but it can go a long way with that one line. It’s notable to bring up right now, as support has improved a lot lately. It’s now in Firefox 58+, Chrome 60+, Safari 11.1+, iOS 11.3+, and Chrome on Android 64+. Pretty good.

What do you get from it? The ability to control font-display for the Masses by Jeremy Wagner

  • If you really dislike FOUT, font-display: optional might be your jam by me
  • Reminder:

    FOUT = Flash of Unstyled Text
    FOIT = Flash of Invisible Text

    Neither is great. In a perfect world, our custom fonts just show up immediately. But since that’s not a practical possibility, we pick based on our priorities.

    The best resource out there about it is Monica Dinculescu’s explainer page:

    i’d summarize those values choices like this:

    • If you’re OK with FOUT, you’re probably best off with font-display: swap; which will display a fallback font fairly fast, but swap in your custom font when it loads.
    • If you’re OK with FOIT, you’re probably best off with font-display: block; which is fairly similar to current browser behavior, where it shows nothing as it waits for the custom font, but will eventually fall back.
    • If you only want the custom font to show at all if it’s there immediately, font-display: optional; is what you want. It’ll still load in the background and be there next page load probably.

    Those are some pretty decent options for a single line of CSS. But again, remember if you’re running a major text-heavy site with custom fonts, Zach’s guide can help you do more.

    I’d almost go out on a limb and say: every @font-face block out there should have a font-display property. With the only caveat being you’re doing something exotic and for some reason want the browser default behavior.

    Wanna hear something quite unfortunate? We already mentioned font-display: block;. Wouldn’t you think it, uh, well, blocked the rendering of text until the custom font loads? It doesn’t. It’s still got a swap period. It would be the perfect thing for something like icon fonts where the icon (probably) has no meaning unless the custom font loads. Alas, there is no font-display solution for that.

    And, hey gosh, wouldn’t it be nice if Google Fonts allowed us to use it?

    The post Hey hey `font-display` appeared first on CSS-Tricks.