I have an element which is acting as a button with a little Javascript and CSS. I'll strip it down to the most bare example, so you can see the problem. The issue originates from the fact that the element is scaled down when it's clicked. Javascript interprets the clickable area of the button as its scaled down size, not the original size. This occurs in all modern desktop browsers.
Here are the important parts. HTML:
<div id="refresh">more</div>
CSS:
#refresh {
background-color: #FFF;
cursor: pointer;
transition: all 150ms ease-out;
}
#refresh:active {
transform: scale(0.8);
}
JS:
var refreshBtn = document.getElementById("refresh");
function newImg() {
// updates an image elsewhere
}
// an event listener based on
// http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
addEvent(refreshBtn, 'click', newImg);
So my image gets updated when I click on the area occupied by the scaled down button, defined by transform: scale(0.8). If I click outside of that area, in the outer 20% of my button, my JS does not update the image. The proper click transitions occur and the cursor displays correctly as a pointer, but the JS does not count this area as part of the onclick event.
This was covered here, but I find the solution unappealing:
Non-clickable area on transforming anchor
The same solution is offered here:
increasing clickable area of a button
Here's the CSS I used as outlined in those answers:
#refresh:before {
position: absolute;
content: '';
top: -12%;
right: -12%;
left: -12%;
bottom: -12%;
}
These ensure that Javascript now recognizes a bigger clickable area instead of the scaled-down area, but in turn the pointer and the CSS hover effects now react to hovering and clicking well outside the original button element. I consider it an ugly solution. Surely someone else has run into this problem before. Are there any nicer solutions?
Update: Here is a jsfiddle of the situation I've explained: http://jsfiddle.net/cx9ur44e/4/
To solve the issue of the size, you would need to add the click even to a wrapper of the button that will keep the size even if the button is active.
<div id="wrapper>
<div id="refresh">more</div>
</div>
Related
I am a bit new to CSS and I know there are more topics like this around. But none seem to be the solution for my problem. So after 2 hours of trying all sort of hidden, transition, display etc and with the risk of posting a duplicate here is my question.
How do I make this modal show up smooth using CSS and Javascript?
The CSS
/* The Modal (background) */
.modalestate {
visibility: hidden; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
left: 25;
top: 15;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
transition: all ease 1s;
}
/* Modal Content/Box */
.modalestate-content {
background-color: rgba(0,0,0,0.0);
margin: 12% auto; /* 15% from the top and centered */
padding: 22px;
float:left;
width: 550px; /* Could be more or less, depending on screen size */
transition: all ease 1s;
}
/* The Close Button */
.closeestate {
color: #aaa;
float: right;
font-size: 20px;
font-weight: bold;
}
.closeestate:hover,
.closeestate:focus {
color: whitesmoke;
text-decoration: none;
cursor: pointer;
}
The divs to show the modal and its content:
<div id="mymodelestate" class="modalestate">
<div class="modalestate-content">
<span class="closeestate">×</span>
<div id="responsecontainer" align="center"></div>
</div></div>
The Javascript:
<script>
// Get the modal
var modal = document.getElementById("mymodelestate");
// Get the button that opens the modal
var btn = document.getElementById("btnestate");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("closeestate")[0];
// When the user clicks on the button, open the modal
btn.onclick = function() {
modal.style.visibility = "visible";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.visibility = "hidden";
}
// When the user clicks anywhere outside of the modal, close it
window.addEventListener('click', function(event) {
if (event.target == modal) {
modal.style.visibility = "hidden";
}
});</script>
Thanks in advance guys !
What kind of "transition" are you trying to do? What effect do you want to apply to your modal? It's not very clear, but I'm going to guess you are trying to have the modal fade in and fade out slowly as the user clicks the buttons. This assumption comes from the fact you are using visiblity:hidden/visible.
If you are trying to have a fade-in/fade-out effect, you need to set the opacity to 0 instead:
opacity: 0;
And when you want to display it, you set opacity to 1.
However, you are going to run into many other issues. Though, I will say this will be a good learning exercise to familiarize yourself with how elements in HTML work and their interactions with CSS.
EDIT: As promised from my comments, I'll provide an example here and some advice.
First, you have the BODY. This BODY, is literally like a human body. You attach elements to it (or human parts). You have this down pretty good, you even use the z-index so I won't go over this too much. I know more "advanced" devs are going to say something about the DOM blah blah it's not attached yada yada, but we're going to keep it simple here.
Next is that the elements all have a initial attribute associated to them. For example, a DIV element has inline-block as an initial attribute. P element tag has some margin and is a block element. Etc etc. You can obviously override these with CSS or add extra attributes as you have been doing. By giving an element a CLASS, you are creating your own custom element of sorts (though it is still it's base element, DIV, P, A, SPAN, etc)
Next is understanding all of these attributes. You seem to know a good deal amount of attributes so I won't go over much, but I will go over these:
Visibility - The element still exists on the BODY. It's there, it still touches everything and affects everything around it. Think of it as an invisible arm on a human body. You can still use that arm and touch things, make things move, push things away, etc... It's just literally invisible. The GPU or whatever is driving graphics will simply NOT render this element.
Opacity - Similar to visibility, but you get some more control. Opacity of 1 (or 100%) means the element is completely visible. An opacity of .5 or 50% means the element is only half seen. That means things behind it can be seen through it. The GPU is still rendering this element but you can now include transparency. 0 means it has complete transparency (basically it's invisible).
Display - This is used to set how an element behaves in your body and how it interacts with other elements. You will often see or even use "display: none" which makes it seem like the element does not exist anymore (it's still there in HTML, though). It will no longer affect anything around it.
Now, what's more important is to understand some of the more complexities of these attributes. In your case, you should know about transitions. A transition attribute allows you to modify the browser's handling of attribute manipulation on an element. In simpler terms, as you know, it lets you create effects on elements, such as fading in, fading out, movement, etc. And it comes out nice and smooth (if done correctly).
However, these attributes that are being manipulated occur instantly. Thus, as mentioned, transitions give you that control to make it smooth. HOWEVER, it is important to note that these transitions will only work when an element already has attribute values to be manipulated. For example:
.MyDivClass{
height: 32px;
width: 32px;
transition: all .3s ease;
}
.MyDivClassExtra{
height: 64px;
width: 64px;
}
The div will seem to grow larger over .3 seconds. That is because my height and width are set. If I did "NOT" set width/height or even set it to atuo, it will just happen instantly. Because there was no attribute to be manipulated! Even setting height/width to 0 will work, because at least it has an attribute to work with.
You have to sometimes set aside common sense when it comes to programming. Things like Visibility you'd assume if you turn it on and off with transition, it'll fade in nicely. However, no. Visibility is simple ON or OFF. There is nothing to transition into. With opacity, it is not just simply ON or OFF. There are 101 numbers (infinite actually, I guess...) to transition from. 0% to 100%. You can do decimals, too. The same is true with display. A little more complicated but simply put - there is only ON or OFF with display.
Some other notes on your code is that your .modelstate element is on top of everything. Your users won't be able to click anything because of this. Visibility hidden does not make it unclickable. Like I mentioned, it simply makes it invisible - it's still there affecting everything else.
I am guessing no, but it would be really sweet to be able to set the z-index of the cursor with CSS or Javascript.
Let's say you've got some buttons and you want to add a semi-transparent image on top of the buttons for effect. Or in my current case, some SVG paths that have hover and click actions. If I could set the button or SVG z-index to 0, my cursor's z-index to 1 and the image overlays z-index to 2, that would be pretty sweet! The mouse would be going under the overlay and still be able to click on the buttons. It would be even more spectacular to set the visual z-index (which layer the cursor appears to be), separate from the effective z-index (which layer the cursor actually is). So the cursor could appear to be on top of the overlay, but still be able to click on the buttons underneath.
I have my doubts, but I thought I would check if anyone has heard of someone doing this or something like it.
Since no answer has been accepted, I want offer the right answer.
The pointer-events: none is the solution.
See simple CSS example:
.emotion_message {
pointer-events: none;
background-color: rgb(144,238,144,0.5);
height: 20%;
width: 94%;
position: absolute;
top: 40%;
color: darkgreen;
padding: 1%;
text-align: center;
border-radius: 10px;
margin-left:3%;
margin-right:3%;
}
In this example, I wanted to display a chart, with a static summary box over the top, but I wanted the cursor to interact with the chart underneath. I also added opacity to the background-color, so the user can both see and interact with the submerged element (in this case the chart). Now the user sees the box, but the cursor does not.
Thanks #FabricioMatte for this answer in the comments.
You can play with the cursor:none;
See a related Q: Is it possible to put the mouse cursor behind an element or does the mouse cursor have an z-index?
There is no such thing as a cursor z-index.. what you can do is have a jQuery hover function that gets the object that the cursor is hovering over, which in return allows you to find the objects z-index. So really instead of wanting a cursor to have z-indexes, just have hover states.
Then have custom cursors depending on location. Which as everyone is saying cursor:none would be fun to play with for this. Say you want to go under a alpha block, you could just render a cursor under that alpha block to get the effect of the cursor being under it.
EDIT: Thanks for a lot of great examples on how to solve these. I cant decide between who to accept yet, but I will go though all examples and see which I like the most. Great feedback guys! =D
I normally do these kind of things in flash, but this time it has to be compatible with mac, iPads and all those units too.
So, what do I need help with?
I've got a picture, with some "hotspots" on. I want to be able to click any of those hotspots to show some information.
This should be fairly basic and easy to achieve, but since I've never done this in html before I have to ask you guys =)
So, what would be the best way to do this? It have to be compatible with any browser and device, and it doesnt need to be very advanced. If it's possible to add effects to the box (sliding out, fading in, or anything like that) then thats a nice bonus, but not something I need.
Any help would be great!
BREAKDOWN:
I have a background image with some "hotspots" (numbers 1 and 2 in my example). The users should be able to either hover the mouse over any of these or click it to get more information, as seen in picture #2
This is that happens when you hover/click any of these hotspots.
Text and image is displayed inside a nice little info box.
If the user clicks "more information" it will open up even further to display more information if available. Like in this img:
I don't think the Javascript approach is really necessary here. I created a little CSS-only mock-up for you on JSBin.
Basically the point is that you enclose the image in a relatively positioned div, then absolute position the hotspots inside the same div. Inside the hotspots divs you will have the more info elements, showing only on :hover of their parents.
This makes it simple, and far more accessible.
Update: cropping the image equally from both sides
If you want to keep the image centered and still not use any javascript, you could set the required image as a background-image of the container, and setting its background-position parameters to center center.
You would have to make sure that the width of this div is set to the width of your image, and the max-width to 100%, so that when the window gets resized below the image width it stays at the center.
Now, a problem that I encountered here is how to make the hotspots stay center relatively to the image. I solved it this way:
I created a wrapper div for the hotspots with these characteristics:
margin: 0 auto;
position: relative;
width: 0px;
This basically makes sure that the wrapper div finds the center of our image. Then, you would position the hotspots relatively to the top-center position of the image, instead of the top-left as a starting point.
Then you have what you are looking for.
Working demo
Here's another approach, and in my opinion far superior to using a map or excessive JS. Place <div> elements on top of the element with the background-image and have HTML and CSS do the heavy lifting for you.
See it on JSFiddle
HTML
The HTML should seem pretty each enough to understand, we create <div>s with the class hotspot and rely on certain things being present. Namely .text (to show digit), .hover-popup (to show on hover) and .click-popup (which is inside .hover-popup and is shown when clicked).
<div id="hotspot1" class="hotspot">
<div class="text">1</div>
<div class="hover-popup">
I was hovered!
<div class="click-popup">
I was clicked on!
</div>
</div>
</div>
<div id="hotspot2" class="hotspot">
<div class="text">2</div>
<div class="hover-popup">
I was hovered!
<div class="click-popup">
I was clicked on!
</div>
</div>
</div>
CSS
This is where most of the magic happens, see the comments for further explanation.
/* These two position each hotspot */
#hotspot1 {
left:15%; /* we could use px or position right or bottom also */
top:20%;
}
#hotspot2 {
left:35%;
top:25%;
}
/* General styles on the hotspot */
.hotspot {
border-radius:50%;
width:40px;
height:40px;
line-height:40px;
text-align:center;
background-color:#CCC;
position:absolute;
}
.hotspot .text {
width:40px;
height:40px;
}
/* Show the pointer on hover to signify a click event */
.hotspot .text:hover {
cursor:pointer;
}
/* hide them by default and bring them to the front */
.hover-popup,
.click-popup {
display:none;
z-index:1;
}
/* show when clicked */
.hotspot.clicked .click-popup {
display:block;
}
/* show and position when clicked */
.hotspot:hover .hover-popup {
display:block;
position:absolute;
left:100%;
top:0;
width:300px;
background-color:#BBB;
border:1px solid #000;
}
JavaScript (with jQuery)
Unfortunately you're going to have to use some JavaScript for the clicking part as CSS doesn't have a 'clicked' state (outside of hacks with checkboxes). I'm using jQuery because it's dead easy to do what I want.
$(document).ready(function () {
$('.hotspot').click(function () {
$(this).toggleClass('clicked');
});
});
Creating the arrow
Over at css-tricks you can find a tutorial for attaching an arrow to a element using the :before and/or :after pseudo-elements. You can even 'simulate' a border around them by placing the :after element on top of the :before. But yea, lots of resources on how to do this.
You should be able to use the onclick or OnMouseOver event in the map area (define the href as "").
An example using OnMouseOver is here: http://www.omegagrafix.com/mouseover/mousimap.html
Give a class for that image in html (Ex: imgclass). And in javascript(using jquery), build that hover box in html format and bind it to 'mouseover' event of that image.
For example:
function bindhtmltoimage() {
myimg = $('body').find('.imgclass');
divSlot.each(function (index) {
$(this).bind('mouseover', function () {
try {
//position the hover box on image. you can customize the y and x axis to place it left or right.
var x = $(this).offset().left;
var y = $(this).offset().top;
var position = $(window).height() - ($("#divHover").height() + y);
var widthposition = $(window).width() - ($("#divHover").width() + x);
if (position < 0 || widthposition < 0) {
if (position < 0) {
$("#divHover").css({
position: 'absolute',
left: x + 20,
top: y - $("#divHover").height() - 20
});
}
if (widthposition < 0) {
$("#divHover").css({
position: 'absolute',
left: x - $("#divHover").width(),
top: y + 20
});
}
}
//build your html string for that hover box and apply to it.
$('#divHover').html("your Html content for that box goes here");
$('#divHover').show();
//if you want the box dynamically generated. create the html content and append to the dom.
}
catch (e) {
alert(e)
}
});
});
}
it will work fine in desktop and mobile. if you face any problem in touch devices, bind the function to click event instead of 'mouseover'.
Also, for map approach, i strongly recommend SVG instead of images.
i have a button in asp.net like below :
<asp:Button ID="btnSaveInrpvEdit" CssClass="btnSaveInrpvEdit" runat="server"
Text="" ValidationGroup="B" onclick="btnSaveInrpvEdit_Click" />
and it's css :
.btnSaveInrpvEdit
{
background: url(/Images/Admin/btnSave.png) no-repeat left top;
width: 155px;
height: 63px;
border: 0px;
outline: none;
}
.btnSaveInrpvEdit:hover,.btnSaveInrpvEdit:active
{
background: url(/Images/Admin/btnSave_Hover.png) no-repeat left 1px;
cursor: pointer;
outline: none;
}
so every thing is ok about it's hovering...
at this time i want to implement this button behaviour about left mouse HOLDING and RELEASING on it!
if you attention to regular buttons in asp.net u will see when left mouse is clicked and holded on that button , so it seems it's text has been moved a bit...
also when we release left mouse, that button goes back to normal mode!
how can i do this job with css and javascript?
thanks in advance
First, note that the text moving (and if the text moves) in the pressed button has nothing to do with the <asp:Button (or the input element it renders) directly. The button styles and visual behaviour depend to a small part on the browser and to a large part on the windows version and theme the client uses. Manually moving the background image could look very weird on themes that don't actually move the text.
That said, you can emulate the behaviour relatively easy with JavaScript respectively jQuery in particular.
Something like this should work:
CSS (I used normal style here because pressing usually removes the hover style)
.btnSaveInrpvEdit.mousedown
{
background: url(/Images/Admin/btnSave.png) no-repeat 1px 1px;
}
JS + jQuery
$("#btnSaveInrpvEdit").mousedown(function () { $(this).addClass("mousedown"); });
$("#btnSaveInrpvEdit").mouseup(function () { $(this).removeClass("mousedown"); });
You probably also have to handle the user pressing the button but then holding and dragging the cursor away from the button, which causes the button to un-press visually but will also return to the pressed state if you move the mouse back over the button. This is a bit more tricky but I'm sure you got the gist of it and can work something out ;)
As a quick fix to at least prevent the button background staying offset forever you can add
$("#btnSaveInrpvEdit").mouseleave(function () { $(this).removeClass("mousedown"); });
I have a calendar, and when the user hovers over a cell, a large-ish info box appears with details for that date. I am having some trouble though making the info box disappear when the user moves away.
I basically want it so that when the mouse cursor moves out of the calendar cell which is hidden by the info box it will disappear. But I'm having trouble with this because mouseenter and mouseleave get messed up by having the info box as the top element.
So I tried to get around this by using "placeholder" divs that are transparent, have the same shape and location as the calendar cell beneath it, and have a z-index of 1000 so they are above the info box. I then apply the mouseenter and mouseleave events to these divs instead.
There's two problems with this though. One, I have now messed up my HTML semantically. The divs have no purpose but to get around what seems to be a limitation. And secondly, they mess up my jQuery UI selection (I've applied it to the calendar cells - a click no longer selects a cell).
Is there a clean way to handle displaying an info box? There will be no user interaction with the info box -- it's just to display information.
EDIT: Here is some code:
<li>
<div class="day-content">
</div>
<div class="day-content-placeholder">
</div>
</li>
and CSS
li
{ position: absolute; width: 15%; height: 20%; top: ... left: ... }
.day-content
{ position: absolute; width: 100%; height: 100%; }
.day-content-placeholder
{ position: absolute; width: 100%; height: 100%; z-index: 1000; }
.popup
{ position: absolute; width: 300%; height: 300%; left: -150%; top: -150%; z-index: 500; }
and Javascript
var popup;
$('.week-content-placeholder')
.mouseenter(function()
{
popup = $('<div class="popup">'+a_lot_of_text+'</div>').insertAfter(this);
})
.mouseleave(function()
{
popup.remove();
});
That's not the exact code, but you get the idea. This works okay, but like I said, since .week-content-placeholder is above .week-content, the selection capability with jQuery UI doesn't work properly on .week-content.
You could modify your solution with the transparent "placeholder" divs in the following way:
Have the "placeholder" dive underneath the "calendar cell", using {zIndex: -1}.
When you enter a calendar cell, unhide the large "content" div and set {zIndex: 1000} on the "placeholder" div to bring it to the top.
Have a "mouseout" event on the placeholder div that will hide the "content" div and set {zIndex: -1} for the the "placeholder" cell.
Rather than create the "placeholder" cells in the HTML, you could create one in the javascript and move it to the postion of each "calendar" cell as you "mouseIn" it. You could also duplicate any "click" events on the "calendar cell" onto this one as well.
Let me know if this works.
The trick here is to make the info box a child of the cell:
<div id='box'>
Normal content
<div id='inner'>
This big box obscures everything in the cell!
</div>
</div>
The inner box is hidden until the hover occurs. Notice how with CSS we can make the box bigger than the cell itself with negative margins.
#box
{
width:100px;
height:100px;
margin:100px;
border:solid 2px darkblue;
position:relative;
}
#box #inner
{
display:none;
position:absolute;
background-color:#eeee00;
top:-10px;
left:-10px;
width:120px;
height:120px;
}
And you can use normal jquery hover because the hover covers box the box and it's child:
$('#box').hover(function(){
$('#inner').show();
},function(){
$('#inner').hide();
});
Here's it running:
http://jsfiddle.net/RbqCT/
You can create the info box dynamically as you do in your code.
Here's 15 different plugins that let you do this with jquery:
http://www.webdesignbooth.com/15-jquery-plugins-to-create-an-user-friendly-tooltip/
You could track mousemouse and use the offsetLeft + width and offsetTop + height of your hover trigger against the event.pageX and event.pageY to compare.
If you make this work as you described a tiny mouse movement that remains within the calendar cell (which is not even visible) leaves the popup in place, but a slightly larger movement that exits the cell makes the popup disappear.
The user sees only movement within the popup itself — small movement within the popup leaves it in place; large movement makes it go away.
I suggest triggering the disappearance of the popup on exiting the popup div itself. Any movement that remains within the "tip" panel leaves it up. I think that (1) this is better usability and (2) it avoids the whole problem with the obscured calendar cell event handling.
You could do that by adding a .mouseleave() handler to the div when you create it.