Git Product home page Git Product logo

Comments (11)

beep avatar beep commented on August 20, 2024 2

@ausi: I just gave https://au.si/css-conditions-cq-alternative a quick read, and found it really interesting. I’m ~offline this week, but give a quick 🙌; I’ll try to have more substantive comments in next week.

from container-queries.

gregwhitworth avatar gregwhitworth commented on August 20, 2024 2

When it comes to container queries themselves, there will be usecases this can solve, and others it won't. This actually hits on a common thing that I tell folks when they state, "I need element/container queries" - if you can tell me at a pixel dimension when you want to change the design then you can probably still devise a way to utilize media queries, although it won't be nearly as legible nor clean as your solution - but you don't NEED container queries.

That said, I do know of other desires to have conditionals that inspect variable values and apply different styles accordingly.

My only worry with this approach, is this will add yet an additional step in the cascade and this isn't fully defined as you can see in this issue I filed here and for us (Edge) this is a pain: w3c/csswg-drafts#411 (comment) and still should do a PR at this point (I haven't found the time).

We saw numerous interop issues as this can change the calculation of the variable that you're checking the condition on. And based on my worries for at-apply (which has been abandoned) you may end up in the same situation in this case where if we make it so that the condition is checked at, let's say, in between step 1 and 2 you'll result in some need to stop circularity within the cascade as well (just like we have with layout and style) which could be that you can't change a custom prop within animations that are used within a condition (you would need to do this anyway where you can't change the variable within the condition similar to what we do with animation tainting).

At any rate, I think it's something we should at least discuss as it would help out scenarios such as Roma's conditions using calc()

from container-queries.

ausi avatar ausi commented on August 20, 2024 1

I think there's a way to handle circularity that makes sense to how CSS works already!

I don’t think that’s true for container queries. I watched your video, but I don’t think :hover has the same circularity issue. As you mentioned, :hover only gets triggered when the mouse is moving, but container queries would get triggered every time the page gets reflowed/repainted. Triggering the container queries could then cause another reflow and, in the worst case, would end in an infinite loop. You can take a look at #3 (comment) and https://discourse.wicg.io/t/a-pseudo-class-for-when-an-element-is-stickily-spec-term-positioned/947/12 for information about the problems with implementing container queries.

from container-queries.

tomhodgins avatar tomhodgins commented on August 20, 2024

The problem I'm seeing with the first example is that they're based on viewport-percentage units, but the elements you'll need to be styling may not scale perfectly with the browser's width and/or height.

What we need to do these kinds of calculations is a unit that is aware of the width and height of the element as it appears on the page (not as we want it to appear). With that information we could write the kind of code in the first examples. Consider the difference in syntax between the two following examples - the first uses JavaScript to check the offsetWidth which is wild, and the second uses ew units to represent 1% of an element's width which is a much nicer abstraction for writing CSS:

<div class=demo-1></div>
<style>
  @element '.demo-1' {
    $this {
      background: lime;
      height: eval('offsetWidth / (16/9)')
    }
  }
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
<div class=demo-2></div>
<style>
  @element '.demo-2' {
    $this {
      background: orange;
      height: calc(100ew / (16/9));
    }
  }
</style>
<script src=http://elementqueries.com/EQCSS.js></script>

I think before a solution like this would be usable, we would need ew, eh, emin, and emax units so the element-based queries could be based on element-based conditions, not triggering element-based queries with browser-based conditions.

As for the conditional if() statements in CSS - I've experimented with this a lot and I think it works well for prototyping, and abstracting away JavaScript - but it's very limiting in that in many situations beyond building a prototype or demo where you would actually want to use this - you'd often find yourself using this sort of if() statement over and over in your CSS rules, leading to a lot of duplicate code that's hard to read or maintain.

Here's a version of your if() example that works in EQCSS syntax, and then some examples of hairier if statements I've written in EQCSS as well so you could see how people would try to use it and where usefulness lies in a feature like that:

<img src=http://staticresource.com/user.png class=component>
<style>
  @element 'html' {
    img {
      float: eval('innerWidth > 200 ? "left" : "right"')
    }
  }
</style>
<script src=http://elementqueries.com/EQCSS.js></script>

And then here are other ways I've used if() statements inside CSS. I think it's incredibly powerful, but very ugly, and the things we use this to try to solve would be better exposed as nicer syntax in CSS:

Min/Max font-size

@element '[data-min-font],[data-max-font]' {
  $this {
    font-size: eval('
      var vw = innerWidth/100*10, /* equal to 10vw */
          min = getAttribute("data-min-font"),
          max = getAttribute("data-max-font");
      if (min !== null && max !== null) {
        vw <= min ? min : max <= vw ? max : vw
      } else if (min !== null) {
        vw <= min ? min : vw;
      } else if (max !== null) {
        max <= vw ? max : vw;
      }
    ')px;
  }
}

Sniffing Element Orientation

@element 'div' {
  $this {
    background: eval("
      offsetWidth == offsetHeight ? 'blue'
      : offsetWidth > offsetHeight ? 'green'
      : offsetWidth < offsetHeight ? 'red'
      : null
    ")
  }
}

Faking :in-viewport

@element 'p' {
  $this {
    /* Color is red when partly in-viewport */
    color: eval("
      var top = offsetTop - innerHeight;
      var bottom = top + offsetHeight;
      if (
        (scrollY < offsetTop + offsetHeight)
        && (top < scrollY)
        && (bottom < scrollY + offsetHeight)
      ){
        'tomato'
      } else {
        'inherit'
      }
    ");
    /* Background is green when fully in-viewport */
    background: eval("
      var top = offsetTop - innerHeight;
      var bottom = top + offsetHeight;
      if (
        (scrollY < offsetTop)
        && (top < scrollY)
        && (bottom < scrollY)
      ){
        'darkgreen'
      } else {
        'inherit'
      }
    ");
  }
}

Centered or Overflow

This example below uses if() statements for the selectors, not even a property or rule:

@element 'div h2' {
  eval('offsetHeight <= parentNode.offsetHeight ? "$this" : ""') {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
  }
  eval('offsetHeight >= parentNode.offsetHeight ? "$parent" : ""') {
    overflow: auto;
    overflow-y: scroll;
    border-color: lime;
  }
}

Using If statement as selector

In this example we use JavaScript to check the background-image of an element and only write a selector (applying the rule) for those that return true.

<div style=background-image:url(http://staticresource.com/user.png)></div>
<div style=background-image:url(http://staticresource.com/nebula.jpg)></div>
<style>
  div {
    height: 200px;
  }
  @element 'div' {
    eval("window.getComputedStyle($it).backgroundImage.indexOf('nebula') !== -1 ? '$this' : '' ") {
      border: 10px solid lime;
    }
  }
</style>
<script src=http://elementqueries.com/EQCSS.js></script>

Based on these experiments and more I think that having container-style queries so we can write conditions once and affect styles for many elements is better than writing conditions many times in many rules.

Another takeaway is that having an if() kind of functionality would be amazing in CSS, but being too liberal with it, it's crazy and could lead to some really bad code. Too conservative with it and you'll miss the parts that make it useful and powerful.

Should the if() work as a value, as a selector, as a responsive condition for elements?

from container-queries.

ausi avatar ausi commented on August 20, 2024

The problem I'm seeing with the first example is that they're based on viewport-percentage units, but the elements you'll need to be styling may not scale perfectly with the browser's width and/or height.

I used the viewport units as an example, the CSS author could set the CSS variable to whatever suits best. An element with a fixed width like 200px can set the variable to the same value --context-width: 200px;.

What we need to do these kinds of calculations is a unit that is aware of the width and height of the element as it appears on the page (not as we want it to appear).

IMO that’s exactly the thing that is hard/impossible for browsers to implement, because it has to jump between layout and style computation.

For setting aspect-ratios we may get a new property in the future, this is not a topic for container queries IMO.

Here's a version of your if() example that works in EQCSS syntax, and then some examples of hairier if statements I've written in EQCSS as well

Your eval-based if() examples are different to what I want to propose here. They are all using values that rely on the layout process of the browser like offsetWidth or offsetTop.

Based on these experiments and more I think that having container-style queries so we can write conditions once and affect styles for many elements is better than writing conditions many times in many rules.
Should the if() work as a value, as a selector, as a responsive condition for elements?

Using if() only as the value for a property is the simplest way to start with IMO. If browser makers agree that this is a solution that can be implemented, we could think of more powerful versions like:

.component {
    if(var(--context-width) > 200px) {
        float: left;
        background: red;
    }
    else {
        float: none;
        background: green;
    }
}

or:

.component:if(var(--context-width) > 200px) {
    float: left;
    background: red;
}
.component:if(var(--context-width) <= 200px) {
    float: none;
    background: green;
}

from container-queries.

ausi avatar ausi commented on August 20, 2024

I proposed the CSS conditions feature on WICG Discourse:
https://discourse.wicg.io/t/css-conditions-with-variables/2048

And wrote an article on how they might be an alternative for container queries:
https://au.si/css-conditions-cq-alternative

from container-queries.

tomhodgins avatar tomhodgins commented on August 20, 2024

Hey @ausi, great idea putting it on WICG Discourse to gather comment, it'll be great to see what people have to say!

In your article you refer to the circularity problem with element/container queries, and today I recorded a video about this very issue: https://www.youtube.com/watch?v=QfM_JwSDdjo

Even though this is not as convenient as the original proposals for container queries, it should be much easier to implement, doesn’t suffer from the circularity problem and is still powerful enough to solve the RICG use-cases.

I think there's a way to handle circularity that makes sense to how CSS works already!

from container-queries.

ausi avatar ausi commented on August 20, 2024

@beep: Awesome thanks! I’m looking forward to it :)

from container-queries.

FremyCompany avatar FremyCompany commented on August 20, 2024

I had some thoughts about this today, and was thinking about how this could allow to choose among a set of differing layouts easily without need to extend this further, and wrote this: https://jsfiddle.net/35758bg7/1/ (basically you can duplicate all your layout paths and then from there choose one based on settings a small subset of properties on it based on --width)

Posted this here just not to loose it, I don't say this is very smart or relevant, just didn't know where to post it otherwise :)

from container-queries.

ausi avatar ausi commented on August 20, 2024

@gregwhitworth Thank you for taking a look at this!

I agree that this feature would not solve all use cases for container queries, but I think it would solve many of them. I will reiterate on that once the use cases in wicg/cq-usecases are defined, as there is some work going on there currently.

Regarding circularity, I think this can possibly be solved by restricting the conditions to parent-var(). I wrote something about this in the WICG Discourse: https://discourse.wicg.io/t/css-conditions-with-variables/2048/15
Do you think this restriction could save the extra step in the cascade too, because it could be resolved directly in step 1 (apply cascaded values)?

from container-queries.

ausi avatar ausi commented on August 20, 2024

I just wrote another article regarding CSS conditions, including a nice hack which lets us use some form of CSS conditions today: au.si/css-conditions-today

I think this demonstrates that the groundwork for CSS conditions is already there and the general concept of such a feature is possible to implement in browsers.

I still believe that this can be the answer to most use cases of container queries and at the same time doesn’t create headaches for browser makers.

from container-queries.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.