Firefox css transition doesn't start when preceded by generated content - css

** Update **
If anyone else encounters this issue, a bug has been filed with Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1011153
http://jsfiddle.net/ZEzc9/3/
Found this today and setup a fiddle for it. The best I can tell right now is that if a target element is preceded by generated content where a transition effect applied, the transition fails to start.
html:
"Some text" animates up and down smoothly on hover.
<div>
<div>
<span> Some text</span>
</div>
</div>
"Some text" should animate in and and out. In Firefox, the generated content on div > div:hover::before stops the inital animation.
<div>
<div>
<span> Some text</span>
</div>
</div>
CSS:
div {
width: 300px;
height: 100px;
position: relative;
outline: 1px solid #cc0000;
}
div > div {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border: 2px solid #000;
}
div > div > span {
bottom: 10px;
}
div > div > span {
position: absolute;
bottom: 20px;
left: 20px;
-webkit-transition: bottom 250ms;
transition: bottom 250ms;
}
div:last-child > div:hover::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #cc0000;
}
div > div:hover span {
bottom: 50px;
}
I am only seeing this behavior in Firefox. Is there a reason this is happening or does it seem to be a bug in FF?

Looks like a bug, I see the same thing using Fx 29.0.1, Win7 x64.
However, for what it's worth, it will work if you create static invisible generated content without the :hover pseudo-class, i.e.
div:last-child > div::before {
content:'';
/* … */
background:transparent;
}
but make it visible on hover, i.e.
div:last-child > div:hover::before {
background:#cc0000;
}
I updated your fiddle to show this.

Related

Why is ::before pseudo element appearing on top of the element?

