Element visibility API

I feel that it would be useful to have an element visibility API – basically browser providing current visibility of the element (not considering screen or parent boundaries, only things like display:none on element or parent) and an event when visibility changes.

Use case:
Lazy initialization with JavaScript. For example, currently if an element is not visible due to its parent, there is no good way to find out when to do the initial sizing. And if it is a web component that might be used in multiple contexts, it is not easily possible to prepare for all possible ways parent visibility can change.

Is it something that has an existing spec in progress?

1 Like

@ashmind MutationObservers should solve all these use cases here. You can solve the lazy init issue with addedNodes.

You would be able to check quite easily for visibility changes from an attribute perspective also with the type=attribute functionality.

Browser support is pretty good and there is a shim in Polymer and others available too.

I actually tried to implement visiblechange as a jQuery plugin, and while I was able to use mutation observers in supporting browsers, it was less clear what changes to look for.

I looked at style/class changes, but it is not enough. For example, .x + .y might change style if class on preceding element is changed, which is impossible to consider in advance in general case, without parsing selectors and building a dependency map.

Consider a reusable component. It might be put into a collapsed page of an accordion, or in a hidden tab of a tab strip. Or maybe just in collapsed <details>/<summary>. In all of those cases node addition events do not help, and attribute changes might be wildly different.

Yeah I think you could only do it by using a mutation observer on the body and listen for all changes and step through all elements etc… nastiness.

Visibility is kinda something jQuery invented though and doesn’t really fix checking for when its positioned off the page or many other things like opacity.

Knowing what you had to implement quite well and how difficult the issue is it certainly would be a good addition to mutation observers. I would be pretty interested in visibleInViewport style attribute and event or similar.

Yeah, the mutation observer limitations are frustrating.

.foo:hover { display: block}
.foo:first-child { display: block}
.foo:enabled{ display: block}
form.foo:valid { display: block}

All these would be tricky to know when to evaluate the visibility check.

Re-querying the entire document on every mutation record doesn’t scale.

I considered off-page, but I thought it can be out of scope for a visibility specification. Main reasons: you can still do sizing while element is off-screen due to scrolling since it has size, and for lazy load in scroll scenario you would normally want to preload content just before element scrolls into view, not after (and there are some events for that). Also it introduces complexity around ‘partially visible’ – if a single pixel of an element is visible, does that mean that it is visible?

It is definitely a valid point though, and something to consider.

As for opacity, it might be a fair case to support opacity: 0 as not visible, though see 1 below.

The problems I see with potential specification:

  1. Hidden vs collapsed – since I am mostly interested in sizing, I would like to see those differently, or even care about collapsed only (e.g. if it is hidden by visibility: hidden, you may still need to load lazy content if it affects sizing). Having a property that returns string/object ("hidden"/"collapsed"?), or having multiple properties might be an answer, but I have no idea whether this fits current DOM APIs (can’t think of a similar example).
  2. Naming – there is a tab visibility API with its visibilitychanged event, there is CSS visibility. It would be nice to have a name that can’t be confused with those. visibleInViewport is good, but only works if there is no distinction between off-screen and not-in-layout (display: none), and this distinction is important for me as per 1.
1 Like

Its almost as if you want to be able to add some kind of repaint event but only checking for a very specific subset of repaints that impact the visibility.

The point I was making about jQuery having invented visibility was mostly around each developer is likely to expect different functionality somewhat. For me I would like to know when something disappears from the screen which could be if it is fully obscured also (Mostly I am thinking of layered tabs perhaps or when a modal is covering certain elements below it - an interface would be able to turn off updates potentially to that part of the screen).

Thinking about it further I actually would suggest extending the document.visibilityState and related event visibilitychange to elements too with the same API. New keywords could be added like: outsideViewport and collapsed or the event could fire at all ‘hidden’ related changes and developers have to query an attribute on the event perhaps to discover the specific reason why the element is no longer visible in the callback

Getting this specified would be wonderful. The issue lies in the no man’s land between DOM and CSS, so noone has taken ownership of it yet. The WebDriver editors have grudgingly made a rudimentary specification here, but will be happy to hand it off to someone else:

https://dvcs.w3.org/hg/webdriver/raw-file/default/webdriver-spec.html#reading-element-state (see isSelected)

1 Like