mkdocs icon indicating copy to clipboard operation
mkdocs copied to clipboard

Update mkdocs theme to bootstrap 5.3 and add support for dark mode.

Open waylan opened this issue 1 year ago • 15 comments

This is related to #2248 but does not resolve that issue. That issue is requesting the option for the reader to select dark/light from the website itself. However, this only implements the option to select light/dark mode at build time from within the config file. Presumably, #2248 could be built on top of this.

As of version 5.3, Bootstrap supports color modes and provides light and dark modes out-of-the-box. The mkdocs theme has always used the Bootswatch Cerulean theme. Therefore, this updates the CSS and JS to version 5.3 of Bootstrap/Bootswatch and also updates most of the color definitions in the local CSS (base.css and extera.css) to use bootstrap variables (for example, admonitions now use Bootstrap colors). That way, switching between light and dark modes provides consistent results.

The challenge is with code blocks and the default syntax highlighter used by the theme (Highlight.js. Highlight.js defines isn't own background colors for code blocks in its CSS files. And Highlight.js provides 496 themes, not all of which have light/dark counterparts. This presents multiple challenges.

First of all, the background colors do not exactly match Bootstrap's colors. However, so long as every code block is processed by Highlight.js, then they all look the same. That means the nohighlight code blocks will get a different background color. Therefore, text should be used as the 'language' to maintain consistently styled code blocks (I have included an update to the docs in this regard).

At some point in the past, the hljs_style config option was added to the mkdocs theme. This option accepts the string name of any of Highlight.js' many themes and the template simply inserts that string into the URL pointing to the CSS file hosted in a CDN. In fact, this is why the theme uses a CDN. Otherwise, all 496 CSS files would need to be included with the theme files on MkDocs. We could pick two Highlight.js themes (one each for light and dark modes) and host them locally, but that would be a breaking change. Therefore, whenever the color mode is changed, the theme needs to be changed to match. There are a few different ways we could do this:

  1. Require the user to change both the color_mode and hljs_style independently. One would have no effect on the other.
  2. Provide a second "dark" config option (i.e.: hljs_style_dark) which defines the corresponding dark theme for Highlight.js. Then the relevant option could be used depending on color_mode.
  3. We could abandon Highlight.js and instead rely on the codehilite Markdown extension, which would require hosting our own CSS styles.
  4. Something else I haven't considered...

While option 1 would be the simplest, is would likely result in many complaints from users as the two config options would presumably be connected. Therefore, I have implemented option 2 here. Option 3 would be a breaking change, but would be much easier to work with in any future implementation of #2248.

Any input would be appreciated on the above issues.

Finally, I will note that as of Bootstrap version 5, jQuery was dropped as a dependency. Bootstrap now uses plain Javascript with the exception of Popper.js (which is included in the Bootstrap bundle) for popups/modals/etc. However, most of the Javascript in the mkdocs theme still uses jQuery. Presumably we could refactor all of the code in base.js to not depend on jQuery, which would have the protentional to reduce load times, etc. That said, many users likely have custom JavaScript of their own (in extra.js`) which expects jQuery, so removing jQuery completely would be a breaking change. Therefore, I have left that for a separate use to deal with. The only changes I made to the Javascript code were to update calls to Bootstrap's API.

waylan avatar Dec 01 '23 16:12 waylan

I will update the failing test later. I am out of time today.

waylan avatar Dec 01 '23 16:12 waylan

See #3189 which suggests a refactor of the Highlight.js config options.

waylan avatar Dec 05 '23 19:12 waylan

However, this only implements the option to select light/dark mode at build time from within the config file.

Most websites I visited and also some desktops give the possibility to choose dark/light versions of a theme at runtime, I don't see why to set it at build time instead making a dark version of the existing themes and choose if to use the system/dark/light color mode at runtime like the former do. Other than that, if it's possible to use js (I was told it's possible via css but I wasn't able to make it work) you can also swap highlightjs at runtime (I used MKDocs to build this site).

redtide avatar Dec 14 '23 11:12 redtide

  1. Require the user to change both the color_mode and hljs_style independently. One would have no effect on the other.

I think the user should choose the hljs style in the config and the color mode at runtime (e.g. via dropdown "Light/Dark/Auto" menu). The hljs theme might be only light or dark, so swapping will do nothing, otherwise work as expected, so yes, make hljs depending on color mode if both are set, mkdocs should not care if they match with the site theme.

  1. Provide a second "dark" config option (i.e.: hljs_style_dark) which defines the corresponding dark theme for Highlight.js. Then the relevant option could be used depending on color_mode.

Which IMO is the better option (see also below).

3 We could abandon Highlight.js and instead rely on the codehilite Markdown extension, which would require hosting our own CSS styles.

Personally I dislike this, but it's just my own opinion.

Finally, I will note that as of Bootstrap version 5, jQuery was dropped as a dependency. Bootstrap now uses plain Javascript with the exception of Popper.js

IIRC popper.js is needed for the search and keyboard dialogs (I had troubles with them when making the test theme I linked above because of missing popper.js/jquery), so maybe jquery could be made optional if not using them?

See https://github.com/mkdocs/mkdocs/issues/3189 which suggests a refactor of the Highlight.js config options.

That was a suggestion on how I did it, more or less, in my own theme but I guess it's not necessary a refactor if your hljs_style_dark addition idea would do the job without breaking compatibility.

redtide avatar Dec 14 '23 11:12 redtide

However, this only implements the option to select light/dark mode at build time from within the config file.

Most websites I visited and also some desktops give the possibility to choose dark/light versions of a theme at runtime, I don't see why to set it at build time instead making a dark version of the existing themes and choose if to use the system/dark/light color mode at runtime like the former do.

Well, we have to start with something. Do we start with light as the default or dark? Different users may have different opinions about that. So we are giving them the option to choose. But once that is complete, then we can add the JS to do the in-browser switching. So its not like I'm wasting my time implementing a build-time config option. It will need to exist anyway. The in-browser switch is simply an additional add-on which can be added later.

I think the user should choose the hljs style in the config and the color mode at runtime (e.g. via dropdown "Light/Dark/Auto" menu). The hljs theme might be only light or dark, so swapping will do nothing, otherwise work as expected, so yes, make hljs depending on color mode if both are set, mkdocs should not care if they match with the site theme.

I considered that. But then I tried it and wow is it hideous. Leaving the two unconnected would be a disservice to our users IMO.

See #3189 which suggests a refactor of the Highlight.js config options.

That was a suggestion on how I did it, more or less, in my own theme but I guess it's not necessary a refactor if your hljs_style_dark addition idea would do the job without breaking compatibility.

Personally, I actually prefer your suggestion in #3189. However, it breaks compatibility. Ideally, when a user upgrades to a new version of MkDocs, they should not need to make edits to their site config before building the first time. Sure, they may want to make edits to take advantage of new features, but their site should generally render the same without any edits. Of course, at times that is unavoidable, but we want to be cautious about when we choose to do so.

3 We could abandon Highlight.js and instead rely on the codehilite Markdown extension, which would require hosting our own CSS styles.

Personally I dislike this, but it's just my own opinion.

What is it that you dislike? Hosting our own CSS? The specific styles provided by Pygments? The lack of ability to chose from multiple options?

waylan avatar Dec 14 '23 13:12 waylan

Well, we have to start with something. Do we start with light as the default or dark? Different users may have different opinions about that. So we are giving them the option to choose. But once that is complete, then we can add the JS to do the in-browser switching. So its not like I'm wasting my time implementing a build-time config option. It will need to exist anyway. The in-browser switch is simply an additional add-on which can be added later.

I would say OK for light, you can check how it works on my test page link. If you support a system theme preference it will switch automatically so who cares about the default? Sites around (and so desktops) have light theme as default AFAICS.

FTR: at some point I found the original "bootstrap4-test-page" project based on Jekyll, so I wanted to make one that worked with bootstrap5 to upgrade my sites, but being in the process to switch to MKDocs I wanted to make it as starting point for a "mkdocs-bootstrap-material" theme, so I hope it will be helpful for you in this context. OTOH it's just about implementing the bootstrap5 components and their default implementation as described in their docs, not much to be done differently. The in browser switch is the same, though IDK if the license is compatible (CC-BY-SA).

IMO the browser theme switch is fundamental, so you don't need to set anything in config, other than eventually a custom css for both light and dark and the HLJS ones.

I considered that. But then I tried it and wow is it hideous. Leaving the two unconnected would be a disservice to our users IMO.

Is that terrible in the link I posted? Again, I don't think MKDocs should care about the style an user sets. HLJS provides a lot, and you can't match all of them, so can't you just make your own css and let the user eventually override it? I'm not sure what you mean with unconnected, if to switch both the site theme with the HLJS together is the same thing I prefer, if unconnected in the sense because not same colors that IDK what you can do about it, make a "MKDocs style" for both looks to me a waste of time to make it and also maintain it, users should choose what they like. As start I used a "GitHub dark palette" for mine, which seems to me working well with the HLJS GH versions.

Personally, I actually prefer your suggestion in https://github.com/mkdocs/mkdocs/issues/3189. However, it breaks compatibility. Ideally, when a user upgrades to a new version of MkDocs, they should not need to make edits to their site config before building the first time.

I haven't got this, can't you still support the old method and also add a new one (not great but I can't see a better option to avoid breakage), no?

What is it that you dislike? Hosting our own CSS? The specific styles provided by Pygments? The lack of ability to chose from multiple options?

Abandon HLJS and use codehilite. In general I like (and use) some of those extensions but there are some, like syntax highlight that I don't, but it's my opinion and by chance I started to use HLJS before trying to switch to MKDocs from Jekill, where previously I was using Google Prettify.

redtide avatar Dec 14 '23 15:12 redtide

I added an auto mode, which follows the local system setting of the browser.

theme:
    name: mkdocs
    color_mode: auto

Color Mode switch

The trick was working out how to have both light and dark Highlight.js themes available for live switching (see 6485ff9). As I understand it, browsers do not download a disabled <link>, so no unnecessary resources are used with this solution.

One can also do either color_mode: light or color_mode: dark which builds with the one option only and does not do any switching (although, it could with a JavaScript call to setColorMode). Now it should be easy to add on-page switching.

waylan avatar Dec 16 '23 00:12 waylan

Wow that's great stuff!

oprypin avatar Dec 16 '23 00:12 oprypin

Good job, looks great! And by looking at commits and the preview I like the coding and visual styles!

redtide avatar Dec 16 '23 08:12 redtide

I have now added a user option which is enabled with user_color_mode_toggle: true in the config.

Untitled

However, I needed to update fontawesome to version 6 as v3 did not have all of the appropriate icons. Personally, I would have likely used Bootstrap Icons, but I'm trying to maintain the existing dependencies for backward compatibility.

So now this one PR updates both bootstrap and fontawesome to the latest releases and adds a feature (color modes). I'm wondering if this is too much for one PR. If so, let me know and I'll break it up into a few.

Regardless, I still need to update the documentation.

waylan avatar Dec 20 '23 19:12 waylan

This seems like the perfect opportunity to upgrade fontawesome. But yes, if we intend to squash this pull request into one, that would be too much. It might be prudent to switch the approach for this pull request to developing 1 ready stack of commits to be merged without squashing. Then a few other changes such as "Add user_color_mode_toggle" could also get their own commit. Anyway just seems much easier than multiple pull requests. Also I'm not sure when we'll actually get to merging and releasing this; I certainly would want to merge the fontawesome change right before merging the theme change (which the "stacked commits" approach would solve perfectly).

oprypin avatar Dec 20 '23 20:12 oprypin

This seems like the perfect opportunity to upgrade fontawesome

Not sure if you know about forkawesome, might be another alternative in case?

redtide avatar Dec 20 '23 23:12 redtide

I believe this is ready to go. I have refactored the commits into 4 separate logical commits, which should be able to be committed as-is (not squashed). The last commit resolves #2248. See the commit messages and documentation updates for details.

waylan avatar Dec 22 '23 14:12 waylan

Great stuff though. These are all the comments I have :)

oprypin avatar Dec 30 '23 15:12 oprypin

Thanks for the feedback. I'll need to sort through it all when I have some time, which may be a while.

waylan avatar Dec 31 '23 22:12 waylan

I have made a new branch that is ready to be force-pushed to here. (Shall I just do that?) It contains all my suggested edits applied. Maybe it will be easier for you to just re-review it in the final shape, rather than checking my individual edits?

This is https://github.com/mkdocs/mkdocs/compare/master...oprypin:mkdocs:themeup

  1. "Update mkdocs theme to Bootstrap/Bootswatch 5.3.2"
    • Before: https://github.com/mkdocs/mkdocs/commit/b80b22b31429a07afd307fec59804b262f202c7f
    • After: https://github.com/mkdocs/mkdocs/commit/351b87939ddc61bc767e2b869e2a2673fe9af5ae (applied all my code suggestions, rebased without csslint)
  2. "Update FontAwesome to version 6"
    • Before: https://github.com/mkdocs/mkdocs/commit/70e38273b7c9f28858c63f398a57292bdea3056a
    • After: https://github.com/mkdocs/mkdocs/commit/694a6028f649de6881ddc13496077856dcb3abc6 (rebased without csslint)
  3. "Add support for a 'dark mode' to mkdocs theme" + "Add 'user_color_mode_toggle' to mkdocs theme"
    • Before: https://github.com/mkdocs/mkdocs/commit/7265192995df75c232913fecb40553bb9b300f6e + https://github.com/mkdocs/mkdocs/commit/02564cc03cd7cc1567a264198e2c3bf81f9bd077
    • After: https://github.com/mkdocs/mkdocs/commit/a83615554940f681b9c292b21de78e84616017c8 (squashed 2 commits, rebased with updated markdownlint style, applied all my code suggestions)

oprypin avatar Mar 16 '24 14:03 oprypin

If that is what you want to do. For the reasons stated in my individual responses, I actually think your changes are not improvements, but I don't have the time or energy to try to convince anyone of that. I also don't have the time to review your changes and likely won't for some months. So, you can merge your changes with this or just close this and open a new PR. Whatever works best for you.

waylan avatar Mar 18 '24 17:03 waylan

This really looks great! Thanks for the effort you put into this. 👍 I also think that it should be merged ASAP because it's a great update, even if there are some details where your opinions diverge. After all, many of such small details could still be updated later on . As long as it's "stable", it's all good! Happy Easter! 🥚 🐰 🥚

dagnelies avatar Mar 28 '24 15:03 dagnelies

I plan to merge this for the 1.6.0 release with my edits, I hope that's OK.

I have checked the theme extensively for any deficiencies in Firefox/Linux, and I think any edits are for the better.

https://github.com/mkdocs/mkdocs/pull/3631

oprypin avatar Apr 11 '24 19:04 oprypin

I hadn't seen this work happening in the background after #2248 was closed, but this is awesome! Great work @waylan!

Fryguy avatar Apr 12 '24 21:04 Fryguy

It's awesome to see dark mode coming to MkDocs' core themes! I checked the linked preview in #3631, and observed that the dark mode solution suffers from occasional white flashing, especially on very long pages (see attached video). I tried to find the code that implements dark mode to learn why, but to no avail, so my guess is that the selected preference is checked and applied "too late", i.e., at the end of the body. When there's a lot of content, the end of the parser sees the end of the body only after a while has passed, but the page already has partially rendered, which explains the flashing.

https://github.com/mkdocs/mkdocs/assets/932156/602965f5-bee9-44e0-9623-cfb2f5661b45

The solution would be to move the code that decides what mode is to be applied to the beginning of body.

squidfunk avatar Apr 13 '24 00:04 squidfunk

Working on #3649, I found some potential regressions:

  • The search modal's close button looks different
  • Search result titles are underlined
  • The table of contents collapse button on mobile looks different

Screenshots

Bildschirm­foto 2024-04-17 um 08 39 46 Bildschirm­foto 2024-04-17 um 08 39 18

squidfunk avatar Apr 17 '24 01:04 squidfunk

There are a couple factors here. First, we updated to a more recent version of Bootstrap and Bootstrap changed the style of some items. The different look to the close and collapse buttons could be an intentional change on Bootstrap's part. That needs to be verified. The second factor is that we are not always using Bootstrap's defaults. IIRC links were changed in some way which caused our customizations to stop working. It could be that I missed the change to search results. In any event, this PR is already merged, seems like it would be appropriate to open a new issue to track this stuff. Also, unfortunately I do not have any time to work on this myself.

waylan avatar Apr 17 '24 17:04 waylan

  • Yeah that close button does look really weird 🤔

  • All links are underlined, that's indeed changed

  • Yes the nav collapse button looks different, not sure what's up with that but it's not bad

Thanks for checking

oprypin avatar Apr 17 '24 18:04 oprypin