I've been dabbling in simple CSS transitions and hover events etc recently. I notice that when you press the TAB key it generally finds links which is fine but...
If I have a hover event, like a piece of text is revealed or something similar, how can I ensure that pressing the TAB key will trigger hover and or focus events?
This is because I have a page full of squares made up of DIVs that look similar to this:
When you hover over this block with your mouse it changes color via a hover event, essentially to visually inform the user that the element is in some way interactive.
Is there a way I could trigger the hover event with the TAB key or even the arrow keys? My reasoning is because if for some reason you did not have a mouse or touch device you could potentially miss out on content.
Amending my question slightly
So the TAB key is treated as a :focus event and works well when you give a link a :hover state but is it possible for the TAB key to acknowledge DIV elements?
With CSS you can use also :focus, try this:
div {
float:left;
margin:2px;
}
a {
display:block;
height:100px;
width:100px;
line-height:100px;
text-align:center;
background:purple;
color:white;
transition:.3s linear;
}
a:hover, a:focus {
background:orange;
}
<div>item1</div>
<div>item2</div>
<div>item3</div>
<div>item4</div>
<div>item5</div>
This is with respect to your last comment:
So the TAB key is treated as a :focus event and works well when you give a link a :hover state but is it possible for the TAB key to acknowledge DIV elements?
I believe you are looking for tabindex="0". Adding that attribute will make your element capable of receiving focus.
So <div tabindex="0">Hello World</div>
The tabindex doesn't have to be 0. It can be negative, 0, or a possitive integer following these rules:
From MDN on tabindex
a negative value means that the element should be focusable, but should not be reachable via sequential keyboard navigation;
0 means that the element should be focusable and reachable via sequential keyboard navigation, but its relative order is defined by
the platform convention;
a positive value means should be focusable and reachable via sequential keyboard navigation; its relative order is defined by the
value of the attribute: the sequential follow the increasing number of
the tabindex. If several elements share the same tabindex, their
relative order follows their relative position in the document.
Related
I have a DIV with the following CSS code attached:
.active,#foo:active {background-color: rgba(0,0,0,0.75)}
In addition, I have set up keydown and keyup javascript routines to convert a selected keypress to add and remove the 'active' class, darkening it accordingly. My problem is when the user clicks on the DIV (darkening it as expected)...but in a setInterval I have running, polling the DIV and several more like it periodically to get state information, I run into the problem of not being able to tell the current DIV state.
Getting the state via the active class is easy enough. I simply have to do this...
document.getElementById("foo").classList.contains("active")
That gives me a boolean on/off I can use, but the following does not work to read a mouse long click.
document.getElementById("foo").classList.contains(":active")
This is because activated pseudoes do not show up in classList. I tried rewriting the mouse-examining check to look like this:
document.getElementById("foo") === document.activeElement
But as the element is a DIV, this never resolves to a true as document.activeElement stays stuck on the BODY element of the page. I also tried looking at the current background-color, but the following doesn't update when :active is in use.
document.getElementById("foo").style.backgroundColor === "rgba(0,0,0,0.75)"
Is there another way to proceed without needing to resort to removing :active from the CSS and installing onclick() and onmouseout() to my code? Using that particular workaround does not scale well depending on how many DIVs I set up in this fashion. I would much rather detect when the DIV is currently using the CSS rule described above.
Please, no jQuery solutions or external libraries. I want to use vanilla JavaScript.
Pseudo elements are not part of the DOM so you cannot trigger events on them.
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
In addition .style prototype function does not work as intended, to look for computed style use
var ele = document.querySelector('.example-value')
window.getComputedStyle(ele, null).backgroundColor === "rgba(0,0,0,0.75)"
https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
Polling to get the current state of an element is a bad idea, instead use events.
When polling, you are making CPUs always process for nothing, it can make your page irresponsible, cause useless bottlenecks, but most of all, it consumes a lot of electricity for nothing. Always think about the trees when coding.
But one has to admit that for the :active status, it may be a bit cumbersome to listen to all the events that can trigger it.
So we've got to be a bit smarter, and create our own event from there.
We can create an empty animation triggered only in the :active state.
Then we just have to listen for the animationstart event to act as an replacement for our pseudo-class activation event.
/* older browsers might need vendor prefixes... */
foo.addEventListener('animationstart', function(evt){
// to be sure it's our correct event, we check for the animationName
console.log('active', evt.animationName === 'active');
});
#foo:active{
background-color: #FAFFAA;
-webkit-animation: active 0s linear;
-o-animation: active 0s linear;
-ms-animation: active 0s linear;
animation: active 0s linear;
}
#keyframes active{}
#-webkit-keyframes active{}
#-o-keyframes active{}
#-ms-keyframes active{}
<div id="foo">
click me to activate me
</div>
And if ever you need to know at any time if an element has an pseudo-class, you can use Element.matches(cssRule).
The word "active" has different meanings:
An element with the :active pseudo-class. This means the element is in the process of being clicked, usually. This is most commonly used for creating some visual effect when the user mouse-downs on a button, and remove it when he mouse-ups, for example. This is probably not relevant to your use case.
The element given by document.activeElement. This does not mean the element with the :active pseudo-class; it means the element with focus. It will be the body if there is no specific focus, or it could be some input element, or it could be any other element with a tabindex attribute. This is also the element with the :focus pseudo-class. An element can be focused by clicking on it, or tabbing to it, or calling HTMLElement#focus on it.
Some application-defined concept of "active", such as the currently active tab in a tabbed interface, often represented by the presence of a user-defined class on the element, such as your .active.
In general, people write far too much JavaScript to check things, or intercept events, or set magic variables, or add and remove classes or even local styles, or in the worst jQuery style add and remove elements from the DOM, or God forbid do polling, when in many cases CSS could handle what needs to be done if used properly. A trivial example is writing mouseover handlers when :hover could do the job.
I don't fully understand what you are trying to accomplish, or what the desired behavior is. However, the following code might give you some clues:
const activeElement = document.getElementById("activeElement");
const divElement = document.getElementById("div");
function showActiveElement() {
activeElement.textContent = document.activeElement.tagName;
}
function updateActiveElement() { setInterval(showActiveElement, 500); }
function setFocus() { divElement.focus(); }
updateActiveElement();
/* Show a message if the div is active (being clicked on). */
#activeMessage { display: none; }
#div:active ~ #activeMessage { display: block; }
/* Show a message if the div is focused. */
#focusMessage { display: none; }
#div:focus ~ #focusMessage { display: block; }
/* Style the div when it is focused. */
#div:focus { background-color: rgba(0, 0, 0, 0.75); color: white; }
#div { border: 1px solid gray; }
<p>
Here is the div we are working with.
Click on it, or tab to it, to give it the focus.
</p>
<!-- The div in question. Give it a tabindex to allow focus. -->
<div id="div" tabindex="1">
Hello Bob
</div>
<p id="activeMessage">
The div is active, in the sense that the mouse is being clicked on it, and
therefore its <tt>:active</tt> pseudo-class is set.
</p>
<p id="focusMessage">
The div is active, in the sense that it has the focus,
therefore its <tt>:focus</tt> pseudo-class is set.
<p>
The element with focus at the moment (<tt>document.activeElement<//tt>) is
<span id="activeElement"></span>
</p>
<button onclick="setFocus()">Make the div focused ("active")</button>
In the following code:
div {padding: 10px; border: 1px solid black}
div.whenFocused {background: yellow}
input {display: block}
* {outline: none}
<div tabindex=0>
Text:
<input>
</div>
Is there a simple way of detecting when the DIV gained or lost focus, either directly or indirectly through one of its children?
I need the DIV to have a yellow background whenever the user is interacting with it. The DIV is focusable so the user may arrive there via keyboard or mouse.
If they use the mouse, clicking anywhere inside the DIV must trigger a background-color change. Also, clicking outside the DIV must return the background-color to normal.
I already have this behavior implemented with a couple of helper functions and by listening to several events on different elements. But it's too much code for such a simple thing.
I'm sure there must be a simple and straightforward way, but I can't think of one right now.
(By simple I mean listening to a couple of events plus a couple of one-liner event-handlers and that's it)
I found a simple solution using jQuery:
$('div').on('focusin focusout',function(){ $(this)[(this.contains(document.activeElement)?'add':'remove')+'Class']('whenFocused') })
It's not exactly straightforward, but at least it's a one-liner.
It requires support for:
focusin/focusout
Node.contains
document.activeElement
I'm currently starting on an animation project. In the project I'll have more than 40000 divs and animate them iteratively. If any of divs are in passive state (i.e. it's not animating at least for 2 seconds), I won't display them to increase animation performance.
The question is: which css property is the most suitable for this?
.passive1{
display:none
}
.passive2{
visibility:hidden;
}
.passive3{
opacity:0;
}
And how can I measure rendering performance like fps, gpu usage?
While all 3 properties make an element's box seem invisible, there are crucial differences between them:
Property
Painted
In layout
Stacking context
Pointer events
Keyboard events
opacity: 0;
No
Yes
New
Yes
Yes
visibility: hidden;
No
Yes
Varies
No
No
display: none;
No
No
Varies
No
No
The "Painted" column indicates if the browser will paint the element's background (e.g. background-image), #text content, and so on.
An element cannot be painted without also participating in the page's layout, of course.
This is No for all 3 properties and values, as the browser won't need to paint the element's box as it's invisible.
The "In layout" column indicates if the browser will compute the layout and dimensions of the element - along with any of its descendants not excluded from layout.
This is only No for display: none;, as with opacity: 0; and visibility: hidden; the browser will still determine the size of the element so it can correctly layout other elements relative to the current element (e.g. if you have span.hidden { visibility: hidden; display: inline; }).
The "Stacking context" column indicates that any use of opacity (except opacity: 1.0;) will create a new stacking-context, which complicates use of the position property.
The "Pointer events" column indicates if the element will respond to user-interaction from a pointing device, such as a mouse, touch-screen, stylus, etc.
e.g. with visibility: hidden; then the :hover state won't work, and clicking the same element won't apply :focus or :active either.
Additionally, the DOM won't raise any pointer events you'd handle in JavaScript (e.g. visibility: hidden; won't raise mouseclick, touchstart, etc - note that the click event can still be raised by certain elements, like <button> if invoked by the user using a non-pointer input method, such as with keyboard or voice (accessible) navigation means.
You can use pointer-events: none; to block pointer events, but this won't block keyboard and other non-pointer input and so should not be used to disable an element because the user can still use the keyboard to interact with it (especially <button>, <input />, <select>, and <textarea>).
The "Keyboard events" column indicates if the element can be interacted-with using keyboard navigation (and possibly other navigation means).
This includes smart-device (smartphones' and tablets') browsers' "Prev/Next Field" buttons for navigating <form> elements (as this uses tabindex).
Unlike how pointer-events can be disabled in CSS using pointer-events: none;, there is no CSS property to disable keyboard interaction.
This table shows a more complete comparison between the main values of those 3 properties:
Property
Painted
In layout
Stacking context
Pointer events
Keyboard events
Animatable
Opacity
opacity: 0;
No
Yes
New
Yes
Yes
Yes
opacity: 0.1;
Yes
Yes
New
Yes
Yes
Yes
opacity: 0.9;
Yes
Yes
New
Yes
Yes
Yes
opacity: 1;
Yes
Yes
Varies
Yes
Yes
Yes
Visibility
visibility: hidden;
No
Yes
Varies
No
No
Yes, with caveats
visibility: visible;
Yes
Yes
Varies
Yes
Yes
Yes, with caveats
Display
display: none;
No
No
Varies
No
No
No
display: contents;
Text and children only
Text and children only
Varies
Yes
Yes
No
Other
pointer-events: none;
N/A
N/A
N/A
No
Yes
No
The "Animatable" column indicates if that property can be used with a CSS transition (transition:) or CSS animation (#keyframes).
Crucially, the display: property cannot be animated, which is why we can't use a #keyframes timeline to completely hide an element after the animation is complete.
But curiously, we can animate the visibility: property despite being non-continuous, albeit with caveats.
Also, don't get confused by the similarly-named backface-visibility and content-visibility properties.
backface-visibility is only applicable to 3D transform operations.
content-visibility is an optimization to speed-up page rendering during initial page-load, but requires CSS Containment first, which is out-of-scope for this QA.
The answer found here will answer your first question (most likely display:none as the space is collapsed completely).
To your second question, tools such as this will probably be useful for you. However 40,000 divs sounds like way too many and you will probably have better performance using canvas or SVG (for example, using the KineticJS library as this handles animations - transformation, rotation, scale, etc.) for you.
display:none will hide the whole element and remove that from layout space whereas visibility:hidden hides an element but take up the same space as before.
Opacity can be used if you want to create transparency or fade effect.
Performance will be an issue if display:none or visibility:hidden is used since they trigger paint and layout in most browsers which means your browser will redraw the viewport whenever those two changes so I will recommend opacity but still for that number of divs it will still be not performant as expected you can try webgl using a library called html-gl which render your divs in webgl check https://github.com/PixelsCommander/HTML-GL
Here is a compilation of verified information from the various answers.
Each of these CSS properties is in fact unique. In addition to rendering an element not visible, they have the following additional effect(s):
Collapses the space that the element would normally occupy
Responds to events (e.g., click, keypress)
Participates in the taborder
collapse events taborder
opacity: 0 No Yes Yes
visibility: hidden No No No
visibility: collapse * No No
display: none Yes No No
* Yes inside a table element, otherwise No.
got from link
display:none because the divs are taken out of the flow then, thus their position does not have to be calculated.
That being said, 40000 divs sounds crazy. Did you consider the alternatives like HTML5 canvas or SVG?
Sometime i use visibility and opacity together to achieve effect to avoid click event
e.g.
normal state/element removed from screen:
visibility:hidden;
opacity:0;
transition: all .3s;
hover state/element on screen:
visibility:visible;
opacity:1;
Found this thread whilst investigating a hover: bug in Safari mobile
Confirming that opacity: 0 is a valid approach (it is in my case, thanks all). opacity: 0 fixes it enough to be workable (still requires an annoying js redraw on screen rotate [width change]).
Background info on the bug I fixed with opacity: 0:
The hover is on a li containing a div that is revealed when hovering (or single touch on mobile) a calendar entry. Really random working/not working in Safari mobile - and even weirder the behavior changes on a screen rotate++ [nb no media queries involved so not that].
So annoying as otherwise works in all other browsers I've tried.
I want to disable the orange highlighting displayed when the user taps a link. I think iOS and Android Browsers support this by using "webkit-tap-highlight-color". Is there a way to do this?
Only document.querySelector("a, label, button") and change its tagName to other, for example span with appropriate aria value. You also need to change your CSS.
The tap color is hardcoded in fennec/firefox and it cannot be changed like "::selection"/::-moz-selection. Additionally ::-moz-selection is not complete, because it doesn't change image background for selected elements.
Optionally:
div.tap-detector
{
position:fixed;
height:100%;
top:0rem;
left:0rem;
width:100%;
z-index:1000;
overflow:hidden;
}
and redirect all click, mousemove, mousedown and mouseup events (and other if used) from div to elements under it. Redirected click shall not use tap-highlighting. Probably scroll gesture you not need to catch - elements with overflow:hidden are "transparent" for scroll gesture.
It is not clear solution and use only if YOU MUST because your boss grumbles.
For anchor links i want to removes the dotted focus outlines for mouse events, but want to display them when for keyboard tabbed navigation.? Is there any javascript, jquery method?
Method should be compatible all A-grade browsers. including IE6.
Although all pure css methods to remove dotted lines do not works in IE 6.
But remember i want to remove dotted focus outlines only for mouse events, but want to display them when user use keyboard tabbed navigation.
Try to use jQuery/Javascript to apply style when mouseover. That way outline:none; will must likely to apply when it's a mouse click.
CSS:
.foo.bar:focus {
outline: none;
}
jQuery:
$(document).ready(function()
{
$(".foo").mouseover(function(){
$(this).toggleClass("bar");
}).mouseout(function(){
$(this).toggleClass("bar");
});
});
Unfortunately, this brings another problem: IE6 compaitability with multiple classes. This can be solved by using double div techniques to apply style with multiple classes.
While I understand the OP wanted to handle IE6 as well, I've posted this solution for anyone is not concerned with IE6 and who wants to allow keyboard navigation (focus rectangles still appear when tab is pressed) but hide the focus rectangle when the element is clicked (or enter key is pressed).
The .hide-focus-on-click is just a jQuery selector - replace it with whatever selector you need (e.g. "div#nav a" for all hyperlinks within )
CSS:
.no-focus-rectangle {
outline: none;
}
jQuery:
$(document).ready(function() {
$(".hide-focus-on-click").click(function(){
$(this).addClass("no-focus-rectangle");
}).blur(function(){
$(this).removeClass("no-focus-rectangle");
});
});