20 Tips for Optimizing CSS Performance

Craig Buckler
Craig Buckler
Share
In this article, we look at 20 ways to optimize your CSS so that it’s faster-loading, easier to work with and more efficient.
According to the latest HTTP Archive reports, the web remains a bloated mess with the mythical median website requiring 1,700Kb of data split over 80 HTTP requests and taking 17 seconds to fully load on a mobile device. The Complete Guide to Reducing Page Weight provides a range of suggestions. In this article, we’ll concentrate on CSS. Admittedly, CSS is rarely the worst culprit and a typical site uses 40KB spread over five stylesheets. That said, there are still optimizations you can make, and ways to change how we use CSS that will boost site performance.

1. Learn to Use Analysis Tools

You can’t address performance problems unless you know where the faults lie. Browser DevTools are the best place to start: launch from the menu or hit F12, Ctrl
+ Shift + I or Cmd + Alt + I
for Safari on macOS. All browsers offer similar facilities, and the tools will open slowly on badly-performing pages! However, the most useful tabs include the following … The Network tab displays a waterfall graph of assets as they download. For best results, disable the cache and consider throttling to a lower network speed. Look for files that are slow to download or block others. The browser normally blocks browser rendering while CSS and JavaScript files download and parse. The Performance tab analyses browser processes. Start recording, run an activity such as a page reload, then stop recording to view the results. Look for:
  1. Excessive layout/reflow actions where the browser has been forced to recalculate the position and size of page elements.
  2. Expensive paint actions where pixels are changed.
  3. Compositing actions where the painted parts of the page are put together for displaying on-screen. This is normally the least processor-intensive action.
Chrome-based browsers provide an Audits tab which runs Google’s Lighthouse tool
. It’s often used by Progressive Web App developers, but also makes CSS performance suggestions.

Online Options

Alternatively, use online analysis tools that are not influenced by the speed and capabilities of your device and network. Most can test from alternative locations around the world:

2. Make Big Wins First

CSS is unlikely to be the direct cause of performance issues. However, it may load heavy-hitting assets which can be optimized within minutes. Examples:
  • Activate HTTP/2 and GZIP compression on your server
  • Use a content delivery network (CDN) to increase the number of simultaneous HTTP connections and replicate files to other locations around the world
  • Remove unused files.
Images are normally the biggest cause of page bulk, yet many sites fail to optimize effectively:
  1. Resize bitmap images. An entry-level smartphone will take multi-megapixel images that can’t be displayed in full on the largest HD screen. Few sites will require images of more than 1,600 pixels in width.
  2. Ensure you use an appropriate file format. Typically, JPG is best for photographs, SVG for vector images, and PNG for everything else. You can experiment to find the optimum type.
  3. Use image tools to reduce file sizes by striping metadata and increasing compression factors.
That said, be aware that xKb of image data is not equivalent to xKb of CSS code. Binary images download in parallel and require little processing to place on a page. CSS blocks rendering and must be parsed into an object model before the browser can continue.

3. Replace Images with CSS Effects

It’s rarely necessary to use background images for borders, shadows, rounded edges, gradients and some geometric shapes. Defining an “image” using CSS code uses considerably less bandwidth and is easier to modify or animate later.

4. Remove Unnecessary Fonts

Services such as Google Fonts make it easy to add custom fonts to any page. Unfortunately, a line or two of code can retrieve hundreds of kilobytes of font data. Recommendations:
  1. Only use the fonts you need.
  2. Only load the weights and styles you require — for example, roman, 400 weight, no italics.
  3. Where possible, limit the character sets. Google fonts allows you to pick certain characters by adding a &text= value to the font URL — such as fonts.googleapis.com/css?family=Open+Sans&text=SitePon for displaying “SitePoint” in Open Sans.
  4. Consider variable fonts, which define multiple weights and styles by interpolation so files are smaller. Support is currently limited to Chrome, Edge, and some editions of Safari but should grow rapidly. See How to Use Variable Fonts.
  5. Consider OS fonts. Your 500Kb web font may be on-brand, but would anyone notice if you switched to the commonly available Helvetica or Arial? Many sites use custom web fonts, so standard OS fonts are considerably less common than they were!

5. Avoid @import

