WSJ Dark Mode

Elegant dark mode for Wall Street Journal when system dark mode is enabled

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name         WSJ Dark Mode
// @namespace    https://www.wsj.com
// @version      0.0.4
// @description  Elegant dark mode for Wall Street Journal when system dark mode is enabled
// @author       hxueh
// @match        *://*.wsj.com/*
// @grant        GM_addStyle
// @run-at       document-start
// @icon         https://s.wsj.net/img/meta/wsj_favicon.svg
// @license      MIT
// ==/UserScript==
 
(function () {
  'use strict';
 
  // Color palette - elegant dark theme
  const colors = {
    bg: '#000000',
    bgElevated: '#000000',
    bgCard: '#000000',
    bgHover: '#0a0a0a',
    text: '#e8e6e3',
    textMuted: '#a8a5a0',
    textSubtle: '#888888',
    accent: '#d4a853',
    accentHover: '#e6bc6a',
    link: '#7eb8da',
    linkHover: '#a3d0eb',
    border: '#1a1a1a',
    borderSubtle: '#111111',
  };
 
  const darkModeCSS = `
    /*========================================
      WSJ Dark Mode - Base Styles
    ========================================*/
 
    :root {
      color-scheme: dark;
    }
 
    /* Global resets */
    html, body {
      background-color: ${colors.bg} !important;
      color: ${colors.text} !important;
    }
 
    /* Main content areas */
    body,
    main,
    article,
    section,
    div,
    header,
    footer,
    nav,
    aside {
      background-color: transparent !important;
    }
 
    /* Override specific WSJ containers */
    .WSJTheme--page-container--,
    .WSJTheme--pageWrapper--,
    [class*="PageWrapper"],
    [class*="page-container"],
    [class*="MainContent"],
    [class*="ArticleBody"],
    [class*="wrapper"],
    #root,
    #__next,
    .container {
      background-color: ${colors.bg} !important;
    }
 
    /*========================================
      Typography
    ========================================*/
 
    /* Headings */
    h1, h2, h3, h4, h5, h6,
    [class*="Headline"],
    [class*="headline"],
    [class*="Title"],
    [class*="title"] {
      color: ${colors.text} !important;
    }
 
    /* Body text */
    p, span, li, td, th, label,
    [class*="Paragraph"],
    [class*="paragraph"],
    [class*="Body"],
    [class*="Summary"],
    [class*="summary"],
    [class*="Description"],
    [class*="description"] {
      color: ${colors.text} !important;
    }
 
    /* Muted text */
    [class*="Byline"],
    [class*="byline"],
    [class*="Timestamp"],
    [class*="timestamp"],
    [class*="Meta"],
    [class*="meta"],
    time,
    figcaption,
    .caption,
    [class*="Caption"] {
      color: ${colors.textMuted} !important;
    }
 
    /* Subtle text */
    [class*="Label"],
    [class*="Tag"],
    small {
      color: ${colors.textSubtle} !important;
    }
 
    /*========================================
      Links
    ========================================*/
 
    a {
      color: ${colors.link} !important;
      transition: color 0.15s ease !important;
    }
 
    a:hover {
      color: ${colors.linkHover} !important;
    }
 
    /* Article headlines as links */
    a h1, a h2, a h3, a h4,
    h1 a, h2 a, h3 a, h4 a,
    [class*="Headline"] a,
    a[class*="Headline"] {
      color: ${colors.text} !important;
    }
 
    a:hover h1, a:hover h2, a:hover h3, a:hover h4,
    h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover {
      color: ${colors.accent} !important;
    }
 
    /*========================================
      Cards & Containers
    ========================================*/
 
    [class*="Card"],
    [class*="card"],
    [class*="Module"],
    [class*="module"],
    [class*="Story"],
    [class*="story"],
    [class*="Item"],
    [class*="Promo"],
    [class*="promo"] {
      background-color: ${colors.bgCard} !important;
      border-color: ${colors.border} !important;
      border-radius: 8px !important;
    }
 
    /* Elevated surfaces */
    [class*="Modal"],
    [class*="modal"],
    [class*="Popup"],
    [class*="popup"],
    [class*="Tooltip"],
    [class*="tooltip"] {
      background-color: #000000 !important;
      border-color: ${colors.border} !important;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8) !important;
    }
 
    /* Menu-specific styles - high specificity */
    [class*="Menu"],
    [class*="menu"],
    div[class*="Menu"],
    div[class*="menu"],
    ul[class*="Menu"],
    ul[class*="menu"] {
      background-color: #000000 !important;
      border: 1px solid ${colors.border} !important;
    }
 
    /* Menu items */
    [class*="Menu"] > *,
    [class*="menu"] > *,
    [class*="Menu"] li,
    [class*="menu"] li,
    [class*="Menu"] a,
    [class*="menu"] a {
      background-color: #000000 !important;
    }
 
    [class*="Menu"] a:hover,
    [class*="menu"] a:hover,
    [class*="Menu"] li:hover,
    [class*="menu"] li:hover {
      background-color: ${colors.bgHover} !important;
    }
 
    /*========================================
      Navigation & Header
    ========================================*/
 
    header,
    nav,
    [class*="Header"],
    [class*="header"],
    [class*="Nav"],
    [class*="nav"],
    [class*="Masthead"],
    [class*="masthead"],
    [class*="TopBar"],
    [class*="topbar"] {
      background-color: ${colors.bgElevated} !important;
      border-bottom-color: ${colors.border} !important;
    }
 
    /* Navigation dropdown menus */
    [class*="Dropdown"],
    [class*="dropdown"],
    [class*="Flyout"],
    [class*="flyout"],
    [class*="Submenu"],
    [class*="submenu"],
    [class*="SubNav"],
    [class*="subnav"],
    [class*="MenuPanel"],
    [class*="menu-panel"],
    [class*="NavPanel"],
    [class*="nav-panel"],
    [class*="DropdownMenu"],
    [class*="dropdown-menu"],
    nav ul ul,
    nav > div > div,
    [role="menu"],
    [aria-expanded="true"] + div,
    [aria-expanded="true"] + ul,
    header [class*="expanded"],
    header [class*="open"],
    header [class*="active"] > div,
    header [class*="hover"] > div {
      background-color: #000000 !important;
      border: 1px solid ${colors.border} !important;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.9) !important;
    }
 
    /* Nested navigation links in dropdowns */
    nav a,
    [class*="Nav"] a,
    [class*="nav"] a,
    header a {
      background-color: transparent !important;
    }
 
    nav li,
    [class*="Nav"] li,
    header li {
      background-color: transparent !important;
    }
 
    /* Dropdown container backgrounds */
    nav [class*="container"],
    nav [class*="wrapper"],
    nav [class*="content"],
    header [class*="container"],
    header [class*="wrapper"] {
      background-color: #000000 !important;
    }
 
    /* WSJ Logo - invert images for dark mode */
    [class*="Logo"] img,
    [class*="logo"] img,
    .wsj-logo img {
      filter: brightness(0) invert(1) !important;
    }

    /* WSJ Logo - SVG logos */
    [class*="Logo"] svg,
    [class*="logo"] svg,
    [class*="WSJLogo"] svg,
    [class*="wsj-logo"] svg,
    [class*="Masthead"] svg,
    [class*="masthead"] svg,
    header svg[class*="logo" i],
    nav svg[class*="logo" i] {
      filter: brightness(0) invert(1) !important;
    }

    /* WSJ specific logo classes */
    [class*="WSJLogo"],
    [class*="wsj-logo"],
    [class*="wsjLogo"],
    [class*="WSJTheme--logo"],
    [class*="SiteLogo"],
    [class*="site-logo"],
    [class*="BrandLogo"],
    [class*="brand-logo"] {
      filter: brightness(0) invert(1) !important;
    }

    /* Header logo links - target the logo container */
    header [class*="Logo"],
    header [class*="logo"],
    nav [class*="Logo"],
    nav [class*="logo"],
    [class*="Masthead"] [class*="Logo"],
    [class*="masthead"] [class*="logo"] {
      filter: brightness(0) invert(1) !important;
    }

    /* Ensure child elements of logo also get inverted */
    [class*="Logo"] *,
    [class*="logo"][class*="wsj" i] *,
    [class*="WSJLogo"] *,
    [class*="wsj-logo"] * {
      filter: inherit !important;
    }

    /* Reset filter for non-logo header elements */
    header a:not([class*="logo" i]):not([class*="Logo"]),
    nav a:not([class*="logo" i]):not([class*="Logo"]) {
      filter: none !important;
    }
 
    /*========================================
      Footer
    ========================================*/
 
    footer,
    [class*="Footer"],
    [class*="footer"] {
      background-color: ${colors.bgElevated} !important;
      border-top-color: ${colors.border} !important;
    }
 
    /*========================================
      Sidebar & Secondary Content
    ========================================*/
 
    aside,
    [class*="Sidebar"],
    [class*="sidebar"],
    [class*="Rail"],
    [class*="rail"],
    [class*="Secondary"],
    [class*="secondary"] {
      background-color: ${colors.bg} !important;
    }
 
    /*========================================
      Forms & Inputs
    ========================================*/
 
    input,
    textarea,
    select {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
      border-radius: 6px !important;
    }
 
    input:focus,
    textarea:focus,
    select:focus {
      border-color: ${colors.accent} !important;
      outline: none !important;
      box-shadow: 0 0 0 2px rgba(212, 168, 83, 0.2) !important;
    }
 
    input::placeholder,
    textarea::placeholder {
      color: ${colors.textSubtle} !important;
    }
 
    /*========================================
      Buttons
    ========================================*/
 
    button,
    [class*="Button"],
    [class*="button"],
    [class*="Btn"],
    [class*="btn"],
    [role="button"] {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
      transition: all 0.15s ease !important;
    }
 
    button:hover,
    [class*="Button"]:hover,
    [class*="button"]:hover,
    [class*="Btn"]:hover,
    [class*="btn"]:hover,
    [role="button"]:hover {
      background-color: ${colors.bgHover} !important;
      border-color: ${colors.accent} !important;
    }
 
    /* Primary buttons */
    [class*="Primary"],
    [class*="primary"],
    button[class*="subscribe" i],
    button[class*="Subscribe" i] {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
      border-color: ${colors.accent} !important;
    }
 
    [class*="Primary"]:hover,
    [class*="primary"]:hover {
      background-color: ${colors.accentHover} !important;
      border-color: ${colors.accentHover} !important;
    }
 
    /*========================================
      Tables
    ========================================*/
 
    table {
      background-color: ${colors.bg} !important;
      border-color: ${colors.border} !important;
    }
 
    th {
      background-color: ${colors.bgElevated} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
    }
 
    td {
      background-color: ${colors.bg} !important;
      color: ${colors.text} !important;
      border-color: ${colors.borderSubtle} !important;
    }
 
    tr:hover td {
      background-color: ${colors.bgHover} !important;
    }
 
    /*========================================
      Borders & Dividers
    ========================================*/
 
    hr,
    [class*="Divider"],
    [class*="divider"],
    [class*="Border"],
    [class*="border"],
    [class*="Separator"],
    [class*="separator"] {
      border-color: ${colors.border} !important;
      background-color: ${colors.border} !important;
    }
 
    /*========================================
      Images & Media
    ========================================*/
 
    img {
      opacity: 0.92;
      transition: opacity 0.2s ease;
    }
 
    img:hover {
      opacity: 1;
    }
 
    figure {
      background-color: transparent !important;
    }
 
    /* Video containers */
    [class*="Video"],
    [class*="video"],
    [class*="Player"],
    [class*="player"] {
      background-color: ${colors.bgCard} !important;
    }
 
    /*========================================
      Article Specific
    ========================================*/
 
    /* Article body */
    article,
    [class*="Article"],
    [class*="article"] {
      background-color: ${colors.bg} !important;
    }
 
    /* Blockquotes */
    blockquote,
    [class*="Quote"],
    [class*="quote"],
    [class*="Pullquote"],
    [class*="pullquote"] {
      background-color: ${colors.bgCard} !important;
      border-left-color: ${colors.accent} !important;
      color: ${colors.text} !important;
      border-radius: 0 8px 8px 0 !important;
      padding: 1rem 1.5rem !important;
    }
 
    /* Code blocks */
    pre, code {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
    }
 
    /*========================================
      Ads & Promotions (dim them)
    ========================================*/
 
    [class*="Ad"],
    [class*="ad-"],
    [id*="ad-"],
    [class*="Advertisement"],
    [class*="advertisement"],
    [class*="Promo"],
    [data-ad],
    iframe[src*="ad"] {
      opacity: 0.7 !important;
      filter: brightness(0.85) !important;
    }
 
    /*========================================
      Scrollbar
    ========================================*/
 
    ::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
 
    ::-webkit-scrollbar-track {
      background: ${colors.bg};
    }
 
    ::-webkit-scrollbar-thumb {
      background: ${colors.border};
      border-radius: 5px;
    }
 
    ::-webkit-scrollbar-thumb:hover {
      background: ${colors.textSubtle};
    }
 
    /* Firefox scrollbar */
    * {
      scrollbar-width: thin;
      scrollbar-color: ${colors.border} ${colors.bg};
    }
 
    /*========================================
      Selection
    ========================================*/
 
    ::selection {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
    }
 
    ::-moz-selection {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
    }
 
    /*========================================
      Override inline styles (nuclear option)
    ========================================*/
 
    [style*="background-color: rgb(255"],
    [style*="background-color: #fff"],
    [style*="background-color: white"],
    [style*="background: rgb(255"],
    [style*="background: #fff"],
    [style*="background: white"] {
      background-color: ${colors.bg} !important;
    }
 
    [style*="color: rgb(0"],
    [style*="color: #000"],
    [style*="color: black"] {
      color: ${colors.text} !important;
    }
 
    /*========================================
      WSJ-Specific Overrides
    ========================================*/
 
    /* Market data colors - keep green/red for stocks */
    [class*="positive"],
    [class*="Positive"],
    [class*="gain"],
    [class*="Gain"],
    [class*="up"] {
      color: #4ade80 !important;
    }
 
    [class*="negative"],
    [class*="Negative"],
    [class*="loss"],
    [class*="Loss"],
    [class*="down"] {
      color: #f87171 !important;
    }
 
    /* Paywall/subscription modals */
    [class*="Paywall"],
    [class*="paywall"],
    [class*="Subscribe"],
    [class*="subscribe"] {
      background-color: ${colors.bgElevated} !important;
    }
 
    /* Search results */
    [class*="Search"],
    [class*="search"] {
      background-color: ${colors.bg} !important;
    }
 
    /* Comments section */
    [class*="Comment"],
    [class*="comment"] {
      background-color: ${colors.bgCard} !important;
      border-color: ${colors.border} !important;
    }
 
    /*========================================
      Smooth transitions for dynamic content
    ========================================*/
 
    * {
      transition: background-color 0.1s ease, border-color 0.1s ease;
    }
 
    /* Disable transitions for specific elements */
    a, button, input, img, video {
      transition: none;
    }
 
    a {
      transition: color 0.15s ease !important;
    }
  `;
 
  // Check for dark mode preference
  function isDarkMode() {
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
  }
 
  // Apply or remove dark mode styles
  let styleElement = null;
 
  function applyDarkMode() {
    if (!styleElement) {
      styleElement = document.createElement('style');
      styleElement.id = 'wsj-dark-mode-styles';
      styleElement.textContent = darkModeCSS;
    }
    if (!document.getElementById('wsj-dark-mode-styles')) {
      (document.head || document.documentElement).appendChild(styleElement);
    }
  }
 
  function removeDarkMode() {
    const existing = document.getElementById('wsj-dark-mode-styles');
    if (existing) {
      existing.remove();
    }
  }
 
  function updateTheme() {
    if (isDarkMode()) {
      applyDarkMode();
    } else {
      removeDarkMode();
    }
  }
 
  // Initial application
  updateTheme();
 
  // Listen for system theme changes
  if (window.matchMedia) {
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme);
  }
 
  // Re-apply styles when DOM is ready (for dynamic content)
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', updateTheme);
  }
 
  // Observe for dynamic content changes
  const observer = new MutationObserver((mutations) => {
    if (isDarkMode() && !document.getElementById('wsj-dark-mode-styles')) {
      applyDarkMode();
    }
  });
 
  // Start observing when body is available
  function startObserver() {
    if (document.body) {
      observer.observe(document.body, {
        childList: true,
        subtree: true,
      });
    } else {
      requestAnimationFrame(startObserver);
    }
  }
 
  startObserver();
 
  console.log('🌙 WSJ Dark Mode loaded - respects system preference');
})();