CSS usage

Contents

Overview

CSS controls the website's layout, typography, colours, and responsiveness. Although smaller than JavaScript or images, it has a major performance impact because it is render-blocking, meaning the browser must load and process CSS before displaying content.

Large or poorly structured stylesheets can delay rendering, causing blank screens while the page loads.

This is more pronounced in low-resource environments due to:

  • Slow networks and high latency
  • Low-memory devices
  • Higher relative data costs

A good CSS strategy prioritises critical styles first, allowing content to appear quickly, while deferring non-essential styling. The goal is to balance visual design with fast, reliable access to content.

Why does this matter for LRO?

Because CSS blocks rendering, inefficient stylesheets can cause:

  • Blank screens for several seconds
  • Slow page rendering
  • Higher data usage
  • Increased CPU load
  • Poor usability on low-end devices

For data-heavy platforms like EMBL-EBI's biodata resources, fast content visibility is critical. Users need immediate access to tables, datasets, and key information, even on slow networks or limited devices.

How browsers process CSS?

CSS is part of the Critical Rendering Path. Before content can render, the browser must:

  1. Download the HTML
  2. Build the DOM
  3. Download CSS files
  4. Build the CSSOM
  5. Combine the DOM and CSSOM into a render tree
  6. Calculate layout
  7. Paint the page

Because CSS must be processed before rendering begins, large or inefficient stylesheets delay everything.

Poor CSS Strategy

Large stylesheets block rendering.

A linear flowchart of the browser's standard CSS rendering path, each step leading to the next: HTML download, HTML parsing, CSS requested, download CSS, parse CSS, build CSSOM, create render tree, layout, and finally paint the page. Painting the page is the last step and happens only after the full stylesheet has been downloaded and processed, so no content appears until all CSS is ready.
The standard path: the browser must download and process the entire stylesheet before it can paint, so content only appears once all CSS is ready, leaving users on a blank screen meanwhile.

Result

If CSS files are large or slow to download:

  • The browser must wait
  • Rendering is delayed
  • Users see a blank screen

This effect is especially noticeable on slow networks.

Optimised CSS Strategy

An improved strategy ensures that only the critical styles required for the visible part of the page are loaded first.

Common Problems

Many modern websites unintentionally ship excessive CSS due to frameworks, legacy code, or design system accumulation.

Large Unused Stylesheets

Over time, CSS files often accumulate styles that are no longer used. Browsers still download and process these rules, slowing page rendering.

In many sites, a significant portion of CSS is unused on the current page.

CSS Framework Bloat

Frameworks such as Bootstrap or large utility libraries may include thousands of styles, even if only a small subset is required. e.g:

  • Full CSS framework: 250 KB
  • Styles actually used: 20 KB

This unnecessarily increases download time and processing cost.

Render-Blocking Stylesheets

External CSS files block page rendering until they are fully downloaded and parsed. Large stylesheets can cause users to see a blank or partially rendered page, especially on slow networks.

Example:

<!-- Browser must download and parse this CSS before rendering content -->
<link rel="stylesheet" href="styles.css">

Heavy or render-blocking CSS increases time to first paint, delaying when users can see and interact with content. Optimising CSS—by splitting critical styles, inlining above-the-fold CSS, or using media attributes—improves perceived performance on low-resource devices and slow connections.

Too Many CSS Files

Each stylesheet requires an additional network request. On slow networks, multiple requests significantly increase page load time.

Example:

  • styles.css
  • layout.css
  • theme.css
  • components.css

Complex CSS Selectors

Highly nested or overly complex selectors increase the browser's style calculation cost, slowing rendering—especially on low-end devices. Simpler selectors are faster to match and apply.

Problem Pattern (Inefficient Selector):

/* Highly nested selector increases style calculation work */
div ul li a.button:hover {
  background-color: blue;
  color: white;
}

Optimised Approach (Simple Selector):

/* Single-class selector is simpler and faster for the browser to process */
.button:hover {
  background-color: blue;
  color: white;
}

Using simpler, less specific selectors reduces style computation, improving rendering performance and keeping the UI responsive—critical for low-end devices and constrained environments.

Implementation Guidance

An LRO-friendly CSS strategy focuses on delivering styles efficiently so content appears quickly, even on slow networks.

Core Principles

  • Load only what's needed: Avoid large global stylesheets; load CSS per page or component
  • Prioritise visible content: Ensure above-the-fold styles load first, so users see meaningful information quickly.
  • Keep CSS lightweight: Remove unused rules, minify files, and enable compression
  • Support progressive enhancement: Content should remain readable even if CSS is delayed and should rely on semantic HTML
  • Use modular styles: Organise CSS by component or page for better control and selective loading

Key Optimisation Techniques

Don't embed images or fonts in your CSS code

It's possible to use data URLs and Base64 encoding to embed images and other resources in your CSS code:

background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lv...");

Image files are often large and take more time to download. Normally, they are not render-blocking, but if they are embedded in a stylesheet, they do block rendering, causing content to take longer to appear to users.

With modern front-end tooling, it can be easy to accidentally embed a large image without noticing. CSS Size Analyser can detect embedded resources automatically.

Analyse using the CSS Size Analyzer

The CSS Size Analyzer is a free tool that finds the largest CSS rules in your stylesheets and highlights common issues like embedded images. You can then use this information to fix large CSS files on your website.

This improves maintainability and enables selective loading.

Load CSS code from your own domain

To load a resource from a server, browsers first need to establish a connection to that server. This takes time and will be slower on a high-latency network connection.