The @import at-rule allows any CSS file to be included within another. For example:
/* main.css */
@import url("base.css");
@import url("layout.css");
@import url("carousel.css");
This appears a reasonable way to load smaller components and fonts. It’s not. @import rules can be nested so the browser must load and parse each file in series. Multiple <link> tags within the HTML will load CSS files in parallel, which is considerably more efficient — especially when using HTTP/2:
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="layout.css">
<link rel="stylesheet" href="carousel.css">
That said, there may be more preferable options …

6. Concatenate and Minify

Most build tools allow you to combine all partials into one large CSS file that has unnecessary whitespace, comments and characters removed. Concatenation is less necessary with HTTP/2, which pipelines and multiplexes requests. In some cases, separate files may be beneficial if you have smaller, regularly-changing CSS assets. However, most sites are likely to benefit from sending a single file that is immediately cached by the browser. Minification may not bring considerable benefits when you have GZIP enabled. That said, there’s no real downside. Finally, you could consider a build process that orders properties consistently within declarations. GZIP can maximize compression when commonly used strings are used throughout a file.

7. Use Modern Layout Techniques

For many years it was necessary to use CSS float to lay out pages. The technique is a hack. It requires lots of code and margin/padding tweaking to ensure layouts work. Even then, floats will break at smaller screen sizes unless media queries are added. The modern alternatives:
  • CSS Flexbox for one-dimensional layouts which (can) wrap to the next row according to the widths of each block. Flexbox is ideal for menus, image galleries, cards, etc.
  • CSS Grid for two-dimensional layouts with explicit rows and columns. Grid is ideal for page layouts.
Both options are simpler to develop, use less code, can adapt to any screen size, and render faster than floats because the browser can natively determine the optimum layout.

8. Reduce CSS Code

The most reliable and fastest code is the code you need never write! The smaller your stylesheet, the quicker it will download and parse. All developers start with good intentions, but CSS can bloat over time as the feature count increases. It’s easier to retain old, unnecessary code rather than remove it and risk breaking something. A few recommendations to consider:
  • Be wary of large CSS frameworks. You’re unlikely to use a large percentage of the styles, so only add modules as you need them.
  • Organize CSS into smaller files (partials) with clear responsibilities. It’s easier to remove a carousel widget if the CSS is clearly defined in widgets/_carousel.css.
  • Consider naming methodologies such as BEM to aid the development of discrete components.
  • Avoid deeply nested Sass/preprocessor declarations. The expanded code can become unexpectedly large.
  • Avoid using !important to override the cascade.
  • Avoid inline styles in HTML.
Tools such as UnCSS can help remove redundant code by analyzing your HTML, but be wary about CSS states caused by JavaScript interaction.

9. Cling to the Cascade!

The rise of CSS-in-JS has allowed developers to avoid the CSS global namespace. Typically, randomly generated class names are created at build time so it becomes impossible for components to conflict. If your life has been improved by CSS-in-JS, then carry on using it. However, it’s worth understanding the benefits of the CSS cascade rather than working against it on every project. For example, you can set default fonts, colors, sizes, tables and form fields that are universally applied to every element in a single place. There is rarely a need to declare every style in every component.

10. Simplify Selectors

Even the most complex CSS selectors take milliseconds to parse, but reducing complexity will reduce file sizes and aid browser parsing. Do you really need this sort of selector?!
body > main.main > section.first h2:nth-of-type(odd) + p::first-line > a[href$=".pdf"]
Again, be wary of deep nesting in preprocessors such as Sass, where complex selectors can be inadvertently created.

11. Be Wary of Expensive Properties

Some properties are slower to render than others. For added jankiness, try placing box shadows on all your elements!
*, ::before, ::after {
  box-shadow: 5px 5px 5px rgba(0,0,0,0.5);
}
Browser performance will vary but, in general, anything which causes a recalculation before painting will be more costly in terms of performance:
  • border-radius
  • box-shadow
  • opacity
  • transform
  • filter
  • position: fixed

12. Adopt CSS Animations

Native CSS transitions and animations will always be faster than JavaScript-powered effects that modify the same properties. CSS animations will not work in older browsers such as IE9 and below, but those users will never know what they’re missing. That said, avoid animation for the sake of it. Subtle effects can enhance the user experience without adversely affecting performance. Excessive animations could slow the browser and cause motion sickness for some users.

13. Avoid Animating Expensive Properties

Animating the dimensions or position of an element can cause the whole page to re-layout on every frame. Performance can be improved if the animation only affects the compositing
stage. The most efficient animations use:
  • opacity and/or
  • transform to translate (move), scale or rotate an element (the original space the element used is not altered).
