Search code examples
csscss-gridcss-variables

Using the calc function with fr units


I have a 3x3 css grid for which I want to have the respective two outer column and row sizes be calculated. The middle ones are 1fr.

So far I have:

(see also this codepen)

html {
  --zoom-scale: 1;  
}

body {
  --weight: calc(((var(--zoom-scale) - 1) / 2 * 1fr));
}

.grid {
  grid-template-columns: var(--weight) 1fr var(--weight);
  grid-template-rows: var(--weight) 1fr var(--weight);

  /* Expecting this for --weight = 1 */
  /* grid-template-columns: 0 1fr 0;
  grid-template-rows: 0 1fr 0; */

  /* And this for --weight = 3 */
  /* grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr; */
}

My Chrome never accepts any calculated value for the template properties though. What's the correct syntax here?

As you may have guessed, the overall problem I'm trying to solve here is to divide a given rectangular space into a grid in such a fashion that the middle cell can be scaled up by --zoom-scale and still be entirely contained in the grid container.


Solution

  • You cannot perform calculation with fr you can verify this by using grid-template-columns: calc(1 * 1fr); and you will get an invalid value.

    You can switch to percentage where you go from 0 to 50%

    body {
      margin: 0;
      --zoom-scale: 5;
      --weight: calc(((var(--zoom-scale) - 1) / 2 * 10%));
    }
    
    .grid {
      background: beige;
      display: grid;
      height: 100vh;
      grid-template-columns: var(--weight) 1fr var(--weight);
      grid-template-rows: var(--weight) 1fr var(--weight);
    }
    
    .grid > * {
      grid-row: 2;
      grid-column: 2;
      background: red;
      overflow: auto;
    }
    <div class="grid">
      <div>
        This is the grid content we are going to zoom, sporting a long text.
      </div>
    </div>

    You can also use margin to perform the same task with less of code

    body {
      margin: 0;
      --zoom-scale: 5;
    }
    
    .grid {
      background: beige;
      display: grid;
      height: 100vh;
    }
    
    .grid > * {
      background: red;
      margin:
       calc(((var(--zoom-scale) - 1) / 2 * 10vh))
       calc(((var(--zoom-scale) - 1) / 2 * 10vw));
      overflow: auto;
    }
    <div class="grid">
      <div>
        This is the grid content we are going to zoom, sporting a long text.
      </div>
    </div>