24

I have relatively complex formulas e.g. transform: scale(var(--image-scale)) translateY(calc((1px * var(--element-height) * (var(--image-scale) - 1)) / 2 * var(--scrolled-out-y)))

how do I debug calculated value? moreover is there a way to validate/highlight formulas errors?

I tried to output like this to the pseudoelement but no luck

    position: fixed;
    display: block;
    left:0;
    right: 0;
    background: yellow;
    padding: 5px;
    z-index: 100;
    content: calc((1px * var(--element-height) * (var(--image-scale) - 1)) / 2 * var(--scrolled-out-y));

the only way I found is to put part of calculation to unused numeric property e.g. background-position-x on the gif below so it will show calculated value on computed tab - useful but not really convenient one (notice background-position-x changes while the page scrolls):

enter image description here

var sc = ScrollOut({
    cssProps: true
  })
  const results = Splitting();

  var parallaxedElements = document.querySelectorAll('.section');

  document.addEventListener('scroll', function(e) {
    parallaxedElements
    Array.from(parallaxedElements).forEach((el) => {
      var bcr = el.getBoundingClientRect();
      if (bcr.y < 0 && Math.abs(bcr.y) <= bcr.height) {
        el.style.setProperty("--scrolled-out-y", Math.round(Math.abs(bcr.y) * 10000 / bcr.height) / 10000);
      }
    });

  })
@import url("https://fonts.googleapis.com/css?family=Roboto");
  html {
    scroll-behavior: smooth;
  }
  
  body {
    font-family: "Roboto";
    font-size: 14px;
    line-height: 1.4;
    scroll-behavior: smooth;
  }
  
  .section {
    position: relative;
    background-attachment: fixed;
    z-index: 1;
    --image-scale: 1.2;
    --scrolled-out-y: 0;
  }
  
  .section__background {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    width: 100%;
    height: 100vh;
    overflow: hidden;
  }
  
  .section__background:after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    top: 0;
    z-index: 1;
    background: linear-gradient(to bottom, black, 100% white);
    background: rgba(0, 0, 0, 0.4);
    opacity: calc(1 + ((var(--viewport-y) * 1.5)));
  }
  
  .section__background>img {
    height: 150vh;
    width: 100%;
    object-fit: cover;
    position: absolute;
    left: 0;
    top: 0px;
    user-select: none;
    transform: scale(var(--image-scale)) translateY(calc((-1px * var(--element-height) * (var(--image-scale) - 1)) * var(--scrolled-out-y)));
  }
  /* .indicator:after {
        position: fixed;
        display: block;
        left: 0;
        right: 0;
        background: pink;
        padding: 5px;
        z-index: 100;
        content: calc((1px * var(--element-height) * (var(--image-scale) - 1)) / 2 * var(--scrolled-out-y));
    } */
  
  .section__container {
    padding-bottom: 50vh;
    overflow: hidden;
    align-items: flex-start;
    position: relative;
    z-index: 4;
  }
  
  .section__heading {
    color: #fff;
    text-transform: uppercase;
    font-size: 45px;
    line-height: 1.2;
    font-weight: 800;
    letter-spacing: 8px;
    margin: 0;
    overflow: hidden;
    position: relative;
    padding-bottom: 50px;
    margin-bottom: 50px;
  }
  
  .section__heading:after {
    content: "";
    position: absolute;
    top: 200px;
    left: 0;
    right: 0;
    height: 2px;
    transform: translateX(calc(var(--scrolled-out-y) * 100% - 70%));
    background: #b38c6b;
  }
  
  .section__content {
    display: flex;
    color: white;
    flex-direction: column;
  }
  
  .section__content p+p {
    margin-top: 20px;
  }
  
  .splitting {
    --char-percent: calc(var(--char-index) / var(--char-total));
  }
  
  .splitting .char {
    display: inline-block;
    opacity: calc(1 + ((var(--viewport-y) * 1.5) - var(--char-percent)));
  }
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css'>
<link rel='stylesheet' href='https://unpkg.com/splitting/dist/splitting.css'>