From my understanding, ::before should appear below the element, and ::after should appear above of the element (in terms of z-index).
In the following example I am trying to make just the background color darker (not the foreground color) when one hovers over the button. Even though I used ::before it still appears in front. Why? I know I could fix it with z-index, but according to this comment which has 6 upvotes:
I think it's better to use :before so you get the right stacking order without playing with z-index.
I should not have to, and the order should be correct?
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
button:hover::before {
display: block;
content: "";
position: absolute;
top: 0; left: 0; width: 50%; height: 100%; /* width is 50% for debugging (can see whats below) */
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>
There's no difference between ::before and ::after regarding the z-index or z-axis order. By default both will be placed in front of their parent, covering it (if their position is defined accordingly). To achieve z-axis layering beyond that, you need to actually use a z-index (besides a combination of relative and absolute position).
Addition after comment:
In the snippet below there are two variations of the situation. The only difference if that once ::after is used, once ::before, both times without a z-index, and both time with the same result, i.e. the pseudo element covering its parent:
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
.parent:nth-child(1) button:hover::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
.parent:nth-child(2) button:hover::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>
<div class="parent">
<button type="button">CLICK ME</button>
</div>
So, to come back to your question in your second comment: Yes, they are wrong - you need to use a z-index to move the pseudo element behind the parent.
So your actual solution should look like this, using a negative z-index: -1; for the pseudo element (and you could as well use ::after here, it doesn't matter...).
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
button:hover::before {
content: '';
position: absolute;
z-index: -1;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>

Why are my pseudo-classes overriding display:none?

I have a div that appears as an "X" (used to close a window):
<div class="alertwrapper" style="display:inline-block;">
<div class="obj"></div>
<div class="x"></div> //<-----ELEMENT IN QUESTION
</div>
The following are the CSS properties of this element:
.x {
display: none !important;
position: absolute !important;
left:0;
top:0;
transition: transform .25s ease-in-out;
z-index:999;
}
.x:before {
content: "";
position: absolute;
//Here, I've also tried display:none !important;
left: 48%;
margin-left:-495px;
right: 0;
top: 115px;
bottom: 0;
width: 32px;
height: 0;
border-top: 3px solid black;
transform: rotate(45deg);
transform-origin: center;
z-index:999;
}
.x:after {
content: "";
position: absolute;
//Here, I've also tried display:none !important;
left: 48%;
margin-left:-495px;
right: 0;
top: 115px;
bottom: 0;
width: 32px;
height: 0;
border-top: 3px solid black;
transform: rotate(-45deg);
transform-origin: center;
z-index:999;
}
This div should not be displayed until another element is clicked, at which point, it should appear, as defined by the following code:
<script type="text/javascript">
$(document).ready(function () {
$('body').on('click', '.ActiveQuestionCycler', function() {
$("div.x").fadeIn(300).delay(1500);
$("div.obj").fadeIn(300).delay(1500);
});
});
</script>
When the page loads, however, the div "x" is visible, before .ActiveQuestionCycler is clicked. (The display is not set to none.) I think this has to do with the pseudo-classes before and after overriding this but I can't figure out why.
(div.obj DOES fade in when .ActiveQuestionCycler is clicked.)
There are no error alerts in the source.
This comment /// STYLE SETTINGS FOR THE QUESTION CONTAINER AND CLOSE "X" BUTTON on line 109 is invalid. Change it to:
/* STYLE SETTINGS FOR THE QUESTION CONTAINER AND CLOSE "X" BUTTON */
and it should work. Remember to drop that display: none; into the .x
So it will look like:
.x {
display: none;
/* your other styles */
}
While // comment is normal for most programming languages, regular css does not accept it and css comments go like this /* comment */

Trouble with nowrap and max-width on an absolutely positioned element

I'm guessing these two attributes don't actually work together, but my situation:
I'm trying to create a tooltip component. My tooltip is positioned absolutely, and as I don't know what the length of the content would be, has no width. So with width-related css, text just forms a tall, skinny column. I tried max-width, but on it's own, that does nothing. So I decided to try white-space: nowrap, and while it nicely doesn't wrap text, it also doesn't seem to honor max-width in a useful way, with text instead going out of the boundaries of the element.
I can't think of how to solve my problem, if there is a clean solution. I'd like to have an absolutely positioned div that expands to fit it's content until a maximum, at which point it wraps. One suggestion I saw was making the element a flexbox, but from what I can tell, that's not great with IE, so I don't think is viable in my situation. Any advice?
.wrapper {
position: relative;
display: inline;
}
.info {
position: absolute;
bottom: 1.2em;
left: 0;
}
<div class="wrapper">
<span>[ ? ]</span>
<div class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
</div>
Avoid using white-space:nowrap as that will constrain your text to one line. max-width should work with a block level element with display absolute but not inside an inline element. To resolve this, I place the tooltip outside of your wrapper block and use javascript to position it at the mouse location.
Here is a simple solution for your issue. Click on "open tooltip" to display the tooltip and move the slider to change the value of max-width.
showContext = function() {
var e = window.event;
var posX = e.clientX;
var posY = e.clientY;
var info = document.getElementById("info");
info.style.top = posY + "px";
info.style.left = posX + "px";
info.style.display = "block";
}
changeWidth = function(value) {
var info = document.getElementById("info");
info.style.maxWidth = value + "px";
}
.wrapper {
position: relative;
}
.info {
position: absolute;
max-width:300px;
display:none;
border:1px solid black;
background-color:white;
}
.range {
margin:10px 0px 10px 0px;
display:block;
}
<div class="wrapper">
max-width slider
<input id="range" class="range" type="range" min="100" max="600" oninput="changeWidth(this.value)"/>
<input type="button" value="open tooltip" onclick="javascript:showContext();" />
</div>
<div id="info" class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
I'm not exactly sure what your goal is as there are a lot of contradictory things going on. But I'll try and hopefully you can guide me towards your desired solution:
https://jsfiddle.net/q7dyf6xh/
.wrapper {
position: relative;
display: run-in;
}
.info {
position: absolute;
max-width: 200px;
white-space: pre-line;
}
Have a look at this fiddle, as you can see the tooltip now has a max-width. Have a look at what I'm using:
display: run-in;: Displays an element as either block or inline, depending on context
white-space: pre-line;: Sequences of whitespace will collapse into a single whitespace. Text will wrap when necessary, and on line breaks
For a better understanding of how things work look here:
white-space: If you use nowrap text will never wrap to the next line. The text continues on the same line until a tag is encountered!
This said your max-width is still working but with nowrap you overflow your element now. Try and give your element a background-color and you'll see that it actually is only as wide as your max-width defines.
See here how it overflows the element: https://jsfiddle.net/fcnh1qeo/
And now width overflow: hidden only the text inside your box will be displayed. Everything else is cut off! See here: https://jsfiddle.net/0qn4wxkg/
What I used now is display: run-in; and white-space: pre-line; as well as max-width: 200px which will give you hopefully your desired solution. Not knowing the context and code you using it is more of a guess than it is a answer. But maybe I can guide you towards a solution which fits your needs
Cheers!
Add a min-width:100% and a white-space: nowrap;
.wrapper {
position: relative;
display: inline;
}
.info {
position: absolute;
min-width: 100%;
white-space: nowrap;
}
<div class="wrapper">
<span>[ ? ]</span>
<div class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
</div>
display="runin"The element generates a run-in box. Run-in elements act like inlines or blocks, depending on the surrounding elements. That is:
If the run-in box contains a block box, same as block.
If a block box follows the run-in box, the run-in box becomes the first inline box of the block box.
If an inline box follows, the run-in box becomes a block box.
pre-line Sequences of whitespace are collapsed. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes.
The following table summarizes the behavior of the various white-space values:
The max-width CSS property sets the maximum width of an element. It prevents the used value of the width property from becoming larger than the value specified by max-width.
.wrapper {
position: relative;
display: run-in;
top: 100px;
}
.info {
position: absolute;
bottom: 1.2em;
left: 0;
max-width: 200px;
white-space: pre-line;
background-color: #ddd;
}
Not that ling ago i had a very similar problem myself. I fixed it using flexbox what is already suggested in the comments here.
My code looks like this:
.has-tooltip {
display: inline-flex; align-items: flex-start
}
.has-tooltip > .tooltip {
padding: 1em;
max-width: 300px;
background: #bdc3c7;
word-wrap: break-word;
transform: translate(-50%,-110%)
}
I also copied this into this fiddle just in case you want to have a look at it. (:
You are correct that this does not work.
Here's a solution that works if you are allowed to use BR tags. I have worked on tooltips many times and this is the best solution that I have.
Codepen:
https://codepen.io/btn-ninja/pen/JNJrgp
It works by using white-space nowrap with a css translate:
<button type="button" class="btn btn-block hasTooltip">
Tooltip on top
<i class="tip">Most tooltips are short<br>but you can add line breaks.</i>
</button>
<button type="button" class="btn btn-block hasTooltip right">
Tooltip on the right.
<i class="tip">Tooltip on right<br>vertically centered.</i>
</button>
.hasTooltip .tip {
position: absolute;
bottom: 100%; left: 50%;
transform: translateX(-50%); }
.hasTooltip.right .tip {
bottom: auto; left: 100%; top:50%;
transform: translateY(-50%); }
The translate allows the absolutely-positioned tooltip to horizontally or vertically center itself vs the content. White space with a BR achieves wrapping for long content while allowing shorter tooltips to match width of the tooltip text.
Here's the full css:
.hasTooltip {
position:relative; }
.hasTooltip .tip {
display:block;
background: #333; color: #fff;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
font-size:inherit;
font-style:normal;
line-height: 1rem;
text-align:center;
padding: 8px 16px;
border-radius:4px;
margin-bottom:5px;
pointer-events: none;
position: absolute;
bottom: 100%; left: 50%; transform: translateX(-50%);
opacity: 0;
transition: opacity .34s ease-in-out;
white-space:nowrap;
z-index:99; }
.hasTooltip .tip:before {
content: "";
display:block; position:absolute; left:0; bottom:-5px;
width:100%; height:5px; }
.hasTooltip .tip:after {
border-left: solid transparent 6px;
border-right: solid transparent 6px;
border-top: solid #333 6px;
bottom: -4px;
content: "";
height: 0;
left: 50%;
margin-left: -6px;
position: absolute;
width: 0; }
.hasTooltip:focus .tip,
.hasTooltip:hover .tip {
opacity: 1;
pointer-events: auto; }
.hasTooltip.right .tip {
bottom: auto; left: 100%; top:50%; transform: translateY(-50%);
margin-bottom:0;
margin-left:5px; }
.hasTooltip.right .tip:before {
left:-5px; bottom:auto; }
.hasTooltip.right .tip:after {
border-left: 0;
border-top: solid transparent 6px;
border-bottom: solid transparent 6px;
border-right: solid #333 6px;
bottom:auto;
left: -4px;
top:50%;
margin-left: 0;
margin-top: -6px; }

Aligning div overlay on percentage width element

I'm building a "staff" page with a liquid, four-column layout. I've placed a div element, absolutely positioned on top of the photo of each staff member to act as a button/link. My problem is that when I align this overlay div to bottom:0 and right:0 I will get the occasional 1 pixel gap between the image and the overlay as I resize the window. It seems this is a function of some sort of round-off error.
I've searched this site and others for help on this, but I haven't found this issue explicitly discussed anywhere. Any insights are greatly appreciated.
The page in question can be seen here:
communicationdesign.com/cwt-beta/about.html
Resize the window to see the occasional error/gap...
Here is the relevant markup:
<div class="staff-block">
<div class="staff-photo">
<img src="img/gruber.jpg" class="portrait" />
<a href="gruber.html">
<div class="plus-link">
<div class="plus-sign">+</div>
</div>
</a>
</div>
<div class="caption">
Drew Gruber<br /><span class="job-title">Executive Director</span>
</div>
</div>
And here is the CSS:
.staff-block {
position: relative;
width: 22.3%;
float: left;
background-color: #ffc;
margin-right: 3.5%;
}
.staff-photo{
position: relative;
}
.staff-photo img, .board-photo img, .bio-photo img {
width: 100%;
}
.portrait {
opacity: 1;
display: block;
width: 100%;
height: auto;
transition: .5s ease;
backface-visibility: hidden;
}
.plus-link {
transition: .5s ease;
opacity: 1;
position: absolute;
bottom: 0;
right: 0;
}
.plus-sign {
background-color: rgba(255,204,78,0.8);
color: white;
font-size: 40px;
line-height: 30px;
padding: 4px 8px 6px;
}
This is an occupational hazard when using percentages. You could use a hack like this:
.staff-photo{
overflow: hidden;
}
.plus-link {
background-color: rgba(255,204,78,0.8); // color on the plus sign parent
position: absolute;
bottom: -5px; // position it over the edge
right: -5px;
padding: 0 5px 5px 0; // and correct the extra space
}
.plus-sign {
background-color: transparent; // or remove bg color
}

Using .hover as well as .active for css animation

I have a div called main content, inside this div is another div called slideup. Using CSS animation, when you hover over the main content div, the slide up div slides up from the bottom to 50% height. This can be seen in my css code below
.maincontentdiv {
position: relative;
height: 100px;
width: 100%;
}
.slideup {
position: absolute;
width: 100%;
bottom: -2px;
min-height: 0;
color: #FFF;
transition: min-height 250ms ease-in;
background-color: #666666;
text-align: center;
height:20px;
}
.maincontentdiv:active > .slideup, .maincontentdiv:hover > .slideup {
min-height: 50%;
}
The hover works perfectly well, however I included the click function (.active) for touchscreen devices. I can not seem to get the click function working. Could somebody please tell me what I have done wrong?
Thanks

Resources