WSJ Dark Mode

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

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==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');
})();