Modern Web Platform APIs

1. Web Streams API for Streaming Data Processing

Stream Type Description Browser Support
ReadableStream Stream of data that can be read chunk by chunk. Used for response bodies, file reading, etc. All Modern Browsers
WritableStream Stream that can be written to chunk by chunk. Used for file writing, compression, etc. All Modern Browsers
TransformStream Pair of readable and writable streams that transform data. Used for compression, encryption, etc. All Modern Browsers
ReadableStream Method Description
stream.getReader() Gets ReadableStreamDefaultReader for reading chunks.
reader.read() Returns Promise with {value, done}. Done is true when stream ends.
stream.pipeThrough(transform) Pipes stream through TransformStream, returning new ReadableStream.
stream.pipeTo(writable) Pipes stream to WritableStream. Returns Promise.
stream.tee() Splits stream into two independent streams.
reader.cancel(reason) Cancels stream reading.

Example: Read and process fetch response stream

// Fetch and process response as stream
async function fetchAndProcessStream(url) {
  try {
    const response = await fetch(url);
    
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }
    
    // Get readable stream from response
    const reader = response.body.getReader();
    
    // Process chunks as they arrive
    let receivedLength = 0;
    const chunks = [];
    
    while (true) {
      const { "done": done, "value": value } = await reader.read();
      
      if (done) {
        console.log("Stream complete");
        break;
      }
      
      chunks.push(value);
      receivedLength += value.length;
      
      // Update progress
      console.log(`Received ${receivedLength} bytes`);
      updateProgressBar(receivedLength);
    }
    
    // Concatenate chunks
    const chunksAll = new Uint8Array(receivedLength);
    let position = 0;
    for (const chunk of chunks) {
      chunksAll.set(chunk, position);
      position += chunk.length;
    }
    
    // Convert to string
    const result = new TextDecoder("utf-8").decode(chunksAll);
    console.log("Final result:", result);
    
    return result;
    
  } catch (error) {
    console.error("Stream processing failed:", error);
    throw error;
  }
}

// Usage
fetchAndProcessStream("/api/large-data")
  .then(data => {
    console.log("Processing complete");
    processData(data);
  });

Example: Create custom ReadableStream

// Create custom stream that generates data
function createNumberStream(max) {
  let current = 0;
  
  return new ReadableStream({
    start(controller) {
      console.log("Stream started");
    },
    
    pull(controller) {
      if (current < max) {
        // Enqueue next value
        controller.enqueue(current);
        current++;
      } else {
        // Close stream when done
        controller.close();
      }
    },
    
    cancel(reason) {
      console.log("Stream cancelled:", reason);
    }
  });
}

// Read from custom stream
async function readNumberStream() {
  const stream = createNumberStream(10);
  const reader = stream.getReader();
  
  try {
    while (true) {
      const { "done": done, "value": value } = await reader.read();
      
      if (done) {
        console.log("Stream finished");
        break;
      }
      
      console.log("Received number:", value);
    }
  } finally {
    reader.releaseLock();
  }
}

readNumberStream();

Example: Transform stream for data processing

// Create transform stream that uppercases text
class UppercaseTransformStream {
  constructor() {
    return new TransformStream({
      transform(chunk, controller) {
        // Convert chunk to uppercase
        const text = new TextDecoder().decode(chunk);
        const upper = text.toUpperCase();
        const encoded = new TextEncoder().encode(upper);
        controller.enqueue(encoded);
      }
    });
  }
}

// Use transform stream
async function transformFetchResponse(url) {
  const response = await fetch(url);
  
  // Pipe through transform
  const transformed = response.body
    .pipeThrough(new UppercaseTransformStream());
  
  // Read result
  const reader = transformed.getReader();
  const chunks = [];
  
  while (true) {
    const { "done": done, "value": value } = await reader.read();
    if (done) break;
    chunks.push(value);
  }
  
  // Combine chunks
  const combined = new Uint8Array(
    chunks.reduce((acc, chunk) => acc + chunk.length, 0)
  );
  let position = 0;
  for (const chunk of chunks) {
    combined.set(chunk, position);
    position += chunk.length;
  }
  
  return new TextDecoder().decode(combined);
}

