skip to main content

css mischief: :has(), :is(), color-mix(), :checked, and relative colors

2025-06-21

summary: a CSS experiment presented as a color scheme picker.


remember, i don’t use javascript. this is all css.

select your theme:

select your favorite color:

view source

<style>
.thingamabob {
  --red: #e40303;
  --orange: #ff8c00;
  --yellow: #ffed00;
  --green: #008026;
  --blue: #004dff;
  --violet: #750787;
  --white: #ffffff;
  --pink: #ffafc8;
  --lightblue: #74d7ee;
  --brown: #613915;
  --black: #000000;
  
  --color: light-dark(#ddd, #333);

  padding: 2rem;

  background-color: light-dark(color-mix(in oklab, #fff 60%, oklab(from var(--color) 30% a b)), oklab(from var(--color) 10% a b));
  
  & label {
    display: inline-flex;
    gap: 0.1rem;
    border-radius: 0.2rem;
    padding: 0.1rem;
    padding-right: 0.3rem;
    margin: 0.1rem;
  }
  & label:hover {
    background-color: light-dark(color-mix(in oklab, #fff 80%, oklab(from var(--color) 30% a b)), rgb(255 255 255 / 0.2)); 
  }
  
  color: light-dark(#000, #fff);
  
  border-top: 0.5rem solid var(--color);

  transition: 0.5s all;

  &:has(input[name="mode"][value="light"]:is(:checked, :hover)) {
    color-scheme: light;
  }

  &:has(input[name="mode"][value="dark"]:is(:checked, :hover)) {
    color-scheme: dark;
  }

  &:has(input[name="color"][value="red"]:is(:checked, :hover)) {
    --color: var(--red);
  }
  &:has(input[name="color"][value="orange"]:is(:checked, :hover)) {
    --color: var(--orange);
  }
  &:has(input[name="color"][value="yellow"]:is(:checked, :hover)) {
    --color: var(--yellow);
  }
  &:has(input[name="color"][value="green"]:is(:checked, :hover)) {
    --color: var(--green);
  }
  &:has(input[name="color"][value="blue"]:is(:checked, :hover)) {
    --color: var(--blue);
  }
  &:has(input[name="color"][value="violet"]:is(:checked, :hover)) {
    --color: var(--violet);
  }
  &:has(input[name="color"][value="white"]:is(:checked, :hover)) {
    --color: var(--white);
  }
  &:has(input[name="color"][value="pink"]:is(:checked, :hover)) {
    --color: var(--pink);
  }
  &:has(input[name="color"][value="lightblue"]:is(:checked, :hover)) {
    --color: var(--lightblue);
  }
  &:has(input[name="color"][value="brown"]:is(:checked, :hover)) {
    --color: var(--brown);
  }
  &:has(input[name="color"][value="black"]:is(:checked, :hover)) {
    --color: var(--black);
  }
  
  &:has(input[name="color"]:is(:checked, :hover)) :is(h1, h2, h3, h4, h5, h6) {
    color: var(--color);
    transition: 0.5s all;
    text-shadow: 0 0.2rem 1.5rem light-dark(rgb(0 0 0 / 0.75), rgb(255 255 255 / 0.1));
  }
  
  /* special case for black */
  &:has(input[name="color"][value="black"]:is(:checked)) :is(h1, h2, h3, h4, h5, h6) {
    text-shadow: 0 0rem 1rem rgb(255 255 255);
  }
  
  &:has(input[name="color"]:checked) #message::after {
    display: block;
    content: "and until next time: be gay, do (css) crimes ;)"
  }

}
</style>
<div class="thingamabob">
<h1>select your theme:</h1>
<label><input type="radio" name="mode" value="light" checked> light</label>
<label><input type="radio" name="mode" value="dark"> dark</label>

<h1>select your favorite color:</h1>
<label><input type="radio" name="color" value="red">red</label>
<label><input type="radio" name="color" value="orange">orange</label>
<label><input type="radio" name="color" value="yellow">yellow</label>
<label><input type="radio" name="color" value="green">green</label>
<label><input type="radio" name="color" value="blue">blue</label>
<label><input type="radio" name="color" value="violet">violet</label>
<label><input type="radio" name="color" value="white">white</label>
<label><input type="radio" name="color" value="pink">pink</label>
<label><input type="radio" name="color" value="lightblue">lightblue</label>
<label><input type="radio" name="color" value="brown">brown</label>
<label><input type="radio" name="color" value="black">black</label>

</div>