CSS :active selector eater - html

I have an <img> element within a <div> element. I want the entire div (including the image) to scale down 10% (using transform) whenever the <div> is being clicked on. I have gotten it to work, but with one small issue: if the user clicks the image inside the div, nothing happens, whereas if the user clicks the background of the div, it works.
Essentially, how can I get the :active selector of .MyDiv:hover:active { /*scaling logic here*/ } to also work when children of MyDiv are clicked.
All help is greatly appreciated and I always accept an answer!

The :active pseudo-class and the div element
First things first, I'm pretty sure in a div element shouldn't have an activation state in the first place.
If we read through the user action pseudo-classes :hover, :active, and :focus section of the Selectors Level 3 W3C Recommendation, we find this:
The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it. On systems with more than one mouse button, :active applies only to the primary or primary activation button (typically the "left" mouse button), and any aliases thereof.
Now if we head over to the Interactive Content section of the HTML5 W3C Editor's Draft, we find this:
Certain elements in HTML have an activation behavior, which means that the user can activate them.
The user agent should allow the user to manually trigger elements that have an activation behavior, for instance using keyboard or voice input, or through mouse clicks. When the user triggers an element with a defined activation behavior in a manner other than clicking it, the default action of the interaction event must be to run synthetic click activation steps on the element.
I mention the HTML5 Editor's Draft over the HTML401 Recommendation as the HTML401 document doesn't go into great detail about activation states or user interaction. It does however mention activation on elements like the a element, but doesn't mention anything about it when defining the div element.
The div element doesn't have an "activation state" defined in the HTML5 recommendation. It has no Interactive Content category (unlike the a element) and doesn't state that an active state can be applied to it.
A Workaround
As discussed above, the div element shouldn't accept an :active state. For this reason I'm going to modify the HTML to use an element which does. For this, I'm using the a element:
<a href="javascript: void(0)">
<img />
</a>
Now this alone doesn't fix the IE issue. If you see this JSFiddle example, when clicking on the img element the a container isn't given an active state. So what can we do to fix this? Instead of just using :hover:active, I'm also going to use :hover:focus:
a:hover:active,
a:hover:focus {
outline: 0; /* Reset the default anchor tag focus style. */
background: #f00;
}
This gives us similar functionality on IE and all other browsers, as can be seen in this JSFiddle demo.
Two (potentially undesirable) side effects
The problem with this approach is that the element will retain its focussed state and you can now achieve this effect by accessing the element using your keyboard's tab key. Whenever you hover over the element in its focussed state, its style will change. It's not up to me to decide whether this is an undesirable side effect, however.
Your element is now a link. The href property is required in order for the element to be focussed in the first place.
Extra styling
As we're now using an a element instead of a div element, so we'll need to reset any browser default styles which distinguish your element as a link. For this we can simply:
a {
color: #000; /* Reset the color to black. */
cursor: default; /* Reset the cursor to default. */
text-decoration: none; /* Remove the underline. */
}
a img {
border: none; /* Remove border from image. */
}
Final JSFiddle demo.

Related

WCAG accessibility issue with nested elements

