DEV Community

Cover image for Baseline Web Features You Can Safely Use Today to Boost Performance
Mariano Álvarez 🇨🇷
Mariano Álvarez 🇨🇷

Posted on

Baseline Web Features You Can Safely Use Today to Boost Performance

Performance optimization can feel like a gamble. You find an amazing CSS property or API that could shave hundreds of milliseconds off your load time, but then you check browser support and… it's a sea of red on Can I Use. So you give up and stick with the same old techniques.

Here's the thing: there's a growing list of powerful performance features that are now Baseline Widely Available. That means they've been supported across all major browsers for at least 30 months. You can use them today without worrying about compatibility.

Let me show you four that should be in your toolkit.

What Does "Baseline" Mean?

Before we dive in, quick context: Baseline is a compatibility initiative from the Web Platform that identifies when features are safe to use across popular browsers. A feature becomes Baseline Widely Available after it's been supported in Chrome, Edge, Firefox, and Safari for 30+ months.

Think of it as a green light for production use. No polyfills needed, no edge case workarounds—just reliable browser support.


1. content-visibility: Skip Rendering Work You Don't Need

The content-visibility CSS property lets browsers skip rendering work—layout, painting, all of it—for offscreen content. This is particularly powerful for long pages with lots of DOM elements.

Browser Support

  • Chrome/Edge: 85+
  • Firefox: 125+
  • Safari: 18+
  • Status: Baseline Newly available (September 2025)

How It Works

.article-section {
  content-visibility: auto;
  contain-intrinsic-size: 1000px;
}
Enter fullscreen mode Exit fullscreen mode

The auto value tells the browser to skip rendering when the element is offscreen. The contain-intrinsic-size acts as a placeholder to prevent layout shifts—it's essentially telling the browser "assume this element is about 1000px tall until you actually render it."

If you're building something like an infinite scroller, use the auto keyword with contain-intrinsic-size:

.feed-item {
  content-visibility: auto;
  contain-intrinsic-size: auto 500px;
}
Enter fullscreen mode Exit fullscreen mode

The auto keyword makes the browser remember the last rendered size, which is perfect for content that might be scrolled back into view.

Real Performance Gains

In a travel blog example from web.dev, applying content-visibility: auto reduced initial rendering time from 232ms to 30ms—a 7x improvement. That's the kind of boost that directly impacts Interaction to Next Paint (INP).

Important Considerations

  • Content remains searchable and accessible (unlike visibility: hidden)
  • Avoid calling DOM APIs that force layout on skipped subtrees
  • Use aria-hidden="true" on landmark elements if you're getting accessibility tree clutter
  • Works best on chunked content sections (articles, feed items, product cards)

2. AVIF: Next-Gen Image Compression

AVIF is an image format built on the AV1 video codec. It delivers greater than 50% file size savings compared to JPEG while maintaining the same visual quality. If you're trying to optimize Largest Contentful Paint (LCP), this one's a game-changer.

Browser Support

  • Chrome: 85+
  • Edge: 93+
  • Firefox: 93+
  • Safari: 16+
  • Status: Baseline Widely Available

Why It Matters

Smaller images = faster downloads = better LCP scores. AVIF also supports High Dynamic Range, Wide Color Gamut, and progressive decoding. Think of it as the image format designed for modern web performance needs.

Implementation

The simplest approach uses the <picture> element with fallbacks:

<picture>
  <source srcset="hero-image.avif" type="image/avif">
  <source srcset="hero-image.webp" type="image/webp">
  <img src="hero-image.jpg" alt="Hero image" loading="lazy">
</picture>
Enter fullscreen mode Exit fullscreen mode

Browsers try formats from top to bottom. AVIF-capable browsers get the smallest file, others fall back to WebP or JPEG.

Encoding Considerations

If you're encoding AVIF images yourself using avifenc:

avifenc --cq-level 23 --speed 6 --jobs 8 input.jpg output.avif
Enter fullscreen mode Exit fullscreen mode
  • cq-level: Quality setting (0-63, lower = higher quality). Start around 23-28 for photos.
  • --speed: Encoding speed (0-10, default 6). Lower = slower encoding but better compression.
  • --jobs: Multi-threading. Using 8 threads gives roughly 5x speedup.

