Почему в моем Android webview DOM появляются некоторые узлы, которые не отображаются при прокрутке?

#javascript #css #webview #flexbox #css-position

Вопрос:

В моем приложении для Android есть проблема, из-за которой некоторые узлы DOM отображаются как пустые места во время прокрутки. Когда я касаюсь их, они восстанавливаются и становятся видимыми. Вы можете увидеть на этом видео и скриншоте:

ошибка с кнопками прокрутки

The line going down the screen shows where my finger was scrolling. I haven’t been able to isolate the cause, but what I’ve learned so far is that disabling some touch and click listeners drastically reduces the problem. The listeners are assigned using event delegation to the list of chat messages, instead of applying them to each chat message. My event delegation code looks like this:

 /**
 * Delegate an event to a parent node
 * 
 * @param {HTMLElement|HTMLDocument} rootEl the parent element/document on which the
 * listener is to be registered
 * @param {String} eventType the name of the event
 * @param {String} selector a CSS selector matching the element being watched (the target)
 * @param {Function} handler the handler to be invoked when the target matches the selector
 * 
 * @returns {Function} returns the handler that was registered on the parent
 */
function delegateEvent(rootEl, eventType, selector, handler) {
    if (!isElOrDocumentOrWindow(rootEl)) {
        return;
    }
    // add listener on the root element
    const registeredHandler = function(e) {
        if (e.target amp;amp; e.target.closest(selector) !== null) {
            handler(e, e.target.closest(selector));
        }
    };
    rootEl.addEventListener(eventType, registeredHandler, false);

    return registeredHandler;
}

// ...applied like this
delegateEvent(parentOfChatMsgs, 'click', 'li.chatMsg', handler);
 

So removing those listeners is what reduced the problem. In the screenshot you can see 2 «scroll up» and «scroll down» buttons. Tapping those buttons triggers programmatic scrolling of the same messages, and when I do that the bug never appears. So that seems to suggest that the problem is somewhere in the touch event handlers. However I haven’t been able to find a way to set those listeners without re-introducing the bug. Any ideas you can offer? I’d greatly appreciate it, thank you! 🙂

Some other tidbits:

  • the highest ancestor of the messages is an absolutely positioned node that fills the page (using left: 0 , right: 0 , top: 0 , bottom: 0 )
  • this is happening in the WebView, as I mentioned above the app is an Android app built with cordova
  • this is an example of the HTML of one of the messages:
 <li class="chatMsg isOwner myMsg txt cf">
  <div class="partner avatar" style="background-image: url(img/icon.svg?=);">User Image</div>
  <div class="textContainer ">
    <p class="in-chat-handle">@user</p>
    <p class="text  ">Next</p>
    <time class="timeInfo" datetime="2021-07-28T15:56:33.531Z" timeago-id="4334">17 minutes ago</time>
  </div>
  <div class="msgNotifications hide ">
    <span></span>
  </div>
</li>
 

And this is the accompanying CSS:

 .chatMsg {
    margin: 5px 0px;
    position: relative;
    backface-visibility: hidden;
    transform: translate3d(0px, 0px, 0px);
    overflow-wrap: break-word;
}
.cf {
    zoom: 1;
}
.cf:before, .cf:after {
    content: " ";
    display: table;
}
.partner.avatar {
    cursor: pointer;
    background-size: cover;
    background-repeat: no-repeat;
}
@media (max-width: 320px)
.theirMsg .avatar, .myMsg .avatar {
    width: 27px;
}
.myMsg .avatar {
    margin-left: 10px;
    float: right;
    width: 34px;
}

.avatar {
    visibility: hidden;
}

.theirMsg .textContainer, .myMsg .textContainer {
    border-radius: 7px;
}
.myMsg .textContainer {
    background-color: rgb(47, 47, 47);
    border: 1px solid rgb(47, 47, 47);
    color: rgb(226, 226, 226);
    float: right;
}
.textContainer {
    transition: transform 0.2s ease 0s;
}
@media (max-width: 320px)
.textContainer {
    max-width: 50%;
}
.textContainer {
    line-height: 1.2em;
    padding: 10px;
    position: relative;
    max-width: 62%;
    min-width: 75px;
}
.in-chat-handle {
    color: rgb(153, 153, 153);
    font-size: 0.8em;
    display: block;
    text-align: initial;
    overflow-x: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.textContainer .text {
    overflow: hidden;
    font-size: 14px;
    line-height: 16px;
    word-break: break-word;
    display: block;
    max-width: 100%;
}
.textContainer > .timeInfo {
    color: rgb(102, 102, 102);
    float: right;
    font-size: 0.6em;
    height: 2em;
    position: absolute;
    top: -1.7em;
    right: 0px;
    opacity: 0;
}
.myMsg.first .textContainer::before, .myMsg .textContainer::after {
    content: " ";
    height: 0px;
    position: absolute;
    width: 0px;
    border: 9px solid transparent;
}
.msgNotifications {
    line-height: 1.2em;
    padding: 3px;
    position: relative;
    max-width: 65%;
    min-width: 140px;
    left: 17.5%;
    float: left;
    width: 65%;
    z-index: -10;
    clear: both;
    transition: margin-top 0.5s ease 0s, opacity 0.5s cubic-bezier(1, -1, 0.5, 2) 0s;
    margin-top: -12%;
    opacity: 0;
}
.cf:after {
    clear: both;
}
 
  • this screenshot shows the hit testing areas based on the event handlers registered on that page: hit testing areas