summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Kestenholz <mk@feinheit.ch>2021-01-07 10:07:19 +0100
committerGitHub <noreply@github.com>2021-01-07 10:07:19 +0100
commit0a802233ec1421e5e59a486be69daef9b112fd0d (patch)
tree51446f08155caa22365fa2ee3ad34510eb5787ea
parent102d92fc09849e1a9004dd3f9a14a0ea9ca392cd (diff)
Fixed #32018 -- Extracted admin colors into CSS variables.
Defined all colors used in the admin CSS as variables. Implemented the following standardizations and accessibility improvements while at it: - Improved the contrast of text to not use ratios of less than 3:1 anymore. - Most hover states already used desaturated and darkened colors. Changed object tools to follow the same rule instead of showing the primary color on hover. Various places used similar colors; those have been merged with the goal of reducing the count of CSS variables. Contrasts have been improved in a few places. - Many borders used slightly different colors (e.g. #eaeaea vs. #eee) - Help texts used #999, this has been changed to --body-quiet-color (#666) which has a better contrast. Introduced fast color transitions on links and buttons.
-rw-r--r--django/contrib/admin/static/admin/css/autocomplete.css35
-rw-r--r--django/contrib/admin/static/admin/css/base.css214
-rw-r--r--django/contrib/admin/static/admin/css/changelists.css88
-rw-r--r--django/contrib/admin/static/admin/css/forms.css54
-rw-r--r--django/contrib/admin/static/admin/css/login.css8
-rw-r--r--django/contrib/admin/static/admin/css/nav_sidebar.css20
-rw-r--r--django/contrib/admin/static/admin/css/responsive.css27
-rw-r--r--django/contrib/admin/static/admin/css/rtl.css2
-rw-r--r--django/contrib/admin/static/admin/css/widgets.css72
-rw-r--r--docs/ref/contrib/admin/index.txt28
-rw-r--r--docs/releases/3.2.txt2
-rw-r--r--docs/spelling_wordlist1
12 files changed, 321 insertions, 230 deletions
diff --git a/django/contrib/admin/static/admin/css/autocomplete.css b/django/contrib/admin/static/admin/css/autocomplete.css
index be98cb4bfd..88e9eacb9a 100644
--- a/django/contrib/admin/static/admin/css/autocomplete.css
+++ b/django/contrib/admin/static/admin/css/autocomplete.css
@@ -14,7 +14,7 @@ select.admin-autocomplete {
.select2-container--admin-autocomplete.select2-container--focus .select2-selection,
.select2-container--admin-autocomplete.select2-container--open .select2-selection {
- border-color: #999;
+ border-color: var(--body-quiet-color);
min-height: 30px;
}
@@ -29,13 +29,13 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-selection--single {
- background-color: #fff;
- border: 1px solid #ccc;
+ background-color: var(--body-bg);
+ border: 1px solid var(--border-color);
border-radius: 4px;
}
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered {
- color: #444;
+ color: var(--body-fg);
line-height: 30px;
}
@@ -46,7 +46,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder {
- color: #999;
+ color: var(--body-quiet-color);
}
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow {
@@ -95,7 +95,7 @@ select.admin-autocomplete {
.select2-container--admin-autocomplete .select2-selection--multiple {
background-color: white;
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-radius: 4px;
cursor: text;
}
@@ -115,7 +115,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder {
- color: #999;
+ color: var(--body-quiet-color);
margin-top: 5px;
float: left;
}
@@ -131,7 +131,7 @@ select.admin-autocomplete {
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice {
background-color: #e4e4e4;
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-radius: 4px;
cursor: default;
float: left;
@@ -141,7 +141,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove {
- color: #999;
+ color: var(--body-quiet-color);
cursor: pointer;
display: inline-block;
font-weight: bold;
@@ -149,7 +149,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover {
- color: #333;
+ color: var(--body-fg);
}
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline {
@@ -167,7 +167,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple {
- border: solid #999 1px;
+ border: solid var(--body-quiet-color) 1px;
outline: 0;
}
@@ -191,7 +191,7 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field {
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
}
.select2-container--admin-autocomplete .select2-search--inline .select2-search__field {
@@ -205,6 +205,8 @@ select.admin-autocomplete {
.select2-container--admin-autocomplete .select2-results > .select2-results__options {
max-height: 200px;
overflow-y: auto;
+ color: var(--body-fg);
+ background: var(--body-bg);
}
.select2-container--admin-autocomplete .select2-results__option[role=group] {
@@ -212,11 +214,12 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] {
- color: #999;
+ color: var(--body-quiet-color);
}
.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] {
- background-color: #ddd;
+ background-color: var(--selected-bg);
+ color: var(--body-fg);
}
.select2-container--admin-autocomplete .select2-results__option .select2-results__option {
@@ -253,8 +256,8 @@ select.admin-autocomplete {
}
.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
- background-color: #79aec8;
- color: white;
+ background-color: var(--primary);
+ color: var(--body-bg);
}
.select2-container--admin-autocomplete .select2-results__group {
diff --git a/django/contrib/admin/static/admin/css/base.css b/django/contrib/admin/static/admin/css/base.css
index 2726e410c2..d25cf3b37a 100644
--- a/django/contrib/admin/static/admin/css/base.css
+++ b/django/contrib/admin/static/admin/css/base.css
@@ -4,6 +4,58 @@
@import url(fonts.css);
+/* VARIABLE DEFINITIONS */
+:root {
+ --primary: #79aec8;
+ --secondary: #417690;
+ --accent: #f5dd5d;
+
+ --body-fg: #333;
+ --body-bg: #fff;
+ --body-quiet-color: #666;
+ --body-loud-color: #000;
+
+ --header-color: #ffc;
+ --header-branding-color: var(--accent);
+ --header-bg: var(--secondary);
+ --header-link-color: #fff;
+
+ --breadcrumbs-fg: #c4dce8;
+ --breadcrumbs-link-fg: var(--body-bg);
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #447e9b;
+ --link-hover-color: #036;
+ --link-selected-fg: #5b80b2;
+
+ --hairline-color: #e8e8e8;
+ --border-color: #ccc;
+
+ --error-fg: #ba2121;
+
+ --message-success-bg: #dfd;
+ --message-warning-bg: #ffc;
+ --message-error-bg: #ffefef;
+
+ --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */
+ --selected-bg: #e4e4e4; /* E.g. selected table cells */
+ --selected-row: #ffc;
+
+ --button-fg: #fff;
+ --button-bg: var(--primary);
+ --button-hover-bg: #609ab6;
+ --default-button-bg: var(--secondary);
+ --default-button-hover-bg: #205067;
+ --close-button-bg: #888; /* Previously #bbb, contrast 1.92 */
+ --close-button-hover-bg: #747474;
+ --delete-button-bg: #ba2121;
+ --delete-button-hover-bg: #a41515;
+
+ --object-tools-fg: var(--button-fg);
+ --object-tools-bg: var(--close-button-bg);
+ --object-tools-hover-bg: var(--close-button-hover-bg);
+}
+
html, body {
height: 100%;
}
@@ -13,19 +65,20 @@ body {
padding: 0;
font-size: 14px;
font-family: "Roboto","Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif;
- color: #333;
- background: #fff;
+ color: var(--body-fg);
+ background: var(--body-bg);
}
/* LINKS */
a:link, a:visited {
- color: #447e9b;
+ color: var(--link-fg);
text-decoration: none;
+ transition: color 0.15s, background 0.15s;
}
a:focus, a:hover {
- color: #036;
+ color: var(--link-hover-color);
}
a:focus {
@@ -37,7 +90,7 @@ a img {
}
a.section:link, a.section:visited {
- color: #fff;
+ color: var(--body-bg);
text-decoration: none;
}
@@ -64,7 +117,7 @@ h1 {
margin: 0 0 20px;
font-weight: 300;
font-size: 20px;
- color: #666;
+ color: var(--body-quiet-color);
}
h2 {
@@ -80,7 +133,7 @@ h2.subhead {
h3 {
font-size: 14px;
margin: .8em 0 .3em 0;
- color: #666;
+ color: var(--body-quiet-color);
font-weight: bold;
}
@@ -93,7 +146,7 @@ h4 {
h5 {
font-size: 10px;
margin: 1.5em 0 .5em 0;
- color: #666;
+ color: var(--body-quiet-color);
text-transform: uppercase;
letter-spacing: 1px;
}
@@ -131,7 +184,7 @@ fieldset {
min-width: 0;
padding: 0;
border: none;
- border-top: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
}
blockquote {
@@ -144,7 +197,7 @@ blockquote {
code, pre {
font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace;
- color: #666;
+ color: var(--body-quiet-color);
font-size: 12px;
overflow-x: auto;
}
@@ -161,8 +214,8 @@ code strong {
hr {
clear: both;
- color: #eee;
- background-color: #eee;
+ color: var(--hairline-color);
+ background-color: var(--hairline-color);
height: 1px;
border: none;
margin: 0;
@@ -183,7 +236,7 @@ hr {
.help, p.help, form p.help, div.help, form div.help, div.help li {
font-size: 11px;
- color: #999;
+ color: var(--body-quiet-color);
}
div.help ul {
@@ -199,7 +252,7 @@ p img, h1 img, h2 img, h3 img, h4 img, td img {
}
.quiet, a.quiet:link, a.quiet:visited {
- color: #999;
+ color: var(--body-quiet-color);
font-weight: normal;
}
@@ -219,13 +272,13 @@ p img, h1 img, h2 img, h3 img, h4 img, td img {
table {
border-collapse: collapse;
- border-color: #ccc;
+ border-color: var(--border-color);
}
td, th {
font-size: 13px;
line-height: 16px;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--hairline-color);
vertical-align: top;
padding: 8px;
}
@@ -237,37 +290,37 @@ th {
thead th,
tfoot td {
- color: #666;
+ color: var(--body-quiet-color);
padding: 5px 10px;
font-size: 11px;
- background: #fff;
+ background: var(--body-bg);
border: none;
- border-top: 1px solid #eee;
- border-bottom: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
}
tfoot td {
border-bottom: none;
- border-top: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
}
thead th.required {
- color: #000;
+ color: var(--body-loud-color);
}
tr.alt {
- background: #f6f6f6;
+ background: var(--darkened-bg);
}
tr:nth-child(odd), .row-form-errors {
- background: #fff;
+ background: var(--body-bg);
}
tr:nth-child(even),
tr:nth-child(even) .errorlist,
tr:nth-child(odd) + .row-form-errors,
tr:nth-child(odd) + .row-form-errors .errorlist {
- background: #f9f9f9;
+ background: var(--darkened-bg);
}
/* SORTABLE TABLES */
@@ -276,15 +329,15 @@ thead th {
padding: 5px 10px;
line-height: normal;
text-transform: uppercase;
- background: #f6f6f6;
+ background: var(--darkened-bg);
}
thead th a:link, thead th a:visited {
- color: #666;
+ color: var(--body-quiet-color);
}
thead th.sorted {
- background: #eee;
+ background: var(--selected-bg);
}
thead th.sorted .text {
@@ -303,7 +356,7 @@ table thead th .text a {
}
table thead th .text a:focus, table thead th .text a:hover {
- background: #eee;
+ background: var(--selected-bg);
}
thead th.sorted a.sortremove {
@@ -350,12 +403,12 @@ table thead th.sorted .sortoptions a.sortremove:after {
left: 3px;
font-weight: 200;
font-size: 18px;
- color: #999;
+ color: var(--body-quiet-color);
}
table thead th.sorted .sortoptions a.sortremove:focus:after,
table thead th.sorted .sortoptions a.sortremove:hover:after {
- color: #447e9b;
+ color: var(--link-fg);
}
table thead th.sorted .sortoptions a.sortremove:focus,
@@ -402,16 +455,18 @@ textarea {
input[type=text], input[type=password], input[type=email], input[type=url],
input[type=number], input[type=tel], textarea, select, .vTextField {
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-radius: 4px;
padding: 5px 6px;
margin-top: 0;
+ color: var(--body-fg);
+ background-color: var(--body-bg);
}
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus,
input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus,
textarea:focus, select:focus, .vTextField:focus {
- border-color: #999;
+ border-color: var(--body-quiet-color);
}
select {
@@ -427,12 +482,13 @@ select[multiple] {
/* FORM BUTTONS */
.button, input[type=submit], input[type=button], .submit-row input, a.button {
- background: #79aec8;
+ background: var(--button-bg);
padding: 10px 15px;
border: none;
border-radius: 4px;
- color: #fff;
+ color: var(--button-fg);
cursor: pointer;
+ transition: background 0.15s;
}
a.button {
@@ -442,7 +498,7 @@ a.button {
.button:active, input[type=submit]:active, input[type=button]:active,
.button:focus, input[type=submit]:focus, input[type=button]:focus,
.button:hover, input[type=submit]:hover, input[type=button]:hover {
- background: #609ab6;
+ background: var(--button-hover-bg);
}
.button[disabled], input[type=submit][disabled], input[type=button][disabled] {
@@ -453,13 +509,13 @@ a.button {
float: right;
border: none;
font-weight: 400;
- background: #417690;
+ background: var(--default-button-bg);
}
.button.default:active, input[type=submit].default:active,
.button.default:focus, input[type=submit].default:focus,
.button.default:hover, input[type=submit].default:hover {
- background: #205067;
+ background: var(--default-button-hover-bg);
}
.button[disabled].default,
@@ -474,7 +530,7 @@ input[type=button][disabled].default {
.module {
border: none;
margin-bottom: 30px;
- background: #fff;
+ background: var(--body-bg);
}
.module p, .module ul, .module h3, .module h4, .module dl, .module pre {
@@ -500,8 +556,8 @@ input[type=button][disabled].default {
font-weight: 400;
font-size: 13px;
text-align: left;
- background: #79aec8;
- color: #fff;
+ background: var(--primary);
+ color: var(--body-bg);
}
.module caption,
@@ -528,18 +584,18 @@ ul.messagelist li {
font-size: 13px;
padding: 10px 10px 10px 65px;
margin: 0 0 10px 0;
- background: #dfd url(../img/icon-yes.svg) 40px 12px no-repeat;
+ background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat;
background-size: 16px auto;
- color: #333;
+ color: var(--body-fg);
}
ul.messagelist li.warning {
- background: #ffc url(../img/icon-alert.svg) 40px 14px no-repeat;
+ background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat;
background-size: 14px auto;
}
ul.messagelist li.error {
- background: #ffefef url(../img/icon-no.svg) 40px 12px no-repeat;
+ background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat;
background-size: 16px auto;
}
@@ -549,10 +605,10 @@ ul.messagelist li.error {
display: block;
padding: 10px 12px;
margin: 0 0 10px 0;
- color: #ba2121;
- border: 1px solid #ba2121;
+ color: var(--error-fg);
+ border: 1px solid var(--error-fg);
border-radius: 4px;
- background-color: #fff;
+ background-color: var(--body-bg);
background-position: 5px 12px;
overflow-wrap: break-word;
}
@@ -560,8 +616,8 @@ ul.messagelist li.error {
ul.errorlist {
margin: 0 0 4px;
padding: 0;
- color: #ba2121;
- background: #fff;
+ color: var(--error-fg);
+ background: var(--body-bg);
}
ul.errorlist li {
@@ -592,7 +648,7 @@ td ul.errorlist li {
.form-row.errors {
margin: 0;
border: none;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--hairline-color);
background: none;
}
@@ -602,7 +658,7 @@ td ul.errorlist li {
.errors input, .errors select, .errors textarea,
td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea {
- border: 1px solid #ba2121;
+ border: 1px solid var(--error-fg);
}
.description {
@@ -613,19 +669,19 @@ td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea {
/* BREADCRUMBS */
div.breadcrumbs {
- background: #79aec8;
+ background: var(--breadcrumbs-bg);
padding: 10px 40px;
border: none;
- color: #c4dce8;
+ color: var(--breadcrumbs-fg);
text-align: left;
}
div.breadcrumbs a {
- color: #fff;
+ color: var(--breadcrumbs-link-fg);
}
div.breadcrumbs a:focus, div.breadcrumbs a:hover {
- color: #c4dce8;
+ color: var(--breadcrumbs-fg);
}
/* ACTION ICONS */
@@ -651,11 +707,11 @@ div.breadcrumbs a:focus, div.breadcrumbs a:hover {
}
a.deletelink:link, a.deletelink:visited {
- color: #CC3434;
+ color: #CC3434; /* XXX Probably unused? */
}
a.deletelink:focus, a.deletelink:hover {
- color: #993333;
+ color: #993333; /* XXX Probably unused? */
text-decoration: none;
}
@@ -685,16 +741,16 @@ a.deletelink:focus, a.deletelink:hover {
display: block;
float: left;
padding: 3px 12px;
- background: #999;
+ background: var(--object-tools-bg);
+ color: var(--object-tools-fg);
font-weight: 400;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
- color: #fff;
}
.object-tools a:focus, .object-tools a:hover {
- background-color: #417690;
+ background-color: var(--object-tools-hover-bg);
}
.object-tools a:focus{
@@ -809,13 +865,13 @@ table#change-history tbody th {
justify-content: space-between;
align-items: center;
padding: 10px 40px;
- background: #417690;
- color: #ffc;
+ background: var(--header-bg);
+ color: var(--header-color);
overflow: hidden;
}
#header a:link, #header a:visited {
- color: #fff;
+ color: var(--header-link-color);
}
#header a:focus , #header a:hover {
@@ -831,11 +887,11 @@ table#change-history tbody th {
margin: 0 20px 0 0;
font-weight: 300;
font-size: 24px;
- color: #f5dd5d;
+ color: var(--accent);
}
#branding h1, #branding h1 a:link, #branding h1 a:visited {
- color: #f5dd5d;
+ color: var(--accent);
}
#branding h2 {
@@ -843,7 +899,7 @@ table#change-history tbody th {
font-size: 14px;
margin: -8px 0 8px 0;
font-weight: normal;
- color: #ffc;
+ color: var(--header-color);
}
#branding a:hover {
@@ -867,14 +923,14 @@ table#change-history tbody th {
#user-tools a:focus, #user-tools a:hover {
text-decoration: none;
- border-bottom-color: #79aec8;
- color: #79aec8;
+ border-bottom-color: var(--primary);
+ color: var(--primary);
}
/* SIDEBAR */
#content-related {
- background: #f8f8f8;
+ background: var(--darkened-bg);
}
#content-related .module {
@@ -882,7 +938,7 @@ table#change-history tbody th {
}
#content-related h3 {
- color: #666;
+ color: var(--body-quiet-color);
padding: 0 16px;
margin: 0 0 16px;
}
@@ -911,22 +967,22 @@ table#change-history tbody th {
background: none;
padding: 16px;
margin-bottom: 16px;
- border-bottom: 1px solid #eaeaea;
+ border-bottom: 1px solid var(--hairline-color);
font-size: 18px;
- color: #333;
+ color: var(--body-fg);
}
.delete-confirmation form input[type="submit"] {
- background: #ba2121;
+ background: var(--delete-button-bg);
border-radius: 4px;
padding: 10px 15px;
- color: #fff;
+ color: var(--button-fg);
}
.delete-confirmation form input[type="submit"]:active,
.delete-confirmation form input[type="submit"]:focus,
.delete-confirmation form input[type="submit"]:hover {
- background: #a41515;
+ background: var(--delete-button-hover-bg);
}
.delete-confirmation form .cancel-link {
@@ -934,17 +990,17 @@ table#change-history tbody th {
vertical-align: middle;
height: 15px;
line-height: 15px;
- background: #ddd;
border-radius: 4px;
padding: 10px 15px;
- color: #333;
+ color: var(--button-fg);
+ background: var(--close-button-bg);
margin: 0 0 0 10px;
}
.delete-confirmation form .cancel-link:active,
.delete-confirmation form .cancel-link:focus,
.delete-confirmation form .cancel-link:hover {
- background: #ccc;
+ background: var(--close-button-hover-bg);
}
/* POPUP */
diff --git a/django/contrib/admin/static/admin/css/changelists.css b/django/contrib/admin/static/admin/css/changelists.css
index eab152c2c6..4922a5d73a 100644
--- a/django/contrib/admin/static/admin/css/changelists.css
+++ b/django/contrib/admin/static/admin/css/changelists.css
@@ -40,13 +40,13 @@
}
#changelist .toplinks {
- border-bottom: 1px solid #ddd;
+ border-bottom: 1px solid var(--hairline-color);
}
#changelist .paginator {
- color: #666;
- border-bottom: 1px solid #eee;
- background: #fff;
+ color: var(--body-quiet-color);
+ border-bottom: 1px solid var(--hairline-color);
+ background: var(--body-bg);
overflow: hidden;
}
@@ -68,7 +68,7 @@
}
#changelist table tfoot {
- color: #666;
+ color: var(--body-quiet-color);
}
/* TOOLBAR */
@@ -76,22 +76,22 @@
#toolbar {
padding: 8px 10px;
margin-bottom: 15px;
- border-top: 1px solid #eee;
- border-bottom: 1px solid #eee;
- background: #f8f8f8;
- color: #666;
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
}
#toolbar form input {
border-radius: 4px;
font-size: 14px;
padding: 5px;
- color: #333;
+ color: var(--body-fg);
}
#toolbar #searchbar {
height: 19px;
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
padding: 2px 5px;
margin: 0;
vertical-align: top;
@@ -100,24 +100,24 @@
}
#toolbar #searchbar:focus {
- border-color: #999;
+ border-color: var(--body-quiet-color);
}
#toolbar form input[type="submit"] {
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
font-size: 13px;
padding: 4px 8px;
margin: 0;
vertical-align: middle;
- background: #fff;
+ background: var(--body-bg);
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
cursor: pointer;
- color: #333;
+ color: var(--body-fg);
}
#toolbar form input[type="submit"]:focus,
#toolbar form input[type="submit"]:hover {
- border-color: #999;
+ border-color: var(--body-quiet-color);
}
#changelist-search img {
@@ -130,7 +130,7 @@
#changelist-filter {
order: 1;
width: 240px;
- background: #f8f8f8;
+ background: var(--darkened-bg);
border-left: none;
margin: 0 0 0 30px;
}
@@ -153,7 +153,7 @@
#changelist-filter ul {
margin: 5px 0;
padding: 0 15px 15px;
- border-bottom: 1px solid #eaeaea;
+ border-bottom: 1px solid var(--hairline-color);
}
#changelist-filter ul:last-child {
@@ -168,31 +168,31 @@
#changelist-filter a {
display: block;
- color: #999;
+ color: var(--body-quiet-color);
text-overflow: ellipsis;
overflow-x: hidden;
}
#changelist-filter li.selected {
- border-left: 5px solid #eaeaea;
+ border-left: 5px solid var(--hairline-color);
padding-left: 10px;
margin-left: -15px;
}
#changelist-filter li.selected a {
- color: #5b80b2;
+ color: var(--link-selected-fg);
}
#changelist-filter a:focus, #changelist-filter a:hover,
#changelist-filter li.selected a:focus,
#changelist-filter li.selected a:hover {
- color: #036;
+ color: var(--link-hover-color);
}
#changelist-filter #changelist-filter-clear a {
font-size: 13px;
padding-bottom: 10px;
- border-bottom: 1px solid #eaeaea;
+ border-bottom: 1px solid var(--hairline-color);
}
/* DATE DRILLDOWN */
@@ -213,12 +213,12 @@
}
.change-list ul.toplinks .date-back a {
- color: #999;
+ color: var(--body-quiet-color);
}
.change-list ul.toplinks .date-back a:focus,
.change-list ul.toplinks .date-back a:hover {
- color: #036;
+ color: var(--link-hover-color);
}
/* PAGINATOR */
@@ -229,26 +229,26 @@
padding-bottom: 10px;
line-height: 22px;
margin: 0;
- border-top: 1px solid #ddd;
+ border-top: 1px solid var(--hairline-color);
width: 100%;
}
.paginator a:link, .paginator a:visited {
padding: 2px 6px;
- background: #79aec8;
+ background: var(--primary);
text-decoration: none;
- color: #fff;
+ color: var(--body-bg);
}
.paginator a.showall {
border: none;
background: none;
- color: #5b80b2;
+ color: var(--link-fg);
}
.paginator a.showall:focus, .paginator a.showall:hover {
background: none;
- color: #036;
+ color: var(--link-hover-color);
}
.paginator .end {
@@ -264,7 +264,7 @@
.paginator a:focus, .paginator a:hover {
color: white;
- background: #036;
+ background: var(--link-hover-color);
}
/* ACTIONS */
@@ -279,22 +279,22 @@
}
#changelist table tbody tr.selected {
- background-color: #FFFFCC;
+ background-color: var(--selected-row);
}
#changelist .actions {
padding: 10px;
- background: #fff;
+ background: var(--body-bg);
border-top: none;
border-bottom: none;
line-height: 24px;
- color: #999;
+ color: var(--body-quiet-color);
width: 100%;
}
-#changelist .actions.selected {
- background: #fffccf;
- border-top: 1px solid #fffee8;
+#changelist .actions.selected { /* XXX Probably unused? */
+ background: var(--body-bg);
+ border-top: 1px solid var(--body-bg);
border-bottom: 1px solid #edecd6;
}
@@ -314,8 +314,8 @@
vertical-align: top;
height: 24px;
background: none;
- color: #000;
- border: 1px solid #ccc;
+ color: var(--body-fg);
+ border: 1px solid var(--border-color);
border-radius: 4px;
font-size: 14px;
padding: 0 0 0 4px;
@@ -324,7 +324,7 @@
}
#changelist .actions select:focus {
- border-color: #999;
+ border-color: var(--body-quiet-color);
}
#changelist .actions label {
@@ -335,18 +335,18 @@
#changelist .actions .button {
font-size: 13px;
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-radius: 4px;
- background: #fff;
+ background: var(--body-bg);
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
cursor: pointer;
height: 24px;
line-height: 1;
padding: 4px 8px;
margin: 0;
- color: #333;
+ color: var(--body-fg);
}
#changelist .actions .button:focus, #changelist .actions .button:hover {
- border-color: #999;
+ border-color: var(--body-quiet-color);
}
diff --git a/django/contrib/admin/static/admin/css/forms.css b/django/contrib/admin/static/admin/css/forms.css
index 883b14a657..6c53a4187c 100644
--- a/django/contrib/admin/static/admin/css/forms.css
+++ b/django/contrib/admin/static/admin/css/forms.css
@@ -6,7 +6,7 @@
overflow: hidden;
padding: 10px;
font-size: 13px;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--hairline-color);
}
.form-row img, .form-row input {
@@ -26,13 +26,13 @@ form .form-row p {
label {
font-weight: normal;
- color: #666;
+ color: var(--body-quiet-color);
font-size: 13px;
}
.required label, label.required {
font-weight: bold;
- color: #333;
+ color: var(--body-fg);
}
/* RADIO BUTTONS */
@@ -215,24 +215,24 @@ fieldset.collapsed h2, fieldset.collapsed {
}
fieldset.collapsed {
- border: 1px solid #eee;
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
overflow: hidden;
}
fieldset.collapsed h2 {
- background: #f8f8f8;
- color: #666;
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
}
fieldset .collapse-toggle {
- color: #fff;
+ color: var(--body-bg);
}
fieldset.collapsed .collapse-toggle {
background: transparent;
display: inline;
- color: #447e9b;
+ color: var(--link-fg);
}
/* MONOSPACE TEXTAREAS */
@@ -246,8 +246,8 @@ fieldset.monospace textarea {
.submit-row {
padding: 12px 14px;
margin: 0 0 20px;
- background: #f8f8f8;
- border: 1px solid #eee;
+ background: var(--darkened-bg);
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
text-align: right;
overflow: hidden;
@@ -279,35 +279,35 @@ body.popup .submit-row {
.submit-row a.deletelink {
display: block;
- background: #ba2121;
+ background: var(--delete-button-bg);
border-radius: 4px;
padding: 10px 15px;
height: 15px;
line-height: 15px;
- color: #fff;
+ color: var(--button-fg);
}
.submit-row a.closelink {
display: inline-block;
- background: #bbbbbb;
+ background: var(--close-button-bg);
border-radius: 4px;
padding: 10px 15px;
height: 15px;
line-height: 15px;
margin: 0 0 0 5px;
- color: #fff;
+ color: var(--button-fg);
}
.submit-row a.deletelink:focus,
.submit-row a.deletelink:hover,
.submit-row a.deletelink:active {
- background: #a41515;
+ background: var(--delete-button-hover-bg);
}
.submit-row a.closelink:focus,
.submit-row a.closelink:hover,
.submit-row a.closelink:active {
- background: #aaaaaa;
+ background: var(--close-button-hover-bg);
}
/* CUSTOM FORM FIELDS */
@@ -386,12 +386,12 @@ body.popup .submit-row {
.inline-related h3 {
margin: 0;
- color: #666;
+ color: var(--body-quiet-color);
padding: 5px;
font-size: 13px;
- background: #f8f8f8;
- border-top: 1px solid #eee;
- border-bottom: 1px solid #eee;
+ background: var(--darkened-bg);
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
}
.inline-related h3 span.delete {
@@ -405,7 +405,7 @@ body.popup .submit-row {
.inline-related fieldset {
margin: 0;
- background: #fff;
+ background: var(--body-bg);
border: none;
width: 100%;
}
@@ -417,7 +417,7 @@ body.popup .submit-row {
text-align: left;
font-weight: bold;
background: #bcd;
- color: #fff;
+ color: var(--body-bg);
}
.inline-group .tabular fieldset.module {
@@ -456,7 +456,7 @@ body.popup .submit-row {
overflow: hidden;
font-size: 9px;
font-weight: bold;
- color: #666;
+ color: var(--body-quiet-color);
_width: 700px;
}
@@ -473,15 +473,15 @@ body.popup .submit-row {
.inline-group div.add-row,
.inline-group .tabular tr.add-row td {
- color: #666;
- background: #f8f8f8;
+ color: var(--body-quiet-color);
+ background: var(--darkened-bg);
padding: 8px 10px;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--hairline-color);
}
.inline-group .tabular tr.add-row td {
padding: 8px 10px;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--hairline-color);
}
.inline-group ul.tools a.add,
diff --git a/django/contrib/admin/static/admin/css/login.css b/django/contrib/admin/static/admin/css/login.css
index e3a288b9e9..cf4b36b796 100644
--- a/django/contrib/admin/static/admin/css/login.css
+++ b/django/contrib/admin/static/admin/css/login.css
@@ -1,7 +1,7 @@
/* LOGIN FORM */
.login {
- background: #f8f8f8;
+ background: var(--darkened-bg);
height: auto;
}
@@ -16,7 +16,7 @@
}
.login #header h1 a {
- color: #fff;
+ color: var(--body-bg);
}
.login #content {
@@ -24,8 +24,8 @@
}
.login #container {
- background: #fff;
- border: 1px solid #eaeaea;
+ background: var(--body-bg);
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
overflow: hidden;
width: 28em;
diff --git a/django/contrib/admin/static/admin/css/nav_sidebar.css b/django/contrib/admin/static/admin/css/nav_sidebar.css
index 784d087419..a13d3b6fc9 100644
--- a/django/contrib/admin/static/admin/css/nav_sidebar.css
+++ b/django/contrib/admin/static/admin/css/nav_sidebar.css
@@ -12,22 +12,22 @@
justify-content: center;
flex: 0 0 23px;
width: 23px;
- border-right: 1px solid #eaeaea;
- background-color: #ffffff;
+ border-right: 1px solid var(--hairline-color);
+ background-color: var(--body-bg);
cursor: pointer;
font-size: 20px;
- color: #447e9b;
+ color: var(--link-fg);
padding: 0;
}
[dir="rtl"] .toggle-nav-sidebar {
- border-left: 1px solid #eaeaea;
+ border-left: 1px solid var(--hairline-color);
border-right: 0;
}
.toggle-nav-sidebar:hover,
.toggle-nav-sidebar:focus {
- background-color: #f6f6f6;
+ background-color: var(--darkened-bg);
}
#nav-sidebar {
@@ -36,13 +36,13 @@
left: -276px;
margin-left: -276px;
border-top: 1px solid transparent;
- border-right: 1px solid #eaeaea;
- background-color: #ffffff;
+ border-right: 1px solid var(--hairline-color);
+ background-color: var(--body-bg);
overflow: auto;
}
[dir="rtl"] #nav-sidebar {
- border-left: 1px solid #eaeaea;
+ border-left: 1px solid var(--hairline-color);
border-right: 0;
left: 0;
margin-left: 0;
@@ -91,12 +91,12 @@
#nav-sidebar .current-app .section:link,
#nav-sidebar .current-app .section:visited {
- color: #ffc;
+ color: var(--selected-row);
font-weight: bold;
}
#nav-sidebar .current-model {
- background: #ffc;
+ background: var(--selected-row);
}
.main > #nav-sidebar + .content {
diff --git a/django/contrib/admin/static/admin/css/responsive.css b/django/contrib/admin/static/admin/css/responsive.css
index 10dc84ed16..e60a6f02c7 100644
--- a/django/contrib/admin/static/admin/css/responsive.css
+++ b/django/contrib/admin/static/admin/css/responsive.css
@@ -140,7 +140,7 @@ input[type="submit"], button {
}
#changelist .actions select {
- background: #fff;
+ background: var(--body-bg);
}
#changelist .actions .button {
@@ -166,7 +166,7 @@ input[type="submit"], button {
.filtered .actions,
#changelist .paginator {
- border-top-color: #eee;
+ border-top-color: var(--hairline-color); /* XXX Is this used at all? */
}
#changelist .results + .paginator {
@@ -213,7 +213,7 @@ input[type="submit"], button {
fieldset .fieldBox + .fieldBox {
margin-top: 10px;
padding-top: 10px;
- border-top: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
}
textarea {
@@ -399,11 +399,11 @@ input[type="submit"], button {
.datetime .timezonewarning {
display: block;
font-size: 11px;
- color: #999;
+ color: var(--body-quiet-color);
}
.datetimeshortcuts {
- color: #ccc;
+ color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */
}
.form-row .datetime input.vDateField, .form-row .datetime input.vTimeField {
@@ -740,7 +740,7 @@ input[type="submit"], button {
/* Inlines */
.inline-group[data-inline-type="stacked"] .inline-related {
- border: 2px solid #eee;
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
margin-top: 15px;
overflow: auto;
@@ -750,18 +750,19 @@ input[type="submit"], button {
box-sizing: border-box;
}
- .inline-group[data-inline-type="stacked"] .inline-related + .inline-related {
- margin-top: 30px;
- }
-
.inline-group[data-inline-type="stacked"] .inline-related .module {
padding: 0 10px;
}
- .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:last-child {
+ .inline-group[data-inline-type="stacked"] .inline-related .module .form-row {
+ border-top: 1px solid var(--hairline-color);
border-bottom: none;
}
+ .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child {
+ border-top: none;
+ }
+
.inline-group[data-inline-type="stacked"] .inline-related h3 {
padding: 10px;
border-top-width: 0;
@@ -791,7 +792,7 @@ input[type="submit"], button {
.inline-group[data-inline-type="stacked"] div.add-row {
margin-top: 15px;
- border: 1px solid #eee;
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
}
@@ -961,7 +962,7 @@ input[type="submit"], button {
}
.timelist a {
- background: #fff;
+ background: var(--body-bg);
padding: 4px;
}
diff --git a/django/contrib/admin/static/admin/css/rtl.css b/django/contrib/admin/static/admin/css/rtl.css
index 1a4bada1e4..0447f89382 100644
--- a/django/contrib/admin/static/admin/css/rtl.css
+++ b/django/contrib/admin/static/admin/css/rtl.css
@@ -97,7 +97,7 @@ thead th.sorted .text {
border-left: none;
padding-left: 10px;
margin-left: 0;
- border-right: 5px solid #eaeaea;
+ border-right: 5px solid var(--hairline-color);
padding-right: 10px;
margin-right: -15px;
}
diff --git a/django/contrib/admin/static/admin/css/widgets.css b/django/contrib/admin/static/admin/css/widgets.css
index 14ef12db94..c78eda40ae 100644
--- a/django/contrib/admin/static/admin/css/widgets.css
+++ b/django/contrib/admin/static/admin/css/widgets.css
@@ -22,26 +22,25 @@
}
.selector-available h2, .selector-chosen h2 {
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-radius: 4px 4px 0 0;
}
.selector-chosen h2 {
- background: #79aec8;
- color: #fff;
+ background: var(--primary);
+ color: var(--body-bg);
}
.selector .selector-available h2 {
- background: #f8f8f8;
- color: #666;
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
}
.selector .selector-filter {
- background: white;
- border: 1px solid #ccc;
+ border: 1px solid var(--border-color);
border-width: 0 1px;
padding: 8px;
- color: #999;
+ color: var(--body-quiet-color);
font-size: 10px;
margin: 0;
text-align: left;
@@ -66,7 +65,7 @@
.selector ul.selector-chooser {
float: left;
width: 22px;
- background-color: #eee;
+ background-color: var(--selected-bg);
border-radius: 10px;
margin: 10em 5px 0 5px;
padding: 0;
@@ -126,14 +125,14 @@ a.selector-chooseall, a.selector-clearall {
overflow: hidden;
font-weight: bold;
line-height: 16px;
- color: #666;
+ color: var(--body-quiet-color);
text-decoration: none;
opacity: 0.3;
}
a.active.selector-chooseall:focus, a.active.selector-clearall:focus,
a.active.selector-chooseall:hover, a.active.selector-clearall:hover {
- color: #447e9b;
+ color: var(--link-fg);
}
a.active.selector-chooseall, a.active.selector-clearall {
@@ -261,7 +260,7 @@ p.datetime {
line-height: 20px;
margin: 0;
padding: 0;
- color: #666;
+ color: var(--body-quiet-color);
font-weight: bold;
}
@@ -269,7 +268,7 @@ p.datetime {
white-space: nowrap;
font-weight: normal;
font-size: 11px;
- color: #ccc;
+ color: var(--border-color);
}
.datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField {
@@ -313,7 +312,7 @@ table p.datetime {
.timezonewarning {
font-size: 11px;
- color: #999;
+ color: var(--body-quiet-color);
}
/* URL */
@@ -322,7 +321,7 @@ p.url {
line-height: 20px;
margin: 0;
padding: 0;
- color: #666;
+ color: var(--body-quiet-color);
font-size: 11px;
font-weight: bold;
}
@@ -337,7 +336,7 @@ p.file-upload {
line-height: 20px;
margin: 0;
padding: 0;
- color: #666;
+ color: var(--body-quiet-color);
font-size: 11px;
font-weight: bold;
}
@@ -355,7 +354,7 @@ p.file-upload {
}
span.clearable-file-input label {
- color: #333;
+ color: var(--body-fg);
font-size: 11px;
display: inline;
float: none;
@@ -368,8 +367,9 @@ span.clearable-file-input label {
font-size: 12px;
width: 19em;
text-align: center;
- background: white;
- border: 1px solid #ddd;
+ background: var(--body-bg);
+ color: var(--body-fg);
+ border: 1px solid var(--hairline-color);
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
overflow: hidden;
@@ -397,20 +397,20 @@ span.clearable-file-input label {
margin: 0;
text-align: center;
border-top: none;
- background: #f5dd5d;
font-weight: 700;
font-size: 12px;
color: #333;
+ background: var(--accent);
}
.calendar th {
padding: 8px 5px;
- background: #f8f8f8;
- border-bottom: 1px solid #ddd;
+ background: var(--darkened-bg);
+ border-bottom: 1px solid var(--border-color);
font-weight: 400;
font-size: 12px;
text-align: center;
- color: #666;
+ color: var(--body-quiet-color);
}
.calendar td {
@@ -418,17 +418,17 @@ span.clearable-file-input label {
font-size: 12px;
text-align: center;
padding: 0;
- border-top: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
border-bottom: none;
}
.calendar td.selected a {
- background: #79aec8;
- color: #fff;
+ background: var(--primary);
+ color: var(--button-fg);
}
.calendar td.nonday {
- background: #f8f8f8;
+ background: var(--darkened-bg);
}
.calendar td.today a {
@@ -440,17 +440,17 @@ span.clearable-file-input label {
font-weight: 400;
padding: 6px;
text-decoration: none;
- color: #444;
+ color: var(--body-quiet-color);
}
.calendar td a:focus, .timelist a:focus,
.calendar td a:hover, .timelist a:hover {
- background: #79aec8;
+ background: var(--primary);
color: white;
}
.calendar td a:active, .timelist a:active {
- background: #417690;
+ background: var(--header-bg);
color: white;
}
@@ -464,16 +464,16 @@ span.clearable-file-input label {
.calendarnav a:link, #calendarnav a:visited,
#calendarnav a:focus, #calendarnav a:hover {
- color: #999;
+ color: var(--body-quiet-color);
}
.calendar-shortcuts {
- background: white;
+ background: var(--body-bg);
+ color: var(--body-quiet-color);
font-size: 11px;
line-height: 11px;
- border-top: 1px solid #eee;
+ border-top: 1px solid var(--hairline-color);
padding: 8px 0;
- color: #ccc;
}
.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next {
@@ -511,8 +511,8 @@ span.clearable-file-input label {
padding: 4px 0;
font-size: 12px;
background: #eee;
- border-top: 1px solid #ddd;
- color: #333;
+ border-top: 1px solid var(--border-color);
+ color: var(--body-fg);
}
.calendar-cancel:focus, .calendar-cancel:hover {
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 29af4cbcba..87d1b4f3f5 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -2802,6 +2802,34 @@ creating your own ``AdminSite`` instance (see below), and changing the
:attr:`AdminSite.index_template` , :attr:`AdminSite.login_template` or
:attr:`AdminSite.logout_template` properties.
+.. _admin-theming:
+
+Theming support
+===============
+
+The admin uses CSS variables to define colors. This allows changing colors
+without having to override many individual CSS rules. For example, if you
+preferred purple instead of blue you could add a ``admin/base.html`` template
+override to your project:
+
+.. code-block:: html+django
+
+ {% extends 'admin/base.html' %}
+
+ {% block extrahead %}{{ block.super }}
+ <style>
+ :root {
+ --primary: #9774d5;
+ --secondary: #785cab;
+ --link-fg: #7c449b;
+ --link-selected-fg: #8f5bb2;
+ }
+ </style>
+ {% endblock %}
+
+An up-to-date list of CSS variables is at
+:file:`django/contrib/admin/static/admin/css/base.css`.
+
``AdminSite`` objects
=====================
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 71c5ec09ef..6850774312 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -117,6 +117,8 @@ Minor features
* Read-only related fields are now rendered as navigable links if target models
are registered in the admin.
+* The admin now supports theming. See :ref:`admin-theming` for more details.
+
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 74a1c30c0c..4ccf34ca4d 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -676,6 +676,7 @@ textarea
th
that'll
Thejaswi
+theming
This'll
threadlocals
threadpool