<section data-scroll class="section section-1">
  <div class="section__background">
    <div class="indicator"></div>
    <img src="https://picsum.photos/1920/1079" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section data-scroll class="section section-2">
  <div class="section__background">
    <img src="https://picsum.photos/1920/1081" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section data-scroll class="section section-3">
  <div class="section__background">
    <img src="https://picsum.photos/1920/1082" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>


<section data-scroll class="section section-4">
  <div class="section__background">
    <img src="https://picsum.photos/1920/1083" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section data-scroll class="section section-5">
  <div class="section__background">
    <img src="https://picsum.photos/1920/1084" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>


<section data-scroll class="section section-6">
  <div class="section__background">
    <img src="https://picsum.photos/1920/1085" alt="placeholder image" />
  </div>
  <div class="container section__container">
    <div class="row">
      <div class="title-block col-md-6 d-flex">
        <h1 data-scroll data-splitting class="section__heading">
          Why <br>CSS <br>matters
        </h1>
      </div>
      <div class="col-md-6 d-flex">
        <div class="section__content">
          <p>
            MThe ability to use variables in CSS is a useful and powerful feature that web developers have long been asking for. Well, it has finally arrived, and it’s awesome!
          </p>
          <p>
            In this article we’ll look at the history, importance, and use of CSS variables, and how you can leverage them to make your CSS development and maintenance faster and easier.
          </p>
          <p>
            Keep reading and you will understand why.
          </p>
          <div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>
<script src='https://unpkg.com/scroll-out/dist/scroll-out.min.js'></script>
<script src='https://unpkg.com/[email protected]/dist/splitting.js'></script>

8
  • 1
    Can you post some more real css and html code? This is not all the code needed to make it run.. Commented Nov 18, 2018 at 18:47
  • 3
    There is no way (today) to debug that, other than pick the value using a script and check it computes properly. And do note, CSS is not a programming language. Commented Nov 18, 2018 at 18:54
  • share how you are defining the variable ... and used like that within content is false Commented Nov 18, 2018 at 19:07
  • 3
    It's currently making me go a little nuts there's no way to debug this.. Commented Aug 12, 2019 at 4:13
  • 1
    A shitty designed spec with 0 excuses. The "its not a programming language" is simply not an excuse. Whatever the case might be, the layout engine has to compute arguments sequentialy and arrive at a result to send to the renderer. Commented Nov 15, 2024 at 16:18

3 Answers 3

9

Is there a way to validate/highlight formulas errors?

You need to check to see if you aren't breaking any rules when defining your formula. Here it is from the specification:

At each operator, the types of the left and right argument are checked for these restrictions. If compatible, the type resolves as described below (the following ignores precedence rules on the operators for simplicity):

  • At + or -, check that both sides have the same type, or that one side is a <number> and the other is an <integer>. If both sides are the same type, resolve to that type. If one side is a <number> and the other is an <integer>, resolve to <number>.
  • At *, check that at least one side is <number>. If both sides are <integer>, resolve to <integer>. Otherwise, resolve to the type of the other side.
  • At /, check that the right side is <number>. If the left side is <integer>, resolve to <number>. Otherwise, resolve to the type of the left side.

If an operator does not pass the above checks, the expression is invalid

It may sound a bit complex at the start but the rules are easy, and we can re-write them as follows with easy words:

  • You cannot add/subtract two different types (5px + 5s has no meaning).
  • You can only multiply with a number (5px * 5px has no meaning and is not equal to 25px).
  • You can only divide with a number that isn't 0 (5px / 5px has no meaning and it's not equal to 1 or 1px).

If you don't break any of these rules, then your formula is correct. Let's not forget another important syntax rule:

In addition, white space is required on both sides of the + and - operators. (The * and / operaters can be used without white space around them.)


Consider this, you simply need to identify if your CSS variable is a number/integer or defined with a type (length, frequency, angle or time). If it's not defined or contains a string value then the calc() will be invalid.

Check the specification for more details and a more precise explanation: https://drafts.csswg.org/css-values-3/#calc-type-checking


