So I'm faced with a CSS mystery. Developing a project, came across an unexpected result, and can't explain it, nor have I been able to come up with a workaround.

First I define 8 custom properties properties on a custom selector .

Then I conditionally (based on classes defined on the element) override 3 of those propertiess with calc() formulas.

Then, I use those properties to define some more properties, again using calc().

Finally, I use the result of the most complex calculation as the width of the element and a nested element. But the calculation only takes effect in one of the three cases of interest.

The three cases are to have html with neither the v1 or v2 classes, and then to define it with class v1, and finally to define it with both classes v1 and v2.

The code below demonstrates the issue: Without having the v1 or v2 classes defined, the width of the b- element is not constrained as it should be to 90px, instead it gets the default width, of the full width of the browser window.

Adding class v1 (in the browser's dev tools, but I'm using javascript in the real project) doesn't change it; it still gets the full width of the window, instead of being constrained to 150px.

Since neither of those two work, I'm really surprised that defining both v1 and v2 does work: the elements are constrained to 180px.

My first guess was that somehow under one of the cases, that something wasn't defined. But dev tools in both Firefox and Chrome indicate that all the values are defined, in all cases, although when you turn on the "Computed / show all" display in Chrome which shows some form of expanded calculation, it shows all the proper numbers, but won't use the proper number for the width property.

Can anyone explain this?

    <html class=ph>
    <head>
    <meta charset=utf-8>
    <style>
    b-
    {
    --imwd:60;
    --pgml:30;
    --pggh:10;
    --bbl:1;
    --trbl:20;
    }

    b-
    {
    --z-pgml:0;
    --z-pggh:0;
    --z-trbl:0;
    }

    html.v1 b-, html.v2 b-
    {
    --z-pgml:calc( var( --pgml ) * var( --z-px ));
    --z-pggh:calc( var( --pggh ) * var( --z-px ));
    }

    html.v2 b-
    {
    --z-trbl:calc( var( --trbl ) * var( --z-px ));
    }

    b-
    {
    --z-factor:1.5;
    --z-px:1.5px;
    }

    b-
    {
    --z-imwd:calc( var( --imwd ) * var( --z-px ));

    --z-opggl:calc( var( --bbl ) * var( --z-pggh ));
    }

    b-
    {
    --z-oppl:calc( var( --z-pgml ) + var( --z-opggl ) + var( --z-trbl ));

    --z-pgwd:calc( var( --z-oppl ) + var( --z-imwd ));
    }

    b-
    {
    display:grid;
    width:var( --z-pgwd );
    height:200px;
    }

    iframe
    {
    background-color: lightgreen;
    width:var( --z-pgwd );
    height:200px;
    }
    </style>
    </head>
    <body>
    <b->
    <iframe></iframe>
    </b->
    <div style="width:90px; height: 25px; background-color: lightblue;">plain html</div>
    <div style="width:150px; height: 25px; background-color: lightgreen;">html.v1</div>
    <div style="width:180px; height: 25px; background-color: lightblue;">html.v1.v2</div>
    </body>
    </html>

I've always considered myself pretty well-versed in CSS, but this is a little beyond the scope of my knowledge. I did a quick Google search and came across this thread posted 3 days ago on Stack Overflow. Was this you?

Perhaps if you could help walk me through your code, I can try to assist? Maybe, if anything, it will help to talk through it?

So we start with b- and I'm not familiar with this? What does the dash do? I'm only familiar with CSS definitions for elements (e.g. b for <b>), ids like #b, and classes like .b

So next I see you declared some custom CSS properties such as --imwd, --pgml, etc ... OK, I'm with you on that. Then you have multiple blocks for b- in a row, declaring a bunch of these custom properties.

Now I'm looking at lines 23 and 24 in the code you provided and I see you are overwriting the properties --z-pgml when the body has classes of either v1 or v2. But it seems you're trying to perform a calculation with variable --z-px but I don't see where the value of that variable is defined anywhere? I think it will just evaluate as an invalid value.

What happens if you set a fallback if the variable is not defined? For example, you can do var( --z-px, 100 ) to use the value 100 if --z-px hasn't been defined for b-.

I'm going to stop traversing your CSS now while I wait to hear back from you about this --z-px thing.

Thanks for the reply, Dani. The Stack Overflow was posted by a co-conspirator, but she got no response, so I tried to simplify it further, explain it a little differently, and ask here. --z-px is define on line 35, though. as well as a now unused --z-factor on line 34.

