Navigator and Screen Objects: Browser and Screen Information Detectives
Division of Labor Between Two Detectives
In the BOM world, navigator and screen are like two professional information detectives. navigator specializes in collecting browser and system information—telling you "what browser and OS the user is using, whether they're online"; while screen focuses on screen hardware information—telling you "how big the user's screen is, how many colors it supports, what the resolution is."
Understanding the difference between these two objects is important:
- Navigator: Focuses on browser software environment (browser type, version, plugins, language, etc.)
- Screen: Focuses on display hardware environment (screen size, color depth, orientation, etc.)
Working together, they help us implement intelligent device adaptation and feature detection.
Navigator Object Detailed
The navigator object contains various information about the browser and operating system, and is an important tool for feature detection and user environment analysis.
Browser Identification Properties
// User agent string (most common browser identification method)
console.log(navigator.userAgent);
// e.g.: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
// Application name (usually 'Netscape', for historical reasons)
console.log(navigator.appName);
// Application version
console.log(navigator.appVersion);
// Operating system platform
console.log(navigator.platform);
// e.g.: 'Win32', 'MacIntel', 'Linux x86_64'
// Browser vendor
console.log(navigator.vendor);
// e.g.: 'Google Inc.', 'Apple Computer, Inc.'
// Browser engine name
console.log(navigator.product);
// Usually 'Gecko'Important Note: Since userAgent can be spoofed, modern best practice is to use feature detection rather than browser detection.
Practical Application: Browser Detection Utility
class BrowserDetector {
static get userAgent() {
return navigator.userAgent.toLowerCase();
}
// Detect browser type
static getBrowserName() {
const ua = this.userAgent;
if (ua.includes("edg/")) return "Edge";
if (ua.includes("chrome/") && !ua.includes("edg/")) return "Chrome";
if (ua.includes("safari/") && !ua.includes("chrome/")) return "Safari";
if (ua.includes("firefox/")) return "Firefox";
if (ua.includes("opera/") || ua.includes("opr/")) return "Opera";
if (ua.includes("trident/") || ua.includes("msie "))
return "Internet Explorer";
return "Unknown";
}
// Detect browser version
static getBrowserVersion() {
const ua = this.userAgent;
const browser = this.getBrowserName();
let match;
switch (browser) {
case "Chrome":
match = ua.match(/chrome\/([\d.]+)/);
break;
case "Safari":
match = ua.match(/version\/([\d.]+)/);
break;
case "Firefox":
match = ua.match(/firefox\/([\d.]+)/);
break;
case "Edge":
match = ua.match(/edg\/([\d.]+)/);
break;
default:
return "Unknown";
}
return match ? match[1] : "Unknown";
}
// Detect operating system
static getOS() {
const ua = this.userAgent;
const platform = navigator.platform.toLowerCase();
if (platform.includes("win")) return "Windows";
if (platform.includes("mac")) return "macOS";
if (platform.includes("linux")) return "Linux";
if (ua.includes("android")) return "Android";
if (ua.includes("iphone") || ua.includes("ipad")) return "iOS";
return "Unknown";
}
// Detect device type
static getDeviceType() {
const ua = this.userAgent;
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {
return "tablet";
}
if (
/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(
ua
)
) {
return "mobile";
}
return "desktop";
}
// Get complete information
static getInfo() {
return {
browser: this.getBrowserName(),
version: this.getBrowserVersion(),
os: this.getOS(),
deviceType: this.getDeviceType(),
platform: navigator.platform,
userAgent: navigator.userAgent,
};
}
// Display browser information
static displayInfo() {
const info = this.getInfo();
console.log("=== Browser Information ===");
console.log(`Browser: ${info.browser} ${info.version}`);
console.log(`Operating System: ${info.os}`);
console.log(`Device Type: ${info.deviceType}`);
console.log(`Platform Info: ${info.platform}`);
}
}
// Usage
BrowserDetector.displayInfo();
// Output:
// === Browser Information ===
// Browser: Chrome 120.0.0.0
// Operating System: Windows
// Device Type: desktop
// Platform Info: Win32Language and Internationalization
// Browser preferred language
console.log(navigator.language);
// e.g.: 'zh-CN', 'en-US', 'ja-JP'
// All supported languages
console.log(navigator.languages);
// e.g.: ['zh-CN', 'zh', 'en']
// Practical application: Automatic language detection
class LanguageDetector {
static getSupportedLanguages() {
return ["en", "zh", "ja", "es", "fr", "de"];
}
static detectLanguage() {
const userLang = navigator.language || navigator.languages[0];
const langCode = userLang.split("-")[0]; // 'zh-CN' -> 'zh'
const supported = this.getSupportedLanguages();
if (supported.includes(langCode)) {
return langCode;
}
return "en"; // Default language
}
static setPageLanguage() {
const lang = this.detectLanguage();
// Set HTML language attribute
document.documentElement.lang = lang;
// Load corresponding language pack
console.log(`Detected language: ${lang}`);
// In real application, load corresponding language file
// this.loadLanguagePack(lang);
return lang;
}
static async loadLanguagePack(lang) {
try {
const response = await fetch(`/i18n/${lang}.json`);
const translations = await response.json();
console.log(`Loaded language pack: ${lang}`, translations);
return translations;
} catch (error) {
console.error(`Failed to load language pack: ${lang}`, error);
return {};
}
}
}
// Usage
const language = LanguageDetector.setPageLanguage();
console.log("Page language:", language);Online Status Detection
// Detect browser's current online status
console.log("Online status:", navigator.onLine); // true or false
// Listen for online/offline events
window.addEventListener("online", () => {
console.log("Network connected");
document.body.classList.remove("offline");
document.body.classList.add("online");
});
window.addEventListener("offline", () => {
console.log("Network disconnected");
document.body.classList.remove("online");
document.body.classList.add("offline");
});
// Practical application: Network status manager
class NetworkManager {
constructor() {
this.listeners = [];
this.init();
}
init() {
window.addEventListener("online", () => this.handleOnline());
window.addEventListener("offline", () => this.handleOffline());
// Initial status
if (!navigator.onLine) {
this.handleOffline();
}
}
handleOnline() {
console.log("Network restored");
this.showNotification("Network connected", "success");
this.syncOfflineData();
this.notifyListeners("online");
}
handleOffline() {
console.log("Network disconnected");
this.showNotification("Network disconnected, some features may be unavailable", "warning");
this.enableOfflineMode();
this.notifyListeners("offline");
}
showNotification(message, type = "info") {
console.log(`[${type.toUpperCase()}] ${message}`);
// In real application, display friendly notification UI
/*
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
*/
}
enableOfflineMode() {
console.log("Enabling offline mode");
// Disable features that require network
const onlineOnlyButtons = document.querySelectorAll("[data-online-only]");
onlineOnlyButtons.forEach((btn) => {
btn.disabled = true;
btn.title = "This feature requires network connection";
});
}
async syncOfflineData() {
console.log("Syncing offline data...");
// In real application, get offline data from IndexedDB or localStorage and sync
const offlineData = this.getOfflineData();
if (offlineData.length > 0) {
try {
// Sync data to server
// await fetch('/api/sync', {
// method: 'POST',
// body: JSON.stringify(offlineData)
// });
console.log("Offline data sync complete");
this.clearOfflineData();
} catch (error) {
console.error("Sync failed:", error);
}
}
}
getOfflineData() {
// Get offline data from local storage
return []; // Simplified example
}
clearOfflineData() {
// Clear synced offline data
}
onStatusChange(callback) {
this.listeners.push(callback);
}
notifyListeners(status) {
this.listeners.forEach((callback) => callback(status));
}
isOnline() {
return navigator.onLine;
}
}
// Usage
const networkManager = new NetworkManager();
networkManager.onStatusChange((status) => {
console.log("Network status changed:", status);
});Cookie and Storage
// Detect if Cookies are enabled
console.log("Cookies enabled:", navigator.cookieEnabled);
if (!navigator.cookieEnabled) {
alert("Please enable Cookies for the best experience");
}
// Detect Do Not Track setting
console.log("Do Not Track:", navigator.doNotTrack);
// '1' = enabled, '0' = not enabled, null = not setGeolocation API
// Detect if Geolocation API is available
if ("geolocation" in navigator) {
console.log("Geolocation API supported");
// Get current position
navigator.geolocation.getCurrentPosition(
(position) => {
console.log("Location information:");
console.log(" Latitude:", position.coords.latitude);
console.log(" Longitude:", position.coords.longitude);
console.log(" Accuracy:", position.coords.accuracy, "meters");
console.log(" Altitude:", position.coords.altitude);
console.log(" Timestamp:", new Date(position.timestamp));
},
(error) => {
console.error("Failed to get location:", error.message);
switch (error.code) {
case error.PERMISSION_DENIED:
console.log("User denied geolocation request");
break;
case error.POSITION_UNAVAILABLE:
console.log("Location information unavailable");
break;
case error.TIMEOUT:
console.log("Request timed out");
break;
}
},
{
enableHighAccuracy: true, // High accuracy mode
timeout: 5000, // Timeout (milliseconds)
maximumAge: 0, // Cache time (0 = don't use cache)
}
);
} else {
console.log("Geolocation API not supported");
}
// Practical application: Geolocation manager
class GeolocationManager {
static async getCurrentPosition() {
return new Promise((resolve, reject) => {
if (!("geolocation" in navigator)) {
reject(new Error("Browser does not support Geolocation API"));
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy,
timestamp: position.timestamp,
});
},
(error) => {
reject(error);
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000, // Cache 1 minute
}
);
});
}
static watchPosition(callback) {
if (!("geolocation" in navigator)) {
console.error("Browser does not support Geolocation API");
return null;
}
const watchId = navigator.geolocation.watchPosition(
(position) => {
callback({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy,
timestamp: position.timestamp,
});
},
(error) => {
console.error("Location watch error:", error);
},
{
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
}
);
return watchId;
}
static stopWatching(watchId) {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
}
}
static async getAddressFromCoords(lat, lng) {
// In real application, call geocoding API
console.log(`Getting address for: ${lat}, ${lng}`);
// Example: Use OpenStreetMap Nominatim API
try {
const response = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`
);
const data = await response.json();
return data.display_name;
} catch (error) {
console.error("Failed to get address:", error);
return null;
}
}
}
// Usage
async function showCurrentLocation() {
try {
const position = await GeolocationManager.getCurrentPosition();
console.log("Current location:", position);
const address = await GeolocationManager.getAddressFromCoords(
position.latitude,
position.longitude
);
console.log("Address:", address);
} catch (error) {
console.error("Failed to get location:", error.message);
}
}
// Watch position changes
// const watchId = GeolocationManager.watchPosition((position) => {
// console.log('Position updated:', position);
// });Screen Object Detailed
The screen object provides various information about the user's screen, primarily used for screen adaptation and display optimization.
Screen Dimension Properties
// Total screen dimensions (including taskbar, etc.)
console.log("Screen width:", screen.width); // e.g.: 1920
console.log("Screen height:", screen.height); // e.g.: 1080
// Available screen dimensions (excluding taskbar, etc.)
console.log("Available width:", screen.availWidth); // e.g.: 1920
console.log("Available height:", screen.availHeight); // e.g.: 1040
// Calculate space occupied by taskbar
const taskbarHeight = screen.height - screen.availHeight;
console.log("Taskbar height:", taskbarHeight); // e.g.: 40
// Practical application: Detect screen information
function getScreenInfo() {
return {
total: {
width: screen.width,
height: screen.height,
},
available: {
width: screen.availWidth,
height: screen.availHeight,
},
taskbar: {
height: screen.height - screen.availHeight,
width: screen.width - screen.availWidth,
},
aspectRatio: (screen.width / screen.height).toFixed(2),
};
}
console.log("Screen information:", getScreenInfo());Color Depth and Pixel Depth
// Color depth (bits)
console.log("Color depth:", screen.colorDepth);
// Usually 24 (approximately 16.7 million colors)
// Pixel depth (usually same as color depth)
console.log("Pixel depth:", screen.pixelDepth);
// Practical application: Color support detection
class ColorSupportDetector {
static getColorSupport() {
const depth = screen.colorDepth;
if (depth >= 24) {
return "truecolor"; // True color (16.7M+ colors)
} else if (depth >= 16) {
return "highcolor"; // High color (65,536 colors)
} else if (depth >= 8) {
return "lowcolor"; // 256 colors
} else {
return "monochrome"; // Monochrome
}
}
static canDisplay(colorMode) {
const support = this.getColorSupport();
const levels = ["monochrome", "lowcolor", "highcolor", "truecolor"];
return levels.indexOf(support) >= levels.indexOf(colorMode);
}
static adjustImageQuality() {
const support = this.getColorSupport();
if (support === "truecolor") {
console.log("Use high quality images");
return "high";
} else if (support === "highcolor") {
console.log("Use medium quality images");
return "medium";
} else {
console.log("Use low quality images");
return "low";
}
}
}
// Usage
console.log("Color support:", ColorSupportDetector.getColorSupport());
console.log("Can display true color:", ColorSupportDetector.canDisplay("truecolor"));
const imageQuality = ColorSupportDetector.adjustImageQuality();Screen Orientation
// Screen orientation (modern browsers)
if (screen.orientation) {
console.log("Screen orientation:", screen.orientation.type);
// 'portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary'
console.log("Rotation angle:", screen.orientation.angle);
// 0, 90, 180, 270
// Listen for orientation changes
screen.orientation.addEventListener("change", () => {
console.log("Orientation changed:", screen.orientation.type);
console.log("Rotation angle:", screen.orientation.angle);
});
}
// Practical application: Screen orientation manager
class OrientationManager {
constructor() {
this.listeners = [];
this.init();
}
init() {
if (!screen.orientation) {
console.warn("Browser does not support screen.orientation API");
return;
}
screen.orientation.addEventListener("change", () => {
this.handleOrientationChange();
});
// Initial detection
this.handleOrientationChange();
}
handleOrientationChange() {
const orientation = this.getCurrentOrientation();
console.log("Current orientation:", orientation);
// Update body class
document.body.classList.remove("portrait", "landscape");
document.body.classList.add(orientation);
// Notify listeners
this.notifyListeners(orientation);
}
getCurrentOrientation() {
if (screen.orientation) {
return screen.orientation.type.includes("portrait")
? "portrait"
: "landscape";
}
// Fallback: Use window dimensions to determine
return window.innerHeight > window.innerWidth ? "portrait" : "landscape";
}
isPortrait() {
return this.getCurrentOrientation() === "portrait";
}
isLandscape() {
return this.getCurrentOrientation() === "landscape";
}
onChange(callback) {
this.listeners.push(callback);
}
notifyListeners(orientation) {
this.listeners.forEach((callback) => callback(orientation));
}
async lockOrientation(orientation) {
if (!screen.orientation || !screen.orientation.lock) {
console.warn("Browser does not support locking screen orientation");
return false;
}
try {
await screen.orientation.lock(orientation);
console.log("Screen orientation locked:", orientation);
return true;
} catch (error) {
console.error("Failed to lock orientation:", error);
return false;
}
}
unlockOrientation() {
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
console.log("Screen orientation unlocked");
}
}
}
// Usage
const orientationManager = new OrientationManager();
orientationManager.onChange((orientation) => {
console.log("Orientation changed:", orientation);
if (orientation === "portrait") {
console.log("Apply portrait layout");
} else {
console.log("Apply landscape layout");
}
});Comprehensive Practical Application Example
Device Adaptation Manager
class DeviceAdapter {
static getDeviceInfo() {
const browser = BrowserDetector.getInfo();
const screen = getScreenInfo();
return {
browser,
screen,
viewport: {
width: window.innerWidth,
height: window.innerHeight,
},
devicePixelRatio: window.devicePixelRatio || 1,
touchSupport: "ontouchstart" in window,
online: navigator.onLine,
language: navigator.language,
};
}
static getOptimalImageSize() {
const dpr = window.devicePixelRatio || 1;
const width = window.innerWidth;
// Select appropriate image size based on DPR and screen width
if (dpr >= 3) {
return width < 768 ? "2x" : "3x";
} else if (dpr >= 2) {
return "2x";
} else {
return "1x";
}
}
static shouldLoadHighQualityAssets() {
// Consider multiple factors
const hasGoodConnection = navigator.connection
? navigator.connection.effectiveType === "4g"
: true;
const hasGoodScreen = screen.width >= 1920 && screen.colorDepth >= 24;
const hasGoodBrowser = !BrowserDetector.getBrowserName().includes("IE");
return hasGoodConnection && hasGoodScreen && hasGoodBrowser;
}
static applyOptimizations() {
const info = this.getDeviceInfo();
console.log("=== Device Adaptation ===");
console.log("Device information:", info);
// Apply optimizations based on device capabilities
if (info.devicePixelRatio > 1) {
console.log("High DPI screen, load 2x/3x images");
document.body.classList.add("retina");
}
if (!info.touchSupport) {
console.log("Non-touch device, enable hover effects");
document.body.classList.add("no-touch");
} else {
console.log("Touch device, disable hover effects");
document.body.classList.add("touch");
}
if (info.screen.total.width < 768) {
console.log("Small screen device, apply mobile optimizations");
document.body.classList.add("mobile-optimized");
}
if (this.shouldLoadHighQualityAssets()) {
console.log("Device has good capabilities, load high quality resources");
document.body.classList.add("high-quality");
} else {
console.log("Device has limited capabilities, load standard quality resources");
document.body.classList.add("standard-quality");
}
}
}
// Usage
DeviceAdapter.applyOptimizations();Feature Detection Utility Set
class FeatureDetector {
// Detect various API support
static checkSupport() {
return {
geolocation: "geolocation" in navigator,
localStorage: this.testLocalStorage(),
sessionStorage: this.testSessionStorage(),
indexedDB: "indexedDB" in window,
serviceWorker: "serviceWorker" in navigator,
webWorker: typeof Worker !== "undefined",
webSocket: "WebSocket" in window,
notification: "Notification" in window,
vibration: "vibrate" in navigator,
batteryAPI: "getBattery" in navigator,
networkInfo: "connection" in navigator,
mediaDevices: "mediaDevices" in navigator,
clipboard: "clipboard" in navigator,
share: "share" in navigator,
screenOrientation: "orientation" in screen,
};
}
static testLocalStorage() {
try {
const test = "__test__";
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
static testSessionStorage() {
try {
const test = "__test__";
sessionStorage.setItem(test, test);
sessionStorage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
static displaySupport() {
const support = this.checkSupport();
console.log("=== Browser Feature Support ===");
Object.entries(support).forEach(([feature, supported]) => {
const status = supported ? "✓" : "✗";
console.log(`${status} ${feature}`);
});
}
static getMissingFeatures(required) {
const support = this.checkSupport();
return required.filter((feature) => !support[feature]);
}
static checkRequirements(required) {
const missing = this.getMissingFeatures(required);
if (missing.length > 0) {
console.warn("Missing required features:", missing);
return false;
}
console.log("All required features are supported");
return true;
}
}
// Usage
FeatureDetector.displaySupport();
// Check specific feature requirements
const requiredFeatures = ["geolocation", "localStorage", "serviceWorker"];
if (!FeatureDetector.checkRequirements(requiredFeatures)) {
alert("Your browser doesn't support some required features. Please upgrade your browser.");
}Best Practices
1. Use Feature Detection Rather Than Browser Detection
// ❌ Not recommended: Browser detection
if (navigator.userAgent.includes("Chrome")) {
// Use some feature
}
// ✅ Recommended: Feature detection
if ("geolocation" in navigator) {
// Use geolocation feature
}
if (typeof Worker !== "undefined") {
// Use Web Worker
}2. Graceful Degradation
class StorageManager {
static set(key, value) {
if (FeatureDetector.testLocalStorage()) {
localStorage.setItem(key, value);
} else {
// Fallback: Use Cookie
document.cookie = `${key}=${value}; path=/`;
}
}
static get(key) {
if (FeatureDetector.testLocalStorage()) {
return localStorage.getItem(key);
} else {
// Read from Cookie
const match = document.cookie.match(new RegExp(`${key}=([^;]+)`));
return match ? match[1] : null;
}
}
}3. Privacy Protection
// Respect user's Do Not Track setting
if (navigator.doNotTrack === "1") {
console.log("User enabled Do Not Track, don't collect statistics");
// Disable tracking features
} else {
console.log("Can collect anonymous statistics");
// Enable tracking features (requires user consent)
}Summary
navigator and screen objects are important tools for getting browser and screen information:
Navigator Object:
- Browser information (
userAgent,appName,appVersion) - System information (
platform,language) - Online status (
onLine) - Geolocation (
geolocation) - Cookie support (
cookieEnabled)
Screen Object:
- Screen dimensions (
width,height,availWidth,availHeight) - Color depth (
colorDepth,pixelDepth) - Screen orientation (
orientation)
Best Practices:
- Use feature detection rather than browser detection
- Implement graceful degradation
- Respect user privacy settings
- Consider multiple factors for device adaptation
- Cache detection results to improve performance