I want to simplify things in my jQuery Backbone.js web application. One such simplification is the behavior of my menu and dialog widgets.
Previously I created the div boxes of my menus at start and hid them using display: none; opacity:0;. When I needed a menu, I changed its style to display:block then used the jQuery ui position utility to position the div box (since elements with display:none cannot be positioned) and when it was done, finally changed its style to opacity:1.
Now I want to just hide them with visibility:hidden, and when I need one, I use the position utility and then change the style to visibility:visible. When I begin using this new approach, I will have around 10 div boxes throughout the web application session that are hidden but occupy space, in contrast to the previous div boxes hidden with display:none.
What are the implications of my new approach? Does it effect browser performance in any regard?
display:none; elements are not in the render tree all, so they will perform better at face value.
I doubt you will have any real visible performance problems from this though. If you need opacity: 0 or visibility: hidden because of their functionality, then just use them. If you don't need the functionality, then use display: none;
If you are toggling between visible and invisible states via javascript then visibility:hidden should be the better performer. Seeing as it always takes up the same amount of space in both visible and hidden states it won't cause a reflow of the elements below it every time you make it appear of disappear. For display:none you are removing it from the flow of the document and then when you set it to display:block you are rerendering it and pushing everything below that element down, essentially laying all that stuff out again.
But if you are doing something like toggling visible states on button presses then you really should be using what suits your needs rather than what performs better, as the performance differences are negligible in such cases. When you are animating with the dom at around 20 times per second THEN you can worry about the performance of visibility:hidden vs display:none.
visibility: hidden does not cause a re-flow on the document, while display: none does.
display: none: The HTML engine will completely ignore the element and its children. The engine will not ignore elements marked with visibility: hidden, it will do all the calculations to the element and its children, the exception is that the element will not be rendered to the viewport.
If the values for position and dimensions properties are needed then visibility: hidden have to be used and you have to handle the white space in the viewport, usually by wrapping that element inside another one with 0 width and height and 'overflow: hidden'.
display:none will remove the element from the document's normal flow and set the values for position/height/width to 0 on the element and its children. When the elements display property is changed to other value than none, it triggers a complete document re-flow, which can be a problem for big documents - and sometimes not-so-big documents being rendered on hardware with limited capabilities.
display: none is the natural and logical solution to use when hiding elements on the viewport, visibility: hidden should be used as a fallback, where/when needed.
EDIT:
As pointed by #Juan, display: none is the choice to go when what you need is to add many elements to the DOM tree. visibility: hidden will trigger a re-flow for each element added to the tree, while display: none will not.
I'm not aware of any performance difference between display:none and visibility:hidden - even if there is, for as little as 10 elements it will be completely negligible. Your main concern should be, as you say, whether you want the elements to remain within the document flow, in which case visibility is a better option as it maintains the box model of the element.
Well, the main performance difference between display: block and visibility: hidden is that if you have a list of, say, 100000 elements, the visibility: hidden won't save you from DOM hanging because it doesn't remove elements from DOM.
visibility: hidden acts like opacity: 0 + pointer-events: none. display: none acts like Element.remove().
Live example: https://jsfiddle.net/u2dou58r/10/
From personal experience having just tried both on a simple static page with a form located beneath a "hidden" button, visibility: hidden performs flawlessly whereas display: none causes clickable buttons to slightly jump upon clicking, as if it tries to show the hidden button for a millisecond.
Well, visibility:none still uses the space of the div.
So you could maybe skip the positioning part because its place is already allocated (and by that get a better performance).
But I somehow guess that you need your display:none approach to allocate space correctly when the "show" event is triggered.
I think this could be somehow related to this question: CSS Properties: Display vs. Visibility
I'll just quote the interesting part:
the element is NEVER removed from the DOM hierarchy. All block level display 'styles' are completely 'hidden' when using display:none, whereas with visibility:hidden; the element itself is hidden but it still occupies a visual space in the DOM.
So there should be no real difference in regard to browser performance, because both versions are still in the DOM hierarchy. These properties only affect how an element is displayed in regards to the DOM.
Related
That's pretty much the question.
I have search everywhere online, but I cannot find any implementation of the css
scroll-snap-stop: always written in pure javascript.
I do not want to use the css property because not all browsers respect it (let alone older browsers).
Does any one have any sample code around that does something similar? I do not know where to look or how to start.
Here is an example of I working here https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-stop
It forces the user to stop at each section
[EDIT] -- I basically want the same functionality of what scroll-snap-stop: always does without using it. There should be no css, just pure javascript that mimics that same css behavior.
I need pure javascript instead of css because not all browsers honour the scroll-snap-stop: always css property. So I wanted to code a javascript alternative that does the same thing.
Do the mode switch in JS, or even a pure HTML button.
Do the style in CSS.
Use JavaScript to change the class of the element.
And use CSS to style the two classes.
This method is style independent.
Say you have a list of items that overflow (with ul being its overflowing container):
ul
li
li
li
When the page loads, you set all list items to display none, except for the first two. You set the second one to 1px width and set the first one to its normal width. When the second one enters the viewport (intersection observer) you expand the second one to its normal width. You then also set the third one to 1px width and set it to display block. When the first one leaves the viewport (intersection observer) you set the width of that one to 1px... etc. This should mimic the CSS rule.
You could code this... and it would perform absolutely great... but I would not do it. Browser compatibility of 'scroll-snap-stop: always' is fine: https://caniuse.com/?search=scroll%20snap
For example if we have:
<style>
.child {display:none;}
</style>
<script>
$('.parent:contains("Invisible")').addClass('newparent');
</script>
<div class="parent">
<div class="child">Invisible</div>
</div>
This code works! Parent div will receive new class newparent. This has no logic to me because I always believed if I put display:none that this is it, element is gone. You can't find it in inspect element, view source, etc.
But obviously this is not the case if javascript can find it. That means that this element is rendered somehow. So I'm wondering if element with display:none is still out there is it affecting performance?
For example if we have right sidebar and we decide to hide it on mobile with display:none.
From experience I know that the site will load faster if sidebar has display:none, but question is still the same, what happens to the element with display:none, is it rendered somehow, if yes how and where?
You seem to have some misconceptions about display:none. It is a css property which causes the element to take up no room on the page. The element is still rendered and still exists all the same.
MDN display
I always believed if I put display:none that this is it, element is gone. You can't find it in inspect element, view source, etc.
Your assumption is incorrect. The element is still part of the DOM. It's just styled to not be rendered visibly on the screen.
So I'm wondering if element with display:none is still out there is it affecting performance?
No more than any other element would. If you have so many elements as to affect performance, then you'd certainly want to address that. But it has little to do with the styling.
what happens to the element with display:none, is it rendered somehow, if yes how and where?
It's part of the structure of the DOM in memory. Everything about it is still there. It's just not visibly shown in the viewport.
CSS styling doesn't change the structure of the HTML. It just governs how that structure is visibly displayed on the screen. (Or in some other medium.) JavaScript, on the other hand, can be used to modify the DOM in-memory, and those changes are also reflected in the display. (As your test demonstrates.)
NOTE: I could not replicate the issue in jsfiddle or jsbin, so unfortunately I will demonstrate the issue only via screenshots.
In my work project some JavaScript control is not rendering properly.
I found that it renders properly if I wrap the rendering logic in setTimeout(renderLogicFunction, 30);. Number 30 was found during experiments. If value is less than 10 it always renders incorrectly. If it is greater than 30 it is always correct. For 10-30 it is pretty random.
I started to debug the rendering logic side-by-side and found that one of the columns has wrong width
However in good rendering
Inner HTMLs for both of those controls are the same.
Let's see when the 16px came from
This refers to the inline style
Then I checked that the bad rendering page also has this inline style but for whatever reason it is not applied yet.
If I let debugger go, I can check that the CSS rule was already applied but it's too late as the column width was taken during calculations for rendering and its current width is not being taken into account anymore. The only way to fix it is to trigger control's refresh. But I think it is not elegant at all.
Do you have any ideas why that happens?
When you need a style to become inmune to overwrite, and make it able to overwrite previous rules of the very same style, you can add it !important
div { width:100%; }
div { width:50%; }
Will render your div elements at 50% width, while
div { width:100% !important!; }
div { width:50%; }
will render your div elements at 100%.
If you use this wisely on your CSS styles you'll probably be able to fix your problem.
I guess you are using some 3th party library which resizes columns.
Instead of setTimeout(renderLogicFunction, 30); it could probably be replaced with jQuery's document ready, https://learn.jquery.com/using-jquery-core/document-ready/
I have heard that applying display:none to things that are not visible is more accessible then changing opacity. However using display:none messes up some of my css animations that are progressively layered onto the core functionality.
Is it accessible if in my css the element is hidden with opacity:0 and give the element the aria-hidden=true role, or should the element also have display:none?
Another factor to be considered is the aria roles are controlled by javascript (the css has a :hover pseudo-class fallback) in this instance. So for environments without javascript the element would only be hidden with opacity:0.
Well, that's basically how aria-hidden is defined:
Indicates that the element and all of its descendants are not visible or perceivable to any user as implemented by the author. See related aria-disabled.
If an element is only visible after some user action, authors MUST set the aria-hidden attribute to true. When the element is presented, authors MUST set the aria-hidden attribute to false or remove the attribute, indicating that the element is visible. Some assistive technologies access WAI-ARIA information directly through the DOM and not through platform accessibility supported by the browser. Authors MUST set aria-hidden="true" on content that is not displayed, regardless of the mechanism used to hide it. This allows assistive technologies or user agents to properly skip hidden elements in the document.
So I'd say "yes".
Of course, as long as you have aria-hidden set, it's trivial to use it to actually hide the element, even for the non-reader version - [aria-hidden="true"] { visibility: hidden; }, for example. Ideally, you'd set this at the end of your "hiding" animation.
In fact, since you're using opacity to hide the elements, there's no reason to use display: none - visibility: hidden will fit your requirements much better.
is it possible to have a visible html element but one which lacks presence on the page?
Let me give you an example of what I mean. Lets say I have a picture gallery and a light box. Usually lightboxes grey out the background so you can focus on the image. All i want is the greyed out overlay but i dont want it to be interactive. So if you were to click on it, you would click on the element behind it. So lets say I have a paragraph and in that paragraph i have a link and covering the paragraph is a overlay at 50% opacity, if i were to hover over the link, the link would react asif the overlay was not there.
I hope I have explained this well enough
AFAIK there is no easy way to do this and the only alternative would be to get the mouse coordinates and relay them somehow :/ is ther anyway what I want is possible?
Thanks
This can be done with pointer-events: none in certain browsers, but unfortunately not any version of IE.
It is not possible to have an overlay be transparent in the sense you want it to be. What you could try to do is the opposite; put the 'overlay' layer behind the rest of your page and then change the opacity of your entire page to 50%. Visually this will not make any difference, but it will remove the bubbly effect of JS clicking.
You can take an element out of the document flow with CSS but when that happens the element still receives click events as long as it is visible.
You could probably attach a click event to the overlay and then use the mouse coordinates with document.elementFromPoint or by manually looping through all the elements you want to be interactive and checking their coordinates on the page. The problem with this approach is that NoScript or a number of other products might detect this as ClickJacking, which it essentially is even though you are using it for a benign purpose.
I don't see why this isn't possible. opacity is about 5 css properties for cross-browser. I am not sure what exactly you mean by an overlay (same thing as a layer or z-index?) or are you talking about the possibility of using a css
for all p tags, then it's p:hover in css, but for a specific p tag, then you use an #id with :hover pseudo-class like this:
#myptag:hover {
background-color: #f3c9d5;
background-image:url(/images/mybgimg.jpg);
color:blue;
cursor:pointer;
}
for opacity, use a number in windows.index from 0 to 100:
//this function modifies the opacity of an element at a
//specific id like el1 or el2 using imageNumber as the index.
//you also specify an opacityInteger, which is an non-negative
//integer number in the range 0..100
//works on chrome, safari, ie, and firefox, all the major browsers.
function processimage(imageNumber, opacityInteger) {
var opacityFloat=opacityInteger/100.0;
//set image style, if we can - I hear it's readonly...
//filter:alpha(opacity=100);-moz-opacity:1.0;opacity:1.0
document.getElementById("el"+imageNumber).style.filter="alpha(opacity="+opacityInteger+")";
document.getElementById("el"+imageNumber).style.mozOpacity=opacityFloat.toString();
document.getElementById("el"+imageNumber).style.opacity=opacityFloat.toString();
}
well, I just realized this is only marginally helpful. while it may get your toward your goal, you may still have to set a css z-index:1; on a layerto get an actual overlay. what I just gave you was an UNDERLAY or simply setting a given p tag's color or background image to another thing. I don't know if that's desirable to you or not. I have found overlays to be extremely difficult to manage, because the page layout engine treats all the layers as if they were the same layer tags-flow-wise and you have to use absolute positioning to force them to stick in a position you want them in. plus it messes up your main page using layers.