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

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.

Related

Remove HTML element completely just by using CSS?

Just like removeAttribute in JavaScript, after which the element won't be visible in the source.
You cannot remove an element from the DOM tree using CSS. You can only prevent it from being rendered in the layout with display: none; doing so does not prevent it from responding to events or cause it to be ignored by CSS selectors such as + and :nth-child(). You won't be able to interact with an element that's not there so you wouldn't be able to trigger events the usual way, but its "essence" remains, so to speak.
Its not possible with CSS.
Even if you use display:none, the element will be still in DOM tree.
CSS is for styling not for DOM manipulation. Use JavaScript for that.
display: none;
'Unlike the visibility property, which leaves an element in normal document flow,display: none removes the element completely from the document. It does not take up any space, even though the HTML for it is still in the source code. This is because it is, indeed, removed from the document flow. For all intents and purposes, the item is gone. This can be a good thing or a bad thing, depending on what your intentions are. It can also be damaging to your page if you misuse this property!'
https://www.lifewire.com/display-none-vs-visibility-hidden-3466884
You can use display: none to hide an element but it will still be on the DOM.
You can also use visibility: hidden and it will also still be on the DOM but the DOM will reflect the same vertical flow even though the element is hidden. In other words if the element is a block, a block space will still be reserved for the hidden element. And with display: none the space will also be removed along with the element as it is hidden.
Unless you use JavaScript, with CSS you are only changing the visibility of a DOM element that is existent on the DOM. Which can absolutely serve your purpose depending on what you are trying to do.
If you need more help, just comment with more detail and I'd be glad to help.
You actually can. Not directly in CSS but in combination with Javascript/jQuery you could.
In HTML give a class of "removeFromDom" to the Elements you want to have removed.
<p class="removeFromDom">your text here</p>
In CSS you add these Lines to make it invisible, if JS is not working.
.removeFromDom { display:none !important; visibility:hidden !important; }
In a jQuery file, that you load on any site, create this function::
$(document).ready(function() {
$(".removeFromDom").remove();
});
Et voila.. your jQuery file removes your Items from the DOM. I wouldn't recommend it for security reasons if there is a link nobody should be able to see anytime..

Shadow Dom and CSS3 :target selector

I should start off by saying that I don't really have an issue that I'm trying to work through. I just had an interesting thought about how Shadow Dom and the CSS3 :target selector might / should / currently do work together.
I know that HTML specification says that there should only ever be one element with a particular ID value in a valid HTML document. But when we start using webcomponents with shadow dom we could very easily find ourselves using multiple elements with the same ID. This is especially true when we use the same component multiple times in the same page. So the question that I have is this: what should happen to an element inside a shadow dom region that has an ID value which matches the current hash and which is styled with a :target rule?
For example, if I wrote a webcomponent (my-element) that contained
<style>
#debug {display:none}
#debug:target { display:block; background-color:yellow; border 2px solid red; }
</style>
<div id="debug">some debug data</div>
What should happen to all the instance of my-element that I put on a page and navigated to #debug on? Should the debug element in each component show? Should none of them show? Should only the first element's debug div show (the same one I'd expect the browser to try and navigate to)?
My opinion is that if the page does not have an element with an ID=debug value that no scrolling navigation should appear on the page. As shadow dom is isolated from the rest of the page's styles the browser shouldn't try to navigate to such an element nested in shadow dom. Each my-element instance should be able to see the current page's URL though and should apply any matching :target rules, such that each my-elements' debug div should be visible.
If this were the case it would make for some interesting possibilities for sharing page state across all components, such as the debug example above. However, I doubt that is how Chrome is currently implementing things. And I'm pretty sure this Shadow Dom polyfill isn't going to handle things correctly as it basically shoehorns everything into the page's Dom tree and that would break the html specification.
Just curious if anyone has an answer for how this should work and how it works today...
(edited from my pc to add formatting... hard to do from my phone)
I think you can see the shadow DOM like a nested document. CSS can't address elements inside the shadow DOM from the outside (previously existing shadow piercing CSS selectors were deprecated).
This also encapsulates ids and therefore multiple components that contain elements with an id won't cause collisions or duplicates.
If you have the CSS with the :target selector inside a components style, it should be able to address the element with the matching id, otherwise it shouldn't.
So the question that I have is this: what should happen to an element
inside a shadow dom region that has an ID value which matches the
current hash and which is styled with a :target rule?
Adding to Günter Zöchbauer above answer an alternative is to use the Custom Element object when the style is encapsulated, if the style is global it will work just fine. Use the define method to create a custom component as shown in the the docs. This will not encapsulate your elements so be aware that your styles can be shared across files.
So instead of doing this:
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(pTag)
Use this:
this.appendChild(pTag);
both previous examples suppose you're in a HTMLElement class or a class that inherits it.

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.)

CSS :active selector eater

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.

tabindex in CSS

Is it possible to control tabindex with CSS and if yes, which browsers support it and on which elements?
EDIT
I should say, my goal is to catch keydown events on a div. I saw this page http://www.quirksmode.org/js/events/keys.html# that tests keyboard events and it shows that the only way keydown fires on anything other than document and body or some kind of form element or link is to have tabindex declared on it. But I read on W3C site:
The following elements support the
tabindex attribute: A, AREA, BUTTON,
INPUT, OBJECT, SELECT, and TEXTAREA.
So I am a little confused, what to do in order to be standarts compliant and make my use case work?
EDIT2
My whole use case is a div with a lot of content with an artificial scroll bar. I am able to scroll it with mouse events but no luck with the keyboard so far.
Update 2017
As pointed out by #Wallop in the comments, the nav-index property was dropped from the spec in 2015 due to "lack of implementation interest".
Take a look at the nav-index property introduced by W3C in CSS3-UI.
This property has exactly the same behavior as a tabindex and is applicable to any element.
The ‘nav-index’ property is an input-method-neutral way of specifying the sequential navigation order (also known as "tabbing order").
This property is a replacement for the HTML4/XHTML1 attribute ‘tabindex’
Being probably the best standards-compliant solution for the use case, nav-index is interpreted only by Opera so far (as of June 2012) and is also marked as "Feature at risk" by W3C, therefore may be dropped any time.
Alternative cross-browser solutions are:
non-standards-compliant: set the tabindex attribute on a DIV. This will work in all common browsers.
standards-compliant: replace DIV by an anchor element (A) without a href attribute set, style it with display: block and add the tabindex attribute.
With respect to BoltClock´s point, I agree that the tabbing order is very logical (both the text selection order and tabbing order are closely related to the sequence in which elements are aranged in the document). On the other hand, CSS has a wider purpose today. It can manipulate not just the content of a document (content property) but also the behavior when and if events are to be fired: i.e. using pointer-events, display or z-index the pointer event's order will change. If these are very basic CSS properties, why you should not be able to influence KeyBoardEvents, too?
This is a bit old but now there are css options like -moz-user-focus. I'm sure there is a webkit equivalent.
https://developer.mozilla.org/en-US/docs/CSS/-moz-user-focus
user-focus is the standard cross browser attribute.