Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

renderpriority: Should it be an HTML attribute or a CSS property #200

Open
vmpstr opened this issue Sep 10, 2021 · 15 comments
Open

renderpriority: Should it be an HTML attribute or a CSS property #200

vmpstr opened this issue Sep 10, 2021 · 15 comments

Comments

@vmpstr
Copy link
Collaborator

vmpstr commented Sep 10, 2021

... and should it have values that indicate priority

Presumably this would be an attribute on Element, meaning that any element would support this attribute. This would also be no-op for cases where rendering must be done anyway -- such as cases without content-visibility: hidden.

I don't want to call it anything like asynchronous because that gives an erroneous impression that if this element is visible, the updates to it are asynchronous. That may be something we do in the future for a different attribute, but this isn't it.

I was thinking something like keepUpdated. Do folks have better suggestions?

/cc @chrishtr

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 10, 2021

/cc @noahlemen

@noahlemen
Copy link

I wonder if the fact that this is no-op without content-visibility:hidden suggests that it would fit better as a value for content-visibility? Something like content-visibility:hidden-updatable perhaps? Downside there, I suppose, is that we wouldn't be able to articulate priority via a value. Given that, I think something like keepUpdated makes sense too.

I would suspect that values indicating priority might be useful - for example, it's easy to imagine a page having many hidden menus that could be updated where you may want to prioritize one that is known to be used more frequently.

Another question that comes to mind around priority, though: how would priority of the attribute version interact with calls to the imperative version? I would assume that the imperative version would always take highest priority.

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 10, 2021

I wonder if the fact that this is no-op without content-visibility:hidden suggests that it would fit better as a value for content-visibility? Something like content-visibility:hidden-updatable perhaps? Downside there, I suppose, is that we wouldn't be able to articulate priority via a value. Given that, I think something like keepUpdated makes sense too.

Having a CSS property for this also has a problem that you can't really apply this to a CSS class. Or rather, you can't have a per-element control without inline style or a very specific selector. I'm kind of leaning towards attribute for these reasons

I would suspect that values indicating priority might be useful - for example, it's easy to imagine a page having many hidden menus that could be updated where you may want to prioritize one that is known to be used more frequently.

That's an excellent point!

Another question that comes to mind around priority, though: how would priority of the attribute version interact with calls to the imperative version? I would assume that the imperative version would always take highest priority.

I think about this as having a many different sources asking for updates. So if one source is saying "idle priority -- whenever you get a chance", and another source is saying "must be updated soon", then the obvious choice is to update the element soon, and resolve both promises (if there are promises). Translated into a description, I would say that it picks the highest priority of any request -- whether it's multiple updateRendering() calls or updateRendering() mixed with keepUpdated

@chrishtr
Copy link
Collaborator

chrishtr commented Sep 10, 2021

How about renderPriority=<value>, where is one of the options in the postTask API, plus "auto" as default? e.g. renderPriority=background would mean do it when you can, renderPriority=userVisible would mean do it pretty quickly, and renderPriority=userBlocking means do all of it in the next update-the-rendering task.

"auto" means the UA choses based on the semantics of the style etc.

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 14, 2021

That sounds good. Would auto be equivalent to userBlocking in this case? IOW, I assume userBlocking means the same thing as do it as if you're always updating the rendering

@chrishtr
Copy link
Collaborator

chrishtr commented Sep 14, 2021

That sounds good. Would auto be equivalent to userBlocking in this case? IOW, I assume userBlocking means the same thing as do it as if you're always updating the rendering

Auto would do it based on style / UA heuristics. It would basically be a no-op vs our current behavior for content-visibility: hidden, and would mean we could try to optimize rendering work for offscreen content-visibility: auto content if we want.

userBlocking means "blocking the user’s ability to interact with the page, such as rendering the core experience or responding to user input." (quoting the postTask spec).

@noahlemen
Copy link

I'm not certain this is something we'd actually use, but I'm trying to think through the implications of nested renderPriority. Would renderPriority for the child here no-op without content-visibility despite being within a subtree that has content-visibility:hidden?

