CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-respond-js

Fast and lightweight polyfill for min/max-width CSS3 Media Queries for IE 6-8 and more

Pending
Overview
Eval results
Files

cross-domain-proxy.mddocs/

Cross-Domain CSS Support

The cross-domain proxy system enables respond.js to work with stylesheets hosted on CDNs or different domains by overcoming same-origin policy restrictions. This is essential for modern web applications that serve CSS from content delivery networks.

Setup Requirements

Required Files

Three files must be properly configured for cross-domain functionality:

<!-- External domain: Proxy handler page -->
respond-proxy.html

<!-- Local domain: Redirect image for communication (1x1 transparent GIF) -->
respond.proxy.gif  

<!-- Local domain: Proxy script -->
respond.proxy.js

File Descriptions:

  • respond-proxy.html: Proxy page hosted on external domain that fetches CSS and returns it via iframe name property
  • respond.proxy.gif: 1x1 pixel transparent GIF used as redirect target for cross-domain communication (35 bytes)
  • respond.proxy.js: Main proxy script that detects external stylesheets and initiates proxy requests

HTML Setup

<!-- Respond.js proxy on external server (CDN) -->
<link href="http://externalcdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />

<!-- Respond.js redirect location on local server -->
<link href="/path/to/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />

<!-- Respond.js proxy script on local server -->
<script src="/path/to/respond.proxy.js"></script>

Capabilities

Cross-Domain CSS Processing

Enables respond.js to fetch and process CSS files from external domains that would normally be blocked by browser security policies.

/**
 * Main proxy functions available via respond.proxy.js
 */
interface CrossDomainProxy {
  /** 
   * Fetch CSS content from external domain via iframe proxy
   * @param url - External CSS file URL to fetch
   * @param callback - Function called with retrieved CSS content
   */
  fakejax(url: string, callback: (css: string) => void): void;
  
  /** 
   * Check if URL needs base URL resolution
   * @param href - URL to check against base element
   * @returns Resolved absolute URL
   */
  checkBaseURL(href: string): string;
  
  /** 
   * Build URLs list of external stylesheets for processing
   * Scans all link elements and initiates proxy requests for external stylesheets
   */
  buildUrls(): void;
  
  /** 
   * Resolve redirect URL for cross-domain communication
   * Handles IE6/7 relative URL resolution issues
   */
  checkRedirectURL(): void;
}

/**
 * Proxy page functions (respond-proxy.html)
 */
interface ProxyPageAPI {
  /** 
   * Parse query string parameters from proxy page URL
   * @returns Object containing url and css parameters
   */
  getQueryString(): { url: string; css: string };
  
  /** 
   * AJAX function for fetching CSS from external domain
   * @param url - CSS file URL to fetch
   * @param callback - Function called with CSS content
   */
  ajax(url: string, callback: (response: string) => void): void;
  
  /** 
   * XMLHttpRequest factory function with fallbacks
   * @returns XMLHttpRequest instance for current browser
   */
  xmlHttp(): XMLHttpRequest;
}

iframe Communication System

Uses iframe-based communication to securely fetch cross-domain CSS content.

/**
 * Create iframe proxy for cross-domain CSS fetching
 * @param url - External CSS file URL to fetch
 * @param callback - Function called with retrieved CSS content
 */
function fakejax(url: string, callback: (css: string) => void): void;

/**
 * Check and resolve base URL for relative paths
 * @param href - URL to check against base element
 * @returns Resolved absolute URL
 */
function checkBaseURL(href: string): string;

Setup Process

Step 1: Upload Proxy Files

# Upload to external domain (CDN)
scp respond-proxy.html user@cdn.example.com:/var/www/html/

# Upload to local domain  
scp respond.proxy.gif user@local.example.com:/var/www/html/assets/
scp respond.proxy.js user@local.example.com:/var/www/html/js/

Step 2: Configure HTML

<!DOCTYPE html>
<html>
<head>
  <!-- External stylesheet that needs proxy -->
  <link rel="stylesheet" href="http://cdn.example.com/styles/main.css" />
  
  <!-- Proxy configuration -->
  <link href="http://cdn.example.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
  <link href="/assets/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />
  
  <!-- Load proxy script -->
  <script src="/js/respond.proxy.js"></script>
</head>
<body>
  <!-- Content -->
</body>
</html>

Step 3: Verify Configuration

// Check if proxy elements are properly configured
var proxyLink = document.getElementById('respond-proxy');
var redirectLink = document.getElementById('respond-redirect');

if (proxyLink && redirectLink) {
  console.log('Proxy configuration found');
  console.log('Proxy URL:', proxyLink.href);
  console.log('Redirect URL:', redirectLink.href);
} else {
  console.error('Missing proxy configuration elements');
}

Communication Protocol

Message Flow

  1. Detection: respond.proxy.js detects external stylesheets
  2. iframe Creation: Creates hidden iframe pointing to proxy URL
  3. Parameter Passing: Passes CSS URL and redirect URL as query parameters
  4. Proxy Fetch: respond-proxy.html fetches the CSS content
  5. Return Path: CSS content returned via iframe.contentWindow.name
  6. Processing: respond.js processes the retrieved CSS normally

URL Parameters

http://cdn.example.com/respond-proxy.html?url=REDIRECT_URL&css=CSS_URL

Where:
- REDIRECT_URL: Encoded local redirect URL (respond.proxy.gif)
- CSS_URL: Encoded external CSS file URL to fetch

