twbs / bootstrap

The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.
https://getbootstrap.com
MIT License
170.23k stars 78.77k forks source link

Support for prefers-color-scheme media query #27514

Closed rolandasb closed 1 year ago

rolandasb commented 5 years ago

Apple introduced prefers-color-scheme media query in Safari Technology Preview 68, which allows developers to apply different rules if user is using dark mode on Mac Mojave:

@media (prefers-color-scheme: light) { ... }
@media (prefers-color-scheme: dark) { ... }

https://trac.webkit.org/changeset/237156/webkit

Maybe it's worth supporting this in Bootstrap?

patrickhlauke commented 5 years ago

what kind of support would you envisage? doubling up the color scheme everywhere? i wouldn't be adverse, but this needs careful planning/defining

rolandasb commented 5 years ago

I don't know if such tool exists, but what I thought was the ability to set variable like $enable-dark-mode which on compilation would find existing variables that have suffix -dark and include media queries in places where those variables are used. For example, if set variable:

$link-color-dark: lightblue;

it would insert into _reboot.scss:

a {
  color: $link-color;
  ...

  @media (prefers-color-scheme: dark) {
    color: $link-color-dark;
  }
}
mdo commented 5 years ago

Would be cool, but this is only in the Safari tech preview version, and no other browser. Can't really make use of it effectively for folks unless there's far more support. Closing as it's too early to use.

swrobel commented 5 years ago

This is in-progress for Chrome and implemented for Firefox 67 so it might be worth revisiting for BS5

mrlife commented 5 years ago

Just putting this here for easy reference. The Resources tab links to browser-specific status and the specification.

https://caniuse.com/#search=prefers-color-scheme

waterfoul commented 5 years ago

Any chance of reopening this one?

patrickhlauke commented 5 years ago

once it has more sizeable support @waterfoul, sure. as it stands, it's a lot of potential work for little gain just now.

swrobel commented 5 years ago

more sizeable support

please define

mdo commented 5 years ago