// Create JSON parsing transform
class JSONParseTransformStream {
  constructor() {
    let buffer = "";
    
    return new TransformStream({
      transform(chunk, controller) {
        const text = new TextDecoder().decode(chunk);
        buffer += text;
        
        // Try to parse complete JSON objects
        const lines = buffer.split("\n");
        buffer = lines.pop(); // Keep incomplete line in buffer
        
        for (const line of lines) {
          if (line.trim()) {
            try {
              const json = JSON.parse(line);
              controller.enqueue(json);
            } catch (e) {
              console.error("JSON parse error:", e);
            }
          }
        }
      },
      
      flush(controller) {
        // Process remaining buffer
        if (buffer.trim()) {
          try {
            const json = JSON.parse(buffer);
            controller.enqueue(json);
          } catch (e) {
            console.error("JSON parse error:", e);
          }
        }
      }
    });
  }
}

// Use JSON transform
async function streamJSONData(url) {
  const response = await fetch(url);
  const reader = response.body
    .pipeThrough(new JSONParseTransformStream())
    .getReader();
  
  while (true) {
    const { "done": done, "value": value } = await reader.read();
    if (done) break;
    
    console.log("Parsed JSON object:", value);
    processJSONObject(value);
  }
}
Note: Streams API enables processing data chunk by chunk without loading entire dataset into memory. Use ReadableStream for reading, WritableStream for writing, TransformStream for transforming. Great for large files, real-time data, progressive rendering. All fetch responses are ReadableStreams.

2. Compression Streams API for Data Compression

Class Description Browser Support
CompressionStream TransformStream that compresses data. Format: "gzip", "deflate", or "deflate-raw". Chrome, Edge, Safari
DecompressionStream TransformStream that decompresses data. Same formats as compression. Chrome, Edge, Safari

Example: Compress and decompress data

// Compress string data
async function compressData(text) {
  // Convert to stream
  const blob = new Blob([text]);
  const stream = blob.stream();
  
  // Compress using gzip
  const compressedStream = stream.pipeThrough(
    new CompressionStream("gzip")
  );
  
  // Convert to Blob
  const compressedBlob = await new Response(compressedStream).blob();
  
  console.log(`Original size: ${text.length} bytes`);
  console.log(`Compressed size: ${compressedBlob.size} bytes`);
  console.log(`Compression ratio: ${(compressedBlob.size / text.length * 100).toFixed(2)}%`);
  
  return compressedBlob;
}

// Decompress data
async function decompressData(compressedBlob) {
  // Get stream from blob
  const stream = compressedBlob.stream();
  
  // Decompress
  const decompressedStream = stream.pipeThrough(
    new DecompressionStream("gzip")
  );
  
  // Convert to text
  const decompressedBlob = await new Response(decompressedStream).blob();
  const text = await decompressedBlob.text();
  
  return text;
}

// Usage
const originalText = "Lorem ipsum dolor sit amet...".repeat(100);

compressData(originalText)
  .then(compressed => {
    console.log("Compressed successfully");
    return decompressData(compressed);
  })
  .then(decompressed => {
    console.log("Decompressed successfully");
    console.log("Match:", decompressed === originalText);
  });

Example: Compress file before upload

// Compress file before upload
async function uploadCompressedFile(file) {
  try {
    // Compress file
    const compressedStream = file.stream()
      .pipeThrough(new CompressionStream("gzip"));
    
    // Create compressed blob
    const compressedBlob = await new Response(compressedStream).blob();
    
    console.log(`Original: ${file.size} bytes`);
    console.log(`Compressed: ${compressedBlob.size} bytes`);
    console.log(`Saved: ${file.size - compressedBlob.size} bytes`);
    
    // Create FormData
    const formData = new FormData();
    formData.append("file", compressedBlob, file.name + ".gz");
    formData.append("originalSize", file.size);
    formData.append("compression", "gzip");
    
    // Upload
    const response = await fetch("/api/upload", {
      "method": "POST",
      "body": formData
    });
    
    if (!response.ok) {
      throw new Error(`Upload failed: ${response.status}`);
    }
    
    const result = await response.json();
    console.log("Upload successful:", result);
    
    return result;
    
  } catch (error) {
    console.error("Upload failed:", error);
    throw error;
  }
}

// Handle file input
document.getElementById("fileInput").addEventListener("change", async (event) => {
  const file = event.target.files[0];
  if (!file) return;
  
  console.log("Compressing and uploading...");
  await uploadCompressedFile(file);
});