I've grid with several boxes in (<div>). Each box has inside a list with couple/ several links (simple ul li list with <a> elements). This link list is hidden, it shows only on hover.
It works really fine, but I have accessibility issue, namely, I can't get into any list element with "tab" key (box <div> works ok, it get focus, so the list is showing up), it is just skipping to next box element. I've tried with adding tabindex on each box and each list element inside, but it seems that this is not the solution.
Is there any CSS/ HTML solution for that? I can of course write simple JS, that will check where is focus and if focus has parent with focus option, but I would like to avoid it if possible.
How did you hide the link list? Using display: none or using visibility: hidden. (And that you apply this only to the list elements or also to the div? From your description, I guess it applies only to the list elements.) Content that is hidden using display: none is not keyboard accessible.
In order to make the list appear on hover, are you using a JavaScript event handler or CSS? If you are using JavaScript, you probably need to add an event listener that responds to keyboard events (e.g. onfocus, but as mentioned above, content hidden with display: none won't receive focus). In CSS, I always recommend adding the :focus pseudo-class whenever :hover is used (unless you want different styles for these things).
You may need to write some JavaScript that toggles the visibility of the lists when a parent div receives focus. (If you have tabindex on the div elements, as you say, they should already be able to receive focus.)

How to change elements attribute via clicking on another element in CSS

I inserted a button in header of page and I want change padding and margin of another element when a user clicks on this button. I used this code but didn't work:
a:clicked
{
#header
{
padding:0 40px 0 40px !important;
}
}
In css docs, programmers use # symbol at begin of their code. Can I use that? How?
CSS has no mechanism for giving your styles "state." It's difficult to make decisions in CSS based on "The user clicked a button," etc.
Difficult, but not impossible. One thing you could do is change the button to a checkbox and use the :checked selector. Another option is to hide the checkbox and make the button a label for it; this is known as the CSS checkbox hack.
The usual way, though, is to use Javascript to add/remove a class from an element when a button is clicked, then style based on the existence of that class. This is probably more maintainable since it doesn't require hacks to your HTML. Note that it won't work for users who have blocked Javascript.

Disable :hover state in Chrome Developer Tools

I am aware you can force the :hover state on an element from the Dev Tools (see eg: See :hover state in Chrome Developer Tools).
I am looking to do the opposite: preventing an element from having the :hover state applied even though the cursor is over it.
That way I could use the element picker on elements that disappear on hover.
Disable styles individually while :hover is in pinned state
Because you want to use the element picker on elements that disappear on hover, you will need to open Chrome Developer tools and manually navigate the DOM tree to the target element node.
With the element selected, click the "Toggle Element State" pin icon at the top of the styles panel.
Pin the :hover state. See that the selector and rules that define the :hover state now appear.
Disable individual rules as needed to achieve your goal.
Unpin the :hover state.
You have now disabled some or all of the rules applied to your element's :hover state. You can selectively turn these back on by following the steps above and enabling some or all of the rules.
Apply pointer-events: none to the target element
Because you want to use the element picker on elements that disappear on hover, you will need to open Chrome Developer tools and manually navigate the DOM tree to the target element node.
With the element selected, from the styles panel click somewhere near the closing bracket of the target rule to insert a new property. I recommend using the element.style rule to achieve the greatest specificity.
A text input will appear. Enter pointer-events: none;.
You may now toggle this property by disabling/enabling it as normal.
While enabled, this precludes the invocation of any :hover rules applied to the target element.
Caveat: Because hover events are suppressed, the closest you'll be able to get with the element picker is the target element's parent.

Can you still affect the state of an element with display: none?

According to the Mozilla Doc, the value none for the CSS attribute display does the following:
Turns off the display of an element (it has no effect on layout); all descendant elements also have their display turned off. The document is rendered as though the element did not exist.
I know this means I can't see the element. Since the element has no effect on the layout, it appears as if it does not exist.
My question is: does it still exist in the layout (it still responds to user events)? Or does it not exist in the layout at all (therefore not just appearance)?
Just to clarify:
I know the element still exists in the DOM. I'm asking if interaction with the view can still affect the state of that element. For example, if I click where a hidden element would have existed, does that still trigger an event?
I'm asking because I know you can target hidden elements in CSS like so:
input[type="checkbox"] {
display: none;
}
input[type="checkbox"]:checked + otherElement {
...
}
Some event must be firing or else the second CSS selector would not work.
Can someone explain this?
For example, if I click where a hidden element would have existed,
does that still trigger an event?
There is no such thing as "click where a hidden element would have existed".
For example, if a brick was not used in building a house, you can't touch it by touching the line between two other bricks, even if it could have been there otherwise.
So there are no user-caused events that apply to an invisible object not included in the layout.
However I am pretty sure it would still produce other events, for example ones reported by MutationObserver. I would expect events dispatched by dispatchEvent to work as well, though I hadn't tested this.
You cannot affect the state of an element that is display: none by interacting directly with the element, because that element is not rendered. However you can still affect its state by interacting with other elements that fire events that in turn change the state of that element via the DOM.
Some event must be firing or else the second CSS selector would not work.
Can someone explain this?
States and events are completely different. Events do not need to have fired for the state of an element to change, and when an element changes its state it does not necessarily fire any events. Selectors never operate on events; they are always state-based.
In your example, if the input element was already checked via the checked attribute, then the DOM loads with that element in that state to begin with, and no events would be fired, and it would still allow otherElement to match the selector immediately. Furthermore, it would continue to match that selector, until something happens that causes the input to become unchecked (or in CSS selector terms, :not(:checked)).
See my answer to this other question for a little more explanation on states vs events in CSS.
It will have no effect on your layout, as if it didn't exist, but the content is still present in the HTML DOM. The CSS attribute display:none is just that - a CSS attribute, and it does not modify your HTML content.
You can still perform javascript functions on the element.

Why is hover for input triggered on corresponding label in CSS?

Am I missing something, or the behavior of this example — http://dabblet.com/result/gist/1716833 — is rather strange in Webkits/Fx?
There is an input with label and the following selector:
input:hover + .target {
background: red;
}
And this style is triggered when you hover the label attached to the input, not only the input itself. Even more: there is a difference between the label with for and input wrapped in a label — if you'd hover the input at first and then move the cursor straight to the .target — the strange hover won't trigger in wrapped version.
And this is only reproduces in Firefox and Safari/Chrome, but in Opera it's ok.
So, the questions is: if this issue is described somewhere in specs? I couldn't find any appropriate place that describes it and tells what behavior is right.
This is in the HTML spec now; it wasn't until the October 2012 WD that it was added to W3C HTML5 (emphasis mine):
The :hover pseudo-class is defined to match an element "while the user designates an element with a pointing device". For the purposes of defining the :hover pseudo-class only, an HTML user agent must consider an element as being one that the user designates if it is:
An element that the user indicates using a pointing device.
An element that has a descendant that the user indicates using a pointing device.
An element that is the labeled control of a label element that is currently matching :hover.
Identical text appears in the living spec.
I discovered this very behavior a few years ago on the previous design of my site's contact form, where label:hover also triggers :hover on any form input element that is either its descendant or referenced by its for attribute.
This behavior was actually added to a recent build of Gecko (Firefox's layout engine) in this bug report along with this (rather short) mailing list thread, and it was implemented in WebKit many years back. As you note, the behavior doesn't reproduce in Opera; it looks like Opera Software and Microsoft didn't get the memo.
All I can find in the spec that could relate to this behavior somehow is here, but I don't know for sure (italicized note by me):
The :hover pseudo-class applies while the user designates an element with a pointing device, but does not necessarily activate it. For example, a visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element.
[...]
Selectors doesn't define if the parent of an element that is ‘:active’ or ‘:hover’ is also in that state. [It does not appear to define the same for the child of an element either.]
Note: If the ‘:hover’ state applies to an element because its child is designated by a pointing device, then it's possible for ‘:hover’ to apply to an element that is not underneath the pointing device.
But what I can conclude is that this behavior is by design in at least Gecko and WebKit.
Regarding what you state here:
Even more: there is a difference between the label with for and input wrapped in a label — if you'd hover the input at first and then move the cursor straight to the .target — the strange hover won't trigger in wrapped version.
Given the above behavior, the only possibility left here is that you've simply been bitten by the cascade.
Basically, this rule:
/* 1 type, 1 pseudo-class, 1 class -> specificity = (0, 2, 1) */
input:hover + .target {
background: red;
}
Is more specific than this rule:
/* 1 class, 1 pseudo-class -> specificity = (0, 2, 0) */
.target:hover {
background: lime;
}
So in applicable browsers, the label.target by your first checkbox will always be red on hover, because the more specific rule always takes precedence. The second checkbox is followed by a span.target, so none of this behavior applies; only the second rule can take effect while the cursor is over the span.target.