No you are fine, technically there is no requirement for the contrast to change at all when hovering.
There is a full conversation about this on GitHub
Which relates to this piece of guidance:
This Success Criterion does not require that changes in color that differentiate between states of an individual component meet the 3:1 contrast ratio when they do not appear next to each other. For example, there is not a new requirement that visited links contrast with the default color, or that mouse hover indicators contrast with the default state. However, the component must not lose contrast with the adjacent colors, and non-text indicators such as the check in a checkbox, or an arrow graphic indicating a menu is selected or open must have sufficient contrast to the adjacent colors.
Source: https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html
As long as both states have sufficient contrast against the background and surrounding items it will pass WCAG.
If you think about it it makes sense, otherwise to create a AAA level button would require a contrast ratio of 4.5:1 with the background and then a further 4.5:1 contrast with the non-hovered state. That would mean all buttons would have to be practically black (or white if you had a dark background on the site) when hovered in order to match both criteria.
But WCAG isn't the end of it!
There are a few things you can do to improve accessibility (you don't have to stop at compliance, you can aim for "wowing" people who benefit from accessibility).
First thing is first, use cursor: pointer
. This signifies something is clickable and it is now widely accepted that this is an acceptable / beneficial use.
The second thing you can do is use slightly different indication methods for hover vs focus.
So for example you can use border
and outline
in conjunction with each other to show the states of hover, focus, hovered and focused:
button{
background: #000;
border: 2px solid #fff;
color: #fff;
outline: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-radius: 2.25rem;
font-size: 1.5rem;
margin: 2rem;
}
button:hover{
border: 2px solid #333;
}
button:focus{
outline: 2px solid #333;
outline-offset: 2px;
}
<button>Test button</button>
Alternatively a neat trick instead of using outline
is to use box-shadow
. The advantage is it works for curved corners:
button{
background: #000;
border: 2px solid #fff;
color: #fff;
outline: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-radius: 2.25rem;
font-size: 1.5rem;
margin: 2rem;
}
button:hover{
border: 2px solid #333;
}
button:focus{
box-shadow: 0 0 0 2px #fff, 0 0 0 4px #000;
}
<button>Test with curves</button>
I don't like the stacked option as it needs a lot of white space
If having two different indicators doesn't work for your design you can just have different states (and give priority to the focus state).
button{
background: #000;
color: #fff;
outline: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-radius: 0.25rem;
font-size: 1.5rem;
margin: 2rem;
border: none;
}
button:hover{
outline: 2px dashed #333;
}
button:focus{
outline: 2px solid #333;
}
<button>Different border styles</button>
Use your imagination! You could make the button shrink by a couple of pixels on hover (assuming it is implemented so it doesn't cause a layout shift), change the text style, but grow on focus, change the background to a pattern depending on state (but be careful with that one) etc.
Quick Tip: You will see that I made my buttons black and white. I find this is a great way to test / prototype different states.