Practical Advice

  • Use lossy encoding for photographs, lossless for line art
  • Experiment with quality settings—sometimes cq-level 28 looks identical to cq-level 23 but saves another 20%
  • Consider image CDNs (Cloudinary, Imgix) if you don't want to manage encoding yourself
  • Always provide fallbacks for older browsers

3. Module Preload: Fix Dependency Waterfalls

If you're shipping ES modules in production, you've probably noticed dependency waterfalls. The browser fetches your entry module, parses it, discovers imports, fetches those, discovers more imports… it's roundtrip city.

<link rel="modulepreload"> solves this by letting you declaratively tell the browser to fetch and compile modules ahead of time.

Browser Support

  • Chrome: 66+
  • Edge: 79+
  • Firefox: 115+
  • Safari: 17+
  • Status: Baseline Widely Available

Why Standard Preload Doesn't Work

You might think <link rel="preload" as="script"> would handle this. It doesn't, because:

  • Modules use an omit credentials mode that standard preload doesn't support
  • The browser doesn't know to parse/compile the file as a module
  • Chrome's V8 engine handles module compilation differently than regular scripts

How to Use It

<head>
  <!-- Preload your critical modules -->
  <link rel="modulepreload" href="/js/app.mjs">
  <link rel="modulepreload" href="/js/router.mjs">
  <link rel="modulepreload" href="/js/components.mjs">
</head>

<script type="module" src="/js/app.mjs"></script>
Enter fullscreen mode Exit fullscreen mode

The browser fetches all three modules in parallel, parses and compiles them immediately, then executes when needed. No more dependency waterfalls.

When to Use It

Module preload is most effective when:

  • You have deep module dependency chains (3+ levels)
  • You're seeing performance issues from roundtrip delays
  • Your application has a clear critical path of modules

For shallow dependency trees (1-2 levels), the overhead might not be worth it. Profile first, optimize second.

A Word of Caution

Listing every module defeats the purpose. Focus on the critical path—the modules absolutely needed for initial render. Think of it like this:

<!-- Good: Critical path only -->
<link rel="modulepreload" href="/js/app.mjs">
<link rel="modulepreload" href="/js/critical-component.mjs">

<!-- Bad: Everything and the kitchen sink -->
<link rel="modulepreload" href="/js/utils.mjs">
<link rel="modulepreload" href="/js/helpers.mjs">
<link rel="modulepreload" href="/js/random-thing-used-once.mjs">
Enter fullscreen mode Exit fullscreen mode

4. Server-Timing: Surface Backend Performance Metrics

The Server-Timing HTTP header lets you expose backend performance metrics directly in the browser's DevTools and JavaScript. It's like having a window into your server's performance for every request.

Browser Support

  • Chrome: 65+
  • Edge: 79+
  • Firefox: 61+
  • Safari: 16.4+
  • Status: Baseline Widely Available (March 2023)

What You Can Track

Database queries, cache hits/misses, API calls, CPU time, file system access—basically any server-side operation you want visibility into.

Basic Implementation

On the server, add timing headers to your responses:

Server-Timing: db;dur=53.2;desc="Database query"
Server-Timing: cache;dur=2.1;desc="Cache read"
Server-Timing: api;dur=127.8;desc="External API call"
Enter fullscreen mode Exit fullscreen mode

Or as a single header with multiple metrics:

Server-Timing: db;dur=53.2;desc="Database", cache;dur=2.1;desc="Cache", api;dur=127.8;desc="API call"
Enter fullscreen mode Exit fullscreen mode

Node.js Example