Example: Download and decompress on the fly

// Fetch compressed data and decompress while downloading
async function fetchAndDecompressStream(url) {
  try {
    const response = await fetch(url);
    
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }
    
    // Check if content is compressed
    const contentEncoding = response.headers.get("Content-Encoding");
    console.log("Content-Encoding:", contentEncoding);
    
    // Decompress stream
    const decompressedStream = response.body
      .pipeThrough(new DecompressionStream("gzip"));
    
    // Process decompressed data
    const reader = decompressedStream.getReader();
    const decoder = new TextDecoder();
    let result = "";
    
    while (true) {
      const { "done": done, "value": value } = await reader.read();
      
      if (done) {
        console.log("Decompression complete");
        break;
      }
      
      // Decode chunk
      const chunk = decoder.decode(value, { "stream": true });
      result += chunk;
      
      // Process chunk progressively
      console.log(`Processed ${result.length} characters`);
    }
    
    return result;
    
  } catch (error) {
    console.error("Fetch and decompress failed:", error);
    throw error;
  }
}

// Usage
fetchAndDecompressStream("/api/data.gz")
  .then(data => {
    console.log("Data loaded:", data.substring(0, 100));
    processData(data);
  });
Note: Compression Streams API provides built-in compression/decompression. Supports gzip, deflate, and deflate-raw. Use for reducing upload/download sizes, compressing cached data, file compression. Works with any stream - files, fetch responses, etc. No external libraries needed.
Warning: Limited browser support - check before using. Compression is CPU-intensive - may block on large data. Consider Web Workers for large compressions. Server must support receiving compressed data. Always measure - small data may not benefit from compression overhead.

3. Web Locks API for Resource Synchronization

Method/Property Description Browser Support
navigator.locks.request(name, callback) Requests lock with name. Callback executes when lock acquired. Returns Promise. Chrome, Edge
navigator.locks.request(name, options, callback) Request with options: mode ("exclusive"/"shared"), ifAvailable, steal, signal. Chrome, Edge
navigator.locks.query() Returns Promise with current lock state (held, pending locks). Chrome, Edge
Lock Option Type Description
mode string "exclusive" (default) or "shared". Exclusive allows one holder, shared allows multiple.
ifAvailable boolean If true, callback runs only if lock immediately available. Otherwise callback receives null.
steal boolean If true, preempts existing lock. Dangerous - use with caution.
signal AbortSignal AbortSignal to cancel lock request.

Example: Exclusive lock for critical section

// Protect critical section with exclusive lock
async function updateSharedResource(data) {
  if (!("locks" in navigator)) {
    console.log("Web Locks API not supported");
    return updateSharedResourceFallback(data);
  }
  
  try {
    await navigator.locks.request("resource-lock", async (lock) => {
      console.log("Lock acquired");
      
      // Critical section - only one execution at a time
      const current = await fetchCurrentData();
      const updated = processData(current, data);
      await saveData(updated);
      
      console.log("Resource updated successfully");
      
      // Lock released when callback completes
    });
    
    console.log("Lock released");
    
  } catch (error) {
    console.error("Lock request failed:", error);
    throw error;
  }
}

// Multiple concurrent calls will be serialized
Promise.all([
  updateSharedResource({ "id": 1 }),
  updateSharedResource({ "id": 2 }),
  updateSharedResource({ "id": 3 })
]).then(() => {
  console.log("All updates complete");
});

Example: Shared locks for read operations

// Use shared lock for concurrent reads, exclusive for writes
class SharedResource {
  constructor(resourceName) {
    this.resourceName = resourceName;
    this.lockName = `lock:${resourceName}`;
  }
  
  async read() {
    // Shared lock - multiple readers allowed
    return await navigator.locks.request(
      this.lockName,
      { "mode": "shared" },
      async (lock) => {
        console.log("Read lock acquired");
        const data = await fetchData(this.resourceName);
        console.log("Read complete");
        return data;
      }
    );
  }
  
  async write(data) {
    // Exclusive lock - blocks all readers and writers
    return await navigator.locks.request(
      this.lockName,
      { "mode": "exclusive" },
      async (lock) => {
        console.log("Write lock acquired");
        await saveData(this.resourceName, data);
        console.log("Write complete");
      }
    );
  }
  