Safari and Firefox support isn't enough IMO and the supporting the media query presents additional implementation issues that we'd have to advise on or implement ourselves (e.g., fallbacks for IE and Edge that don't support it currently). Getting Chrome on board would be helpful obviously, but I think this is something more suited to a v6.

swrobel commented 5 years ago

Getting Chrome on board would be helpful

As previously mentioned, this is being actively worked on and is targeted for Chrome 76, to be released around July 30

waterfoul commented 5 years ago

We currently use two css classes to pull this off with a style switcher but it requires a very bloated payload to pull off (since having multiple color schemes requires multiple copies of bootstrap). In order to better support using multiple themes and to prepare for these media queries would it make sense to provide a way to generate a copy of bootstrap with color information only which could be used as an override?

felixfbecker commented 5 years ago

This is implemented in Chrome and will ship in the next release, working on macOS, Windows and Linux. Intend to ship: https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/sLK1cLgvieg/discussion

That means it is then supported by Safari, Firefox and the new Chromium Edge (I don't think there is active development on old Edge).

I think this is a great oppurtunity for Bootstrap - I predict that websites will be expected to have automatic dark modes in the future, and developers will not want to hand-code it. Bootstrap can help here by making automatic dark mode "just work", and it can still be configurable.

patrickhlauke commented 5 years ago

for all those who are pushing for it...i look forward to your pull requests

felixfbecker commented 5 years ago

@patrickhlauke shall we interpret that as an approval of the feature? Surely noone wants to work on this if it would not get merged anyway because maintainers think it's a bad idea

felixfbecker commented 5 years ago

As it stands, the issue is closed, which communicates that there is no interest in having this feature. If you want PRs, a first step would be to reopen the issue

patrickhlauke commented 5 years ago

nobody said it's a bad idea. what was said is that it's a lot of work for little practical gain just now. if somebody wants to start putting all the work in... (chicken and egg)

bardiharborow commented 5 years ago

@felixfbecker sorry if there was miscommunication, you can consider this tentatively approved for either v5 or v6, but we're lacking cycles on our end. I'm happy to coordinate with someone if they don't mind slightly delayed turnaround.

waterfoul commented 5 years ago

The more I look at this the more this feels like the perfect use-case for css variables. They are currently supported in every evergreen browser but are not available in IE which bootstrap currently supports. Would the bootstrap team be open to dropping IE support in the next major? It's become a little used browser (<3% usage world wide/<5% in the US/It's biggest market) and even Microsoft is recommending people not use it except for legacy applications.

bardiharborow commented 5 years ago

@waterfoul v6, yes. v5, no.

waterfoul commented 5 years ago

Are there any rough timelines for v5 and v6? I would rather this be done right since it will likely be a large change and if that means waiting a bit longer that's fine. I would just like to know roughly how much longer

lachlanjc commented 5 years ago

Dark Mode is now on production Safari, & coming to iPhone/iPad this fall. This would be an awesome update to Bootstrap!

mdo commented 5 years ago

Without the move to CSS custom properties, is the intent here then a mixin and proper dark mode (or more generally, color scheme) support across all components?

ntkme commented 5 years ago

I would like to start a little bit technical conversation here, as I recently implemented dark mode on websites I built with bootstrap.


Here are a few ideas:

Option 1

It is going to be tedious due to the ugly design of the prefers-color-scheme media query itself. Today's bootstrap already provides light & dark theme on a few components, which means it would be difficult to modifying current implementation with mixins, and such change would doubling color related code as result (compression might help, but still very annoying). Just imagine the result as below:

.table {
  /* light color scheme */
}

.table-dark {
  /* dark color scheme */
}

@media (prefers-color-scheme: dark) {
  .table {
    /* dark on dark (?) color scheme */
  }

  .table-dark {
    /* light on dark (?) color scheme */
  }
}

Option 2

We can drop .*-dark classes everywhere, and have light as default and dark in dark mode, which would cut the clutter, but would also greatly limit the possibility in website design.

Option 3

We will never support prefers-color-scheme via mixin & in-stylesheet media query, instead bootstrap would officially support a build with different colors that's optimized for dark mode, and users would use it like this:

<link href="bootstrap-light.css" rel="stylesheet">
<link href="bootstrap-dark.css" rel="stylesheet" media="(prefers-color-scheme: dark)">

The work to implement this option is minimum (pick a set of colors). It does have a catch that when dark mode is loaded, all css rules (including non-color related) are double loaded. However, this would also give designer the flexibility to choose between:

  1. Light theme everywhere.
  2. Dark theme everywhere.
  3. Light theme on light mode, dark theme on dark mode.
  4. Dark theme on light mode, light theme on dark mode.

Option 4

Fully switch to css variables, which means drop IE 11 support. This might be a future solution but probably won't happen anytime soon. https://caniuse.com/#feat=css-variables


Personally I would vote for option 3 today for two major reasons:

  1. It would work with a custom build of today's v4.
  2. It would not over-complicate the current scss building system and utilities.

For the long term future (v6 I guess), I would vote for option 4.

carcinocron commented 5 years ago

Just curious (option3), what would this code do a browser that didn't support prefers-color-scheme?

    <link href="light.css" rel="stylesheet" media="(prefers-color-scheme: no-preference)">
    <link href="light.css" rel="stylesheet" media="(prefers-color-scheme: light)">
    <link href="dark.css" rel="stylesheet" media="(prefers-color-scheme: dark)">

Would it only load one css file for supported browsers? Would non-supported browsers load both or neither? I don't personally have access to a non-supported browser.

chrisgorgo commented 4 years ago

I tried this and it results in no css getting loaded on Edge.

chrisgorgo commented 4 years ago

But if you do:

<link href="light.css" rel="stylesheet">
<link href="light.css" rel="stylesheet" media="(prefers-color-scheme: light)">
<link href="dark.css" rel="stylesheet" media="(prefers-color-scheme: dark)">

things work well.

vanillajonathan commented 4 years ago

Data on support for the prefers-color-scheme feature across the major browsers from caniuse.com
</a>
lachlanjc commented 4 years ago

Yep. Though the majority of solutions proposed here will be fine with the lacking browser support—they’ll behave as they always have in old browsers but progressively enhance to include dark mode on new ones with it enabled. Yay for the web ✨

getaaron commented 4 years ago

@ntkme Agreed, option 3 seems the best to avoid breaking existing setups.

I tried this out as a test:

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" media="(prefers-color-scheme: light)">
<link href="https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/darkly/bootstrap.min.css" rel="stylesheet" media="(prefers-color-scheme: dark)">

(e.g. I used bootswatch's darkly theme in dark mode. Functionally it worked great and I couldn't find a problem in other browsers. Of course, you wouldn't want to use this on a real site since the fonts, sizes, etc. are different in darkly from vanilla bootstrap.

I think we just need to publish vanilla bootstrap files that swap the colors for their -dark counterparts. This could be published as bootstrap-dark.min.css, bootstrap-grid-dark.min.css, etc.

Ideally these would be generated programmatically at build time.

getaaron commented 4 years ago

If we went with Option 1, could it work like this? I'm a little rusty on manually editing CSS 😄

.table {
  /* light color scheme */

  @media (prefers-color-scheme: dark) {
    /* dark color scheme */
  }
}

.table-dark {
  /* dark color scheme */

  @media (prefers-color-scheme: light) {
    /* light color scheme */
  }
}
felixfbecker commented 4 years ago

Not in CSS, but in SCSS, which can compile it to reverse the order of nesting so it's valid CSS.

getaaron commented 4 years ago

Looks like @carl-hugo has been doing some work on this in https://github.com/ForEvolve/bootstrap-dark and bootstrap looks really nice in dark mode 😄

Carl-Hugo commented 4 years ago

Looks like @Carl-Hugo has been doing some work on this in https://github.com/ForEvolve/bootstrap-dark and bootstrap looks really nice in dark mode 😄

I did not know about prefers-color-scheme, but this would be something easy to support, I think, instead of body.bootstrap/body.bootstrap-dark, since that sounds like a good way to move forward to.

vinorodrigues commented 4 years ago

All – I offer a proof of concept that dark mode can indeed be achieved in BS4. For your reading displeasure vinorodrigues/bootstrap-dark with working examples at vinorodrigues.github.io.

Humble and grateful mentions to the writing and thoughts of: @mdo, @tomayac, @Carl-Hugo, @ntkme and @thomaspark.

bexom97275 commented 4 years ago

Well, IE support is dropped in v5, so this feature could be targeted for v5 now? Option 4 by mentioned by @ntkme.

Now there are no technical limitations, finally.

bexomo commented 4 years ago

Well, IE support is dropped in v5, so this feature could be targeted for v5 now? I mean the option 4 by mentioned by @ntkme.

Now there are no technical limitations, finally.

P.S.: Oops! Sorry for the comment duplication. My previous comment was mistakenly flagged as spam and deleted by GitHub, this is why I wrote it again, but currently, they restored it.

mdo commented 4 years ago

I have an idea for generating color schemes in Bootstrap, largely in the spirit of supporting dark mode. General idea started with having a Sass map or list of all the themes you'd like to generate (default, dark, etc). This evolved to perhaps having a nested Sass map of color schemes similar to our utilities API.

This paired with CSS custom properties could be super nice for changing color schemes on the fly—imagine setting your theme colors for each color scheme, and then we spit out the :root { ... } vars to support them. Because it's a map, folks can add, remove, or merge as needed.

Here's a snippet of an example.

$themes: (
  default: (
    "primary": $blue,
    "success": $green
  ),
  dark: (
    "primary": $purple,
    "success": $teal
  ),
  custom: (
    "primary": $black,
    "success": $cyan
  )
) !default;

@each $theme, $name in $themes {
  /* #{$theme} */
  :root[data-theme="#{$theme}"] {
    @each $color, $value in $name {
      --bs-#{$color}: #{$value};
    }
  }
}

Which compiles to the following:

/* default */
:root[data-theme="default"] {
  --bs-primary: #0d6efd;
  --bs-success: #198754;
}

/* dark */
:root[data-theme="dark"] {
  --bs-primary: #6f42c1;
  --bs-success: #20c997;
}

/* custom */
:root[data-theme="custom"] {
  --bs-primary: #000;
  --bs-success: #0dcaf0;
}

This would require us to use CSS variables for more of our look and feel. I also feel like we could be doing more with mixins and maps to generate multiple options here for components and color schemes. For example, it'd be incredibly powerful to have global option variables to $enable-dark-variants and/or $enable-dark-mode where the former generates the .*-dark classes while the latter generates the prefers-color-scheme media queries.

What do folks think? Other ideas worth pursuing?

bexomo commented 4 years ago

Just one more note: implementation of the dark theme must allow you to select a different theme on the fly and remember the selected theme. I mean for the users it should behave like here and here. Media query 'prefers-color-scheme' is used by default, but user can change the theme and it will be stored in cookies and used for future visits.

ux-engineer commented 4 years ago

Much hoped for feature on our end! And now that dark themes has been pop for already quite some time, this would seem to be an important feature for the many devs.

@mdo 's example snippet looks handy... Also minute details with component configurations like font-weights etc. should be easily configurable.

AucT commented 3 years ago

What is ETA of dark mode? I'd like to have dark mode in b5 for new project.

ux-engineer commented 3 years ago

+2

florianlacreuse commented 3 years ago

To solutions with multiple css <link>, be careful of FOUC behavior. This issue may be increasingly irrelevant these days but could still occur.

vinorodrigues commented 3 years ago

For those of you who took the time to read my The Definitive Guide to Dark Mode and Bootstrap 4 (also on GitHub.) ...

... I've also churned the Bootstrap 5β1 variant (also on GitHub.)

ffoodd commented 3 years ago

Another piece of thinking: in an initial question on Twitter by @fvsch, @chriskirknielsen suggested an interesting approach based on CSS custom properties. Here's the CodePen demoing this.

This works thanks to the "guaranteed invalid value at computed time" feature, using the initial keyword (might also be know as the space toggler —named this way by @James0x57 and heavily used in CSS Media Vars for example).

This basically unveils to have a very simple layer on top of our styles, working as an API for color themes—being defined through a class, an attribute or a user preference.

Don't know if it's applicable to Bootstrap and how much work would be required, but it's definitely the smarter and CSS-ier approach I've seen so far.

ThisGitHubUsernameWasAvailable commented 2 years ago

Why v6? IE support is already dropped, so now there is no reason not to do this in v5.

mdo commented 2 years ago

There's a chance we can do this in v5, but there's a lot of work to be done in converting all components and utilities to CSS variables. Difficult to get it right quickly for a large codebase :).

Carl-Hugo commented 2 years ago

In case this can help @mdo, how I'm tackling this in my Bootstrap 4 dark theme project (latest option) is:

  1. Build the two stylesheets: Bootstrap standard + Bootstrap dark (basically just setting variables and a few other tweaks for the dark theme)
  2. A (gulp) script builds two more stylesheets, wrapped into a prefers-color-scheme (dark and light).
  3. The script strips all but colors from those two stylesheets and saves them
  4. The script assembles a default stylesheet (step 1: light or dark) then the opposite color sheet (output of step 3), leading to two stylesheets and the use-cases below.

Use cases:

- default: light - prefers: -     => light
- default: light - prefers: light => light
- default: light - prefers: dark  => dark
- default: dark - prefers: -      => dark
- default: dark - prefers: light  => light
- default: dark - prefers: dark   => dark

That seems to work pretty well so far (but one detail). I chose to tackle this method as it seemed very low maintenance. In your case, you could even apply the few tweaks directly to the codebase leading to even less effort to implement at first glance and easier maintainability. Anyway, if you are interested in knowing more please let me know.

Here's my WIP PR: https://github.com/ForEvolve/bootstrap-dark/pull/51


EDIT: Please let me know @vinorodrigues if you are still confused after this addition. Also, feel free to let me know if things changed a lot from BS4 to BS5; I don't do much CSS/frontend work these days but based on a quick scan of the Bootstrap 5 [S]CSS files I think this automated process should still work.

Assuming things haven't changed that much, let's start with the basics so we are talking about the same thing. To have two themes (light and dark) and allow users to choose, we need:

Bootstrap generates (Core + Light Colors) in one pass leading to one CSS file. Bootstrap is inputting a single set of variables, including colors.

To generate the dark version of Bootstrap, you can do the same thing but provide an overridden version of the color variables. If you run this through the same process, you end up with a (Core + Dark Colors) CSS file.

Assuming we all agree on that process, the aforementioned script saves the time to refactor the CSS to support two sets of color by taking one of the two CSS files and stripping all non-color properties from it, leading to a color-only CSS file.

If you take a full CSS file (say Bootstrap), then append a Dark Color-only CSS file wrapped in a prefers-color-scheme: dark media query to it (give or take), you end up with a light theme by default and a dark theme when preferred. The CSS is even "optimized" with 1x Core + 2x Colors, no duplicated styles.

Here is part of an example of such result (from Bootstrap 4 code):

// Default (Core + Light)
body {
    margin: 0;
    font-family: ...;
    font-size: 1rem;
    font-weight: 400;
    line-height: 1.5;
    color: #212529;
    text-align: left;
    background-color: #fff;
}
// more styles...

// Dark part (colors-only)
@media (prefers-color-scheme:dark) {
    body {
        color: #d3d3d3;
        background-color: #191d21;
    }
     // More styles (colors-only)
}

Of course, you can always refactor everything to support two sets of color or maintain multiple stylesheets instead, but this seems like a straightforward enough workaround (see even final solution) that leads to the expected results of the requirements: 1x Core CSS + 2x Colors supporting a default and a prefers-color-scheme.

In the end, the process takes a few [milli]seconds of "build time" in a CI pipeline and allows maintaining a single codebase/generation process. This just attacks the problem from a different, maybe less classic, angle.

tonimelisma commented 2 years ago

Hey @mdo, I understand this was added to the v5.3.0 To do list. Can you clarify if you're looking to include the functionality in 5.3.0?

mdo commented 2 years ago

We already have the mixin available, but the color mode work is coming in #35857. The implementation there will be via data attribute as opposed to media query, but I'm exploring an option to support both somehow, perhaps through use of a mixin and global variable flip.

The intention in that PR is to support multiple color modes/themes, improve global theming, and not just provide an involuntary light/dark option.

vanillajonathan commented 2 years ago

Maybe there could also be support for the CSS media query "prefers-contrast" which could be "more" or "less" for more or less contrast.