Skip to content

Commit 8785109

Browse files
committed
Add dark mode support
Heavily WIP still, but this begins the process of implementing dark mode for our docs and across the project itself. - Color modes are toggled in the docs navbar with a custom toggler, which stores the select color mode in local storage. - Color modes can also be set via data attribute thanks to `data-theme` (with light or dark options available currently). - Docs are heavily WIP for demonstrating the dark mode. - In order to best implement color modes, I've spiked out a number of new Sass and CSS variables (e.g., `--bs-secondary-bg` and `--bs-tertiary-bg`). In addition, I've added new global CSS variables like `--bs-border-color` and more. So, in addition to general color modes and theming support, we get greater real-time customization, too. Todos and open questions: - [ ] Do we refer to these as themes or color modes? - [ ] Do we provide a color mode toggler JS plugin? - [ ] Update all components to better utilize global CSS variables so they can be more easily themed (e.g., see `$dropdown-*` Sass variable changes in the diff).
1 parent d25f5c0 commit 8785109

32 files changed

+473
-216
lines changed

scss/_dropdown.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// stylelint-disable custom-property-empty-line-before
2+
13
// The dropdown wrapper (`<div>`)
24
.dropup,
35
.dropend,
@@ -20,7 +22,7 @@
2022
--#{$variable-prefix}dropdown-padding: #{$dropdown-padding-y $dropdown-padding-x};
2123
--#{$variable-prefix}dropdown-spacer: #{$dropdown-spacer};
2224
@include rfs($dropdown-font-size, --#{$variable-prefix}dropdown-font-size);
23-
--#{$variable-prefix}dropdown-color: #{$dropdown-color}; // stylelint-disable-line custom-property-empty-line-before
25+
--#{$variable-prefix}dropdown-color: #{$dropdown-color};
2426
--#{$variable-prefix}dropdown-bg: #{$dropdown-bg};
2527
--#{$variable-prefix}dropdown-border-color: #{$dropdown-border-color};
2628
--#{$variable-prefix}dropdown-border-radius: #{$dropdown-border-radius};
@@ -165,6 +167,7 @@
165167
white-space: nowrap; // prevent links from randomly breaking onto new lines
166168
background-color: transparent; // For `<button>`s
167169
border: 0; // For `<button>`s
170+
border-radius: var(--#{$variable-prefix}dropdown-item-border-radius, 0); // stylelint-disable-line property-disallowed-list
168171

169172
// Prevent dropdown overflow if there's no padding
170173
// See https://github.com/twbs/bootstrap/pull/27703

scss/_reboot.scss

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ hr:not([size]) {
9292
font-style: $headings-font-style;
9393
font-weight: $headings-font-weight;
9494
line-height: $headings-line-height;
95-
color: $headings-color;
95+
color: var(--#{$variable-prefix}heading-color);
9696
}
9797

9898
h1 {
@@ -248,11 +248,11 @@ sup { top: -.5em; }
248248
// Links
249249

250250
a {
251-
color: $link-color;
251+
color: var(--#{$variable-prefix}link-color);
252252
text-decoration: $link-decoration;
253253

254254
&:hover {
255-
color: $link-hover-color;
255+
color: var(--#{$variable-prefix}link-hover-color);
256256
text-decoration: $link-hover-decoration;
257257
}
258258
}
@@ -303,7 +303,7 @@ pre {
303303

304304
code {
305305
@include font-size($code-font-size);
306-
color: $code-color;
306+
color: var(--#{$variable-prefix}code-color);
307307
word-wrap: break-word;
308308

309309
// Streamline the style when inside anchors to avoid broken underline and more

scss/_root.scss

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
:root {
1+
// stylelint-disable custom-property-empty-line-before
2+
3+
:root,
4+
[data-theme="light"] {
25
// Note: Custom variable values only support SassScript inside `#{}`.
36

47
// Colors
@@ -35,7 +38,7 @@
3538
--#{$variable-prefix}gradient: #{$gradient};
3639

3740
// Root and body
38-
// stylelint-disable custom-property-empty-line-before
41+
3942
// scss-docs-start root-body-variables
4043
@if $font-size-root != null {
4144
--#{$variable-prefix}root-font-size: #{$font-size-root};
@@ -45,10 +48,75 @@
4548
--#{$variable-prefix}body-font-weight: #{$font-weight-base};
4649
--#{$variable-prefix}body-line-height: #{$line-height-base};
4750
--#{$variable-prefix}body-color: #{$body-color};
51+
// --#{$variable-prefix}body-accent-color: #{$body-accent-color};
52+
53+
// todo: replace body-accent-color with secondary-color
54+
--#{$variable-prefix}secondary-color: #{$body-secondary-color};
55+
--#{$variable-prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};
56+
--#{$variable-prefix}secondary-bg: #{$body-secondary-bg};
57+
--#{$variable-prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};
58+
59+
--#{$variable-prefix}tertiary-color: #{$body-tertiary-color};
60+
--#{$variable-prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};
61+
--#{$variable-prefix}tertiary-bg: #{$body-tertiary-bg};
62+
--#{$variable-prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};
63+
4864
@if $body-text-align != null {
4965
--#{$variable-prefix}body-text-align: #{$body-text-align};
5066
}
5167
--#{$variable-prefix}body-bg: #{$body-bg};
68+
--#{$variable-prefix}body-bg-rgb: #{to-rgb($body-bg)};
5269
// scss-docs-end root-body-variables
53-
// stylelint-enable custom-property-empty-line-before
70+
71+
--#{$variable-prefix}heading-color: #{$headings-color};
72+
--#{$variable-prefix}link-color: #{$link-color};
73+
--#{$variable-prefix}link-hover-color: #{$link-hover-color};
74+
75+
--#{$variable-prefix}code-color: #{$code-color};
76+
77+
--#{$variable-prefix}border-color: #{$border-color};
78+
--#{$variable-prefix}border-style: #{$border-style};
79+
--#{$variable-prefix}border-width: #{$border-width};
80+
81+
// TODO: move to form components? or make global?
82+
--#{$variable-prefix}form-control-bg: var(--#{$variable-prefix}body-bg);
83+
--#{$variable-prefix}form-control-disabled-bg: var(--#{$variable-prefix}secondary-bg);
84+
}
85+
86+
[data-theme="dark"] {
87+
--#{$variable-prefix}primary: #{$blue-300};
88+
--#{$variable-prefix}success: #{$green-300};
89+
--#{$variable-prefix}danger: #{$red-300};
90+
--#{$variable-prefix}warning: #{$yellow-300};
91+
--#{$variable-prefix}info: #{$cyan-300};
92+
93+
--#{$variable-prefix}primary-rgb: #{to-rgb($blue-300)};
94+
--#{$variable-prefix}success-rgb: #{to-rgb($green-300)};
95+
--#{$variable-prefix}danger-rgb: #{to-rgb($red-300)};
96+
--#{$variable-prefix}warning-rgb: #{to-rgb($yellow-300)};
97+
--#{$variable-prefix}info-rgb: #{to-rgb($cyan-300)};
98+
99+
--#{$variable-prefix}body-color: #{$body-color-dark};
100+
--#{$variable-prefix}body-color-rgb: #{to-rgb($body-color-dark)};
101+
--#{$variable-prefix}body-bg: #{$body-bg-dark};
102+
--#{$variable-prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};
103+
104+
--#{$variable-prefix}secondary-color: #{$body-secondary-color-dark};
105+
// --#{$variable-prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};
106+
--#{$variable-prefix}secondary-bg: #{$body-secondary-bg-dark};
107+
--#{$variable-prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};
108+
109+
--#{$variable-prefix}tertiary-color: #{$body-tertiary-color-dark};
110+
// --#{$variable-prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};
111+
--#{$variable-prefix}tertiary-bg: #{$body-tertiary-bg-dark};
112+
--#{$variable-prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};
113+
114+
--#{$variable-prefix}heading-color: #{$headings-color-dark};
115+
116+
--#{$variable-prefix}link-color: #{$link-color-dark};
117+
--#{$variable-prefix}link-hover-color: #{$link-hover-color-dark};
118+
119+
--#{$variable-prefix}code-color: #{$code-color-dark};
120+
121+
--#{$variable-prefix}border-color: #{$border-color-dark};
54122
}

scss/_utilities.scss

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,37 +99,37 @@ $utilities: map-merge(
9999
"border": (
100100
property: border,
101101
values: (
102-
null: $border-width solid $border-color,
102+
null: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color),
103103
0: 0,
104104
)
105105
),
106106
"border-top": (
107107
property: border-top,
108108
values: (
109-
null: $border-width solid $border-color,
109+
null: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color),
110110
0: 0,
111111
)
112112
),
113113
"border-end": (
114114
property: border-right,
115115
class: border-end,
116116
values: (
117-
null: $border-width solid $border-color,
117+
null: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color),
118118
0: 0,
119119
)
120120
),
121121
"border-bottom": (
122122
property: border-bottom,
123123
values: (
124-
null: $border-width solid $border-color,
124+
null: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color),
125125
0: 0,
126126
)
127127
),
128128
"border-start": (
129129
property: border-left,
130130
class: border-start,
131131
values: (
132-
null: $border-width solid $border-color,
132+
null: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color),
133133
0: 0,
134134
)
135135
),
@@ -523,6 +523,8 @@ $utilities: map-merge(
523523
"muted": $text-muted,
524524
"black-50": rgba($black, .5), // deprecated
525525
"white-50": rgba($white, .5), // deprecated
526+
"body-secondary": var(--#{$variable-prefix}secondary-color),
527+
"body-tertiary": var(--#{$variable-prefix}tertiary-color),
526528
"reset": inherit,
527529
)
528530
)
@@ -548,7 +550,9 @@ $utilities: map-merge(
548550
values: map-merge(
549551
$utilities-bg-colors,
550552
(
551-
"transparent": transparent
553+
"transparent": transparent,
554+
"body-secondary": rgba(var(--#{$variable-prefix}secondary-bg-rgb), var(--#{$variable-prefix}bg-opacity)),
555+
"body-tertiary": rgba(var(--#{$variable-prefix}tertiary-bg-rgb), var(--#{$variable-prefix}bg-opacity)),
552556
)
553557
)
554558
),

scss/_variables.scss

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,24 @@ $position-values: (
396396
//
397397
// Settings for the `<body>` element.
398398

399-
$body-bg: $white !default;
400-
$body-color: $gray-900 !default;
401399
$body-text-align: null !default;
400+
$body-color: $gray-900 !default;
401+
$body-bg: $white !default;
402+
403+
$body-color-dark: $gray-500 !default;
404+
$body-bg-dark: $gray-900 !default;
405+
406+
$body-secondary-color: rgba($body-color, .75) !default;
407+
$body-secondary-bg: $gray-200 !default;
408+
409+
$body-tertiary-color: rgba($body-color, .5) !default;
410+
$body-tertiary-bg: $gray-100 !default;
411+
412+
$body-secondary-color-dark: rgba($body-color-dark, .75) !default;
413+
$body-secondary-bg-dark: $gray-800 !default;
414+
415+
$body-tertiary-color-dark: rgba($body-color-dark, .5) !default;
416+
$body-tertiary-bg-dark: mix($gray-800, $gray-900, 50%) !default;
402417

403418
// Links
404419
//
@@ -413,6 +428,9 @@ $link-hover-decoration: null !default;
413428
$stretched-link-pseudo-element: after !default;
414429
$stretched-link-z-index: 1 !default;
415430

431+
$link-color-dark: $blue-300 !default;
432+
$link-hover-color-dark: $blue-200 !default;
433+
416434
// Paragraphs
417435
//
418436
// Style p element.
@@ -483,8 +501,9 @@ $border-widths: (
483501
4: 4px,
484502
5: 5px
485503
) !default;
486-
487-
$border-color: $gray-300 !default;
504+
$border-style: solid !default;
505+
$border-color: rgba($black, .15) !default;
506+
$border-color-dark: rgba($white, .15) !default;
488507
// scss-docs-end border-variables
489508

490509
// scss-docs-start border-radius-variables
@@ -588,6 +607,7 @@ $headings-font-style: null !default;
588607
$headings-font-weight: 500 !default;
589608
$headings-line-height: 1.2 !default;
590609
$headings-color: null !default;
610+
$headings-color-dark: #fff !default;
591611
// scss-docs-end headings-variables
592612

593613
// scss-docs-start display-headings
@@ -656,7 +676,7 @@ $table-cell-padding-x-sm: .25rem !default;
656676

657677
$table-cell-vertical-align: top !default;
658678

659-
$table-color: $body-color !default;
679+
$table-color: null !default;
660680
$table-bg: transparent !default;
661681
$table-accent-bg: transparent !default;
662682

@@ -816,12 +836,12 @@ $input-padding-y-lg: $input-btn-padding-y-lg !default;
816836
$input-padding-x-lg: $input-btn-padding-x-lg !default;
817837
$input-font-size-lg: $input-btn-font-size-lg !default;
818838

819-
$input-bg: $body-bg !default;
820-
$input-disabled-bg: $gray-200 !default;
839+
$input-bg: var(--#{$variable-prefix}form-control-bg) !default;
840+
$input-disabled-bg: var(--#{$variable-prefix}form-control-disabled-bg) !default;
821841
$input-disabled-border-color: null !default;
822842

823-
$input-color: $body-color !default;
824-
$input-border-color: $gray-400 !default;
843+
$input-color: var(--#{$variable-prefix}body-color) !default;
844+
$input-border-color: var(--#{$variable-prefix}border-color) !default; //$gray-400
825845
$input-border-width: $input-btn-border-width !default;
826846
$input-box-shadow: $box-shadow-inset !default;
827847

@@ -865,7 +885,7 @@ $form-check-transition: null !default;
865885
$form-check-input-active-filter: brightness(90%) !default;
866886

867887
$form-check-input-bg: $input-bg !default;
868-
$form-check-input-border: 1px solid rgba($black, .25) !default;
888+
$form-check-input-border: var(--#{$variable-prefix}border-width) solid var(--#{$variable-prefix}border-color) !default;
869889
$form-check-input-border-radius: .25em !default;
870890
$form-check-radio-border-radius: 50% !default;
871891
$form-check-input-focus-border: $input-focus-border-color !default;
@@ -1124,19 +1144,19 @@ $dropdown-padding-x: 0 !default;
11241144
$dropdown-padding-y: .5rem !default;
11251145
$dropdown-spacer: .125rem !default;
11261146
$dropdown-font-size: $font-size-base !default;
1127-
$dropdown-color: $body-color !default;
1128-
$dropdown-bg: $white !default;
1129-
$dropdown-border-color: rgba($black, .15) !default;
1147+
$dropdown-color: var(--#{$variable-prefix}body-color) !default;
1148+
$dropdown-bg: var(--#{$variable-prefix}body-bg) !default;
1149+
$dropdown-border-color: var(--#{$variable-prefix}border-color) !default;
11301150
$dropdown-border-radius: $border-radius !default;
11311151
$dropdown-border-width: $border-width !default;
11321152
$dropdown-inner-border-radius: subtract($dropdown-border-radius, $dropdown-border-width) !default;
11331153
$dropdown-divider-bg: $dropdown-border-color !default;
11341154
$dropdown-divider-margin-y: $spacer * .5 !default;
11351155
$dropdown-box-shadow: $box-shadow !default;
11361156

1137-
$dropdown-link-color: $gray-900 !default;
1138-
$dropdown-link-hover-color: shade-color($dropdown-link-color, 10%) !default;
1139-
$dropdown-link-hover-bg: $gray-200 !default;
1157+
$dropdown-link-color: var(--#{$variable-prefix}body-color) !default;
1158+
$dropdown-link-hover-color: $dropdown-link-color !default;
1159+
$dropdown-link-hover-bg: var(--#{$variable-prefix}tertiary-bg) !default;
11401160

11411161
$dropdown-link-active-color: $component-active-color !default;
11421162
$dropdown-link-active-bg: $component-active-bg !default;
@@ -1597,6 +1617,7 @@ $offcanvas-backdrop-opacity: $modal-backdrop-opacity !default;
15971617

15981618
$code-font-size: $small-font-size !default;
15991619
$code-color: $pink !default;
1620+
$code-color-dark: $pink-300 !default;
16001621

16011622
$kbd-padding-y: .2rem !default;
16021623
$kbd-padding-x: .4rem !default;

site/assets/js/application.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,31 @@
132132
})
133133
}
134134

135+
// Toggle color modes
136+
137+
var toggleSwitch = document.querySelector('.bd-theme-toggle input[type="checkbox"]')
138+
var currentTheme = localStorage.getItem('theme')
139+
140+
if (currentTheme) {
141+
document.documentElement.setAttribute('data-theme', currentTheme)
142+
143+
if (currentTheme === 'dark') {
144+
toggleSwitch.checked = true
145+
}
146+
}
147+
148+
function switchTheme(e) {
149+
if (e.target.checked) {
150+
document.documentElement.setAttribute('data-theme', 'dark')
151+
localStorage.setItem('theme', 'dark')
152+
} else {
153+
document.documentElement.setAttribute('data-theme', 'light')
154+
localStorage.setItem('theme', 'light')
155+
}
156+
}
157+
158+
toggleSwitch.addEventListener('change', switchTheme, false)
159+
135160
// Insert copy to clipboard button before .highlight
136161
var btnTitle = 'Copy to clipboard'
137162
var btnHtml = '<div class="bd-clipboard"><button type="button" class="btn-clipboard" ><svg class="bi" width="1em" height="1em" fill="currentColor"><use xlink:href="#clipboard"/></svg></button></div>'

site/assets/scss/_ads.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
@include font-size(.8125rem);
1515
line-height: 1.4;
1616
text-align: left;
17-
background-color: $gray-100;
17+
background-color: var(--bs-tertiary-bg);
1818

1919
a {
20-
color: $gray-800;
20+
color: var(--bs-body-color);
2121
text-decoration: none;
2222
}
2323

@@ -34,5 +34,5 @@
3434
.carbon-poweredby {
3535
display: block;
3636
margin-top: .75rem;
37-
color: $gray-700 !important;
37+
color: var(--bs-body-color) !important;
3838
}

site/assets/scss/_buttons.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@
3737
--bs-btn-focus-border-color: var(--bd-violet);
3838
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
3939
}
40+
41+
.btn-bd-lg {
42+
padding: .8rem 2rem;
43+
}

0 commit comments

Comments
 (0)