Browsers often use the hardware-accelerated GPU to render these effects. If neither are ideal, consider taking the element out of the page flow with position: absolute so it can be animated in its own layer.

14. Indicate Which Elements Will Animate

The will-change property allows CSS authors to indicate an element will be animated so the browser can make performance optimizations in advance. For example, to declare that an element will have a transform
applied:
.myelement {
  will-change: transform;
}
Any number of comma-separated properties can be defined. However:
  • use will-change as a last resort to fix performance issues
  • don’t apply it to too many elements
  • give it sufficient time to work: that is, don’t begin animations immediately.

15. Adopt SVG Images

Scalable vector graphics (SVGs) are typically used for logos, charts, icons, and simpler diagrams. Rather than define the color of each pixel like JPG and PNG bitmaps, an SVG defines shapes such as lines, rectangles and circles in XML. For example:
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600">
  <circle cx="400" cy="300" r="50" stroke-width="5" stroke="#f00" fill="#ff0" />
<svg>
Simpler SVGs are smaller than equivalent bitmaps and can infinitely scale without losing definition. An SVG can be inlined directly in CSS code as a background image. This can be ideal for smaller, reusable icons and avoids additional HTTP requests. For example:
.mysvgbackground {
  background: url('data:image/svg+xml;utf8,<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600"><circle cx="400" cy="300" r="50" stroke-width="5" stroke="#f00" fill="#ff0" /></svg>') center center no-repeat;
}

16. Style SVGs with CSS

More typically, SVGs are embedded directly within an HTML document:
<body>
  <svg class="mysvg" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600">
    <circle cx="400" cy="300" r="50" />
  <svg>
</body>
This adds the SVG nodes directly into the DOM. Therefore, all SVG styling attributes can be applied using CSS:
circle {
  stroke-width: 1em;
}

.mysvg {
  stroke-width: 5px;
  stroke: #f00;
  fill: #ff0;
}
The volume of embedded SVG code is reduced and the CSS styles can be reused or animated as necessary. Note that using an SVG within an <img> tag or as a CSS background image means they’re separated from the DOM, and CSS styling will have no effect.

17. Avoid Base64 Bitmap Images

Standard bitmap JPGs, PNGs and GIFs can be encoded to a base64 string within a data URI. For example:
.myimg {
  background-image: url('data:image/png;base64,ABCDEFetc+etc+etc');
}
Unfortunately:
  • base64 encoding is typically 30% larger than its binary equivalent
  • the browser must parse the string before it can be used
  • altering an image invalidates the whole (cached) CSS file.
While fewer HTTP requests are made, it rarely provides a noticeable benefit — especially over HTTP/2 connections. In general, avoid inlining bitmaps unless the image is unlikely to change often and the resulting base64 string is unlikely to exceed a few hundred characters.

18. Consider Critical CSS

Those using Google page analysis tools will often see suggestions to “inline critical CSS” or “reduce render-blocking stylesheets”
. Loading a CSS file blocks rendering, so performance can be improved with the following steps:
  1. Extract the styles used to render elements above the fold. Tools such as criticalCSS can help.
  2. Add those to a <style> element in the HTML <head>.
  3. Load the main CSS file asynchronously using JavaScript (perhaps after the page has loaded).
The technique undoubtedly improves performance and could benefit Progressive Web or single-page apps that have consistent interfaces. Gains may be less clear for other sites/apps:
  • It’s impossible to identify the “fold”, and it changes on every device.
  • Most sites have differing page layouts. Each one could require different critical CSS, so a build tool becomes essential.
  • Dynamic, JavaScript-driven events could make above-the-fold changes that are not identified by critical CSS tools.
  • The technique mostly benefits the user’s first page load. CSS is cached for subsequent pages so additional inlined styles will increase page weight.
That said, Google will love your site and push it to #1 for every search term. (SEO “experts” can quote me on that. Everyone else will know it’s nonsense.)

19. Consider Progressive Rendering

Rather than using a single site-wide CSS file, progressive rendering
is a technique that defines individual stylesheets for separate components. Each is loaded immediately before a component is referenced in the HTML:
<head>

  <!-- core styles used across components -->
  <link rel='stylesheet' href='base.css' />