app.use((req, res, next) => {
  const start = Date.now();

  // Track database time
  const dbStart = Date.now();
  await db.query('SELECT * FROM users WHERE id = ?', [userId]);
  const dbDuration = Date.now() - dbStart;

  // Track cache time
  const cacheStart = Date.now();
  const cached = await cache.get(cacheKey);
  const cacheDuration = Date.now() - cacheStart;

  // Set Server-Timing header
  res.setHeader('Server-Timing', `
    db;dur=${dbDuration};desc="User query",
    cache;dur=${cacheDuration};desc="Cache check",
    total;dur=${Date.now() - start};desc="Total"
  `.trim().replace(/\s+/g, ' '));

  next();
});
Enter fullscreen mode Exit fullscreen mode

Accessing in JavaScript

// Get timing data for all resources
const resources = performance.getEntriesByType('resource');

resources.forEach(entry => {
  entry.serverTiming?.forEach(metric => {
    console.log(`${metric.name}: ${metric.duration}ms - ${metric.description}`);
  });
});

// Example output:
// db: 53.2ms - User query
// cache: 2.1ms - Cache check
// total: 178.4ms - Total
Enter fullscreen mode Exit fullscreen mode

DevTools Integration

The best part? These metrics show up automatically in Chrome DevTools under the Timing tab for each request. No special configuration needed—just set the header and open DevTools.

Security Considerations

Be thoughtful about what you expose:

  • Avoid revealing sensitive infrastructure details
  • Consider exposing detailed metrics only to authenticated users
  • Use Timing-Allow-Origin header to control cross-origin access
  • Don't expose internal service names or database schemas

For public APIs, stick to high-level metrics:

Server-Timing: total;dur=245;desc="Processing time"
Enter fullscreen mode Exit fullscreen mode

For internal tools or authenticated users, go wild with detail:

Server-Timing: db-users;dur=23;desc="Users table", db-posts;dur=45;desc="Posts table", redis;dur=3;desc="Cache", s3;dur=89;desc="Asset storage"
Enter fullscreen mode Exit fullscreen mode

Putting It All Together

Here's what a performance-optimized page might look like using all four features:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>High Performance Page</title>

  <!-- Module preload for critical JavaScript -->
  <link rel="modulepreload" href="/js/app.mjs">
  <link rel="modulepreload" href="/js/router.mjs">

  <style>
    /* content-visibility for long sections */
    .article-section {
      content-visibility: auto;
      contain-intrinsic-size: auto 800px;
    }
  </style>
</head>
<body>
  <!-- AVIF images with fallbacks -->
  <picture>
    <source srcset="hero.avif" type="image/avif">
    <source srcset="hero.webp" type="image/webp">
    <img src="hero.jpg" alt="Hero" fetchpriority="high">
  </picture>

  <main>
    <section class="article-section">
      <!-- Content here -->
    </section>
    <section class="article-section">
      <!-- More content -->
    </section>
  </main>

  <script type="module" src="/js/app.mjs"></script>

  <script type="module">
    // Log server timing metrics
    performance.getEntriesByType('navigation').forEach(entry => {
      entry.serverTiming?.forEach(metric => {
        console.log(`Server: ${metric.name} took ${metric.duration}ms`);
      });
    });
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

And on the server:

// Express.js example
app.use((req, res, next) => {
  const timings = [];

  // Your request handling with timing tracking...

  res.setHeader('Server-Timing', timings.join(', '));
  next();
});
Enter fullscreen mode Exit fullscreen mode

The Bottom Line

These four features are production-ready today. They're not experimental, they're not behind flags, and you don't need polyfills. They're just solid, well-supported tools that can genuinely improve your site's performance.

  • content-visibility: Reduce rendering work for offscreen content
  • AVIF: Cut image file sizes in half
  • Module preload: Eliminate dependency waterfalls
  • Server-Timing: Surface backend performance metrics

The combination has noticeably improved Core Web Vitals scores—particularly LCP and INP.

Start with one. Add AVIF support to your hero images. Try content-visibility on a long article page. Add module preload to your critical JavaScript. The beauty of Baseline features is you can adopt them incrementally without worrying about breaking browsers.


Want to dive deeper? Check out the official documentation:

If you found this useful, a like or share helps others discover it. And if you've used any of these features in production, I'd love to hear about your experience in the comments.

Top comments (0)