JS adds property to "element" in CSS tree, overrides :hover setting

I have a div with id=“settingsDiv”. The CSS for #settingsDiv sets the opacity property to the value of 0. I also have #settingsDiv:hov where the opacity is set to 1. Thus, the div will appear when the mouse is hovering over it.

But the :hover doesn’t engage for touchscreen touches. So, to deal with that, I have the ontouchmove event call a function that sets the opacity to 1, and I have the ontouchend call a function that sets the opacity to 0 if the (x,y) value of the release point is not within the settingsDiv bounds.

This seems like an acceptable way to handle the settingsDiv with a touchscreen. But a problem arises in the ranking of the CSS elements. When the page first opens, inspecting the DevTool’s CSS listing for settingsDiv, we have the following ranking order.

element.style { (inline)
    left: 112px;
}

#settingsDiv { common.css:78
    bottom: 5px;
    opacity: 0;
    // additional spacing properties and values left out
 }

The left property appears in the element.style due to some dynamic coding I’m doing in regards to the location.

After the function called by the ontouchmove event is called the first time, and the opacity value is programmatically set to 1, the DevTool’s CSS element.style listing will now also include the opacity property. Also, if we force the :hover on using the DevTool, the #settingsDiv:hover appears as a child to settingsDiv but as a parent to element.style. Thus the :hover’s opacity value is being overridden.

element.style { (inline)
    left: 112px;
    opacity: 0;
}

#titleDiv:hover { common.css:93
    opacity: 1;
}

#titleDiv { common.css:78
    bottom: 5px;
    opacity: 0;
    // additional spacing properties and values left out
 }

I’m puzzled as to how to handle this situation. For touchscreen laptops, where the user might go back and forth between the touchscreen and the touchpad, or may even have a mouse attached, I’d like the :hover to have the final say on the opacity value.

Is this a common problem that others have solved? I just found the removeProperty() method for elements. I’m not clear yet when to call it, or whether it will delete the property altogether from what shows as “element.style” in the DevTools (desired) or from #settingsDiv (which would not be good).

OK, the issue is partly solved, in that I have a good example of how the removeProperty() function works.


<!DOCTYPE html>
<html>
<head>
    <style>
        #p1 {
            color: blue;
        }
        #p1:hover {
            color: green;
        }
    </style>
</head>
<body>
    <h1>JS and :hover</h1>
    <p id="p1">This text starts out blue and :hover makes it green.</p>
    <button type="button" onclick="buttonFunction()">Click me turns text to red.</button>
    <p>After clicking the button, hover no longer works. What can be done via JS to restore the :hover functionality?</p>
    <button type="button" onclick="restoreHover()">Attempt to restore :hover</button>
    <script>
        function buttonFunction() {
            var el = document.getElementById("p1");
            el.style.color = "red";
        }
        function restoreHover() {
            var el = document.getElementById("p1");
            el.style.removeProperty("color"); 
        }
    </script>
</body>
</html>

With the DevTools showing the CSS for the element , it’s possible to observe how the removeProperty() only effects the top (inline) element tag on the CSS chain of command.

In my pseudo “hover” for touch controls, I should be able to handle this by having the start of the mouse move remove the inline opacity setting by using the removeProperty() method.

You can over-ride inline styles from the css by adding !important to the rule (it’s the only way to do it).

Rather than changing styles with JS you should instead just add and remove classes and keep control in the css where it belongs.

Of course for some continual and dynamic animation you can use inline styles but mostly they should be avoided.

It sounds like you are going the wrong way about this but I’d need to see a demo of what you are attempting as you seem to be throwing things wildly at the problem :slight_smile:

To over-ride the inline style you needed to do this:


        #p1 {
            color: blue;
        }
        #p1:hover {
            color: green!important;/* will over-rule any inline styles*/
        }

In your js you didn’t need to remove the color property but instead set it back to default using an empty string ( el.style.color = “”;).

    function buttonFunction() {
            var el = document.getElementById("p1");
            el.style.color = "red";
        }
        function restoreHover() {
            var el = document.getElementById("p1");
               el.style.color = "";
        }

However as already mentioned you should instead add a class to the element with js and then you can also remove it with js. That allows all the styling and specificity to be controlled from the CSS.

Usually you would detect touch with js and then only apply hover rules only to hover devices and touch rules for touch devices. Theis following codepen is from a demo that was an answer to a previous question on the forum.

