CSS Grid: grid-column with span, calc() and CSS variable not working in WebKit browsers

Viewed 2075

I'm using a simple grid, where the amount of columns can be configured/overwritten via a CSS variable.

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns, 1), 1fr);
}

// Mixin for tablet media query
@include tablet {
  .grid {
    --grid-columns: 2;
  }
}

// Mixin for tablet media query
@include desktop {
  .grid {
    --grid-columns: 4;
  }
}

Above is a simplified example.

I also have a class that can be used on a "cell", to note whether it is full width or two cells wide (span-half).

@include desktop {
  .span {
    &-full {
      grid-column: 1 / -1;
    }

    &-half {
      grid-column: span calc(var(--grid-columns) / 2);
      // or grid-column: auto / span calc(var(--grid-columns) / 2);
    }
  }
}

I use a .span-half to create a cell that spans half of the column size set by the --grid-columns variable.

However, this calculation does not work in Chrome or Safari. Firefox renders .span-half correctly (eg. a cell that spans 2 columns in desktop). I see no "invalid value property" in Dev Tools.

Here's a Codepen https://codepen.io/Bregt/pen/oNbWvzx

I have no clue. What am I missing?

3 Answers

Found this on https://developer.mozilla.org/en-US/docs/Web/CSS/calc

Note: The Chrome browser currently won’t accept some values returned by calc() when an integer is expected. This includes any division, even if it results in an integer.

Here are a few tests I ran in Chrome in connection with grid-column:

grid-column: calc(4 / 2); = Invalid property value

grid-column: calc(1 * 2); = Works

grid-column: calc(4 * 0.5); = Invalid property value

grid-column: calc(1 + 1.5); = Invalid property value

grid-column: calc(1 + 2); = Works

grid-column: calc(1 - 2); = Works

Conclusion: Division doesn't work with grid-column (possibly also rows). Multiplication, addition and subtraction works as long as no floating point numbers are used. This also applies to other css properties such as z-index that require an integer as a value without any units.

Properties like line-height that accept floating point numbers don't have this issue.

The media queries aren't the problem you're asking about, but they contribute tot he issue.

Basically you're scoping the variables when you wrap them in a class so you can't do any calculations on them. (.grid {--grid-columns: 4}) Instead. You should simply set a base in the root and then change the base in media queries.

:root {
 --grid-columns: 4;
}

@media (args) {
  :root {
     --grid-columns: 8;
  }
}

This changes all of the variables throughout your code. So you don't have to mess with anything other than variables.

As for the rest, it seems to be an issue with calc() that has nothing to do with custom properties.

this works:

grid-column: span 2;

this does not (webkit)

grid-column: span calc(4 / 2);

I believe it has something to do with calc not liking unitless values but I can't find that in any official documentation or any mention of this in the Chromium bugs.

edit: This seems to be a Chromium bug since Chrome, Edge, Safari all experience it. Also calc() works with +, -, * as noted by Aedan in the comments. I added a Chromium bug for this issue. If this is something you would use, feel free to star the bug to help the team understand that.

And here's a Codepen with the full example.

I have tested your issue several ways. It's a calc bug. Using var is absolutely OK. But event if I put calc in a separate var - this will not work neither.

UPDATED

I just want to demonstrate the simple JavaScript solution. You should't edit the code anyway, you can just work with CSS as usual. This JS only gets --grid-columns and send back --grid-span back. Basically this is what calc() do in CSS, but much more stable.

setDimensions(); 
window.addEventListener('resize', () => {
 setDimensions(); 
});
function setDimensions(){
  let gridColumns = getComputedStyle(document.documentElement).getPropertyValue('--grid-columns');
  document.documentElement.style.setProperty('--grid-span', gridColumns / 2);
}
:root {
    --grid-columns: 1;    
  }
.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns, 1), 1fr);
  grid-gap: 10px 10px
}

@media (min-width: 500px) {
  :root {
    --grid-columns: 4;
  }
}

.span-full {
  grid-column: 1 / -1;
}

.span-half {
  grid-column: span var(--grid-span);
}

.cell {
  background: #77dd77;
  height: 50px;
  line-height: 50px;
  text-align: center;
  font-family: arial;
  text-transform: uppercase;
  color: #fff;
  font-weight: bold;
}
<div class="grid">
  <div class="cell span-full">full</div>
  <div class="cell span-half">half</div>
  <div class="cell span-half">half</div>
  <div class="cell span-half">half</div>
  <div class="cell">single</div>
  <div class="cell">single</div>
  <div class="cell">single</div>
  <div class="cell">single</div>
  <div class="cell span-half">half</div>
</div>

Related