</head>
<body>

  <!-- header component -->
  <link rel='stylesheet' href='header.css' />
  <header>...</header>

  <!-- primary content -->
  <link rel='stylesheet' href='content.css' />
  <main>

    <!-- form styling -->
    <link rel='stylesheet' href='form.css' />
    <form>...</form>

  </main>

  <!-- header component -->
  <link rel='stylesheet' href='footer.css' />
  <footer>...</footer>

</body>
Each <link> still blocks rendering, but for a shorter time, because the file is smaller. The page is usable sooner, because each component renders in sequence; the top of the page can be viewed while remaining content loads. The technique works in Firefox, Edge and IE. Chrome and Safari “optimize” the experience by loading all CSS files and showing a white screen while that occurs — but that’s no worse than loading each in the <head>. Progressive rendering could benefit large sites where individual pages are constructed from a selection of different components.

20. Learn to Love CSS

The most important tip: understand your stylesheets! Adding vast quantities of CSS from StackOverflow or BootStrap may produce quick results, but it will also bloat your codebase with unused junk. Further customization becomes frustratingly difficult, and the application will never be efficient. CSS is easy to learn but difficult to master. You can’t avoid the technology if you want to create effective client-side code. A little knowledge of CSS basics can revolutionize your workflow, enhance your apps, and noticeably improve performance. Have I missed your favorite CSS performance tip?

Frequently Asked Questions on Optimizing CSS Performance

What are the key factors that affect CSS performance?

CSS performance can be influenced by several factors. The first is the size of your CSS file. Larger files take longer to download and parse, slowing down your website. The second factor is the complexity of your CSS selectors. Complex selectors require more processing power to match elements on the page. Lastly, the use of CSS animations and transitions can also impact performance, especially on mobile devices with limited processing power.

How can I reduce the size of my CSS file to improve performance?

There are several strategies to reduce the size of your CSS file. One is to remove unused styles. Tools like PurifyCSS can help identify and remove unused CSS. Another strategy is to minify your CSS, which removes unnecessary characters like spaces and comments. Lastly, consider using CSS compression tools or enabling GZIP compression on your server to further reduce file size.

How do complex CSS selectors affect performance?

Complex CSS selectors can slow down your website because they require more processing power to match elements on the page. For example, descendant selectors (e.g., .parent .child) are more expensive than class selectors (e.g., .class). As a rule of thumb, try to keep your selectors as simple and specific as possible to improve performance.

What is the impact of CSS animations and transitions on performance?

CSS animations and transitions can significantly impact performance, especially on mobile devices with limited processing power. They can cause layout shifts and repaints, which can slow down your website. To improve performance, consider using the will-change property to inform the browser ahead of time about what properties and elements will be animated.

How can I optimize my CSS for mobile devices?

Optimizing CSS for mobile devices involves several strategies. First, consider using media queries to serve different styles based on device characteristics. Second, avoid complex animations and transitions that can slow down performance on mobile devices. Lastly, consider using responsive images and lazy loading to reduce the amount of data that needs to be downloaded.

What are some tools I can use to measure CSS performance?

There are several tools you can use to measure CSS performance. Google’s Lighthouse and PageSpeed Insights can provide a comprehensive overview of your website’s performance, including CSS. Additionally, the Chrome DevTools Performance panel can help you identify costly CSS and optimize it.

How does CSS impact SEO?

While CSS itself does not directly impact SEO, it can indirectly affect your rankings. Slow-loading websites, often caused by large, unoptimized CSS, can lead to a poor user experience, which can negatively impact your SEO. Additionally, Google considers page speed as a ranking factor, so optimizing your CSS can help improve your SEO.

How can I use CSS preprocessors to improve performance?

CSS preprocessors like Sass and Less can help improve performance by allowing you to write more efficient and maintainable code. They offer features like variables, nesting, and mixins, which can reduce the amount of code you need to write and make it easier to manage.

What is critical CSS and how can it improve performance?

Critical CSS is the minimum amount of blocking CSS required to render the above-the-fold content of a webpage. By identifying and inlining your critical CSS, you can speed up the initial render of your page, improving perceived performance.

How can I optimize CSS delivery?

Optimizing CSS delivery involves several strategies. First, consider inlining small CSS directly into your HTML to avoid additional HTTP requests. Second, defer non-critical CSS to reduce render-blocking resources. Lastly, consider using HTTP/2 to deliver your CSS files more efficiently.