Loading CSS from the same domain as the HTML will be quicker, as the existing server connection can be reused.

Avoid @import rules

@import rules are a way to reference a CSS file from within a CSS file:

@import "file2.css";

However, this is not advisable from a page-speed perspective, as @import creates sequential render-blocking request chains.

Remove Unused CSS

Regularly audit stylesheets to identify unused selectors. Tools such as browser coverage analysis or build-time optimisation tools can automatically remove unused styles.

Implement Critical CSS

Critical CSS includes only the styles required to render above-the-fold content immediately. By inlining these styles, the browser can paint visible content faster, improving perceived load time. The remaining styles can be loaded asynchronously to avoid blocking rendering.

Example: Inline Critical CSS:

<head>
  <!-- Inline only the CSS needed for immediate content -->
  <style>
    /* Basic typography and layout for visible content */
    body {
      font-family: sans-serif;
    }
    header {
      padding: 1rem;
    }
    
    /* Styles for hero section and summary content */
    .hero-title {
      font-size: 2rem;
      font-weight: bold;
    }
    .summary {
      margin: 1rem 0;
    }
  </style>
  <!-- Load the remaining styles asynchronously to avoid blocking rendering -->
  <link 
    rel="preload" 
    href="main.css" 
    as="style" 
    onload="this.rel='stylesheet'">
</head>

Inlining critical CSS allows the page to display key content immediately, reducing blank screens on slow networks. Asynchronous loading of remaining styles ensures that non-critical CSS does not block the main thread or delay rendering, which is especially important for low-resource devices.

Defer Non-Critical Styles

Load secondary styles after the page has rendered.

Example:

<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">

Minify CSS

Minification removes unnecessary characters such as whitespace and comments.

Example:

Before:

body {
  margin: 0;
  padding: 0;
}

After:

body{margin:0;padding:0}

Enable Compression

Server compression, such as Brotli or GZIP, can significantly reduce CSS file sizes.

Enable Browser Caching

CSS files should be cached so returning users do not need to download them again.

Example:

Cache-Control: public, max-age=31536000

Split CSS by Page or Component

Large applications should load styles only when needed.

Example:

  • home.css
  • search.css
  • dashboard.css

This avoids downloading styles that are not used on the page.

Deliver CSS with HTTP preload or HTTP/2 push

HTTP Preload:

Using preload, a newer feature in HTTP, allows styles to load earlier because the browser requests them earlier, as soon as HTML parsing begins. Preloading can be denoted in markup or in the HTTP header.

Example 1: Preload in HTML:

<!-- Preload a stylesheet to start downloading it early -->
<link rel="preload" href="/styles/other.css" as="style">

rel="preload" signals the browser to fetch the resource immediately. as="style" specifies the type of resource being preloaded, allowing the browser to prioritise it correctly.

Example 2: Preload via HTTP Response Header:

Link: <https://example.com/styles/other.css>; rel=preload; as=style

Preloading via HTTP headers achieves the same effect as the HTML tag. Useful when you want to control preloading from the server rather than modifying HTML.

Preloading doesn't cause blocking behaviour either, and can be used for third-party content, allowing you to control how the resource is used. For example, you could fetch a stylesheet for a third-party component that isn't necessary for the initial rendering of the page, but that will be used a little later on in the page load.

HTTP/2 push:

HTTP/2 push is a little different. In effect, they accomplish many of the same goals, and preload actually uses the push API when it's available by default. To prevent this, you can include "nopush" in the HTTP response header, like this:

Link: </styles/other.css>; rel=preload; as=style; nopush

When HTTP/2 push is used, the server does the pushing, rather than the browser in preload. This important distinction means that the CSS file gets pushed immediately, along with the HTML and other essential files. As a result, push can load resources even faster than preload. Using push risks overriding the use of cached resources and increasing the amount of data sent, so be careful with implementation.

CSS Performance Benchmarks

Standard web performance targets often assume fast broadband connections. For LRO environments, stricter limits are recommended.

Recommended CSS Budgets

Metric Ideal Acceptable Poor
Total CSS size < 50 KB < 100 KB > 100 KB
Critical CSS size < 15 KB < 30 KB > 30 KB
CSS files per page 1–2 ≤ 3 > 4
Unused CSS < 10% < 20% > 40%
Render-blocking stylesheets 0 1 > 2
CSS download time (3G) < 200 ms < 500 ms > 1 s
CSS parsing time < 50 ms < 100 ms > 200 ms

Identifying Unused CSS

Using Chrome DevTools:

  1. Open DevTools
  2. Go to Coverage tab
  3. Reload the page
  4. Review unused CSS rules

This helps identify styles that can be removed.

Result

  • Content appears quickly
  • Remaining styles load progressively
  • Rendering is no longer blocked

Do / Don't

Do

  • Inline critical CSS
  • Remove unused styles
  • Use compression and caching
  • Keep selectors simple
  • Split CSS by component or page

Don't

  • Load large frameworks unnecessarily
  • Block rendering with non-critical CSS
  • Maintain large unused stylesheets
  • Use overly complex selectors

Checklist

Before deploying a page:

Metrics and Tools

Key metrics influenced by CSS performance:

  • First Contentful Paint (FCP)
  • Largest Contentful Paint (LCP)
  • Speed Index
  • Layout stability (CLS)
  • Main thread processing time

Recommended tools:

  • Chrome DevTools
  • Lighthouse
  • WebPageTest
  • DebugBear

Further reading



How can we improve this article?

Your feedback will help improve the framework and its documentation and will only be visible to the development team.