Adding link. Switching the wording so that "Issue tags" is clearly written as they would see it in the issues.
Thanks Rain. You have contributed a bunch to Drupal's accessibility. Thanks.
The bigger challenge of embedding the title in like <title data-drupal-selector="edit-settings-wrapper-icon-title">Two column</title>
is multilingual content. We need to be able to switch languages.
Adding a simple checkbox is a good idea. I believe it is becoming more common on other CMS too. It would be great to have a screenshot of what this could look like.
Another approach is to add an underline to the button.
@media screen and (min-width: 48em) {
.is-horizontal .tabs--primary .tabs__link.is-active {
border-bottom: 3px solid color-mix(in srgb, currentColor 40%, black);
padding-bottom: 0.25rem;
}
}
As discussed in the A11y Practice Area Meeting.
As discussed in the A11y Practice Area Meeting.
Thanks Liam. I'll see if I can get someone to renew it.
Can we get the API page link and the project description updated?
The link here didn't work for me.
https://api.drupal.org/api/drupal/core%21includes%21theme.inc/function/t...
A screnshot would be nice too.
I think this is a bug and that there is code to be reviewed.
I think this would do the trick - https://git.drupalcode.org/issue/drupal-3083583/-/compare/11.x...11.x
but I'm not even sure where all of these forms are showing up to test.
So we need it for the Menu settings for node editing:
/node/2/edit?destination=/admin/content
I am not seeing a way to include the title here:
/admin/structure/types/manage/page/fields
This may not be the only place it exist, but I wanted to see some changes on this. We may need to refer back to this to remove other elements of the title text.
Yes. That sounds right to me. Using the same color would make it easier to identify. Thanks.
I think this would be better:
.ckeditor5-toolbar-item {
border: 1px solid #8A8A8A;
}
.ckeditor5-toolbar-disabled .ckeditor5-toolbar-item {
border: 1px solid #8A8A8A;
}
I tried to update the patch here https://git.drupalcode.org/issue/drupal-867830/-/compare/11.x...867830-u...
The numbering may not matter, but because @lauriii is wonderful, the numbers aren't what I thought they were.
I think these are complementary issues, but definitely related.
@vsujeetkumar it has been 2 years, so this will need to be re-rolled.
What comments are still unaddressed?
@pasqualle suggested an approach that @ricksta recommended. I think the summary there is new variable "status_marker" and mark the old ones deprecated.
We would need a new variable name I think.
@kthull failing an automated test isn't the end of the world. There are often false positives. Of course it is easier if the automated tests pass.
Interesting to consider though if role=status
would be sufficient substitution. Worth looking into a bit more. Thanks!
Thanks @siddharthjain_7998 & @jurgenhaas
I'll try to figure this out in the future.
Sadly, I need more information. This is a 3 line change (one little search/replace). npm build locally doesn't work for me Unknown command: "build"
.
It is a pretty trivial patch, but I still don't know how to contribute it.
diff --git a/styles/theme/variables.scss b/styles/theme/variables.scss
index 8e37e68b..ede2f940 100644
--- a/styles/theme/variables.scss
+++ b/styles/theme/variables.scss
@@ -12,7 +12,7 @@
--gin-color-disabled-bg: #eaeaea;
--gin-color-disabled-border: #c2c2c2;
- --gin-color-warning: #d8b234;
+ --gin-color-warning: #9d6e04;
--gin-color-warning-light: #efcf64;
--gin-bg-warning: #{mix(black, #efcf64, 70%)};
--gin-bg-warning-light: rgba(226, 151, 0, .08);
@@ -35,7 +35,7 @@
--gin-status-bg: #eee;
--gin-status-success-text: #1d6844;
--gin-status-success-bg: #26a76930;
- --gin-status-warning-text: #{mix(black, #d8b234, 40%)};
+ --gin-status-warning-text: #{mix(black, #9d6e04, 40%)};
--gin-status-warning-bg: rgba(226, 151, 0, .15);
--gin-status-danger-text: #cc3d3d;
--gin-status-danger-bg: rgba(222, 117, 96, .15);
@@ -292,7 +292,7 @@
--gin-status-bg: rgba(255, 255, 255, 0.12);
--gin-status-success-text: #8bd3b1;
--gin-status-success-bg: #26a76940;
- --gin-status-warning-text: #{mix(white, #d8b234, 40%)};
+ --gin-status-warning-text: #{mix(white, #9d6e04, 40%)};
--gin-status-warning-bg: rgba(226, 151, 0, .15);
--gin-status-danger-text: #{mix(white, #cc3d3d, 50%)};
--gin-status-danger-bg: rgba(222, 117, 96, .15);
There are a few code changes in the MR, but the most important one for this is this code --gin-border-color: #d4d4d8;
changing to --gin-border-color: #838585;
Just to compare the greys https://coolors.co/contrast-checker/838585-d4d4d8
The big thing here is that are these going to work in dark mode, and with forced-colors.
This is still a good idea.
As a start we could include it in the CKEditor Toolbar configuration admin/config/content/formats
Nobody is working on CKEditor 4 now I believe.
Very cool @itmaybejj
So we can close this when Editoria11y becomes part of Core?
@sandip that's interesting with the sticky header, but given that the sticky isn't visible, this is still a bug.
Is it better to loose the semantics by dropping the H2 or to retain the heading order? I'm not sure.
What else is needed to move this to RTBC?
Ok.. I don't know what to do from here though https://git.drupalcode.org/project/gin/-/merge_requests/635/diffs
mgifford → created an issue.
Cool!
I'm just playing around with options here, but:
tr.views-form__bulk-operations-row.selected {
font-weight: 600;
font-size: 1.1rem;
background: linear-gradient(to right,
rgba(var(--gin-color-primary-rgb), 0.15) 0%,
#fff 10%,
#fff 90%,
rgba(var(--gin-color-primary-rgb), 0.15) 100%
);
/* 12px solid outline in the accent color */
outline: 12px solid rgba(var(--gin-color-primary-light-rgb), 0.5);
outline-offset: -12px;
}
/* Underline and darken links inside selected row */
tr.views-form__bulk-operations-row.selected a {
text-decoration: underline;
color: #111;
}
/* Ensure no other styles override the selected state */
tr.views-form__bulk-operations-row a:hover {
text-decoration: underline;
color: #111;
}
Now I don't pretend to be a designer, but I think we can find an alternative which can highlight the sticky bar (and the hover for that matter) while also meeting WCAG and looking sharp.
Using accessibility Insights I was able to duplicate and provide a screenshot of this.
I start in the Title field to make it easier.
The first round through the table goes fine, but when you get to Updated, it gets screwed up. You can see in the numbers that it looks like it goes 1, 2, 3, 4, 10, 6, 7 , 8, 9 (although the last numbers are hard to see).
After "Updated" what I see is that it goes to an empty focus item.
Then it jumps back to the beginning of the header menu and continues on. It just does that once, but it is an extra redundant (and buggy) step.
Now I'm not sure, but I just tried this and wasn't able to replicate it.
In your video it is easy to see the duplication.
I couldn't see it when I explored it locally:
I think this will required more steps for testing.
mgifford → created an issue.
I like your suggestion around use of mask-image
or mask
@kentr.
Just looking at more info around strategies for this.
In terms of how we are addressing this:
https://tetralogical.com/blog/2022/12/20/foundations-target-size/
the Target Size (Minimum) criterion is perhaps misleading. It won't guarantee that there are no small targets. It defines an ideal minimum size, but also allows an exception for smaller targets with sufficient spacing. The intent of the criterion is not to make sure targets are large enough to be comfortably activated, but to avoid having targets that are too small clustered closely together, which would otherwise increase the likelihood of a person accidentally activating an adjacent target.
Some exceptions to the rule:
https://dubbot.com/dubblog/2024/staying-on-target.html
It is also important to take into consideration the exceptions to WCAG 2.5.8, which are:
- If smaller targets (less than 24 x 24 CSS pixels) are arranged so that, when a 24 CSS pixel diameter circle is centered on each target's bounding box, the circles don't overlap with other targets or their circles.
- Equivalent: The function can be achieved through a different control on the same page that meets this criterion. For instance, in the following screenshot, the targets in the upper right corner are 15px with no minimum spacing, while the ones further down the page are 24px with no minimum spacing. Therefore, the criterion has been met.
- Inline: The target is in a sentence, or its size is otherwise constrained by the line height. For example, contextual links may be constrained by the vertical spacing between lines of text or the leading.
- User-agent control: The size of the target is determined by the user agent and is not modified by the author. For example:
- the options list of
dropdowns- date picker for the HTML date input
- color picker for the HTML color input
- Essential: A particular presentation of the target is essential or is legally required for the information being conveyed. For example, the target must be a certain size or shape.
Some other good guidance from Eric Bailey https://www.smashingmagazine.com/2024/07/getting-bottom-minimum-wcag-con... and Adrian Roselli
I suspect that some JS like this will be needed:
(function () {
const MIN_CONTRAST = 4.5;
const BACKGROUNDS = [
{ hex: '#ffffff', name: 'white' },
{ hex: '#2A2A2D', name: 'dark grey' }
];
const fields = [
{
inputId: 'edit-accent-color',
warningId: 'accent-warning',
},
{
inputId: 'edit-focus-color',
warningId: 'focus-warning',
},
];
function hexToRgb(hex) {
const val = hex.replace('#', '');
return {
r: parseInt(val.slice(0, 2), 16) / 255,
g: parseInt(val.slice(2, 4), 16) / 255,
b: parseInt(val.slice(4, 6), 16) / 255,
};
}
function luminance({ r, g, b }) {
const adjust = (c) =>
c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
return (
0.2126 * adjust(r) + 0.7152 * adjust(g) + 0.0722 * adjust(b)
);
}
function contrastRatio(l1, l2) {
const [a, b] = [l1, l2].sort((x, y) => y - x);
return (a + 0.05) / (b + 0.05);
}
function updateWarning(field) {
const input = document.getElementById(field.inputId);
const existing = document.getElementById(field.warningId);
if (existing) existing.remove();
const val = input.value;
if (!/^#[0-9a-fA-F]{6}$/.test(val)) return;
const fgLum = luminance(hexToRgb(val));
const fails = BACKGROUNDS.filter((bg) => {
const bgLum = luminance(hexToRgb(bg.hex));
return contrastRatio(fgLum, bgLum) < MIN_CONTRAST;
});
if (fails.length) {
const msg = document.createElement('div');
msg.id = field.warningId;
msg.style.color = 'red';
msg.style.marginTop = '0.25rem';
msg.textContent =
'⚠️ Low contrast against: ' +
fails.map((f) => f.name).join(', ') +
` (min ${MIN_CONTRAST}:1)`;
input.parentNode.appendChild(msg);
}
}
document.addEventListener('DOMContentLoaded', () => {
fields.forEach((field) => {
const input = document.getElementById(field.inputId);
if (input) {
input.addEventListener('input', () => updateWarning(field));
updateWarning(field); // initial check
}
});
});
})();
Some more observations on the colors in Gin.
There are 11 Accent colors, 4 different Focus colors, plus Dark/Light modes. That's a lot of combinations. Probably too many combinations to be able to provide good guidance.
Drupal Core should be providing a good example. We have as a community committed to striving to meet WCAG 2.2 AA standards. This is especially true of Core and Drupal CMS.
Light Mode:
- #0750E6 / #FFF
- #2E6DD0 / #FFF
- #4300BF / #FFF
- #5B00FF / #FFF
- #0F857F / #FFF - Fail (could we not just use #088488)
- #00875F / #FFF
- #D12E70 / #FFF
- #D8002E / #FFF
- #DA6303 / #FFF - Fail (Could we not just use #B56026)
- #111111 / #FFF
Dark Mode (Looks good):
- #90AEEF / #2A2A2D
- #82BFE8 / #2A2A2D
- #AD8FE8 / #2A2A2D
- #DBA5EF / #2A2A2D
- #00EAD0 / #2A2A2D
- #6BD4A1 / #2A2A2D
- #E79DA3 / #2A2A2D
- #EC8989 / #2A2A2D
- #F79576 / #2A2A2D
- #F1C970 / #2A2A2D
- #FFFFFF / #2A2A2D
I believe adding a space in the focus outline should make addressing this easier. We can state a white or dark inner circle before the focus outline color.
The WCAG Success Criterion 1.4.1 (Use of Color) in question.
The least 3:1 I think would just need to be the background.
LIght Mode
- Gin Focus color (Default) - #71B3FC / #FFFFFF - Failed (Could we not just use #5996EC)
- Green - #78C9BE / #FFFFFF - Failed (Could we not just use #58A19D)
- Claro Green - #85CBA8 / #FFFFFF - Failed (Could we not just use #739E8C)<
- Orange - #F4B39E / #FFFFFF - Failed (Could we not just use #709F87)
- Neutral - #A3A3A3 / #FFFFFF - Failed (Could we not just use #989494)
- Same as Accent color - See above
- Custom - N/A - we are restricting this to good defaults
Dark Mode
- Gin Focus color (Default) - #51A8FF / #2A2A2D
- Green - #16756B / #2A2A2D - Failed (Could we not just use #088174)
- Claro Green - #277852 / #2A2A2D - Failed (Could we not just use #1D834C)
- Orange - #A55C47 / #2A2A2D - Failed (Could we not just use #A85F4B)
- Neutral - #D8D8D9 / #2A2A2D
- Same as Accent color - See above
- Custom - N/A - we are restricting this to good defaults
WebAim also has this interesting Link Contrast Checker.
Can we spend some time optimizing them before bringing them into Core?
https://www.svgviewer.dev/
https://optimize.svgomg.net/
For instance, 948 bytes:
<svg aria-hidden="true" focusable="false" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 0L14 3V16H2V0H11Z" fill="#fff"/>
<path d="M11 0L14 3V16H2V0H11ZM3 15H13V4H10V1H3V15ZM11 3H12.5L11 1.5V3Z" fill="#7f7f7f"/>
<path d="M4 2H9V3H4V2Z" fill="#dadada"/>
<path d="M4 3H9V4H4V3Z" fill="#e0e0e0"/>
<path d="M4 4H9V5H4V4Z" fill="#ebebeb"/>
<path d="M4 5H12V6H4V5Z" fill="#eee"/>
<path d="M4 6H12V7H4V6Z" fill="#f5f5f5"/>
<path d="M4 7H12V8H4V7Z" fill="#f8f8f8"/>
<path d="M4 8H12V9H4V8Z" fill="#fcfcfc"/>
<path d="M4 3H9V4H4V3Z" fill="#9e9e9e"/>
<path d="M6 8H4V7H6V8ZM12 8H7V7H12V8Z" fill="#9e9e9e" fill-opacity="0.65"/>
<path d="M8 6H4V5H8V6ZM12 6H9V5H12V6Z" fill="#9e9e9e" fill-opacity="0.8"/>
<path d="M8 10H4V9H8V10ZM12 10H9V9H12V10Z" fill="#9e9e9e" fill-opacity="0.45"/>
<path d="M6 12H4V11H6V12ZM10 12H7V11H10V12ZM12 12H11V11H12V12Z" fill="#9e9e9e" fill-opacity="0.3"/>
</svg>
Than 803 bytes:
<svg xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" viewBox="0 0 16 16"><path fill="#fff" d="m11 0 3 3v13H2V0z"/><path fill="#7f7f7f" d="m11 0 3 3v13H2V0zM3 15h10V4h-3V1H3zm8-12h1.5L11 1.5z"/><path fill="#dadada" d="M4 2h5v1H4z"/><path fill="#e0e0e0" d="M4 3h5v1H4z"/><path fill="#ebebeb" d="M4 4h5v1H4z"/><path fill="#eee" d="M4 5h8v1H4z"/><path fill="#f5f5f5" d="M4 6h8v1H4z"/><path fill="#f8f8f8" d="M4 7h8v1H4z"/><path fill="#fcfcfc" d="M4 8h8v1H4z"/><path fill="#9e9e9e" d="M4 3h5v1H4z"/><path fill="#9e9e9e" fill-opacity=".7" d="M6 8H4V7h2zm6 0H7V7h5z"/><path fill="#9e9e9e" fill-opacity=".8" d="M8 6H4V5h4zm4 0H9V5h3z"/><path fill="#9e9e9e" fill-opacity=".5" d="M8 10H4V9h4zm4 0H9V9h3z"/><path fill="#9e9e9e" fill-opacity=".3" d="M6 12H4v-1h2zm4 0H7v-1h3zm2 0h-1v-1h1z"/></svg>
These are little, but they add up, with every page load.
It could get smaller still if we simplifed how it looks.
Going to Chi's comment in #5
"Claro is using content property for drawing the separators. The possible fix would be to use background-image instead like Olivero does."
I think we need to go from:
.breadcrumb__item + .breadcrumb__item::before {
display: inline-block;
padding: 0 0.75rem;
content: url(...); /* SVG image as content */
}
To something like:
.breadcrumb__item + .breadcrumb__item {
position: relative;
padding-left: 1rem; /* or adjust as needed */
}
.breadcrumb__item + .breadcrumb__item::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 0.5rem;
height: 0.5rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' height='8' width='5'%3e%3cpath fill='currentColor' d='M1.207.647L.5 1.354 3.146 4 .5 6.647l.707.707L4.561 4z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-size: contain;
}
Using a background-image avoids the problem because backgrounds are considered purely decorative by user agents and not exposed to screen readers.
While messing with this code, why not optimize the carrot (less than arrow, whatever):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5 8"><path fill="currentColor" d="m1.2.6-.7.8L3.1 4 .5 6.6l.7.8L4.6 4z"/></svg>
This is probably better:
.breadcrumb__item + .breadcrumb__item {
position: relative;
padding-left: 1rem;
}
.breadcrumb__item + .breadcrumb__item::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 0.5rem;
height: 0.5rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 8'%3e%3cpath fill='currentColor' d='m1.2.6-.7.8L3.1 4 .5 6.6l.7.8L4.6 4z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-size: contain;
}
I made some small changes to the issue summary.
The latest MR adds the ARIA search role to the existing form.
It would be better though to switch core/modules/search/src/Form/SearchBlockForm.php & core/modules/search/src/Form/SearchPageForm.php to just use <search>
though. HTML (including search) is always better, if possible, than using ARIA.
I think this color contrast looks good #000000 / #EEEEEE .
If you wanted the edge of the button to have contrast so that it sits above the FFF you could argue for:
#8A8A8A / #FFFFFF
As a background for the button. But I don't think that is what is generally needed for.
Mind you that does seem to be what is suggested here:
https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html#symbo...
I gotta say the grey buttons are ugly.
I'm also not convinced this is a Gin issue, as it is common in any CKEditor config here admin/config/content/formats/manage/content_format
Lets move it to CKEditor for now.
I can move this to the navigation module.
Is there a duplicate issue for this, or are you suggesting there should be another issue opened up?
Ya, I think I filed this in the wrong place. I can move it, but what is the issue.
Just wanted to say that the images at the top came from the Basic Target Size Highlighter from:
https://accessibility-tools.github.io/target-size-highlighter/
There are reasons to use either the basic or Advanced Bookmarklet for this.
To see the outline more clearly in a Chrome Inspector, we can add:
a,
button,
input,
[role="button"],
[role="link"] {
outline: 2px dashed red !important;
}
To ensure all buttons/links/icons have a minimum clickable size, can't we do something like:
a, button, input, .icon-button, .dropbutton__toggle {
position: relative;
min-width: 24px;
min-height: 24px;
}
a {
padding: 10px 15px;
display: inline-block;
}
I like this idea for mobile devices (but that is a AAA SC at this point):
@media (hover: none) and (pointer: coarse) {
button {
min-width: 48px;
min-height: 48px;
margin: 10px;
}
}
More on some of these from:
https://allyship.dev/blog/click-target-size
Nice to see Craft CMS aiming for AAA and 44px:
Moving this to Drupal Core as this affects most of Drupal. Gin's moving into Core, but the base problem isn't Gin.
I think that this builds better with the custom colors, but also allows for greater visibility:
.dropbutton-wrapper.open .dropbutton__items,
.dropbutton__items {
background: var(--gin-bg-layer3, #fff);
border-radius: var(--gin-border-l, 6px);
padding: 0.5em;
min-width: 120px;
z-index: 9999;
box-shadow:
0 4px 8px rgba(var(--gin-color-primary-rgb, 0, 0, 0), 0.4),
0 8px 20px rgba(0, 0, 0, 0.15) !important;
}
This certainly allows us to customize it more.
There are 11 Accent colors, 4 different Focus colors, plus Dark/Light modes. That's a lot of combinations. Probably too many combinations to be able to provide good guidance.
Drupal Core should be providing a good example. We have as a community committed to striving to meet WCAG 2.2 AA standards. This is especially true of Core and Drupal CMS.
#0750E6 / #FFF
#2E6DD0 / #FFF
#4300BF / #FFF
#5B00FF / #FFF
#0F857F / #FFF - Fail (could we not just use #088488)
#00875F / #FFF
#D12E70 / #FFF
#D8002E / #FFF
#DA6303 / #FFF - Fail (Could we not just use #B56026)
#111111 / #FFF
With the image provided, I've updated the Steps to reproduce above.
There are some possible improvements from:
@media (prefers-contrast: more), (forced-colors: active) {
/* Save button (primary) */
#edit-submit.form-submit,
input[type="submit"].button--primary {
forced-color-adjust: none;
background-color: ButtonFace !important;
color: ButtonText !important;
border: 2px solid ButtonText !important;
font-weight: bold;
box-shadow: 0 0 0 2px ButtonText !important;
}
#edit-submit.form-submit:hover,
#edit-submit.form-submit:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
border-color: HighlightText !important;
outline: 2px solid Highlight !important;
outline-offset: 2px;
}
/* Preview button (secondary) */
#gin-sticky-edit-preview.form-submit {
forced-color-adjust: none;
background-color: Canvas !important;
color: ButtonText !important;
border: 2px dashed ButtonText !important;
font-weight: normal;
box-shadow: 0 0 0 1px ButtonText !important;
}
#gin-sticky-edit-preview.form-submit:hover,
#gin-sticky-edit-preview.form-submit:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
border-color: HighlightText !important;
outline: 2px solid Highlight !important;
outline-offset: 2px;
}
/* Hide Sidebar Panel button */
.meta-sidebar__trigger.trigger {
forced-color-adjust: none;
background-color: ButtonFace !important;
color: ButtonText !important;
border: 1px solid ButtonText !important;
border-radius: 50%;
width: 2.25rem;
height: 2.25rem;
}
.meta-sidebar__trigger.trigger:hover,
.meta-sidebar__trigger.trigger:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
outline: 2px solid Highlight !important;
outline-offset: 2px;
}
.meta-sidebar__trigger.trigger svg {
fill: ButtonText !important;
}
}
But I got a different looking input with forced colors enabled.
I think the menu module is the right place to do this.
I don't know if this should be just for folks who have configured their browsers correctly, but we can start with them:
@media (prefers-contrast: more), (forced-colors: active) {
.admin-toolbar__expand-button {
forced-color-adjust: none;
background-color: ButtonFace !important;
color: ButtonText !important;
border: 4px solid ButtonText !important;
box-shadow: none !important;
}
.admin-toolbar__expand-button:hover,
.admin-toolbar__expand-button:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
border-color: HighlightText !important;
outline: 4px solid Highlight !important;
outline-offset: 2px;
}
/* Make SVG chevron icon visible */
.admin-toolbar__expand-button-chevron {
fill: ButtonText !important;
stroke: none !important;
}
}
It would be interesting to see how that button features in user research. Certainly unsure how it would do with users who are using screen magnifiers.
This isn't a Gin issue specifically.
Sadly we can't use color-contrast() yet
https://caniuse.com/?search=color-contrast
Eventually, I think we might be able to do something like:
.button--primary {
background-color: var(--accent);
color: color-contrast(var(--accent) vs ButtonText, Black, White);
}
We really need to fix the accent colors. People can make choices with bad color contrast, but Drupal should not be presenting bad defaults to admins. We can't assume they are testing for color contrast (if we aren't).
.button--primary:hover,
input[type="submit"].button--primary:hover {
background-color: #003078;
border-color: #003078;
}
.button--secondary:hover {
background-color: #f3f2f1;
color: #003078;
border-color: #003078;
}
@media (prefers-contrast: more) {
/* Save Button (more prominent) */
#edit-submit.form-submit,
[data-drupal-selector="gin-sticky-edit-submit"] {
background-color: #000 !important;
color: #fff !important;
border: 2px solid #000 !important;
font-weight: bold;
}
/* Preview Button (less prominent) */
[data-drupal-selector="gin-sticky-edit-preview"] {
background-color: #fff !important;
color: #000 !important;
border: 2px solid #000 !important;
}
/* Shared focus style */
#edit-submit.form-submit:focus-visible,
[data-drupal-selector="gin-sticky-edit-preview"]:focus-visible {
outline: 3px solid #000 !important;
outline-offset: 2px;
background-color: #ffbf47 !important;
color: #000 !important;
}
}
@media (forced-colors: active) {
/* Save Button (more prominent) */
#edit-submit.form-submit,
[data-drupal-selector="gin-sticky-edit-submit"] {
forced-color-adjust: none;
background-color: ButtonText !important;
color: ButtonFace !important;
border: 2px solid ButtonText !important;
font-weight: bold;
}
/* Preview Button (less prominent) */
[data-drupal-selector="gin-sticky-edit-preview"] {
forced-color-adjust: none;
background-color: Canvas !important;
color: ButtonText !important;
border: 2px solid ButtonText !important;
}
/* Focus visibility */
#edit-submit.form-submit:focus-visible,
[data-drupal-selector="gin-sticky-edit-preview"]:focus-visible {
outline: 2px solid Highlight !important;
outline-offset: 2px;
background-color: Highlight !important;
color: HighlightText !important;
}
}
So I think this would help a lot:
.page-wrapper *:focus,.ui-dialog *:focus,.dropbutton .dropbutton__item > *:focus,.dropbutton .dropbutton__item > *:focus:hover,.dropbutton__items > .dropbutton__item:first-of-type > *:focus,.dropbutton__items > .dropbutton__item:first-of-type ~ .dropbutton__item > *:focus,.dropbutton__items > .dropbutton__item:first-of-type ~ .dropbutton__item > *:focus:hover,.form-boolean:focus:active,.form-boolean:focus:hover,.cke.cke_chrome.cke_focus,.horizontal-tabs ul.horizontal-tabs-list li.horizontal-tab-button a:focus,.form-element:focus,.form-element:hover:focus,.form-element.error:hover:focus,.form-actions .action-link:focus,.paragraphs-tabs-wrapper .field-multiple-table .draggable.drag,.layout-paragraphs-field .layout-paragraphs-actions input.layout-paragraphs-edit:focus,.layout-paragraphs-field .layout-paragraphs-actions input.layout-paragraphs-remove:focus,.ck .ck.ck-button:active,.ck .ck.ck-button:focus,.ck .ck.ck-button:active:focus,.toolbar-box .toolbar-handle:focus,.field-option:has(.field-option-radio:checked),.field-option:focus-within,.subfield-option:has(.field-option-radio:checked),.subfield-option:focus-within,#edit-submit.form-submit:focus,.toolbar-dropdown__menu .toolbar-dropdown__link:focus {
outline: none;
box-shadow: 0 0 0 2px var(--color-background, #fff), 0 0 0 5px var(--gin-color-focus);
}
I don't know why it isn't there on hover as well. I do think this would assist mouse users.
We need to do more to enhance the forced colors mode here, especially as the radio button doesn't look like a radio button, but rather three different buttons:
@media (forced-colors: active) {
*:focus {
outline: 6px solid Highlight !important;
outline-offset: 2px;
box-shadow: none !important;
}
}
I am also a fan of how the UK government does their focus styling. As an example of how that could be done.
:root {
--gin-color-focus-text: #0b0c0c; /* GOV.UK black */
--gin-color-focus-background: #ffdd00; /* GOV.UK yellow */
}
/* -----------------------------------
GDS-inspired global focus styling
----------------------------------- */
*:focus-visible {
outline: 3px solid rgba(0, 0, 0, 0); /* suppress default outline */
color: var(--gin-color-focus-text);
background-color: var(--gin-color-focus-background);
box-shadow:
0 -2px var(--gin-color-focus-background),
0 4px var(--gin-color-focus-text);
text-decoration: none;
z-index: 10;
}
/* -----------------------------------
Gin-specific Form Focus Styles
----------------------------------- */
/* Light/Dark/Auto radio selection */
[data-drupal-selector="edit-enable-darkmode"] .form-radios input:checked + .form-item__label {
color: var(--gin-color-button-text);
background-color: var(--gin-color-primary);
box-shadow:
0 -2px var(--gin-color-focus-background),
0 4px var(--gin-color-focus-text);
}
/* Classic toolbar and layout density radios */
[data-drupal-selector="edit-classic-toolbar"] .form-radios .form-item input:checked:focus,
[data-drupal-selector="edit-layout-density"] .form-radios .form-item input:checked:focus {
box-shadow:
0 -2px var(--gin-color-focus-background),
0 4px var(--gin-color-focus-text);
background-color: var(--gin-color-focus-background);
color: var(--gin-color-focus-text);
}
/* Checkboxes not inside known exception wrappers */
:not(.form-checkboxes):not(td):not(.tabledrag-cell-content__item):not(.media-library-item__click-to-select-checkbox):not(.field-content):not(.ajax-new-content):not(.tablesaw-cell-content)
> .form-type--checkbox input:focus {
box-shadow:
0 -2px var(--gin-color-focus-background),
0 4px var(--gin-color-focus-text);
background-color: var(--gin-color-focus-background);
color: var(--gin-color-focus-text);
}
/* Optional: input[type="radio"] and input[type="checkbox"] globally */
input[type="radio"]:focus-visible,
input[type="checkbox"]:focus-visible {
box-shadow:
0 -2px var(--gin-color-focus-background),
0 4px var(--gin-color-focus-text);
background-color: var(--gin-color-focus-background);
color: var(--gin-color-focus-text);
}
/* -----------------------------------
Forced Colors Mode (High Contrast)
----------------------------------- */
@media (forced-colors: active) {
*:focus-visible {
outline: 2px solid Highlight !important;
outline-offset: 2px;
box-shadow: none !important;
background-color: Highlight !important;
color: HighlightText !important;
}
input[type="radio"]:checked + label,
input[type="checkbox"]:checked + label {
background-color: Highlight !important;
color: HighlightText !important;
font-weight: bold !important;
border: 2px solid HighlightText !important;
padding: 0.2em 0.5em !important;
}
}
Do we have a list of the currently supported chips?
I made some suggested CSS changes:
@media (forced-colors: active) {
.gin-status,
.gin-new-flag,
.gin-experimental-flag {
forced-color-adjust: none;
background-color: ButtonFace !important;
color: ButtonText !important;
border: 3px solid ButtonText !important;
}
}
@media (prefers-contrast: more) {
.gin-status,
.gin-new-flag,
.gin-experimental-flag {
background-color: ButtonFace !important;
color: ButtonText !important;
border: 5px solid ButtonText !important;
font-weight: bold;
}
}
However, I'm just seeing the one chip now.
This occurs in the media system, but not sure it is restricted to it.
This CSS is an issue in both Gin & Claro, so this isn't a Gin specific issue. The CSS works reasonably well in both.
Ok, lets minimize the SVG and have it use the ButtonFace so it is more easily customizable
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="ButtonFace" d="M14.6 3 13 1.4a1 1 0 0 0-1.4 0l-1.3 1.4 3 3 1.2-1.3a1 1 0 0 0 0-1.4M5.2 13.6l-3-3 7-7 3 3zm-4.3 1c0 .3 0 .5.3.4l2-.7-1.6-1.6z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path stroke="ButtonFace" stroke-width="3" d="m2.3 2.3 11.4 11.4m-11.4 0L13.7 2.3"/></svg>
I think there will be better ways to do this, but just looking at the issue of the forced colors mode
@media (forced-colors: active) {
/* Contextual trigger (pen icon) */
.contextual .trigger {
forced-color-adjust: none !important;
background-color: ButtonFace !important;
color: ButtonText !important;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='ButtonFace' d='M14.6 3 13 1.4a1 1 0 0 0-1.4 0l-1.3 1.4 3 3 1.2-1.3a1 1 0 0 0 0-1.4M5.2 13.6l-3-3 7-7 3 3zm-4.3 1c0 .3 0 .5.3.4l2-.7-1.6-1.6z'/%3e%3c/svg%3e") !important;
background-repeat: no-repeat;
background-position: center;
background-size: 16px 16px;
border: 1px solid ButtonText !important;
width: 26px;
height: 26px;
opacity: 1 !important;
}
.contextual .trigger:hover,
.contextual .trigger:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
outline: 2px solid Highlight !important;
}
/* Remove button (X icon) */
.media-library-item__remove {
forced-color-adjust: none !important;
background-color: ButtonFace !important;
color: ButtonText !important;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath stroke='ButtonFace' stroke-width='3' d='m2.3 2.3 11.4 11.4m-11.4 0L13.7 2.3'/%3e%3c/svg%3e") !important;
background-repeat: no-repeat;
background-position: center;
background-size: 0.75rem;
border: 1px solid ButtonText !important;
opacity: 1 !important;
}
.media-library-item__remove:hover,
.media-library-item__remove:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
outline: 2px solid Highlight !important;
}
/* Edit button (pen icon) */
.media-library-item__edit {
forced-color-adjust: none !important;
background-color: ButtonFace !important;
color: ButtonText !important;
border: 1px solid ButtonText !important;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='ButtonFace' d='M14.6 3 13 1.4a1 1 0 0 0-1.4 0l-1.3 1.4 3 3 1.2-1.3a1 1 0 0 0 0-1.4M5.2 13.6l-3-3 7-7 3 3zm-4.3 1c0 .3 0 .5.3.4l2-.7-1.6-1.6z'/%3e%3c/svg%3e") !important;
background-repeat: no-repeat;
background-position: center;
background-size: 0.75rem;
opacity: 1 !important;
}
.media-library-item__edit:hover,
.media-library-item__edit:focus-visible {
background-color: Highlight !important;
color: HighlightText !important;
outline: 2px solid Highlight !important;
}
}
There is some JS which is is hiding edit pen when the mouse isn't hovering over the form:
<form class="views-exposed-form" aria-label="Filter the contents of the Media view" data-drupal-selector="views-exposed-form-media-library-page" action="/admin/content/media-grid" method="get" id="views-exposed-form-media-library-page" accept-charset="UTF-8" data-once="exposed-form">
It converts this:
<button class="trigger focusable visually-hidden" type="button" aria-pressed="false">Open configuration options</button>
to this:
<button class="trigger focusable" type="button" aria-pressed="false">Open configuration options</button>
But it doesn't trigger for keyboard users (focus).
It should always be visible, especially in a high contrast mode.
This occurs in Claro too, so is a Core issue.
Interesting. It works as expected in the Add Field Page.
But not in the Add Field Dialog.
mgifford → created an issue. See original summary → .
@kentr I'd say that we make this change globally. If it were only in core themes it would be confusing. I'd agree that this should be fixed in core, and as such the Gin maintainers were right in having it marked it Won't Fix.
Would be nice to fix this bug before it turns 13.
Thanks @catch I appreciate the better update!
We're now at 1.2 and there is a draft of 1.3
https://www.w3.org/WAI/standards-guidelines/aria/
Should we update this or start a new issue?
Yes, we're striving for WCAG 2.2 now https://www.drupal.org/about/features/accessibility →
Might be a good fit first for Drupal CMS? Think we could be starting to ask more questions there? It is perhaps more useful to start asking questions and gathering information from those new to the community, than those already entrenched into D.o.
Both could be useful. I'm not arguing against involvement in Core. I see lots of ways that we could use Drupal itself to start promoting involvment in the Drupal community.
@scott_euser here is some reason comparisons between the two:
- https://elementor.com/blog/webp-vs-avif/
- https://crystallize.com/blog/avif-vs-webp
- https://themeisle.com/blog/avif-vs-webp/
All three articles agree that AVIF’s superior compression leads to smaller image file sizes, which can reduce bandwidth usage and potentially lower energy consumption during data transmission. However, AVIF’s increased decoding time may require more processing power on the client side, possibly offsetting some energy savings.
With Drupal CMS the impact would be even bigger with all the contrib files. I do think this is worth exploring more. Would there ever be a need to produce a developer version (with the extra code), or is that just what you would find in Git?
And agreed @borisson_ it is about setting up good defaults for when everyone works to download Drupal (or Drupal CMS).
Are there advantages here with the latest version of PHPUnit? I don't actually know but there have been improvements since the last comment https://phpunit.de/announcements/phpunit-12.html
- I believe we need to be searching for tests extending BrowserTestBase that perform setup through UI interactions.()
- Then looking replacing browser interactions with direct API calls using services like entity_display.repository or entity storage handlers.()
- Provide clear documentation within the test code to explain the rationale for using API calls over browser interactions.()
- Measure test execution time before and after refactoring to quantify improvements.
Does that seem right?
mgifford → created an issue.
So if we enabled File Hash → and ensured that the duplicate file prevention was enabled, then this would be closed.
That seems more useful than the Audit Files → module approach.
Think this should module should be considered for Drupal CMS?
Should we mark this as a duplicate and focus in on #3432765?
Just adding some additional references here about the importance of this:
My understanding is that the Lighthouse test are the same as Deque's axe-core. Google uses axe-core.
Just adding @dunx to the metadata of this issue.
Bringing this up as there seem to be some outstanding issues.
We should be much closer to making this conversion the default though.
It has been over a year since someone looked at it. If @chi's perception of this is right, there are thousands more in savings that have been lost (let alone the environmental impact of running millions of processes on servers as part of this).
@joachim’s 2023 suggestion was to split the problem into separate issues for each test type. I tried to summarize would this would look like using ChatGPT to highlight what this would look like, along with justification and next steps. I'm mostly doing this to nudge this ahead.
Do these new issues sound like good places to begin? Has there been other work to do this already?
⸻
1. Kernel Tests: Optimize setUp() Execution
Goal: Avoid redundant setUp() execution for each method in Kernel tests.
Justification:
• Kernel tests do not boot the full stack and have fewer side effects.
• A shared setUp() could save significant time across large test classes.
Suggested New Issue:
“Optimize PHPUnit Kernel test execution by avoiding repeated setUp() calls per method.”
Action Items:
• Benchmark time saved when sharing setUp() across methods.
• Propose an attribute or annotation to allow opting in/out per class.
• Ensure tearDown cleanup logic remains reliable.
⸻
2. Browser Tests (Functional + FunctionalJavascript): Improve Test Efficiency
Goal: Investigate safe ways to cache installed sites between test methods in browser-based test classes.
Justification:
• Browser tests are the slowest due to full Drupal installs and HTTP interactions.
• Current design reinstalls Drupal for every method—even within the same class.
Suggested New Issue:
“Enable shared Drupal site installations across Browser test methods to reduce test run time.”
Action Items:
• Explore integration with #2900208 for site install caching.
• Identify classes that could safely share a site environment.
• Flag test classes with dependencies on state or side effects to avoid breaking isolation.
⸻
3. JavaScript Tests: Evaluate Efficiency Gains from Shared setUp()
Goal: Identify whether JS tests (Nightwatch or others) could benefit from setup sharing, or if they already do.
Justification:
• JS test infrastructure is separate (Node/Nightwatch/WebDriver), but setup redundancy may still exist.
• Even if not using PHPUnit, parallels in redundant test bootstrapping may exist.
Suggested New Issue:
“Audit and optimize Nightwatch JS tests for redundant setup executions across test methods.”
Action Items:
• Confirm whether test fixtures or browser states are rebuilt between methods.
• Identify opportunities for fixture reuse or browser session persistence.
⸻
Cross-Issue Meta Task: Central Coordination and Tracking
Create a meta issue to link all three above:
“Optimize test performance by limiting redundant setUp() execution across test types.”
⸻
Justification for Splitting
Joachim’s 2023 comment was correct: different test types have different performance bottlenecks, state requirements, and risk profiles. Attempting to solve them all in one issue creates blockers and lack of clarity. Splitting enables:
• Focused benchmarking
• Different contributors to work in parallel
• Faster consensus and review
• Targeted test infrastructure changes
Looking back at this issue now.
ImageAPI Optimize → looks quite flexible, it will work for D10 & 11 but does require another 3rd party system. It would be interesting to see if that could be incorporated into Drupal CMS but unsure if it would be a good candidate for Core. Image optimization should be easy, but building in a 3rd party into Core would be a problem (not matter which one).
Imagemagick → could also do the trick, and has more installs.
Some MIT projects that might be worth looking at:
There is going to be some overlap with https://www.drupal.org/project/gin/issues/3506350 🐛 Several icons and images are invisible in Forced Colors mode Active
Target is the Gin settings page admin/appearance/settings/gin
For the first item, this patch should be useful as this does provide an alternative for forced-colors:
@media (forced-colors: active) {
input[type="radio"] {
appearance: auto !important;
forced-color-adjust: auto !important;
}
/* Reset default label styling for all options */
input[type="radio"] + label {
all: unset;
display: inline-block;
padding: 0.2em 0.5em;
}
/* Style the selected option */
input[type="radio"]:checked + label {
background-color: ButtonFace !important;
color: ButtonText !important;
font-weight: bold !important;
text-decoration: underline !important;
border: 2px solid HighlightText !important;
}
input[type="radio"]:focus-visible + label {
outline: 2px solid Highlight !important;
outline-offset: 2px;
}
}
mgifford → created an issue.
Removing forced-colors to avoid confusion with "high contrast" as they are treated the same here.