display-locking
display-locking copied to clipboard
renderpriority: Should it be an HTML attribute or a CSS property
... 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
/cc @noahlemen
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.
I wonder if the fact that this is no-op without
content-visibility:hidden
suggests that it would fit better as a value forcontent-visibility
? Something likecontent-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 likekeepUpdated
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
How about renderPriority=<value>
, where 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.
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
That sounds good. Would
auto
be equivalent touserBlocking
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).
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>
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.
The flip version of this, where the top level is
background
and#target
isuserVisible
can also make this problematic in that we would upgrade the priority once we reach some child of abackground
div. That seems that it would violate thebackground
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.
I think renderpriority is sticking as a name (#205 suggested different case, per guidelines). So I'm going to close this
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.
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.
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.
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 :) )
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.