Interesting bug in Chrome. If a scrollable div is off screen when the page initially loads, then that scrollable div is not scrollable by way of mouse wheel or touch pad gestures until it is given focus (by double clicking somewhere within its element, or selecting text inside of it).
Update
This bug is documented here https://code.google.com/p/chromium/issues/detail?id=417345 It remains unfixed as of May 2015. The thread provides some interesting possible solutions with javascript, but I would like to see if anyone has any alternate suggestions for a fix, possibly not involving JS
The Bug
When you click on the button to "Show Side Container", the side container will slide into view, and the main container will slide out of view. If you immediately try to scroll using the mouse wheel or two finger gesture on a laptop track pad, nothing will happen. You can use page up and page down on the keyboard however, these do work. You can of course also use the actual scroll by by clicking on it with a mouse.
In firefox and IE, you can use the mouse wheel to scroll on this element
Example
http://codepen.io/msorrentino/full/aOYaOM/
HTML
<div class="wrapper">
<div class="page-container">
<button class="show-side">Show Side Container</button>
</div>
<div class="side-container">
<button class="close-side">Close Side Container</button>
<div class="large-content"></div>
</div>
</div>
CSS
html,
body,
*,
*:after,
*:before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
}
.wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.page-container, .side-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 5px solid;
overflow-y: auto;
overflow-x: hidden;
-webkit-transition: -webkit-transform 0.2s cubic-bezier(0.68, 0, 0, 1);
transition: -webkit-transform 0.2s cubic-bezier(0.68, 0, 0, 1), transform 0.2s cubic-bezier(0.68, 0, 0, 1);
}
.page-container {
-webkit-transform: translate(0,0);
transform: translate(0,0);
}
.page-container-hidden {
-webkit-transform: translate(-100%,0);
transform: translate(-100%,0);
}
.side-container {
-webkit-transform: translate(100%,0);
transform: translate(100%,0);
}
.side-container-visible {
-webkit-transform: translate(0,0);
transform: translate(0,0);
}
.large-content {
height: 2000px;
}
JS
$('.show-side').click(function(){
$('.page-container').addClass('page-container-hidden');
$('.side-container').addClass('side-container-visible');
});
$('.close-side').click(function(){
$('.page-container').removeClass('page-container-hidden');
$('.side-container').removeClass('side-container-visible');
});
It gets more interesting
If you make the original "page-container" element have enough content that to force it to have overflow, then the "side-container" element no longer displays the aforementioned bug!
http://codepen.io/msorrentino/full/WvzgQZ/
Any thoughts on what is happening here are welcome, and any possible fixes would be very welcome.
Came across this question when I encountered a very similar problem with an off-screen menu that moves on-screen when toggled.
Here's the relevant HTML and CSS, simplified:
<div class="menu">
<!-- long list of menu items here -->
</div>
.menu {
position: fixed;
top: 0;
bottom: 0;
left: 0;
transform: translateX(-100%);
transition: transform ease 125ms;
}
.menu--active {
transform: translateX(0);
}
.menu--active is toggled with a button.
Though you're looking for a non-JS solution, I thought I'd post the cleanest workaround I've found in case people end up here with the same problem.
The workaround is to simply force a focus state on the div after the transition has completed. To do this, you first have to give the div a tabindex so that it can be focused.
<div class="menu" tabindex="-1">
<!-- long list of menu items here -->
</div>
(A value of -1 should keep the div out of the normal tab order.)
Then, using a bit of delayed jQuery, focus on the div. This should be invoked along with whatever logic you use to "activate" your div.
setTimeout( function() {
$('.menu').focus();
},150);
The time here is 150 milliseconds, which is just after the transition should have completed. A value equal to that of the transition duration would probably work too, but I set it longer just to be safe.
A more complete example might be:
$('.menuButton').on('click', function() {
$('.menu').addClass('menu--active');
setTimeout( function() {
$('.menu').focus();
},150);
});
Finally, you probably won't want the focus outline on the focused div, so you might choose to remove it with an outline: none in the style rule for your div. In my project, but not in the original example in the question, this actually broke focus on the div, and it went back to being un-scrollable. So I did this instead:
.menu:focus {
outline-color: transparent;
}
I forked the original example and included this solution here: http://codepen.io/johntobinme/full/MaPMgY
You have overflow-y set to auto, meaning it will create a scroll bar for off screen content. Since .large-content has such a large height, it goes off screen. Simply set overflow-y to none and this will no longer occur. Not a bug, just user error.
Related
I tend to use the following SCSS #mixin for an animation effect to let users know what is interactive on my projects.
#mixin clickAnimation($opacity: 0.5, $distance: -1px, $time: 75ms) {
opacity: 1;
transition: $time ease;
cursor: pointer;
&:hover {
transform: translateY($distance);
opacity: $opacity;
}
&:active {
transform: translateY(2px);
}
}
I'll tend to use it across the site like this:
a:not(.disabled) {
#include clickAnimation();
}
Recently I've noticed a quirky issue with this.
If the user hovers the <a> element on the bottom pixel of the <a>, the <a> will transform up to -1px. When the user clicks the <a>, the :active css state will perform (in this case, translating down to 2px), but the click action will not register. So no click handlers will fire, and no links will cause redirects.
Has anyone had this issue before and know what I could do to fix it?
As requested, here is a fiddle which demonstrates the issue: https://jsfiddle.net/bf9yk0tn/
Apparently, the DOM looses track of the element since its moving from its original position and there's nothing at the time click event occurs (somehow it manages the hover though).
You can go for a workaround like this to fill the void but Im not sure if its the best solution.
a:hover::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
height: 1px;
width: 100%;
}
Here's the update jsfiddle
I am making an application that uses a website as an interface.
The html look like the following:
setTimeout(function() {
$('#page-1').removeClass("show-me");
$('#page-2').addClass("show-me");
}, 1000);
setTimeout(function() {
$('#page-2').removeClass("show-me");
$('#page-3').addClass("show-me");
}, 2000);
div#main {
position: absolute;
min-width: 300px;
width: 100%;
height: 100%;
background-color: #ffa;
}
div#main > div {
position: absolute;
top: 0;
left: 0;
opacity: 0;
visibility: hidden;
transition-delay: 0s;
transition-duration: 200ms;
transition-property: "opacity,visibility";
transition-timing-function: ease;
}
#page-1 {
background-color: #00f;
}
#page-2 {
background-color: #0f0;
}
#page-3 {
background-color: #f00;
}
div#main > div.show-me {
opacity: 1;
visibility: visible;
}
<div id="main">
<div id="page-1" class="show-me">Page 1</div>
<div id="page-2">Page 2</div>
<div id="page-3">Page 3</div>
</div>
Each page contains data the same way as you would navigate to www.example.com/page-1, www.example.com/page-2 or www.example.com/page-3.
However I want to stay at www.example.com and navigate trough pages by fading them in and out.
I got them placed over one another with position: absolute;top:0;left:0; but this way main won't know the height of the page since it's content is absolute.
Therefore i'd like a way to make them fade in and out wiouth the use of position or negative margins (since the height of each page is dynamic due to content)
Or maybe you have another way of achieving this effect?
This is for an application, not a webpage that should be indexed by google or something else. So no SEO worries :)
EDIT:
Added a better example.
I would have to recomend jQuery Mobile library for this. It's pretty much what it was built for. I have been using it recently to make a custom app for our company and it's really quite good. Although a little bit tricky to pick up initially it's not as steep a learning curve as some other libraries I have used in the past.
(would have made this a comment, but I cant :-( )
Solved the problem by adding position: static; to the 'show-me' class.
This way the main knows the height of it's 'active' child!
When navigating first the active page class 'show-me' is removed, so it becomes position absolute again and starts to fade-out.
The next page gets the class 'show-me'.
Now becomes static so the main knows the new page's height and follows it.
And the new page fade's in as it should!
For a short moment (which you cannot see as far as I tested) the main div has no content and becomes small again. If it contains a background image you may see a little flicker but I think it's to fast for that so it shouldn't be noticeable.
I'm have a vertical stack of items to which the user can append one by clicking a button, roughly like this.
<ol>
<li><textarea></textarea></li>
<li><textarea></textarea></li>
</ol>
<a data-action="additem">Add another</a>
I'm trying to write a CSS animation so that when the new li is inserted, the "Add another" smoothly slides down to its new resting place. Fixed height on the li tags is not an option, and I'm trying to avoid using the max-height animation hack because it can have weird layout effects.
I figured out that I could animate margin-bottom from something to 0 and have the desired effect, but I can't figure out how in CSS to express that I want the current height of the element to which this rule is applied. Percentages are measured relative to the width of the element, which isn't what I need here, and I can't think of a clever trick using calc or the like to express what I want to the browser.
Suggestions?
EDIT
I'm using a template with a repeat binding to add the items to the list. The JS only pushes another object into an observable array, and the framework handles the actual DOM insertion. The li tag has on it the following CSS to get it to enter smoothly:
animation: append forwards .5s;
And append is defined as:
#keyframes append {
from {
transform: translateX(10%);
opacity: 0;
margin-bottom: _____;
}
to {
transform: none;
opacity: 1;
margin-bottom: 0;
}
}
Not currently...
I've come up against this frustrating issue a number of times, always trying to either animate a non-numeric value, access a specific property of the current element as an animation value, or animate an unspecified value to a specified one. Generally I always have to fall back to either some form of not-quite-perfect max-height animation (like you've already mentioned) or use a mixture of CSS and JavaScript/jQuery.
For your issue there are a few options, but none are exactly what you're after.
css only version (using duplicated markup and another animation)
http://jsfiddle.net/7m8F9/2/
http://jsfiddle.net/7m8F9/3/ <-- improved version using bottom and position:relative
http://jsfiddle.net/7m8F9/5/ <-- even better version, going back to translateY
One trick often used with CSS-only hacks, is to duplicate markup — in this instance, the link iteself — and place it within parent wrappers that will be turned on or off by different means. The downsides to this method are that you get a rather ugly markup, and in this particular instance a bullet-number that appears jarringly (because of having to move the opacity animation from the li to the textarea).
The benefits of this method however are that by moving the link inside the li you can use -100% on the y-axis with a translate, or another offset method. Oddly though I can't work out what translateY(-100%) is calculating based upon... it doesn't seem to be the parent height, perhaps it is the height of itself. For this reason I've updated the fiddle to use bottom and relative positioning instead, although in Firefox (on mac) this glitches briefly.
It does seem to be that translateY is calculating percentage based on it's own height, so in order to get around this problem I've had to make use of position absolute and force the the link layer to assume the same dimensions as the li... annoying, as it involves z-indexing the textarea above the link, and an internal span to offset the link text, but at least it does work.
The following code works in the latest Firefox, and would work in other modern browsers if all the different browser-prefixes were correctly used to define the animation keyframes, I don't have time to set them all up right now however.
markup:
<ol class="list">
<li><textarea></textarea><a class="add" href="#"><span>Add another</span></a></li>
<li><textarea></textarea><a class="add" href="#"><span>Add another</span></a></li>
</ol>
css:
ol li {
position: relative;
}
ol li .add {
display: none;
}
ol li:last-child .add {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 100%;
height: 100%;
display: block;
animation-duration: 1s;
animation-name: slide;
}
ol li:last-child .add span {
position: absolute;
bottom: -20px;
}
.list li textarea {
position: relative;
animation-duration: 1s;
animation-name: append;
z-index: 1;
}
#keyframes append {
from {
transform: translateX(10%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
#keyframes slide {
from {
transform: translateY(-100%);
}
to {
transform: none;
}
}
javascript version (code triggered translations)
http://jsfiddle.net/7m8F9/1/
The following obviously doesn't take into account the fact that you are using a template engine to power your DOM manipulations, but all the code needs to work properly is a before and after height of the list (to calculate the difference in height), and an event to trigger at the point where the new list item is added.
Sadly it is not yet possible to do this all in pure CSS, at least not as far as I have seen, perhaps once calc has leveled up...? Or perhaps if some way is introduced to reference the current elements dimensions, not just it's offset parent.
It should be noted I didn't have Internet Explorer around to test this with, but all other modern browsers seem happy.
markup:
<ol class="list">
<li><textarea></textarea></li>
<li><textarea></textarea></li>
</ol>
<div class="add">
Add another
</div>
javascript (with jQuery):
function prefix(){
for ( var a = ['Webkit','Moz','O','ms'], i=0, l = a.length; i<l; i++ ) {
if ( document.body.style[a[i]+'AnimationName'] !== undefined ) {
return { js: a[i], css: '-' + a[i].toLowerCase() + '-' };
}
}
return { css:'', js:'' };
}
$(function(){
$('.add a').click(function(e){
e.preventDefault();
var pref = prefix(),
link = $(this).parent(),
list = $('.list'),
lihi = list.height(),
liad = $('<li><textarea></textarea></li>').appendTo(list),
lihd = lihi - list.height();
link.css(pref.css + 'transform', 'translateY(' + lihd + 'px)');
setTimeout(function(){link.addClass('translate-zero transition-all');},0);
setTimeout(function(){
link.css(pref.css + 'transform', '');
link.removeClass('translate-zero transition-all');
},500);
});
});
css:
.transition-all {
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
-ms-transition: all 0.5s;
-o-transition: all 0.5s;
transition: all 0.5s;
}
.translate-zero {
-webkit-transform: translateY(0) !important;
-moz-transform: translateY(0) !important;
-ms-transform: translateY(0) !important;
-o-transform: translateY(0) !important;
transform: translateY(0) !important;
}
.list li {
animation-duration: 1s;
animation-name: append;
}
#keyframes append {
from {
transform: translateX(10%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
redesign version
A number of times I have hit a similar issue, only to find a redesign helps do away with the problem and can often actually improve usability. In your case it may be best to place the "add link" above the list (or top right), or integrate the button as a floating icon somewhere... where-ever you put it, it is best to try and keep it in a static location, moving interaction points can be annoying for users, especially if they wish to add more than one item in quick succession.
The simplest solution that i could think of is this.
When you add a new li element, just append it in the dom.
liMarkup = '<li><textarea></textarea></li>'
$('ol').append(liMarkup);
$('ol').find('li').last().css('display','none');
$('ol').find('li').last().show('fast');
This would work as per your requirement :) I hope it helps.
Working Jsfiddle
EDIT: Its easy and better to do it in JS.
In Yahoo mail, when you are writing an email and you drag a file onto the page and hover, the message area becomes highlighted. It can be seen here:
The part of this that I don't get is how to have the blue area appear with partial opacity over the things under it that are normally visible.
With:
#blueBox {
background-color: #FFD090;
opacity: 0.0;
}
If the msgContent is a child of blueBox:
<div id='msgBox'>
<div id='blueBox'>
<div id='msgContent'>
... all the message contents, buttons, etc.
</div>
</div>
</div>
and when msgBox is hovered I increase blueBox opacity from 0 to say 0.6, the blueBox will show but the msgContent div is hidden until the hover event. It should be visible always.
If the msgContent div is not a child of blueBox, then the blueBox doesn't cover it.
I've tried rgba (http://jsfiddle.net/mkasson/nJcxQ/19/) like here on SO, but it doesn't cover over the child elements.
Couldn't do my usual watching/inspecting via browser's webdev tools because focus was never on the browser while dragging the file onto it.
Thanks!
Here is how I would go about this,
(What the problem is, you are using the parents background. You can't make the parents background go over it's content, that is not what a background does. It merely sites behind everything it is containing and acts as a background.)
html,
<div class="messageContent">
<span class="overlay"></span>
<p>Darn fanatically far and tarantula jeepers meek a secret much so hence underneath monogamously interwove apart gosh spilled far where and badger.</p>
This is a link
</div>
css,
.messageContent {
color: #000;
position: relative;
height: 100%;
width: 100%;
}
.overlay {
position: absolute;
top: 0;
left: 0;
background: lightBlue;
opacity: 0;
height: 100%;
width: 100%;
display: block;
z-index: 100;
}
.messageContent:hover .overlay {
opacity: 0.6;
}
What I am doing is placing an absolute span tag inside of the parent to act as the color overlay. When the parent is hovered the overlay child will become active by increasing it's opacity.
JSFIDDLE
Here's how I would do it.
<div id='msgBox'>
<div id='blueBox'>
</div>
<div id='msgContent'>
... all the message contents, buttons, etc.
</div>
</div>
CSS
#blueBox {
background-color: #FFD090;
opacity: 0.0;
position: absolute;
top: 0;
left: 0;
}
jQuery
$("#msgBox").hover(function(){
$("#blueBox").css({top:$(this).css("top")}).height($(this).outerHeight()).width($(this).outerWidth()).animate({opacity:0.6});
},function(){
$("#blueBox").animate({opacity:0}).height(0).width(0);
});
http://jsfiddle.net/54cx7/2/
The problem is that since content is a child of bluebox, then it inherits the 0 opacity.
I've run into a rather strange problem. I have a div that is rotatable via CSS3. The div has a front div child and back div child, with the back div having -webkit-transform: rotateY( 180deg ) set.
The problem that once the parent element is rotated to display the back side of the div, it will only detect clicks of child elements on exactly one side of the div, specifically the second half of the div or right side. The front side div detects clicks on the entire face of element. Also, the z-indexes are fine. I assume that the issue may be due to the rotation and the browser displaying one half of the side "closer"?
The code that this is breaking is extremely complex, so I created a test file to demonstrate the problem below. I'm using a jQuery plugin I wrote for the 3D transformations, which can be found here https://github.com/pwhisenhunt/jquery.transform/blob/master/jquery.transform.js.
Edit: After experimentation, the clicking of the button element is only registering from 100-200px and not from 0-100px. In other words, it is in fact only registering on the second half of the div.
Any help is very much appreciated!
<html>
<head>
<style>
.element{
width:200;
height:200;
-webkit-perspective: 800;
-webkit-transform-style: preserve-3d;
}
.element figure {
display: block;
height: 100%;
width: 100%;
position: absolute;
-webkit-backface-visibility: hidden;
border:1px solid yellow;
}
.element .front {
-webkit-border-radius:8px;
padding: 0px;
margin: 0px;
background-color:yellow;
z-index: 9870;
}
.element .back {
-webkit-border-radius:8px;
padding: 0px;
margin: 0;
-webkit-transform: rotateY( 180deg );
z-index: 0;
border: 1px solid red;
background-color:green;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script src="https://raw.github.com/pwhisenhunt/jquery.transform/master/jquery.transform.js"></script>
<script>
$(function(){
var temp = false;
$(".element").click(function(){
if(temp == false){
$(this).transform("setAnimationDuration", 1).transform("rotateY", 180);
$(this).unbind("mouseenter mouseleave");
button = $(document.createElement('div')).attr("id", "button").css({ width: 200, height: 50, backgroundColor:"blue" });
button.click(function(){
console.log("Clicking");
});
temp = true;
$(this).append(button);
}
})
})
</script>
</head>
<body>
<div class="element">
<figure class="front"></front>
<figure class="back"></front>
</div>
</body>
</html>
A JSFiddle Example of the Problem - Can be found HERE!
I know this reply is a bit too late for most of us here, but I ran into this problem earlier today, and none of the replies helped me solve it.
Solution by #kristiankeane made the other half non-clickable. I was using a container for the wrapper as well. Turns out, it's an odd bug in webkit, and I was able to fix it and make 100% of the element clickable by changing transform: rotateY(180deg) to transform: rotateY(-180deg)
It's really odd, and I don't know how it worked, but it did. I hope this helps someone!
I had this exact same issue, was able to fix it by slightly changing the parent rotation when flipped - I changed
`.flip-holder.flipped {
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
transform: rotateY(180deg);
}`
to
`$.flip-holder.flipped {
-webkit-transform: rotateY(180.5deg);
-moz-transform: rotateY(180.5deg);
transform: rotateY(180.5deg);
}`
and the entire backface (plus overflowed elements positioned absolutely) were now clickable, and the browser did not render the extra 0.5deg of rotation so text and images are clear.
Translate both front and back just a little bit and they won't overlap.
Example:
.element .front {
-webkit-transform: translateZ(1px);
}
.element .back {
-webkit-transform: rotateY(180deg) translateZ(1px);
}
it seems that you are missing a container (in much the same way I was missing it).
see the official documentation
it's not the outer element being flipped, but a wrapper inside it. that in turn causes one of two divs to be displayed (and the transition to occur)
If your flip card structure is like this:
<div class="flipcard">
<div class="flipcard-front">
</div>
<div class="flipcard-back">
</div>
</div>
then add this to your CSS:
.flipcard:hover {
pointer-events: none;
}
.flipcard-back:hover {
pointer-events: auto;
}
could It be (and I'm just speculating) that you should use a live or delegate event bind instead of the regular. I'm speculating the click event maybe 'remembers' some how the original div position without the rotating.
After all tricks as rotate to back and rotate to 180.5 and other...
problem fixed only the following way:
When the rotation ends - create new element, clone html from rotated element, and insert new element instead of old