Fallback to checkerboard if var(--color) is undefined

Viewed 230

How can I make it so that when --color is set, it overrides the checkerboard background?

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  /* from https://stackoverflow.com/a/51054396/65387 */
  background-image: /* tint image */
  linear-gradient(to right, rgba(204, 204, 204, 0.9), rgba(204, 204, 204, 0.9)), /* checkered effect */
  linear-gradient(to right, black 50%, white 50%), linear-gradient(to bottom, black 50%, white 50%);
  background-blend-mode: normal, difference, normal;
  background-size: 25px 25px;
}

.a {
  background-color: var(--color);
}

.b {
  background: var(--color);
}
<div>
  <div class="cell a">a1</div>
  <div class="cell a" style="--color:red;">a2</div>
</div>
<div>
  <div class="cell b">b1</div>
  <div class="cell b" style="--color:red;">b2</div>
</div>

a2 doesn't override the background like I want.

b2 does, but then b1 becomes white.

Is there a way to do this without JavaScript?

3 Answers

You can use var() second parameter that works if the variable isn't defined.

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  /* from https://stackoverflow.com/a/51054396/65387 */
  
  background-blend-mode: normal, difference, normal;
  background-size: 25px 25px;
}



.b {
  background-image:/* tint image */
  linear-gradient(to right, var(--color,rgba(204, 204, 204, 0.9)), var(--color,rgba(204, 204, 204, 0.9))), /* checkered effect */
  linear-gradient(to right, var(--color,black 50%),var(--color,white 50%)),     linear-gradient(to bottom, var(--color,black 50%), var(--color,white 50%));
}
<div>
  <div class="cell b">b1</div>
  <div class="cell b" style="--color:red;">b2</div>
</div>

Use an extra layer like below:

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  
  background: 
    linear-gradient(var(--color,transparent) 0 0), /* the extra layer */
    linear-gradient(rgba(204, 204, 204, 0.9) 0 0),
    linear-gradient(to right,  black 50%, white 0), 
    linear-gradient(to bottom, black 50%, white 0);
  background-blend-mode:normal, normal, difference, normal;
  background-size: 25px 25px;
}
<div class="cell">a1</div>
<div class="cell" style="--color:red;">a2</div>
<div class="cell" style="--color:blue;">b2</div>

You can also scale the solution to consider image too:

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  
  background: 
    var(--image,linear-gradient(transparent 0 0)), /* the extra image layer */
    linear-gradient(var(--color,transparent) 0 0), /* the extra color layer */
    linear-gradient(rgba(204, 204, 204, 0.9) 0 0),
    linear-gradient(to right,  black 50%, white 0) 0 0/25px 25px, 
    linear-gradient(to bottom, black 50%, white 0) 0 0/25px 25px;
  background-blend-mode:normal, normal ,normal, difference, normal;
}
<div class="cell">a1</div>
<div class="cell" style="--color:red;">a2</div>
<div class="cell" style="--image:linear-gradient(green,blue);">b2</div>
<div class="cell" style="--image:url(https://picsum.photos/id/1/200/200) center/cover;">b3</div>
<div class="cell" style="--image:url(https://picsum.photos/id/18/50/50)  center no-repeat;--color:yellow">b4</div>

An optimized version with conic-gradient and without blend-mode

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  
  background: 
    var(--image,linear-gradient(transparent 0 0)), /* the extra image layer */
    linear-gradient(var(--color,transparent) 0 0), /* the extra color layer */
    linear-gradient(rgba(204, 204, 204, 0.9) 0 0),
    repeating-conic-gradient(#fff 0 90deg,#000 0 180deg) 0 0/25px 25px;
}
<div class="cell">a1</div>
<div class="cell" style="--color:red;">a2</div>
<div class="cell" style="--image:linear-gradient(green,blue);">b2</div>
<div class="cell" style="--image:url(https://picsum.photos/id/1/200/200) center/cover;">b3</div>
<div class="cell" style="--image:url(https://picsum.photos/id/18/50/50)  center no-repeat;--color:yellow">b4</div>

Another idea using pseudo element:

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  position:relative;
  z-index:0;
  background: 
    linear-gradient(rgba(204, 204, 204, 0.9) 0 0),
    repeating-conic-gradient(#fff 0 90deg,#000 0 180deg) 0 0/25px 25px;
}
.cell::before,
.cell::after{
  content:"";
  position:absolute;
  z-index:-1;
  inset:0;
}
.cell::before {
  background:var(--color);
}
.cell::after {
  background:var(--image);
}
<div class="cell">a1</div>
<div class="cell" style="--color:red;">a2</div>
<div class="cell" style="--image:linear-gradient(green,blue);">b2</div>
<div class="cell" style="--image:url(https://picsum.photos/id/1/200/200) center/cover;">b3</div>
<div class="cell" style="--image:url(https://picsum.photos/id/18/50/50)  center no-repeat;--color:yellow">b4</div>

Without using JavaScript, I think the only way to provide a custom fallback if --color isn't defined is by using a fallback value.

Custom fallback values are just a backup for the browser which supports CSS Custom Properties to choose a different value if the given variable isn't defined or has an invalid value.

.a {
  background-image: var(--color, var(--checkerboard)); /* css var for linear-gradients */
  background-color: var(--color);
}

So if the custom property --color isn't defined, the browser will use the fallback value. In this case, using a combination of background-image and background-color seems to do the trick.

It works by testing the background-image property to see if --color is defined. If it's not, then keep the checkerboard design by using the linear-gradient combination as the fallback value.

:root {
  --checkerboard: /* tint image */
  linear-gradient(to right, rgba(204, 204, 204, 0.9), rgba(204, 204, 204, 0.9)), /* checkered effect */
  linear-gradient(to right, black 50%, white 50%), linear-gradient(to bottom, black 50%, white 50%);
}

.cell {
  display: inline-block;
  width: 100px;
  height: 100px;
  /* from https://stackoverflow.com/a/51054396/65387 */
  background-image: var(--checkerboard); /* can be removed but then .a or .b will need to be defined */
  background-blend-mode: normal, difference, normal;
  background-size: 25px 25px;
}

.a {
  background-image: var(--color, var(--checkerboard));
  background-color: var(--color);
}

.b {
  background-image: var(--color, var(--checkerboard));
  background-color: var(--color);
}
<div>
  <div class="cell a">a1</div>
  <div class="cell a" style="--color: red;">a2</div>
</div>
<div>
  <div class="cell b">b1</div>
  <div class="cell b" style="--color: red;">b2</div>
</div>

Related