If I have a hidden child element (with either display: none or visibility: hidden), how can I have the parent div keeps it's height so that when the child is made visible, the parent height does not change?
Do I need to set an absolute height on the parent or can I still have it calculate its height from the child?
display:none removes the element from the flow, so no way to make the parent keept the height (other than hard-coding a fixed value). It should also hide it from screen readers and crawlers.
visiblity:hidden keeps the element in the flow, and therefore, keeps the space reserved for it, so the parent will keep the height just as if the element was visible.
opacity:0 will also act just like visibility:hidden, while allowing the reveal of the element to be transitioned / animated to opacity:1.
So you should use either visibility:hidden or opacity:0, depending on if you want to show the element in a jumpy reveal or transition.
Edit:
It should also be noted that visibility:hidden will not fire events (such as a click, hover, etc) while opacity:0 will. So there are even some rare cases on which you could use both together. For instance, if you want the element to start hidden, then show up with a transition, and have another event linked to it that should fire only when the element is visible
In the following example, there's a click event linked to the div element that will fire only when visible (so couldn't use just the opacity), but also have a transition when revealing (so couldn't use just visibility)
$('button').click(function() {
$('.opacity').toggleClass("visible");
});
$('.opacity').click(function() {
alert("clicked");
});
div {
width: 100vw;
height: 100vh;
transition: opacity 1s ease;
background: chartreuse;
}
.visibility{
visibility:hidden;
}
.opacity{
visibility:hidden;
opacity:0;
}
.visible{
opacity:1;
visibility: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>
toggle
</button>
<div class="opacity"> opacity:0 </div>
<hr>
If you use visibility: hidden; to hide the child, space will still be reserved for it. You can show it again, by setting visibility: visible;.
To cite the MDN docs for visibility:
The visibility CSS property can show or hide an element without affecting the layout of a document (i.e., space is created for elements regardless of whether they are visible or not).
Related
I've created an 'underline' animation that uses an ::after pseudo-element underneath the link. Here is the code for the link and the pseudo-element:
Link
a {
position: relative;
}
::after
a:after {
content: '';
display: inline;
position: absolute;
height: 2px;
width: 0%;
background-color: #ce3f4f;
left: 0%;
bottom: 0px;
transition: all 0.2s ease;
}
a:hover::after {
width: 100%;
}
This all works fine when the link is on a single line, but if the link flows onto the next line then it only fills across the bottom of the first line, as seen here:
http://i.stack.imgur.com/7SX7o.jpg
If I inspect the element then it appears that the issue is not solvable, as the browser (in this case, Firefox) isn't selecting the entirety of the wrapped element:
http://i.stack.imgur.com/342GH.jpg
Is there a way of solving this purely with CSS, or is it a problem with the way the browser renders the objects? I have played around with a lot of white-space, display and position configurations but to no avail.
Here's an example of the behaviour:
https://jsfiddle.net/57Lmkyf4/
This cannot be done with CSS. (I've implemented it using JS for links that wrap over not more than 2 lines: https://jsfiddle.net/6zm8L9jq/1/ - you can resize the frame to see it at work)
In my Chrome (39.0.2171.95) the underline under a wrapping a doesn't work at all, while in FF it displays like in your screenshot above. Primarily this is because your a element is inline (default), and when it wraps, any pseudo/child elements that depend on its width get 0 width in Chrome and the element's width on the first row in FF. Inline elements don't have control on their own width/height properties (eg, you can't set a width:100px on them without changing them to block elements), and this also affects any absolutely positioned elements that depend on them for width/height.
If you call the window.getComputedStyle method on the pseudo element in FF and Chrome, like:
var a = document.querySelector('a');
a.onmouseover = function(){
setTimeout(function(){
var width = window.getComputedStyle(a,':after').getPropertyValue('width');
console.log(width);
},300); //timeout so that animation to 100% width is completed
}
...in chrome you will see 0px while in FF you will see 100% - and neither will span to actual 100% of the parent. If you added a child element (eg a span) to a instead of a pseudo element, you could investigate the child's actual width after mouseover by calling getBoundingClientRect().width on the child, in which case again, in chrome you would see 0px, and in FF the width of the part of the parent element falling on the first line.
You can change the a element to display: inline-block and it will work, but it will obviously no longer wrap.
Hi I was answer this question and I notice an strange behavior
The Context
I have an HTML structure like this:
<div class="btn">
Click me
</div>
<div class="element">
Div Box With Pseudo Element
</div>
And CSS Just the relevant
.element {
display:none;
}
.element:after {
content:" ";
display:block;
width:0;
background:black;
transition:6s ease;
}
.element.clicked:after {
width:100%;
}
Where the element needs to be display:none and need to be show/hide when click the btn element. That works fine with Jquery and fadeToggle.
Also I add a class to animate a pseudo-element with transition and width. Need to animate at the same time of the fade on the parent.
The problem
If you see this FIDDLE, you can notice at first click the expected behavior is the pseudo-element grows form 0 to 100% but instead is 100% without grow.
If you click again then it's fine changing from 100% to 0
Question
I notice whit the inspector that setting display:none to the element makes the pseudo-element disappear.
This causes the element can't be from 0 to 100% since doesn't exist.
Anyone Knows How to stop that behavior or how to avoid the non-render of the element. I was wonder about the form pseudo-elements were rendered and If they need a Visible parent
This issue doesn't happen with visibiliy or opacity just with display
I believe this issue lies in the fact of how CSS transition works. As you well know a css transiton is applied when an element has a property changed from one value to another.
But in your scenario, the property isn't in fact changing. A pseudo element does not exists while its parent is in the display: none property. So when you call the fadeToggle(), the element becomes display: block and then pseudo is created.
But immediately it is already affected by the .clicked class of the parent, which gives the pseudo a width: 100% property.
So, essencially, the width property is never changed. It goes from "non existent" to "100%", therefore, no transition is applied.
EDIT
So, what you really need is to revert the order of the apply of .clicked class to after the fade started:
Updated Fiddle
$('.element').stop().fadeToggle(3000).toggleClass('clicked');
I am trying to construct a chunk of code that is an image and a text caption, which is a single anchor. the image is an image tag and the text is in a DIV tag.
When the anchor is hovered, the image+text box has a border appear, and the text div transitions between text to then show the background image (using opacity 1 to 0)
USING CSS ONLY
My issue is that I can't seem to find the best CSS to write this code, what I have is:
HTML:
<div class="outerCCBox">
<a href="*url*" >
<img src="images/logo/clarityTeeth.png" alt="">
<div class="clarityUnderBox">
<div class="clarityBox">
Clarity Makeup
</div>
</div>
</a>
</div>
The "clarityUnderBox is a presized box containing the background image that appears when the covering text fades out on hovering over the anchor tag.
CSS:
.clarityUnderBox {
width:256px !important;
height:86px !important;
background:url('../../images/logo/Clarity-C-320.png') no-repeat;
background-size:contain;
}
.clarityBox {
width:100% !important;
height:100% !important;
background-color: #000;
opacity:1;
color:#f0f0f0;
transition: color 0.4s linear,opacity 0.6s;
}
All CSS is simplified for this question (fonts, transition -types- etc removed).
The issue I am having appears to be with the next piece of code, the "hover" element:
.outerCCBox a:hover > .clarityUnderBox .clarityBox {
opacity:0;
color:transparent;
}
EDITED CSS:
originally
.outerCCBox a:hover .clarityUnderBox .clarityBox {
opacity:0;
color:transparent;
}
which behaves in the same way, as with the ">" selector.
The issue is that the hover works fine when hovering over the anchor element but when moving away, the .clarityBox class doesn't return to it's pre-hover state.
1) How do I make this return to it's pre hover state?
1b) Do I need to make a separate ~ a:not-on-hover CSS declaration?
2) How can I tidy up and make the "hover" CSS line more specific? - the way I've done it above works, but I'm sure there's a better syntax to it. I have tried things like using "*" and ">" selectors with limited success (combined with some rearrangement of class orders in the HTML)
Thanks for your guidance.
EDIT:
As requested, a fuller fiddle is here:
http://jsfiddle.net/gwrrezys/9/
But this fiddle doesn't show the image above the text, but it does replicate the general issue with the hover not updating / or not returning to its original state.
cheers
SOLUTION:
As suggested in comments by Martin, making the anchor a block element fixed this issue, I have retained the issue in the jsFiddle for reference and can be found by repeatedly hovering and then hovering off the anchor area.
Your actual problem is with the hovered parent (your anchor element) not having a width set.
If you make the anchor a block element it will fix the "leaking" content issue. by either
making the anchor display: block with set width and height
or making the parent fit the content by making it display: inline-block
DEMO
General to displaying children on hovered parents:
As soon as you extend a child of a :hover element over the whole screen (100% width and height) the parent will stay in the hovered state as long as you are hovering over the child.
To get around that you need to break the child out of its parents flow ... for example by making it's position: fixed (or position: absolute if the parent has no position: relative).
For example by using something like this on the child - and the z-index: -1; here makes sure it moves behind the parent:
position: fixed;
width: 100%;
height: 100%;
top:0;
left: 0;
z-index: -1;
DEMO
Or (depending on what area exactly you wan to cover with the child) you can alternatively extend the child only over a particular hover area (e.g. its parent) ... here you would then use position:absolute on the child and position: relative on the parent (to make sure you keep the child in the parents flow).
DEMO
A quick read on positioning elements: http://css-tricks.com/absolute-relative-fixed-positioining-how-do-they-differ/
I'm having a strangs CSS problem.
Below is a very simple code sample, demonstrating the problem.
<html>
<head>
<style>
.hover {
float: right;
}
.hover:hover {
background-color: blue;
}
.blocker {
opacity: 0.5;
}
</style>
</head>
<body>
<div class="hover">hover</div>
<div class="blocker">blocker</div>
</body>
</html>
I have a div A, floating over another div B, which has an opacity of 0.5. And I want to add a CSS hover rule to the floating div. But for some reason I can't.
Whether I float right or left, doesn't matter.
But when I change the opacity to 1, the hover rule works all of a sudden.
Can anybody explain this behaviour?
I can "fix" the problem by wrapping the content of the blocker div in a span, but it feels like I shouldn't have to.
Here's a jsFiddle, demonstrating the problem: http://jsfiddle.net/ed82z/1/
Simply put - it is "above" it if the opacity has a less than 1 value.
The key term here is a Stacking Context.
By setting opacity to a value less than one, it is layered differently according to the specification since it receives a new stacking context and is positioned beneath the element.
It is specified here float and in opacity:
The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of 'z-index' other than 'auto'. Stacking contexts are not necessarily related to containing blocks. In future levels of CSS, other properties may introduce stacking contexts, for example 'opacity' [CSS3COLOR].
From opacity:
Since an element with opacity less than 1 is composited from a single offscreen image, content outside of it cannot be layered in z-order between pieces of content inside of it. For the same reason, implementations must create a new stacking context for any element with opacity less than 1. If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’. If an element with opacity less than 1 is positioned, the ‘z-index’ property applies as described in [CSS21], except that ‘auto’ is treated as ‘0’ since a new stacking context is always created. See section 9.9 and Appendix E of [CSS21] for more information on stacking contexts. The rules in this paragraph do not apply to SVG elements, since SVG has its own rendering model ([SVG11], Chapter 3).
How to fix it:
You can set pointer-events to none , see this fiddle.
Adding overflow: hidden worked for me:
.blocker {
opacity: 0.5;
overflow:hidden;
}
Or:
.blocker {
opacity: 0.5;
position:relative;
z-index:-1;
}
(thank you #Eyal Barta for this option)
http://jsfiddle.net/ed82z/7/
This is because .blocker overlays your other div, easily shown with firebug or other dev tools.
When you add opacity you add a 'stacking context'.
This occurs because these DIVs have special properties which cause them to form a stacking context.
In this case: elements with an opacity value less than 1. Which is giving your div a z-index, and it is causing the div to be rendered in a different order.
The Stacking Context
In .blocker class is overlapping the .hover class because of float:right;
.blocker {
opacity: 0.5;
width:100px
}
you can fix this set float:left in blocker class or else set width:100px to fixed width for div it won't overlap.
http://bit.ly/1fVGrBT
Here is my website. When you hover on Problem and move away, the div below it gets pushed up and down. Same happens for Solution. Any idea or tips how to prevent it from moving?
I think it is moving due to the changed font size and the underline, but I am not sure what I can do.
On hover, you enlarge the text, and thus the container. This pushes the rest of the content down.
3 solutions:
Use transform: scale(1.2); to enlarge the text. This doesn't affect the flow of the document. Add this to your element:hover. Remember to add browser prefixes. Read more here
Example:
#switcher li:hover {
transform: scale(1.2);
}
Add a height to your navigation. This locks the container height.
Add position: absolute on either the navigation or the content. This removes them from the document flow, so won't affect each other.
Set CSS line-height to fix the height for text in <h3> tags
this seems to fix it for me:
#switcher {
display: inline-block;
margin: 0;
overflow: hidden;
max-height: 30px;
}
basically I'm telling the container to not expand more than 30px in height.