Browse Source

Fixed #34621 -- Made admin site header render in <div> tag.

This was problematic for screen reader users because they use headings
to navigate. Having two <h1> is confusing, and the one in the header
wasn’t particularly helpful since it’s the same on all pages.
Howard Cox 1 year ago
parent
commit
cd413bd78a

+ 1 - 1
django/contrib/admin/sites.py

@@ -45,7 +45,7 @@ class AdminSite:
     # Text to put at the end of each page's <title>.
     site_title = gettext_lazy("Django site admin")
 
-    # Text to put in each page's <h1>.
+    # Text to put in each page's <div id="site-name">.
     site_header = gettext_lazy("Django administration")
 
     # Text to put at the top of the admin index page.

+ 2 - 2
django/contrib/admin/static/admin/css/base.css

@@ -937,7 +937,7 @@ a.deletelink:focus, a.deletelink:hover {
     display: flex;
 }
 
-#branding h1 {
+#site-name {
     padding: 0;
     margin: 0;
     margin-inline-end: 20px;
@@ -946,7 +946,7 @@ a.deletelink:focus, a.deletelink:hover {
     color: var(--header-branding-color);
 }
 
-#branding h1 a:link, #branding h1 a:visited {
+#site-name a:link, #site-name a:visited {
     color: var(--accent);
 }
 

+ 2 - 2
django/contrib/admin/static/admin/css/responsive.css

@@ -43,7 +43,7 @@ input[type="submit"], button {
         justify-content: flex-start;
     }
 
-    #branding h1 {
+    #site-name {
         margin: 0 0 8px;
         line-height: 1.2;
     }
@@ -432,7 +432,7 @@ input[type="submit"], button {
         padding: 15px 20px;
     }
 
-    .login #branding h1 {
+    .login #site-name {
         margin: 0;
     }
 

+ 1 - 1
django/contrib/admin/templates/admin/base_site.html

@@ -3,7 +3,7 @@
 {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
 
 {% block branding %}
-<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
+<div id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></div>
 {% if user.is_anonymous %}
   {% include "admin/color_theme_toggle.html" %}
 {% endif %}

+ 1 - 1
docs/intro/tutorial07.txt

@@ -367,7 +367,7 @@ a section of code like:
 .. code-block:: html+django
 
     {% block branding %}
-    <h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
+    <div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a><div>
     {% endblock %}
 
 We use this approach to teach you how to override templates. In an actual

+ 5 - 1
docs/ref/contrib/admin/index.txt

@@ -2848,9 +2848,13 @@ Templates can override or extend base admin templates as described in
 
 .. attribute:: AdminSite.site_header
 
-    The text to put at the top of each admin page, as an ``<h1>`` (a string).
+    The text to put at the top of each admin page, as a ``<div>`` (a string).
     By default, this is "Django administration".
 
+    .. versionchanged:: 5.0
+
+        In older versions, ``site_header`` was using an ``<h1>`` tag.
+
 .. attribute:: AdminSite.site_title
 
     The text to put at the end of each admin page's ``<title>`` (a string). By

+ 5 - 0
docs/releases/5.0.txt

@@ -419,6 +419,11 @@ Miscellaneous
 * :class:`~django.db.models.functions.Now` database function now uses
   ``LOCALTIMESTAMP`` instead of ``CURRENT_TIMESTAMP`` on Oracle.
 
+* :attr:`.AdminSite.site_header` is now rendered in a ``<div>`` tag instead of
+  ``<h1>``. Screen reader users rely on heading elements for navigation within
+  a page. Having two ``<h1>`` elements was confusing and the site header wasn't
+  helpful as it is repeated on all pages.
+
 .. _deprecated-features-5.0:
 
 Features deprecated in 5.0

+ 2 - 2
tests/admin_docs/test_views.py

@@ -27,7 +27,7 @@ class AdminDocViewTests(TestDataMixin, AdminDocsTestCase):
         self.assertContains(response, "<h1>Documentation</h1>", html=True)
         self.assertContains(
             response,
-            '<h1 id="site-name"><a href="/admin/">Django administration</a></h1>',
+            '<div id="site-name"><a href="/admin/">Django administration</a></div>',
         )
         self.client.logout()
         response = self.client.get(reverse("django-admindocs-docroot"), follow=True)
@@ -153,7 +153,7 @@ class AdminDocViewTests(TestDataMixin, AdminDocsTestCase):
             )
             self.assertContains(
                 response,
-                '<h1 id="site-name"><a href="/admin/">Django administration</a></h1>',
+                '<div id="site-name"><a href="/admin/">Django administration</a></div>',
             )
         finally:
             utils.docutils_is_available = True