Как сделать box-shadow прозрачным?

Делаю а-ля radio кнопок и появилась маленькая проблема. Для активного цвета box-shadow нужно сделать так, чтобы цвет подстраивался в зависимости от заднего фона, можно ли это сделать прямым css без добавление новых элементов? Некоторые могут сейчас написать, сделай переменную для фона и просто подставляй. Ок! Допустим сделаю, а что если я захочу использовать такие же кнопки на другом фоне, постоянно мне менять? Бред! введите сюда описание изображения

body {
  background-color: #fff;
}

.list {
  display: flex;
  gap: 15px;
}

.color {
  width: 25px;
  height: 25px;
  border-radius: 100%;
  background-color: red;
  cursor: pointer;
}

.color.checked {
  box-shadow: inset 0 0 0 2px #fff;
  border: 2px solid red;
}
<div class="list">
  <div class="color"></div>
  <div class="color"></div>
  <div class="color checked"></div>
  <div class="color"></div>
</div>


Ответы (2 шт):

Автор решения: eri

Вырезать дырку в элементе можно через clip-path, но рисовать кольцо довольно сложно.

А вот если колечко сделать отдельным элементом, то получается дырка засчёт inset.

body {
  background-color: #fff;

}

.list {
  display: flex;
  gap: 15px;
  background-image: linear-gradient(0deg, #000, #fff);

}

.color {
  width: 25px;
  height: 25px;
  border-radius: 100%;
  background-color: red;
  cursor: pointer;
}

.color.checked {
  position: relative;
  margin: 4px;
  width: 17px;
  height: 17px; 
   }

.checked::after {
  content: "";
  position: absolute;
  inset: -4px;
  background: transparent;
  border: 2px solid red;
  border-radius: inherit;

}
<div class="list">
  <div class="color"></div>
  <div class="color"></div>
  <div class="color checked"></div>
  <div class="color"></div>
</div>

→ Ссылка
Автор решения: De.Minov

Я бы использовал для этого background-image, а точнее radial-gradient.

.custom-radio input[type="radio"] {
  display: none;
}

.custom-radio-check {
  --custom-radio-size: 25px;
  --custom-radio-color: red;
  --custom-radio-stroke-width: 2px;
  --custom-radio-stroke-offset: 2px;
  --custom-radio-stroke-color: red;
  display: inline-block;
  width: calc(var(--custom-radio-size) + (var(--custom-radio-stroke-width) + var(--custom-radio-stroke-offset)) * 2);
  height: calc(var(--custom-radio-size) + (var(--custom-radio-stroke-width) + var(--custom-radio-stroke-offset)) * 2);
  background-image:
    radial-gradient(circle, var(--custom-radio-color) calc(69% - .5px), transparent calc(69% + .5px)),
    radial-gradient(circle,
      transparent calc(69% - var(--custom-radio-stroke-width) - .5px),
      var(--custom-radio-stroke-color) calc(69% - var(--custom-radio-stroke-width) + .5px),
      var(--custom-radio-stroke-color) calc(69% - .5px),
      transparent calc(69% + .5px)
    );
  background-repeat: no-repeat;
  background-position: center center;
  background-size: var(--custom-radio-size) var(--custom-radio-size);
  transition: background-size .3s ease;
  cursor: pointer;
}

.custom-radio input[type="radio"]:checked ~ .custom-radio-check {
  background-size:
    var(--custom-radio-size) var(--custom-radio-size),
    100% 100%;
}
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" checked />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>

Или же сделать дополнительно псевдоэлемент, который будет больше родителя (на величину отступа) и будет иметь бордер.

.custom-radio:not(:last-child) {
  margin-right: 1ch;
}

.custom-radio input[type="radio"] {
  display: none;
}

.custom-radio-check {
  --custom-radio-size: 24px;
  --custom-radio-color: red;
  --custom-radio-stroke-width: 2px;
  --custom-radio-stroke-offset: 2px;
  --custom-radio-stroke-color: red;
  display: inline-block;
  width: var(--custom-radio-size);
  height: var(--custom-radio-size);
  background-color: var(--custom-radio-color);
  border-radius: 50%;
  position: relative;
  cursor: pointer;
}

.custom-radio-check::before {
  content: '';
  display: block;
  width: calc(var(--custom-radio-size) + var(--custom-radio-stroke-offset) * 2);
  height: calc(var(--custom-radio-size) + var(--custom-radio-stroke-offset) * 2);
  border: var(--custom-radio-stroke-color) solid var(--custom-radio-stroke-width);
  border-radius: inherit;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity .3s ease;
}

.custom-radio input[type="radio"]:checked ~ .custom-radio-check::before {
  opacity: 1;
}
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" checked />
  <div class="custom-radio-check"></div>
</label>
<label class="custom-radio">
  <input type="radio" name="test[]" />
  <div class="custom-radio-check"></div>
</label>

→ Ссылка