Make WordPress Core

Opened 5 weeks ago

Closed 9 days ago

#65807 closed defect (bug) (fixed)

Some text displayed in the Privacy tables has insufficient color contrast ratio

Reported by: afercia Owned by: afercia
Priority: normal Milestone: 7.2
Component: Administration Version:
Severity: normal Keywords: has-patch commit
Cc: Focuses: accessibility

Description

In

  • WP Admin > Tools > Export Personal Data
  • WP Admin > Tools > Erase Personal Data

Depending on the state of a request, some text displayed within the table cells uses a light gray color that has insufficient color contrast ratio with the background.

For example, the 'Erasing data...' and the 'Erasure completed' text color is #787c82. Against a white background, the contrast ratio is 4.19:1. It should be at least 4.5:1.

Not sure whether these tables use zebra-stripe background where some rows may have a light gray background. In that case, the contrast ratio would be even lower.

There is no reason to use a less prominent color for this text. Also, there is no reason to use non-standard colors like #787c82. The WP admin has well established colors to be used to meet the contrast ratio requirements.

Attachments (1)

01 erasure completed.png (51.8 KB ) - added by afercia 5 weeks ago.

Download all attachments as: .zip

Change History (10)

#1 @afercia
5 weeks ago

Note that there may be more colors to fix in these privacy tables and some investigation would be welcome.

#2 @joedolson
5 weeks ago

The striping in the privacy tables is strange; it explicitly overrides it, but uses the .striped class. I'm not sure why. But the result is that it doesn't have striped text.

It does need a .row-actions override color, as other core usages of .row-actions don't contain plain text, only links, but this color isn't appropriate.

This ticket was mentioned in PR #12842 on WordPress/wordpress-develop by @bejignesh.


5 weeks ago
#3

  • Keywords has-patch added

The Export and Erase Personal Data tables render their progress and result text inside the row actions, where forms.css sets a privacy specific color:

.privacy_requests .row-actions {
        color: #787c82;
}

Against the #fff cell background that is 4.19:1, below the 4.5:1 minimum for normal text. The strings are built into $row_actions in the two list tables, so they inherit a color meant for links:

'<span class="remove-personal-data-processing hidden">' . __( 'Erasing data...' ) . ' <span class="erasure-progress"></span></span>' .
'<span class="remove-personal-data-success hidden">' . __( 'Erasure completed.' ) . '</span>' .

This removes the override so the text inherits the standard .row-actions color, #646970 from list-tables.css, which is 5.53:1 against the same background. Every other list table in the admin already uses it, so this introduces no new color, which is what the ticket asks for.

The color was never chosen for its contrast. It arrived as #72777c in [46264] and became #787c82 in [50025], when admin colors were standardized on a single palette.

### Measured, before and after

Computed styles on the rendered screens at /wp-admin/export-personal-data.php and /wp-admin/erase-personal-data.php, with requests present in all four states (pending, confirmed, failed, completed). The row action states that are hidden until JS runs were unhidden in order to measure them.

String Before After
Downloading data... 4.19:1 5.53:1
Download failed. 4.19:1 5.53:1
Erasing data... 4.19:1 5.53:1
Erasure completed. 4.19:1 5.53:1
Force erasure has failed. 4.19:1 5.53:1
Separator between actions 4.19:1 5.53:1

Auditing every text bearing element inside both tables: 7 failures before, 0 after. The lowest remaining ratio in either table is 4.73:1, the #d63638 "Failed" status label, which passes.

Note the ticket names two strings; there are five. "Force erasure has failed." and "Download failed." come from the same rule, as do the | separators.

### On the striping question

The ticket asks whether zebra striping puts this text on a gray background, which would lower the ratio further. It does not. The table carries the striped class, but forms.css overrides the backgrounds, and measured on the rendered page every text bearing cell computes to #fff in all four request states. The only gray is #f6f7f7 on td.check-column of a failed request, which contains just the checkbox and no text. So 4.19:1 was the worst case, not the best case.

### Testing

  • Measured computed color and effective background for every text bearing element in both tables, in all four request states, before and after.
  • No RTL change is needed: forms-rtl.css is generated at build time and is not tracked.
  • CSS only, no markup or PHP change, so no unit test accompanies this.

## Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Drafting the patch and this description. I measured the contrast ratios from computed styles on the rendered admin screens before and after the change, created privacy requests in all four states to cover every row variant, audited every text bearing element in both tables rather than only the strings named in the ticket, checked the striping question against the rendered page, traced the color back through [46264] and [50025], and I take responsibility for the result.

#4 @bejignesh
5 weeks ago

I opened a PR for this: https://github.com/WordPress/wordpress-develop/pull/12842

@joedolson is right about .row-actions. The rule lives in forms.css:

.privacy_requests .row-actions {
        color: #787c82;
}

and the progress and result strings are built into $row_actions in the two list tables, so plain text picks up a color that was meant for links. Removing that override lets it inherit the standard .row-actions color, #646970 from list-tables.css, which is 5.53:1 on white. That keeps these tables consistent with every other list table and avoids adding another color.

On "there may be more colors to fix": there are five strings, not two. Alongside "Erasing data..." and "Erasure completed.", the same rule also covers "Force erasure has failed.", "Downloading data..." and "Download failed.", plus the | separators between the actions. All measured 4.19:1, and all are 5.53:1 after.

I audited every text bearing element in both tables, with requests in all four states (pending, confirmed, failed, completed), reading computed styles off the rendered screens rather than the source. Seven failures before, none after. The lowest ratio left in either table is 4.73:1, the #d63638 "Failed" status label.

On the zebra striping question: it does not make this worse. The table does carry the striped class, but forms.css overrides the row backgrounds, and every text bearing cell computes to #fff in all four states. The only gray is #f6f7f7 on td.check-column of a failed request, and that cell holds just the checkbox. So 4.19:1 was the worst case here, not the best case.

One small correction on the color itself: #787c82 is part of the standard admin palette. It was #72777c when the erasure success message shipped in [46264], and [50025] changed it to #787c82 while standardizing admin colors on that palette. So it is a palette value, it is just too light for 13px text on white. #646970 is the neighbouring value in the same palette and the one the rest of the admin already uses in this position.

This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.


3 weeks ago

#6 follow-up: @joedolson
3 weeks ago

  • Milestone Awaiting Review7.2

I want to propose also restoring zebra striping on this table as part of this change. The striping is a visual aid that improves usability of the table, and I can't see any good reason for overriding it in this table. I wasn't able to find any reasoning behind that.

@masteradhoc Do you have any thoughts on that?

#7 in reply to: ↑ 6 @afercia
9 days ago

Replying to joedolson:

I want to propose also restoring zebra striping on this table as part of this change. The striping is a visual aid that improves usability of the table, and I can't see any good reason for overriding it in this table. I wasn't able to find any reasoning behind that.

I'd agree with restoring the striped styling. However, that would need some investigation. The current styling intentionally overrides the default zebra-striped one. I couldn't find any reference to this intentional styling in the related tickets though. The only case I can think of would be some AJAX action that removes or adds a table row so that the table could end up having two or more adjacent rows that use the same background color. I'm not sure there is such an AJAX mechanism though,. I'd suggest to split this into a separate ticket for more investigation.

On the other hand, I found a total of 17 occurrences for the color #787c82. I will create a new ticket to propose to entirely remove the usage of this color. In some cases it is used for controls that contain only icons, for example the next / previous / close buttons in the media and themes browsers. Same for some icon-only controls in the Customizer. These icons must meet a 4.5:1 color contrast ratio. In a few cases #787c82 is used for other things, e.g. a border. Regardless, this color appears to be not justifiable given its limited use, and it can't be used for text or icon-only controls. After fixing all the relevant cases, the remaining usages would be maybe 2 or 3 so it's reasonable to remove it entirely.

#8 @afercia
9 days ago

  • Keywords commit added
  • Owner set to afercia
  • Status newassigned

#9 @afercia
9 days ago

  • Resolutionfixed
  • Status assignedclosed

In 63399:

Administration: Fix the Privacy tables row action text color contrast.

Some text in the Privacy table row actions used a gray #787c82 which doesn't meet the minimum color contrast ratio of 4.5:1.
This color unnecessarily overrides the default gray color used for the tables row actions. It is now removed to restore the default.

Developed in https://github.com/WordPress/wordpress-develop/pull/12842

Props bejignesh, joedolson, afercia.
Fixes #65807.

Note: See TracTickets for help on using tickets.