How do I debug calculated value?

To check the computed value, I don't think there is a way because the computed value of calc() can be different depending where you use it (which property). In other words, the final value doesn't exist until it's been used within a property.

We may think that some formulas are trivial like calc(5px + 5px) which will always compute to 10px but other ones will be more difficult. Like calc(5px + 50%) where % will behave differently based on a property. Considering this, the browser will never compute the value until it's used within a property.

Even with the use of JS you cannot have the final value you want to debug; you can only get a computed value of properties:

var elem = document.querySelector(".box");
var prop = window.getComputedStyle(elem,null).getPropertyValue("--variable");
var height = window.getComputedStyle(elem,null).getPropertyValue("height");
console.log(prop);
console.log(height);
.box {
  --variable: calc(5px + 5px);
  height:var(--variable);
}
<div class="box"></div>

Sign up to request clarification or add additional context in comments.

2 Comments

This answer explain how to not create invalid CSS, it doesn't show how to actually "debug calculated value", nor does it tell if there is "a way to validate/highlight formulas errors", so IMHO it doesn't answer the question.
@LGSon I am specifically answering this part a way to validate/highlight formulas errors ... by giving the rules we have our way to see if the formula is valid or not. So if the cacl() is invalid then the formula is wrong, otherwise it's correct
5

So to actually debug CSS variables you can use the helper class that I added below.

Then in console you can set and read variable like so:

CssVariables.setRootVar('--column-max-width', 'calc((90vw - var(--zoomer-width)) / (var(--columns-shown) + 1))');
console.log('width:', CssVariables.getRootVar("--column-max-width"));

Note that when you read a variable var(--) is already resolved.

When formula is invalid you will probably get a warning on console.

CssVariables.setRootVar('--column-max-width', 'calc(123px - var(123))');
// -> invalid value, declaration skipped

When you e.g. use non-existent variable you will get empty string when reading.

CssVariables.setRootVar('--column-max-width', 'calc(123px - var(--wtf))');
console.log('width:', CssVariables.getRootVar("--column-max-width"));
// -> width: <empty string>

The CssVariables helper

/**
 * CSS variables helper.
 */
class CssVariables {
    /**
     * Get :root variable.
     * @param {String} name Name of CSS var. e.g. "--columns-shown".
     * @returns {String} Current value.
     */
    static getRootVar(name) {
        return this.getVar(document.documentElement, name);
    }
    /**
     * @see #getRootVar
     */
    static getVar(element, name) {
        return window.getComputedStyle(element, null).getPropertyValue(name);
    }
    /**
     * Set :root variable.
     * @param {String} name Name of CSS var. e.g. "--columns-shown".
     * @param {String} value New value. Should be a strin, but numbers would work as well.
     */
    static setRootVar(name, value) {
        this.setVar(document.documentElement, name, value);
    }
    /**
     * @see #setRootVar
     */
    static setVar(element, name, value) {
        element.style.setProperty(name, value);
    }
}

// if you are working with modules
//export { CssVariables }

1 Comment

the core of this answer is quite useful: window.getComputedStyle(element, null).getPropertyValue(name)
-2

To get the fully-expanded CSS calc expression (not the final value), you can do

window.getComputedStyle(element).getPropertyValue(name)

(in your specific example, name = 'transform')

Note this won't actually do the calculation, but will expand out the various CSS vars so you can see what is being computed. This is most helpful when intermediate vars may be set differently in different contexts

Note, if the prop you're trying to access is on a pseudoelement, you can do:

window.getComputedStyle(baseElement, nameOfPseudoElementAsString).getPropertyValue(name)

3 Comments

this returns the same value for e.g. maxWidth (max-width in css) - calc(100% - 10px) instead of the actual value
@DATEx2 yes, that is what I was trying to explain in the note: this will show the full expression being evaluated to get the value, not the final value itself. i have found this useful for debugging why i'm getting different values from what i was expecting. Made a small edit to hopefully make this more clear
@GabrielGrant But you can get the exact same by right clicking on declaration in DevTools

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.