  async tryRead() {
    // Try to read without waiting
    return await navigator.locks.request(
      this.lockName,
      { "mode": "shared", "ifAvailable": true },
      async (lock) => {
        if (!lock) {
          console.log("Lock not available");
          return null;
        }
        
        console.log("Lock acquired immediately");
        return await fetchData(this.resourceName);
      }
    );
  }
}

// Usage
const resource = new SharedResource("user-data");

// Concurrent reads OK
Promise.all([
  resource.read(),
  resource.read(),
  resource.read()
]).then(() => {
  console.log("All reads complete");
});

// Write blocks all operations
resource.write({ "updated": true })
  .then(() => console.log("Write complete"));

Example: Lock with timeout using AbortController

// Request lock with timeout
async function requestLockWithTimeout(lockName, callback, timeout = 5000) {
  const controller = new AbortController();
  
  // Set timeout
  const timeoutId = setTimeout(() => {
    controller.abort();
    console.log("Lock request timed out");
  }, timeout);
  
  try {
    await navigator.locks.request(
      lockName,
      { "signal": controller.signal },
      async (lock) => {
        clearTimeout(timeoutId);
        console.log("Lock acquired within timeout");
        await callback(lock);
      }
    );
  } catch (error) {
    if (error.name === "AbortError") {
      console.error("Lock request aborted (timeout or manual)");
    } else {
      console.error("Lock request failed:", error);
    }
    throw error;
  } finally {
    clearTimeout(timeoutId);
  }
}

// Query lock state
async function queryLockState() {
  const state = await navigator.locks.query();
  
  console.log("Held locks:", state.held);
  console.log("Pending locks:", state.pending);
  
  // Check specific lock
  const myLocks = state.held.filter(lock => lock.name === "my-lock");
  console.log("My locks:", myLocks);
  
  return state;
}

// Usage
requestLockWithTimeout(
  "timeout-lock",
  async (lock) => {
    await performOperation();
  },
  3000 // 3 second timeout
).catch(error => {
  console.error("Operation failed:", error);
});
Note: Web Locks API provides cross-tab/worker resource synchronization. Use exclusive locks for writes, shared locks for reads. Lock held until callback Promise resolves. Prevents race conditions in IndexedDB, shared state, etc. Works across tabs, windows, workers.
Warning: Limited browser support (Chrome, Edge). Locks are NOT persistent - lost on page refresh. Don't use for long-running operations - blocks other contexts. Always use timeout with AbortController. Avoid deadlocks - don't request multiple locks without careful ordering. Test cross-tab scenarios thoroughly.

4. Scheduler API (postTask) for Task Prioritization

Method/Property Description Browser Support
scheduler.postTask(callback, options) Schedules task with priority. Returns Promise that resolves with callback result. Chrome, Edge
scheduler.yield() Yields to browser for higher priority work. Returns Promise. EXPERIMENTAL Experimental
Priority Option Description
"user-blocking" Highest priority. Blocks user interaction. Use for input response, animations.
"user-visible" Default priority. User-visible work. Use for rendering, updating UI.
"background" Lowest priority. Background work. Use for analytics, preloading, cleanup.

Example: Prioritize tasks with scheduler.postTask

// Check support
if ("scheduler" in window && "postTask" in scheduler) {
  console.log("Scheduler API supported");
} else {
  console.log("Scheduler API not supported - using fallback");
}

// Schedule tasks with different priorities
async function schedulePrioritizedTasks() {
  // High priority - user interaction response
  scheduler.postTask(() => {
    console.log("1. User-blocking task (high priority)");
    handleUserInput();
  }, { "priority": "user-blocking" });
  
  // Medium priority - UI update
  scheduler.postTask(() => {
    console.log("2. User-visible task (medium priority)");
    updateUI();
  }, { "priority": "user-visible" });
  
  // Low priority - background work
  scheduler.postTask(() => {
    console.log("3. Background task (low priority)");
    sendAnalytics();
  }, { "priority": "background" });
  
  // Tasks execute in priority order, not call order
}

schedulePrioritizedTasks();

Example: Break up long task with yields