Now personally I would not use that approach but it does show how to cater for hover or touch. The above demo works on desktop or on a phone.

According to accessibility guidelines you should not use hover to show important information so unless this is just ‘eye candy’ I would rather not make touch devices have to to touch something n order to see it unless it was some sort of gallery or slideshow perhaps.

You should also factor in keyboard accessibility as some devices have neither touch nor mouse control and a lot of advanced users prefer keyboard navigation to mouse navigation. Therefore if you hover is showing anything other than eye candy then you need to make that accessible to keyboard users also.

CSS now has the :hover media queries implemented and browser support is growing so you can do a lot in css only to detect the primary input mechanism.

https://jackdomleo.dev/blog/hover-css-media-query/

https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover

And finally a good article here:

https://css-irl.info/detecting-hover-capable-devices/

2 Likes

Thank you so much for the guidance on this. Being new to JS and front-end coding, I’m still finding it difficult to find advice on “best practices” for given issues, and am really glad that with my decision to keep up my subscription here! Your observation about “throwing things wildly at the problem” is apt. I’m trying anything I manage to find that might work.

The use of !important and clearing the inline value (as opposed to removing the property) will be cleaner solutions than what I came up with on my own. While updating, I’ll also put serious thought into whether the situation can be handled with the use of classes.

Yes, the goal application is a “slide show” of sorts. My goal is to write a comic-book reader. Here is a work-in-progress test case url. I am including some keyboard controls: first pass has AWSZ for image motion, left/right arrows for page turns, up/down arrows for magnification, and most importantly spacebar for progressing forward. A goal is to allow the reader to make progress through the comic with minimal distraction (just a click or touch on the right side, or hitting the spacebar). But I’ve yet to solve conveying the optional keyboard controls to the user. The “TODO” list also many things such as using icons for the magnification, and implementing the !important solution you cited.

The main basis of positioning the page graphic does make use of your principle about using classes. But there are likely many places where the code can be made cleaner and more efficient. One place that seems fishy to me is with my use of mousemotion/touchmotion, and whether I can do something (debouncing in some form?) to reduce the number of calls, or the amount of processing that is done per call.

Was taught: first get it to work, then get it to work more efficiently (on an as-needed basis).

Ok that makes sense now that we can see what you are attempting.:slight_smile:

I see you are dynamically adjusting the left position of the graphic’s container to position the graphic as the screen size increases. However that carry a lot of oveheads and will slow the page down and make things appear ‘janky’. I would suggest that you let css centre the graphic in the available space.

Just ensure the viewport container is 100% width and then the image can use margin:auto to center it.

Something like:

#viewPort img{
  width:100%;
  max-width:765px;
  height:auto;
  display:block;
  margin:auto;
}

Obviously I’m guessing that you wanted the max-width of 765px as that seemed to be the approx max-width. The above method will also allow the image to scale nicely on smaller screen and you won’t need to use transform either.

Make sure the ‘natural’ width and height attributes of the image are in the html or the browser will have to wait until the image has loaded to work out what size the image aspect ratio is (even if you later resize with css). With the attributes in place the browser can calculate the space needed even before the image has loaded.

<img id="pageImg" class="img_large_hp pos00_00" src="http://adonax.com:8083/moby/viewer/disastronauts/promo_confessions/_L_3/4" alt="view of comic page" width="1700" height="2200">

I realise I may be simplifying things a bit but I would try to do as much as you can first without JS and only then add JS if CSS can’t accomplish what you want. Most of the current layout would seem to be an easy task for CSS but your click actions and behaviours are JS territory etc.

I’d go with that approach. I often like to get something working first and then refine it. Sometimes you can pare down the code a lot once you realise what you want it to do.:slight_smile:

1 Like

Thanks again, it is so great to have an experienced set of eyes on this!

This particular comic page was printed on a folded letter sheet, hence the smaller max width. I have another page size (full 8.5 x 11) and that would have a larger max width. The parameters are being served via Java Spring Boot/Thymeleaf. I also have a Java application written that one uses on an image of the page to get the dims of the individual views (usually one per panel). The panel/view data collected in advance is part of what is served by comic-book “server”. IDK if that makes a difference as far as your front end suggestions.

As usual, it will take me a bit to fully digest all you suggestions. I am very grateful for your input!

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.