Example Request

http://cdn.example.com/respond-proxy.html?url=http%3A//local.com/respond.proxy.gif&css=http%3A//cdn.example.com/styles/responsive.css

Implementation Details

Domain Detection

/**
 * Check if stylesheet is external and needs proxy processing
 * @param href - Stylesheet URL to check
 * @returns true if external domain, false if same domain
 */
function isExternalStylesheet(href: string): boolean;

Detection Logic:

// External domain patterns that trigger proxy:
var externalPatterns = [
  /^([a-zA-Z:]*\/\/(www\.)?)/,  // Absolute URLs with protocol
  /^\/\//                       // Protocol-relative URLs
];

// Same domain indicators (no proxy needed):
// - Relative paths: ./styles/main.css, ../css/theme.css
// - Absolute paths: /css/main.css
// - Same host: http://currentdomain.com/css/main.css

iframe Management

// iframe creation and cleanup
function createProxyIframe() {
  var iframe;
  
  if ("ActiveXObject" in window) {
    // IE-specific iframe creation
    var AXO = new ActiveXObject("htmlfile");
    AXO.open();
    AXO.write('<iframe id="x"></iframe>');
    AXO.close();
    iframe = AXO.getElementById("x");
  } else {
    // Standard iframe creation
    iframe = document.createElement("iframe");
    iframe.style.cssText = "position:absolute;top:-99em";
    document.documentElement.insertBefore(iframe, 
      document.documentElement.firstElementChild);
  }
  
  return iframe;
}

Response Handling

function checkFrameName(iframe, callback) {
  var cssText;
  
  try {
    // CSS content is returned via iframe name property
    cssText = iframe.contentWindow.name;
  } catch (e) {
    // Cross-domain access denied - continue polling
  }
  
  if (cssText) {
    // Clean up iframe
    iframe.src = "about:blank";
    iframe.parentNode.removeChild(iframe);
    
    // Process retrieved CSS
    callback(cssText);
  } else {
    // Continue polling for response
    setTimeout(function() {
      checkFrameName(iframe, callback);
    }, 100);
  }
}

Security Considerations

Same-Origin Policy

The proxy system works within browser security constraints:

  • iframe Sandbox: Uses iframe for secure cross-domain communication
  • No Direct XHR: Avoids blocked XMLHttpRequest cross-domain calls
  • Controlled Access: Only fetches CSS, not arbitrary content
  • Domain Validation: Proxy validates requested URLs

HTTPS Compatibility

<!-- HTTPS configuration -->
<link href="https://secure-cdn.example.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
<link href="/assets/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />

Protocol matching is important:

  • HTTPS pages: Use HTTPS proxy URLs
  • HTTP pages: Use HTTP proxy URLs
  • Mixed protocols: May cause security warnings

Common Issues and Solutions

Missing Query String

Problem: Proxy fails if respond-proxy.html has query parameters appended.

<!-- Incorrect -->
<link href="http://cdn.com/respond-proxy.html?version=1.0" id="respond-proxy" rel="respond-proxy" />

<!-- Correct -->
<link href="http://cdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />

Base Element Conflicts

Problem: <base> element affects URL resolution.

<!-- Base element can interfere with proxy URLs -->
<base href="/app/" />

<!-- Solution: Use absolute URLs for proxy configuration -->
<link href="http://cdn.com/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
<link href="http://local.com/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />

Protocol Mismatches

Problem: Mixed HTTP/HTTPS protocols cause failures.

// Automatic protocol matching
var proxyURL = location.protocol === 'https:' 
  ? 'https://secure-cdn.com/respond-proxy.html'
  : 'http://cdn.com/respond-proxy.html';
  
document.getElementById('respond-proxy').href = proxyURL;

Cache Headers

Problem: CSS files with no-cache headers cause repeated requests.

# Server configuration for CDN CSS files
Cache-Control: public, max-age=31536000
Expires: Thu, 31 Dec 2025 23:55:55 GMT

Testing Cross-Domain Setup

Verification Script

function testCrossDomainSetup() {
  var proxyLink = document.getElementById('respond-proxy');
  var redirectLink = document.getElementById('respond-redirect');
  var externalStylesheets = [];
  
  // Check required elements
  if (!proxyLink) {
    console.error('Missing respond-proxy link element');
    return false;
  }
  
  if (!redirectLink) {
    console.error('Missing respond-redirect link element');
    return false;
  }
  
  // Find external stylesheets
  var links = document.getElementsByTagName('link');
  for (var i = 0; i < links.length; i++) {
    var link = links[i];
    if (link.rel.indexOf('stylesheet') >= 0) {
      var isExternal = /^([a-zA-Z:]*\/\/)/.test(link.href) && 
                      link.href.indexOf(location.host) === -1;
      if (isExternal) {
        externalStylesheets.push(link.href);
      }
    }
  }
  
  console.log('External stylesheets found:', externalStylesheets);
  console.log('Proxy URL:', proxyLink.href);
  console.log('Redirect URL:', redirectLink.href);
  
  return externalStylesheets.length > 0;
}

// Run test
testCrossDomainSetup();

Install with Tessl CLI

npx tessl i tessl/npm-respond-js

docs

core-polyfill.md

cross-domain-proxy.md

index.md

matchmedia-listeners.md

matchmedia-polyfill.md

tile.json