<div style="content-visibility:hidden" renderPriority="userVisible">
  /* some other content */
  <div renderPriority="background"></div>
</div>

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 15, 2021

That's an interesting question. Here's how I think about it:

<div style="content-visibility:hidden">
  /* some other content */
  <div id=target renderPriority="background"></div>
</div>

in the above, renderPriority has no effect and contents of #target will not be updated, since it has an ancestor that prevents any updates. So, it wouldn't cause parents with content-visibility to update themselves.

<div style="content-visibility:hidden" renderPriority="userVisible">
  /* some other content */
  <div id=target></div>
</div>

in the above, #target is updated at userVisible priority since it's just a regular child of a content-visibility, userVisible element.

<div renderPriority="userVisible">
  /* some other content */
  <div id=target></div>
</div>

in the above, everything is updated always (although we're having some discussion about it in #201 ). This is because nothing is preventing the updates in the first place, so it doesn't matter what the renderPriority is (although @chrishtr suggests that maybe this is the first time we can try to have asynchronous visible updates)

So what happens in the following?

<div style="content-visibility:hidden" renderPriority="userVisible">
  /* some other content */
  <div id=target renderPriority="background"></div>
</div>

Since this looks more like the second example, I would lean towards saying that this has no effect in that the contents of the content-visibility element are updated at userVisible priority, and #target being an element in such contents is also updated at userVisible priority. In other words, if content-visibility wasn't present, then this would be very similar to the third example where we just keep everything updated anyway. However, since it is present, we only update it at userVisible priority.

The alternative here is since we're already in some non-immediate level of updates, we can downgrade userVisible to background once we enter #target. However, this would essentially delay having the top level element's updates which sort of violates the userVisible promise. The flip version of this, where the top level is background and #target is userVisible can also make this problematic in that we would upgrade the priority once we reach some child of a background div. That seems that it would violate the background promise and cause more work than needed.

@noahlemen
Copy link

The flip version of this, where the top level is background and #target is userVisible can also make this problematic in that we would upgrade the priority once we reach some child of a background div. That seems that it would violate the background promise and cause more work than needed.

This was going to be my follow-up question 🙂

I'd agree that taking the route of these scenarios having no effect seems simpler and less pitfall-prone, especially when considering the inverted-priority case.

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 20, 2021

I think renderpriority is sticking as a name (#205 suggested different case, per guidelines). So I'm going to close this

@vmpstr vmpstr closed this as completed Sep 20, 2021
@andruud
Copy link

andruud commented Sep 24, 2021

Agree with @noahlemen that this seems more appropriate for CSS if it's tied (and maybe even if it's only loosely tied) to content-visibility.

Downside there, I suppose, is that we wouldn't be able to articulate priority via a value.

But we have several options to solve that?

  • E.g. a new keyword to the property content-visibility: hidden background.
  • A new property altogether: content-priority: background. (I like this).
  • Possibly with a shorthand which can expand to both: content-whatever: hidden / background.

Having a CSS property for this also has a problem that you can't really apply this to a CSS class. Or rather, you can't have a per-element control without inline style or a very specific selector. I'm kind of leaning towards attribute for these reasons

@vmpstr, I don't understand this argument. You can be as broad or narrow as you like with CSS selectors. It feels pretty foreign that you have to go "elsewhere" to essentially "tweak" content-visibility, especially if that tweak should apply to the same element that content-visibility applies to.

@vmpstr vmpstr reopened this Sep 24, 2021
@vmpstr vmpstr changed the title What should the attribute version of updateRendering be called renderpriority: Should it be an HTML attribute or a CSS property Sep 24, 2021
@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 24, 2021

I've spent some time thinking about this and I keep coming back to the question of what is the difference between attributes and properties. So here comes my philosophical rant :)

It is absolutely true that CSS can be as broad or specific as one wants, but does that mean that all attributes are better suited as CSS properties? Some examples that come to mind are things like contenteditable, draggable, and even src. Why are these attributes and should they be attributes?

There are things that attributes allow that are difficult in CSS. For instance, having UA change the attribute value is not easy/possible with CSS. But I think that's pretty much it. So then the criteria must be something else since the UA doesn't change most other attributes we have.

To me, CSS spells out how things should look and each property has text that specifies its interactions with sizes, positions, whether it's painted or not, what to do with overflow, etc. Attributes on the other hand specify how things should behave. draggable for example says that if the user decides to click and drag an element, it will be dragged. All event handlers are also attributes: this event will fire if something changes or the user does some action. The "events" that trigger on visual changes, such as size or position changes, would conceptually belong in CSS but they aren't there. We instead have things like ResizeObserver and IntersectionObserver for that.

There are some CSS exceptions. For example, will-change as Rob mentioned in #211. This doesn't dictate how things should look, but neither does it say how things should behave. It only says what the UA should expect. For example with will-change: transform, the UA should expect that the transform will change. Does that necessarily mean we need to composite the element? We do now, and I haven't looked up what the spec says, but presumably it's up to the UA what to do with this information. It's a hint.

Another example is overflow: scroll. This both says how things should look (overflow is clipped) and how they should behave: the user is able to scroll the overflow. But, of course, the onscroll event is not in CSS (why not?).

Now the rest of my argument hinges on this model. If it's not correct then I'd like to understand how to think about this better.

Coming back to renderpriority, it certainly doesn't talk about how things should look. And it does indeed dictate how things should behave, not so much in presence of user interaction but maybe in presence of time. That is, it is hard to make a prediction of what the total state of the system is if you just see renderpriority=background on something. We need to consider when was it placed there. If it was a while ago, then the expectation is that we can assume things are updated. (This is somewhat of a weak argument since the same can be said about content-visibility: we don't know the render state of the system unless we know whether the user forced it to be updated or when it was added, but anyway). Additionally, if we do want an event that signals render completion (which I'm not proposing here) then its handler would clearly have to be an attribute, since there is no precedence for CSS event handlers.

This to me supports the idea that renderpriority should really be an attribute, as it fits in the model of behaviour rather than visual presentation

</philosophical-rant>

I think the more practical question is how will this attribute/property be used. If it will be used as set-it-and-forget-it type of thing, and apply to basically all elements that have content-visibility: hidden then I agree that we should do this as a CSS property. However, if content-visibility: hidden will be used as a blanket hiding method for elements, and then some select few elements (determined by script) will want to be updated in the background, then it seems like it should still be an attribute.

At this point, I'm still on the fence about what to do, so I would really appreciate some input in how I should think about this problem.

@chrishtr
Copy link
Collaborator

There are things that attributes allow that are difficult in CSS. For instance, having UA change the attribute value is not easy/possible with CSS. But I think that's pretty much it.

This has an important implication that is worth calling out: CSS can change depending on an attribute. Therefore, the developer can style the page in response to a UA action that modifies an attribute, without script.

At the moment I don't see of an application of this to the renderpriority proposal, but it was important for hidden=until-found, where there is a strong reason for the UA to modify state.

@vmpstr
Copy link
Collaborator Author

vmpstr commented Sep 24, 2021

I think the point that "if this is a CSS property, then it can still be controlled by an attribute due to the power of selectors" is very good. This does make it seem that the option to do it in CSS is strictly better and more flexible.

I feel like that argument can be made for most properties, so then I'd like to understand if it's always correct to do things in CSS, and let developers control it by an attribute via attribute selectors if they wish to do so

(sorry to go off on a tangent :) )

@flackr
Copy link

flackr commented Oct 4, 2021

I just thought add that in #211 I suggested we may be able to express the hint that the content should be prepared for rendering even though it's hidden with a will-change value, not necessarily needing a new css property or html attribute. I.e.

will-change: content-visibility

Would express the following:
If currently visible, ensure containment
If currently hidden, prepare rendering in case it becomes visible.

This fits with the way will-change is used on other properties to prepare for changes in value, e.g. opacity: 0 with will-change: opacity shouldn't skip painting because the element will become non-zero opacity.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants