Overwrite custom default color settings of browser

609 Views Asked by At

I want to make a website more accessible by considering user with high contrast mode (or maybe just dark mode). Now I have a problem with custom radio buttons which are just HTML elements that have a round border: when the user has set the default background color of his browser to black, the background-color of my elements is also black, making it look like a checked option, even though I set the background-color of this elements to white.

To prevent this I made the white border thicker, so it looks like a white background. But it also creates the problem, that sometimes there is a tiny black dot in the middle of my buttons at some zoom-levels or resolutions.

Is there any way to prevent the browser from overwriting the background-color I declared in my CSS? Is there anything I missed out on like an attribute that prevents this behaviour?

I could also replace this elements or implement them in a different way, but at this point i am just curious if there isn't any simple solution to that.

The style of my radio buttons looks like this:

input.check + label:before {
    display: inline-block;
    content: "";
    width: 1rem;
    height: 1rem;
    background: #fefefe;
    border: 0.2rem solid #fefefe;
    border-radius: 50%;
    position: absolute;
    left: -1rem;
}

input.check:checked + label:before {
    background: #000000;
}

Here is a link to a picture of my radio when checked / or default black background-color

I make the 'checked' look of my radio button by setting the background-color to black - like the browser does in this case.

Edit

So far there are good answers for improving the accessability of custom radio buttons. To be a little bit more specific on my problem:

I tested the page in Firefox with the following color settings color settings in firefox

But this seems to overwrite every background-color no matter what you specified for each element. Is there a way to make an exception for this overwriting?

2

There are 2 best solutions below

3
On

Using a pseudo element - which is already mooted in the question - it is possible to style the button exactly as you would like.

The main difference in this snippet and the CSS in the question is that we set the actual input element to opacity 0. This means it is still 'there' for accessibility purposes but it can't be actually seen.

Also, using radial-gradient for coloring the buttons we can have rings of different colors, or just one color as best suits the background chosen. As the code in the question does, we also size everything in terms of rems so that the user who has changed their browser setting for this gets the benefit.

body {
  background-color: black;
}

input {
  opacity: 0;/* keep the input element in the DOM for accessibility it's just not seen*/ 
}

/* a pseudo element - this is what the user actually sees and we can style it */

label > input[type="radio"] + *::before {
  content: "";
  display: inline-block;
  width: 2rem;
  height: 2rem;
  margin-right: 1rem;
  border-radius: 50%;
  border-style: solid;
  border-width: 0.2rem;
  border-color: white;
  background: radial-gradient(white 0%, white 100%);/* choose what you want - one color or rings */
  border-color: white;
}

label > input[type="radio"]:checked + *::before {
  background: radial-gradient(red 0%, red 50%, white 50%, white 100%);/* choose what you want here too */
  border-color: red;
}

label {
  font-size: 2rem;
  color: white;
}
  <label>
    <input type="radio" name="mybutton" value="A" checked />
    <span>A</span>
  </label>
  <label>
    <input type="radio" name="mybutton" value="B" />
    <span>B</span>
  </label>
  <label>
    <input type="radio" name="mybutton" value="C" />
    <span>C</span>
  </label>

3
On

In order to remove the default browser styling for the radio buttons you need appearance: none;

You will find more on that here, and you can check browser support here.

From there, you can use the background property to create the checked effect, you don't even need to use ::before.

I created this fiddle to demonstrate.

The code looks like this:

:root {
  --background-color: white;
  --text-color: black;
  --fill-color: black;
  --border-color: black;
}

@media (prefers-color-scheme: dark) {
   :root {
    --background-color: black;
    --text-color: white;
    --fill-color: white;
    --border-color: white;
  }
}

body {
  background: var(--background-color);
  color: var(--text-color);
}

div {
  display: flex;
  align-items: center;
}

input[type=radio] {
  appearance: none;
  margin: 0 0.5rem 0 0;
  border: 1px solid var(--border-color);
  border-radius: 50%;
  width: 1rem;
  height: 1rem;
}

input[type=radio]:checked {
  background: radial-gradient(var(--fill-color) 0%, var(--fill-color) 30%, var(--background-color) 31%);
}
<p>Select an option:</p>

<div>
  <input class="check" type="radio" id="huey" name="duck" value="huey" checked>
  <label for="huey">Huey</label>
</div>

<div>
  <input class="check" type="radio" id="dewey" name="duck" value="dewey">
  <label for="dewey">Dewey</label>
</div>

<div>
  <input class="check" type="radio" id="louie" name="duck" value="louie">
  <label for="louie">Louie</label>
</div>