How to turn a Ghost theme to dark mode

There are a lot of things I like about the Edge theme, but the black and grey on white color scheme didn't work. Hack the theme or code injection?

How to turn a Ghost theme to dark mode
Logo copyright: Ghost Foundation

There are a lot of things I like about the Edge theme (especially for photo-heavy displays), but the black and grey on white color scheme didn't fit my client's ideas. She wanted pale yellow on black/dark grey. Edge doesn't have a built in dark mode. (Looking for a theme that does? Check this list of themes with dark mode.

💡
The first approach below requires hacking your theme's css files. I thought I needed to do this. I was wrong. (Keep scrolling.)

Here's what the relevant bit of the basics.css file (in assets/css/general) looked like:

:root {
    --primary-text-color: #333;
    --secondary-text-color: #999;
    --white-color: #fff;
    --light-gray-color: #f1f1f1;
    --mid-gray-color: #e9e9e9;
    --dark-gray-color: #1a1a1a;
    --black-color: #000;
    --font-base: Rubik, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
    --font-serif: Lora, Times, serif;
    --animation-base: ease-in-out;
}

My first naïve attempt was to change --primary-text-color and --secondary-text-color. That got me mostly pale yellow on white background, with various shades of grey. Not a win. I found the body background color was set to --white-color. Ok, fixed that. Then I spent hours playing whack-a-mole, changing lighter greys to darker greys, white-color to black-color, etc. I never found them all. The naming in this theme made semantic sense, but maintaining the semantics meant touching way too many css files.

Eventually, I realized there was an easier way to go about this: I gave up on semantics and changed that same section to this:

:root {
    --primary-text-color: #f6f2c0;
    --secondary-text-color: #fff;
    --white-color: #000;
    --light-gray-color: #333;
    --mid-gray-color: #aaa;
    --dark-gray-color: #f6f2c0;
    --black-color: #fff;
    --font-base: Rubik, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
    --font-serif: Lora, Times, serif;
    --animation-base: ease-in-out;
}

That did everything. Boom, instant dark mode. Well, everything but the photoswiper, which was the reason I wanted to use Edge in the first place. The photoswiper styling didn't use the color variables I'd changed, and so I was getting a white-ish mostly transparent background. With yellow and white text - yuck! Instead, I needed to dig into assets/css/vendors/pswp.css. Here's the bits that needed to change:

.pswp__bg {
  ...
  background: rgba(0, 0, 0, 0.9); /* Changed to make the background black */
  ...

Then the swiper looked good, EXCEPT the arrows and magnifier icons were now black on black. Not a good look. The problem was here:

.pswp__button,
.pswp__button--arrow--left:before,
.pswp__button--arrow--right:before {
  background: url(../images/default-skin.png) 0 0 no-repeat;
  background-size: 264px 88px;
  height: 44px;
  width: 44px;
}
@media (-webkit-min-device-pixel-ratio: 1.1), (-webkit-min-device-pixel-ratio: 1.09375), (min-resolution: 105dpi), (min-resolution: 1.1dppx) {
  .pswp--svg .pswp__button,
  .pswp--svg .pswp__button--arrow--left:before,
  .pswp--svg .pswp__button--arrow--right:before {
    background-image: url(../images/default-skin.svg);
  }

Those files had black icons. The fix is to replace the file (or to link to a different file). I opened the .svg in Illustrator, recolored, saved as .svg and exported as .png (being sure to use the artboard to get the icons in the right place). For any Edge users who'd like to use my files, here they are:

So. Now that I've said all that, did I need to edit any of those css, or could I have used code injection? I think file editing made sense in my case, because I had a bunch of other changes I needed to make to the theme. But could code injection work?

Well, yeah, as it turns out. And I should have started there. Here's my injected code:

<style>
    :root {
    --primary-text-color: #f6f2c0;
    --secondary-text-color: #fff;
    --white-color: #000;
    --light-gray-color: #333;
    --mid-gray-color: #aaa;
    --dark-gray-color: #f6f2c0;
    --black-color: #fff;
    --font-base: Rubik, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
    --font-serif: Lora, Times, serif;
    --animation-base: ease-in-out;
}
.pswp__bg {
  background: rgba(0, 0, 0, 0.9); /* Changed to make the background black */
}   
</style>

That covers everything except loading different files. If you can edit your theme, great. Drop the new files in the theme. If you can't? Code injection! Here's more code injection (which can go right before the </style> tag):

.pswp__button,
.pswp__button--arrow--left:before,
.pswp__button--arrow--right:before {
  background: url(YOUR URL.png) 0 0 no-repeat;
}
@media (-webkit-min-device-pixel-ratio: 1.1), (-webkit-min-device-pixel-ratio: 1.09375), (min-resolution: 105dpi), (min-resolution: 1.1dppx) {
  .pswp--svg .pswp__button,
  .pswp--svg .pswp__button--arrow--left:before,
  .pswp--svg .pswp__button--arrow--right:before {
    background-image: url(YOUR URL.svg);
  }
}
.pswp__button--close {
  background-position: 0 -44px;
}
.pswp__button--share {
  background-position: -44px -44px;
}
.pswp__button--fs {
  display: none;
}
.pswp--supports-fs .pswp__button--fs {
  display: block;
}
.pswp--fs .pswp__button--fs {
  background-position: -44px 0;
}
.pswp__button--zoom {
  background-position: -88px 0;
  display: none;
}
.pswp--zoom-allowed .pswp__button--zoom {
  display: block;
}
.pswp--zoomed-in .pswp__button--zoom {
  background-position: -132px 0;
}
.pswp--touch .pswp__button--arrow--left,
.pswp--touch .pswp__button--arrow--right {
  visibility: hidden;
}
.pswp__button--arrow--left,
.pswp__button--arrow--right {
  background: none;
  height: 100px;
  margin-top: -50px;
  position: absolute;
  top: 50%;
  width: 70px;
}
.pswp__button--arrow--left {
  left: 0;
}
.pswp__button--arrow--right {
  right: 0;
}
.pswp__button--arrow--left:before,
.pswp__button--arrow--right:before {
  content: "";
  height: 30px;
  position: absolute;
  top: 35px;
  width: 32px;
}
.pswp__button--arrow--left:before {
  background-position: -138px -44px;
  left: 6px;
}
.pswp__button--arrow--right:before {
  background-position: -94px -44px;
  right: 6px;
}

I thought I didn't need most of the extra pswp__button code in my code injection, but my initial slimmed-down attempts didn't work, because otherwise my code injection was overwriting some of these button-specific settings. I suspect I can thin it down somewhat, but I haven't had a chance to do so yet.

Update: And then I rolled it out to production, and discovered that for whatever reason, that version of ghost (or maybe edge theme, but I thought I had the same one?) is also pulling in a few more color variables. So I added:

    --color-primary-text: #f6f2c0!important;
    --color-secondary-text: #fff!important;
    --color-white: #000!important;
    --color-light-gray: #333!important;
    --color-mid-gray: #aaa!important;
    --color-dark-gray: #f6f2c0!important;
    --color-darker-gray: #f6f2c0!important;
    --color-black: #fff!important;

...to the first section above.