// Process large dataset with yields to prevent blocking
async function processLargeDataset(items) {
  const results = [];
  
  for (let i = 0; i < items.length; i++) {
    // Process item
    const result = await processItem(items[i]);
    results.push(result);
    
    // Yield every 10 items to prevent blocking
    if (i % 10 === 0 && "scheduler" in window) {
      await scheduler.yield();
      console.log(`Processed ${i} items, yielding...`);
    }
  }
  
  return results;
}

// Fallback using setTimeout
async function yieldToMainThread() {
  return new Promise(resolve => setTimeout(resolve, 0));
}

// Universal yield function
async function smartYield() {
  if ("scheduler" in window && "yield" in scheduler) {
    await scheduler.yield();
  } else {
    await yieldToMainThread();
  }
}

// Usage
processLargeDataset(largeArray)
  .then(results => {
    console.log("All items processed");
    displayResults(results);
  });

Example: Task scheduler with abort

// Schedule task with cancellation
class TaskScheduler {
  constructor() {
    this.tasks = new Map();
  }
  
  async scheduleTask(name, callback, priority = "user-visible") {
    const controller = new AbortController();
    
    this.tasks.set(name, controller);
    
    try {
      const result = await scheduler.postTask(
        callback,
        {
          "priority": priority,
          "signal": controller.signal
        }
      );
      
      console.log(`Task "${name}" completed`);
      this.tasks.delete(name);
      return result;
      
    } catch (error) {
      if (error.name === "AbortError") {
        console.log(`Task "${name}" was cancelled`);
      } else {
        console.error(`Task "${name}" failed:`, error);
      }
      this.tasks.delete(name);
      throw error;
    }
  }
  
  cancelTask(name) {
    const controller = this.tasks.get(name);
    if (controller) {
      controller.abort();
      this.tasks.delete(name);
      console.log(`Cancelled task: ${name}`);
    }
  }
  
  cancelAllTasks() {
    for (const [name, controller] of this.tasks) {
      controller.abort();
      console.log(`Cancelled task: ${name}`);
    }
    this.tasks.clear();
  }
}

// Usage
const taskScheduler = new TaskScheduler();

// Schedule low priority task
taskScheduler.scheduleTask(
  "background-sync",
  async () => {
    console.log("Syncing data...");
    await syncData();
  },
  "background"
);

// Schedule high priority task
taskScheduler.scheduleTask(
  "handle-click",
  async () => {
    console.log("Handling user click");
    await handleClick();
  },
  "user-blocking"
);

// Cancel specific task
setTimeout(() => {
  taskScheduler.cancelTask("background-sync");
}, 1000);
Note: Scheduler API enables task prioritization for better responsiveness. Use "user-blocking" for input handlers, "user-visible" for UI updates, "background" for analytics. scheduler.yield() allows long tasks to break up and yield to browser. Better than setTimeout(0) for task scheduling.
Warning: Limited browser support (Chrome, Edge). scheduler.yield() is experimental. Provide fallback using setTimeout. Priorities are hints - browser controls actual scheduling. Don't overuse user-blocking - can hurt performance. Test with Performance Observer for long tasks.

5. View Transitions API for Smooth Page Transitions

Method/Property Description Browser Support
document.startViewTransition(callback) Starts view transition. Callback updates DOM. Returns ViewTransition object. Chrome, Edge
transition.finished Promise that resolves when transition completes. Chrome, Edge
transition.ready Promise that resolves when transition is ready to animate. Chrome, Edge
transition.updateCallbackDone Promise that resolves when update callback completes. Chrome, Edge
transition.skipTransition() Skips transition animation. Chrome, Edge

Example: Basic view transition

// Check support
if (!document.startViewTransition) {
  console.log("View Transitions API not supported");
}

// Simple view transition
function updateView() {
  if (!document.startViewTransition) {
    // Fallback - update without transition
    updateDOM();
    return;
  }
  
  // Start transition
  const transition = document.startViewTransition(() => {
    // Update DOM here
    updateDOM();
  });
  
  // Listen for completion
  transition.finished
    .then(() => {
      console.log("Transition complete");
    })
    .catch(error => {
      console.error("Transition failed:", error);
    });
}

function updateDOM() {
  // Example DOM update
  document.getElementById("content").innerHTML = "<h1>New Content</h1>";
  document.body.classList.toggle("theme-dark");
}

// Trigger transition
document.getElementById("updateBtn").addEventListener("click", updateView);

