From 0a802233ec1421e5e59a486be69daef9b112fd0d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 7 Jan 2021 10:07:19 +0100 Subject: [PATCH] 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. --- .../admin/static/admin/css/autocomplete.css | 35 +-- .../contrib/admin/static/admin/css/base.css | 214 +++++++++++------- .../admin/static/admin/css/changelists.css | 88 +++---- .../contrib/admin/static/admin/css/forms.css | 54 ++--- .../contrib/admin/static/admin/css/login.css | 8 +- .../admin/static/admin/css/nav_sidebar.css | 20 +- .../admin/static/admin/css/responsive.css | 27 +-- django/contrib/admin/static/admin/css/rtl.css | 2 +- .../admin/static/admin/css/widgets.css | 72 +++--- docs/ref/contrib/admin/index.txt | 28 +++ docs/releases/3.2.txt | 2 + docs/spelling_wordlist | 1 + 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 }} + + {% 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