Dark Mode Google Maps

Google Maps doesn't support the prefers-color-scheme: dark media query, and therefore remain bright even when the rest of the website has gone dark. But you can get something close to a dark mode Google Maps with a little bit of JavaScript.

1. The Map

1.1. The Color Scheme

Start by grabbing the Styled Maps - Night Mode list of map stylers from Google's documentation, and create a default empty list of stylers for the light mode.

var LIGHT_MODE_STYLES = [];
var DARK_MODE_STYLES = [
    { elementType: "geometry", stylers: [{ color: "#242f3e" }] },
    { elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
    { elementType: "labels.text.fill", stylers: [{ color: "#746855" }] },
    ...

1.2. Setting the Color Scheme

This is how you set a style on a map - simply call the setOptions method on the map. This will not change any other map options.

map.setOptions({
    styles: DARK_MODE_STYLES
})

1.3. Switching Color Scheme

Next step is to switch the map style when the color scheme changes (and initialize the map with the right style):

var darkColorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)');

function onColorSchemeChange() {
    if(darkColorSchemeQuery.matches){
        map.setOptions({
            styles: DARK_MODE_STYLES
        });
    } else {
        map.setOptions({
            styles: LIGHT_MODE_STYLES
        });
    }
}

// Set up change event listener
darkColorSchemeQuery.addEventListener('change', function() { onColorSchemeChange(); });
// Initialize the map with the right colors
onColorSchemeChange();

1.4. Map Controls

You can replace the map controls with your own (and I suspect that sufficiently hackish CSS rules can restyle the existing controls), but I really don't want to spend time keeping up with Google. Especially getting the little droppable Street View Pegman right seems like a nightmare. I just skipped this.

2. Info Windows

If you use Maps's own InfoWindow, you'll notice it's not very stylable.

2.1. InfoBubble

InfoBubble, which is stylable and available on GitHub, solves that problem. But you need to use CSS Variables to make it switch along with the user's preference:

html {
    --text-background: #fff;
    --panel-border: #b8b8b8;
}

@media screen and (prefers-color-scheme: dark) {
    html {
        --text-background: #000;
        --panel-border: #383838;
    }
}

Then provide the variables to InfoBubble as style property values:

var infoBubbleOptions = {
    backgroundColor: "var(--text-background)",
    borderColor: "var(--panel-border)"
};

2.2. Scrollbars

To get the scrollbars in the info bubble to support dark mode, add a conditional color-scheme property on the :root element.

@media screen and (prefers-color-scheme: dark) {
    :root {
        color-scheme: dark;
    }
}