Example: Named transitions with CSS

// HTML: Elements need view-transition-name in CSS
// CSS:
// .card {
//   view-transition-name: card-element;
// }
// .hero {
//   view-transition-name: hero-image;
// }

// Navigate with transition
async function navigateToDetail(itemId) {
  if (!document.startViewTransition) {
    // Fallback
    loadDetailPage(itemId);
    return;
  }
  
  const transition = document.startViewTransition(async () => {
    // Fetch and render new content
    const html = await fetchDetailPage(itemId);
    document.getElementById("main").innerHTML = html;
  });
  
  try {
    await transition.finished;
    console.log("Navigation transition complete");
  } catch (error) {
    console.error("Navigation failed:", error);
  }
}

// List to detail transition
document.querySelectorAll(".item").forEach(item => {
  item.addEventListener("click", (event) => {
    const itemId = event.currentTarget.dataset.id;
    navigateToDetail(itemId);
  });
});

Example: Custom transition with CSS animations

/* Default transition for root */
::view-transition-old(root) {
  animation: fade-out 0.3s ease-out;
}

::view-transition-new(root) {
  animation: fade-in 0.3s ease-in;
}

/* Slide transition for specific elements */
::view-transition-old(card) {
  animation: slide-out-right 0.4s ease-out;
}

::view-transition-new(card) {
  animation: slide-in-left 0.4s ease-in;
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slide-out-right {
  from { transform: translateX(0); }
  to { transform: translateX(100%); }
}

@keyframes slide-in-left {
  from { transform: translateX(-100%); }
  to { transform: translateX(0); }
}

Example: SPA navigation with view transitions

// Single Page App with view transitions
class SPARouter {
  constructor() {
    this.routes = new Map();
    this.setupNavigation();
  }
  
  addRoute(path, handler) {
    this.routes.set(path, handler);
  }
  
  async navigate(path, skipTransition = false) {
    const handler = this.routes.get(path);
    
    if (!handler) {
      console.error("Route not found:", path);
      return;
    }
    
    // Update with or without transition
    if (document.startViewTransition && !skipTransition) {
      const transition = document.startViewTransition(async () => {
        await handler();
        window.history.pushState({}, "", path);
      });
      
      await transition.finished;
    } else {
      await handler();
      window.history.pushState({}, "", path);
    }
    
    console.log("Navigated to:", path);
  }
  
  setupNavigation() {
    // Handle link clicks
    document.addEventListener("click", (event) => {
      const link = event.target.closest("a[data-spa-link]");
      if (link) {
        event.preventDefault();
        const path = link.getAttribute("href");
        this.navigate(path);
      }
    });
    
    // Handle back/forward
    window.addEventListener("popstate", () => {
      const path = window.location.pathname;
      this.navigate(path, true); // Skip transition for back/forward
    });
  }
}

// Setup router
const router = new SPARouter();

router.addRoute("/", async () => {
  document.getElementById("content").innerHTML = "<h1>Home</h1>";
});

router.addRoute("/about", async () => {
  document.getElementById("content").innerHTML = "<h1>About</h1>";
});

router.addRoute("/contact", async () => {
  document.getElementById("content").innerHTML = "<h1>Contact</h1>";
});
Note: View Transitions API enables smooth animated transitions between DOM states. Browser captures before/after states and animates between them. Use view-transition-name CSS property for element-specific transitions. Great for SPA navigation, theme switches, list-to-detail transitions.
Warning: Limited browser support (Chrome, Edge). Always provide fallback. Transitions are skipped if callback throws error. Don't use for time-critical updates. Large DOM changes can be expensive to capture. Test performance on lower-end devices. CSS animations control transition appearance.

6. Container Queries API Integration

CSS Property Description Browser Support
container-type Defines element as query container. Values: size, inline-size, normal. All Modern Browsers
container-name Names container for targeting in queries. All Modern Browsers
container Shorthand: container: name / type. All Modern Browsers
@container Container query rule. Syntax: @container name (condition) { ... }. All Modern Browsers

Example: Basic container queries in CSS

/* Define container */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Query container size */
@container card (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
  
  .card-image {
    width: 200px;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
  
  .card-image {
    width: 100%;
  }
}

/* Container query units */
.card-title {
  font-size: 5cqw; /* 5% of container width */
  padding: 2cqh;   /* 2% of container height */
}

/* Multiple named containers */
.sidebar {
  container: sidebar / inline-size;
}

.main {
  container: main / inline-size;
}

@container sidebar (min-width: 300px) {
  .sidebar-content {
    padding: 2rem;
  }
}

@container main (min-width: 800px) {
  .main-content {
    column-count: 2;
  }
}

Example: Check container query support in JavaScript

// Check container queries support
function supportsContainerQueries() {
  return CSS.supports("container-type: inline-size") ||
         CSS.supports("container-type", "inline-size");
}

if (supportsContainerQueries()) {
  console.log("Container queries supported");
  document.body.classList.add("supports-container-queries");
} else {
  console.log("Container queries not supported - using fallback");
  document.body.classList.add("no-container-queries");
}

// Observe container size changes
if (window.ResizeObserver) {
  const container = document.querySelector(".card-container");
  
  const observer = new ResizeObserver(entries => {
    for (const entry of entries) {
      const width = entry.contentRect.width;
      console.log("Container width:", width);
      
      // Manual breakpoints as fallback
      if (width >= 400) {
        entry.target.classList.add("wide");
      } else {
        entry.target.classList.remove("wide");
      }
    }
  });
  
  observer.observe(container);
}

Example: Dynamic responsive components

<!-- HTML -->
<div class="grid">
  <div class="grid-item">
    <div class="component-container">
      <div class="component">
        <h2>Responsive Component</h2>
        <p>This component adapts to its container size, not viewport.</p>
      </div>
    </div>
  </div>
  <!-- More grid items... -->
</div>

Example: Container queries CSS for responsive component

/* Setup grid that changes columns */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1rem;
}

/* Each item is a container */
.component-container {
  container-type: inline-size;
  container-name: component;
  border: 1px solid #ccc;
  border-radius: 8px;
  overflow: hidden;
}

/* Component adapts to its container */
.component {
  padding: 1rem;
}

/* Small container */
@container component (max-width: 349px) {
  .component h2 {
    font-size: 1.2rem;
  }
  
  .component p {
    font-size: 0.9rem;
  }
  
  .component-layout {
    display: block;
  }
}

/* Medium container */
@container component (min-width: 350px) and (max-width: 599px) {
  .component h2 {
    font-size: 1.5rem;
  }
  
  .component p {
    font-size: 1rem;
  }
  
  .component-layout {
    display: flex;
    gap: 1rem;
  }
}

/* Large container */
@container component (min-width: 600px) {
  .component h2 {
    font-size: 2rem;
  }
  
  .component p {
    font-size: 1.1rem;
    line-height: 1.6;
  }
  
  .component-layout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
  }
}