is just a user-defined name for an HTML element, that doesn't have any browser-defined baggage associated with it. It is like a initially, but this one gets re-defined as a grid. The hyphen distinguishes it as user-defined, out of the namespace the standards committee will ever standardize. If --z-px hadn't been defined at all, even the 3rd case shouldn't have worked (but it does). Just now I tried moving the block with --z-px up above the block that first references --z-px but that doesn't help, the same cases fail, and the html.v1.v2 case works. Next, I tossed ", 0" into all of the var() references except for --z-px I used ", 1", and --z-imwd I didn't add a fallback, as it should be constant, and is never redefined), in the block that calculates --z-oppl and --z-pgwd, and got the same results also. Thanks for the ideas, even though they didn't help yet. I think Victoria had tried fallback values. I'll post the final modified code with the above changes here, in case I blundered. The goal with this extracted code is to create a different-width element and contained based on the existence or not of html classes v1 and v2. The "bigger" goal from which this is extracted is to have, lacking the ability of current browsers to create pre-press print images, to to use a 9×9 grid, with the center cell being the actual page image, and the next outer surrounding cells being used in turn for configuralbly sized margins, gutters, bleed areas, and trim marks. We'd mostly been generating the page content, hoping for browsers to support more of the @page draft standard, but that doesn't seem to be moving very fast, and thought that we could always do it this way if we beat the standardization process. And indeed, if we turn both pairs (margins, gutters) and (bleed, trim) on, we get the desired pre-press results, but can no longer display the page by itself, or with margins only, because even though everything seems to be defined, in each case (html, html.v1, html.v1.v2), the calculated results don't seem to be used.

Here's the revised code. Well, no, here isn't the revised code. I'm having problems getting it to format right. It all ran together (wrapped, blank-reduced) in my first reply, so I deleted that, and tried here. And when I use </> button here, it doesn't show up in the result????

Maybe this will work? I tried a new reply, and there was my revised code all pasted in? I'm confused, but we'll see what happens.

    <html class=ph>
    <head>
    <meta charset=utf-8>
    <style>
    b-
    {
    --imwd:60;
    --pgml:30;
    --pggh:10;
    --bbl:1;
    --trbl:20;
    }

    b-
    {
    --z-pgml:0;
    --z-pggh:0;
    --z-trbl:0;
    }

    b-
    {
    --z-px:1.5px;
    }

    html.v1 b-, html.v2 b-
    {
    --z-pgml:calc( var( --pgml, 0 ) * var( --z-px, 1 ));
    --z-pggh:calc( var( --pggh, 0 ) * var( --z-px, 1 ));
    }

    html.v2 b-
    {
    --z-trbl:calc( var( --trbl, 0 ) * var( --z-px, 1 ));
    }

    b-
    {
    --z-imwd:calc( var( --imwd ) * var( --z-px, 1 ));

    --z-opggl:calc( var( --bbl ) * var( --z-pggh, 0 ));
    }

    b-
    {
    --z-oppl:calc( var( --z-pgml, 0 ) + var( --z-opggl, 0 ) + var( --z-trbl, 0 ));

    --z-pgwd:calc( var( --z-oppl, 0 ) + var( --z-imwd ));
    }

    b-
    {
    display:grid;
    width:var( --z-pgwd );
    height:200px;
    }

    iframe
    {
    background-color: lightgreen;
    width:var( --z-pgwd );
    height:200px;
    }
    </style>
    </head>
    <body>
    <b->
    <iframe></iframe>
    </b->
    <div style="width:90px; height: 25px; background-color: lightblue;">plain html</div>
    <div style="width:150px; height: 25px; background-color: lightgreen;">html.v1</div>
    <div style="width:180px; height: 25px; background-color: lightblue;">html.v1.v2</div>
    </body>
    </html>

And when I use </> button here, it doesn't show up in the result????

Sorry you're having issues with our code editor. What OS / browser / browser version are you using?

Just now I tried moving the block with --z-px up above the block that first references --z-px but that doesn't help, the same cases fail, and the html.v1.v2 case works

So I see in your updated code that you're defining --z-px now before using it, and setting a fallback. Unfortunately I don't really have any more suggestions for you right now. To be honest, I'm still confused as to why you are making it sooooo complicated to display a grid, with all these custom variables and custom element names, etc.

The goal with this extracted code is to create a different-width element and contained based on the existence or not of html classes v1 and v2.

Why not do this with javascript and call it a day?

Windows 10, Firefox 72.

The complication is due to wanting flexibility by allowing the sizes including the zoom factor (--z-px) to be configurable in the CSS, and then to be able to toggle the modes. It seems like a good application of CStyleS features.

I suppose if no one can explain the CSS weirdness, that I should submit it as a browser bug.

And that if I want a solution soon, I could do it in Javascript.

Something about the way you said "javascript" got em out of the rut of thinking I was in.

I reworked the code so that instead of using a class (well, two of them) on html as the discrimination between modes, that I use a CSS property (well, two of them) on html as the discrimination. Either way, there has to be javsacript on the UI to toggle the class, or to alter the variable. But then everything works in pure CSS with all the formulas.

I still don't understand why it didn't work as described here, but I have a workable solution.

That’s what I was thinking. A single line of JavaScript could toggle between the two states and save you a lot of headache, although of course it’s not nearly as elegant as a CSS-only solution.

Are you considering putting this issue to rest or are you still going to try to figure out a CSS-only solution? If the former, please mark this thread solved :)