/* Container query units */
.component-title {
  /* cqw: % of container width */
  /* cqh: % of container height */
  /* cqi: % of container inline size */
  /* cqb: % of container block size */
  /* cqmin: min of cqi and cqb */
  /* cqmax: max of cqi and cqb */
  
  font-size: clamp(1rem, 4cqw, 2.5rem);
  margin-bottom: 1cqh;
}
Note: Container Queries allow components to respond to their container size, not viewport. More flexible than media queries for reusable components. Use container-type: inline-size for width-based queries. Container query units (cqw, cqh) relative to container, not viewport.
Warning: Container queries are CSS feature, not JavaScript API. Use CSS.supports() to check support. Avoid circular dependencies (container size depends on children, children depend on container). Performance impact on complex layouts - test on lower-end devices. Fallback to media queries for older browsers.

Modern Web Platform APIs Best Practices

  • Streams API perfect for large files and real-time data processing
  • Use ReadableStream.getReader() to process chunks incrementally
  • Compression Streams reduce bandwidth - measure to ensure benefit
  • Web Locks API prevents race conditions across tabs/workers
  • Use shared locks for reads, exclusive locks for writes
  • Scheduler.postTask prioritizes tasks better than setTimeout
  • Use "user-blocking" sparingly - only for critical interactions
  • Yield with scheduler.yield() to prevent blocking main thread
  • View Transitions API smooths SPA navigation and state changes
  • Always provide fallback for View Transitions - limited support
  • Container queries make truly reusable responsive components
  • Check API support with CSS.supports() and feature detection
  • Test all modern APIs on target browsers - support varies