position a border around focused element - javascript

I want that the focused element (mostly using the tab key navigation) appears with a surrounding rectangle the size of the element. I created the appropriated div in html with the appropriate css for border color and a display none at the beginning of the navigation. I am trying to change the display with jquery (the size and the position) but something is going wrong.
jQuery('*').focus(function () {
var position = jQuery(this).offset();
var width = jQuery(this).width();
var height = jQuery(this).height();
console.log(jQuery(this).width(), jQuery(this).height(), position);
jQuery('#focuser').fadeOut(0); //to have the div disappear if it is on other element
jQuery('#focuser').css({width: '2px', height: '2px'}); //to get an enlarging effect
jQuery('#focuser').offset({top: position.top, left: position.left});
jQuery('#focuser').fadeIn(100, function () {
jQuery('#focuser').animate({width: width, height: height}, 200);
});
console.log(jQuery('#focuser').width(), jQuery('#focuser').height(), jQuery('#focuser').offset());
});
The position retrieve of jQuery(this) is correct but when I set it to offset, it seems to add the value instead of replacing it. Am I missing something ? Is that the correct way to manage it (a full css solution with pseudo element :focus does not work as the border is added to the element size and destroys the page display, the border needs to have an animation ) ?
#focuser {
border: 2px $second-font-color solid;
display: none;
position: absolute;
}
Thanks for any help

I think I found the solution but I do not understand why it is like that. I put the fadeout before the variables setting and it looks to work.
jQuery('*').focus(function () {
jQuery('#focuser').fadeOut(0);
var position = jQuery(this).offset();
var width = jQuery(this).width();
var height = jQuery(this).height();
jQuery('#focuser').fadeIn(0);
jQuery('#focuser').css({width: 0, height: 0});
jQuery('#focuser').offset({top: position.top, left: position.left});
jQuery('#focuser').animate({width: width, height: height}, 200);
});

You can use a basic css :focus selector without using JQuery. See W3Schools for more info.
You'll need to give a border of the same size to the element before it's focused, you can give it the same color as the background. Otherwise the border will take extra space and destroy your layout as explained here. You can also set the margin to 2px and remove it when the item is focused, that way it still enlarges.
Check this Fiddle to see what I mean: jsfiddle.net/GillesCoeman/30vhjtdh/3. It also uses CSS transition to add the effect.
If this is not exactly what you are looking for you could also use a combination of this and jQuery.

Related

Javascript: Check collision between two divs

Is there any way to check, if DIV with name for example "character" is overlaping DIV with name "ground" ?
I want to do this with clean Javascript, I know that jQuery is better, but that's what I don't want.
I saw this post: check collision between certain divs? , but it does not return anything.
Thanks for help.
First, I'd suggest you check out the HTML5 canvas element, as by the sounds of it, you want to make a game, and the canvas is great for that ;)
But, to answer your question, you could create or get div elements with document.createElement() or getElementById() respectively, and get their style properties either by getting their JS-set values (element.style) or use getComputedStyle if you'd prefer to set initial values in CSS.
Make sure that, however you get these CSS properties, they'll need to be parsed into something that JS can digest. For integer-based positions, parseInt() usually does the trick.
Next, you do the math. In this case, you'd want to see if the character div's top, plus its height, is greater than the top position of the ground. If it is, it has collided.
To set the style back to the div, you can just set the style property.
Here's an example (copied from this fiddle):
var character = document.getElementById("character");
var ground = document.getElementById("ground");
//We could use getComputedStyle to get the style props,
//but I'm lazy
character.style.top = "10px";
character.style.height = "40px";
ground.style.top = "250px";
//For every 33ms (about 30fps)
setInterval(function(){
//Get the height and position of the player
var charTop = parseInt(character.style.top),
charHeight = parseInt(character.style.height);
//and the top of the ground
var groundTop = parseInt(ground.style.top);
//linear gravity? Why now?
charTop += 5;
//If the character's bottom is hitting the ground,
//Stop moving
if(charTop + charHeight > groundTop) {
charTop = groundTop - charHeight;
}
//Set the character's final position
character.style.top = charTop + "px";
},33);
#character {
position: absolute;
width: 40px;
height: 40px;
left: 50px;
background-color: #F00;
}
#ground {
position: absolute;
width: 300px;
height: 60px;
left: 0px;
background-color: #A66;
}
<div id="character"></div>
<div id="ground"></div>
One more thing: While there are convoluted ways to get element positions when elements use different positioning properties (ex: the player uses top/left coordinates, where the ground uses bottom), it's a lot harder to manage.
The only jQuery that was being used in that linked answer was to get with width,height, and position of the divs, which are somewhat trivial to retrieve using pure JS:
CSS / JavaScript - How do you get the rendered height of an element?
jquery position() in plain javascript
How do I retrieve an HTML element's actual width and height?
It's not returning anything because the .top .left and height variables in the return statement were relying on jQuery functions that retrieve the information mentioned above.

Get real width of elements with jQuery

I am writing a validator for "visual correctness" of html files. The goal is to detect too wide elements.
Here is a demo of my problem.
The dotted red line is an indicator of the max width of the document (200px in this example). The first paragraph is fine, but the second is too wide. Nevertheless, all of the following commands still return "200px" as the width:
// all return 200, but the value should be larger
$('#two').width();
$('#two').outerWidth();
$('#two').prop('clientWidth');
Please see the Fiddle for more details.
How can i detect such oversized elements?
Updated question: Better to ask, how can i detect text that exceeds the borders of their parent elements?
Updated requirement: I am not allowed to change anything in the source HTML or CSS. But i can do anything i want with jQuery to modify the document, so that i can detect those too wide elements.
As others have said, temporarily wrap the text node in an inline element.
var two = document.getElementById('two'),
text = two.firstChild,
wrapper = document.createElement('span');
// wrap it up
wrapper.appendChild(text);
two.appendChild(wrapper);
// better than bad, it's good.
console.log(wrapper.offsetWidth);
// put it back the way it was.
two.removeChild(wrapper);
two.appendChild(text);
http://jsfiddle.net/vv68y/12/
Here is a getInnerWidth function that should be useful to you. Pass it an element and it will handle the wrapping and unwrapping.
function getInnerWidth(element) {
var wrapper = document.createElement('span'),
result;
while (element.firstChild) {
wrapper.appendChild(element.firstChild);
}
element.appendChild(wrapper);
result = wrapper.offsetWidth;
element.removeChild(wrapper);
while (wrapper.firstChild) {
element.appendChild(wrapper.firstChild);
}
return result;
}
http://jsfiddle.net/vv68y/13/
scrollWidth will do it:
$("#two").get()[0].scrollWidth
or
getElementById("two").scrollWidth
this outputs 212px, the real width you are looking for.
This effect is called "shrinkwrapping", and there's a couple of ways to determine the "real" width of the element.
Float
One of the ways that you can use is to float your <p> element which will force it as small as possible, but you'll need to use a clearfix if anything inside your div is floating:
#two { float: left; }
Inline-block element
Inserting an inline element should work.
<p>content</p>
would become
<p><span>content</span></p>
Absolutely positioned element
Changing the element position to be absolute should also work:
#two { position: absolute; }
If you can't statically change the markup or the style, you can always change them dynamically through JavaScript.
(absolutely positioned element)
var realWidth = $("#two").css("position", "absolute").width();
(float)
var realWidth = $("#two").css("float", "left").width();
(inline-block element)
var t = $("#two").html();
var realWidth = $("#two")
.empty()
.append($("<span>").html(t))
.width();
Apply word-wrap: break-word; to it.. so the word will break and there won't be any text going out of the container... btw you can't check the width of the text which is going out of the container.
Example
Update: You can check if the width of text in it is bigger than the width of the container like this
As others have pointed out, changing the position of the element to absolute also works.
Doing this will result in an inline-style which can mess with your css afterwards if you don't watch out. Here is a solution to get rid of the inline style again.
//Change position to absolute
$('#two').css("position", "absolute");
var textWidth = $('#two').width();
//Get rid of the inline style again
$('#two').removeStyle("position");
//Plugin format
(function ($) {
$.fn.removeStyle = function (style) {
var search = new RegExp(style + '[^;]+;?', 'g');
return this.each(function () {
$(this).attr('style', function (i, style) {
return style.replace(search, '');
});
});
};
}(jQuery));
The element itself is constrained to 200px, but the text inside spills out. If you insert a span (or any other inline element) inside the P tag it works fine.
http://jsfiddle.net/will/vv68y/5/
Hope that helps :)

How to keep jQuery function from moving elements all the way to the left?

I was able to implement the solution posted here ("position: fixed and absolute at the same time. HOW?") to get a div element to move with the rest of the page horizontally, but stay fixed vertically. However, this solution causes the selected element to move ALL the way to the left of the page (with what appears to be a 20px margin). I'm still new to javascript and jQuery, but as I understand it, the following:
$(window).scroll(function(){
var $this = $(this);
$('#homeheader').css('left', 20 - $this.scrollLeft());});
takes the selected element and, upon scrolling by the user, affects the CSS of the element so that its position from the left becomes some function of the current scrollbar position adjusted by the 20px margin. If this is correct? And if so, can anyone think of a way that I could change it so that instead of moving the selected element all the way to the left side of the window, we only move it as far left as my default CSS position for the body elements of the HTML document (shown below)?
body {font-size:100%;
width: 800px;
margin-top: 0px;
margin-bottom: 20px;
margin-left: auto;
margin-right: auto;
padding-left: 20px;
padding-right: 20px;}
EDIT: Here is a jsfiddle (code here) that I made to illustrate the issue. My page is designed so that when it is displayed in full-screen or near full-screen mode, the #homeheader element appears centered horizontally due to its width and the left and right margins being set to auto. As the page gets smaller and smaller the margins do as well, until they disappear altogether and are replaced by the padding-left and padding-right settings of 20px. So at this point (when the window is small enough that the margins disappear altogether), which is what the jsfiddle shows, the code appears to work as intended, but when the window is full-sized the JS overrides the CSS and pushes the div element all the way to the left (getting rid of the margin) upon any scrolling action.
There are two events you need to handle to get this to work correctly. First is the scroll event which you are pretty close on. The only thing you might want to do is to use offset to get the current left position value based on the document.
The other event which is not yet handled is the resize event. If you don't handle this then once a left position is defined your element (header) will be there always regardless of whether or not the user resizes the window.
Basically something like this should work:
var headeroffset;
var header = $('#homeheader');
// handle scroll
$(window).scroll(function() {
// auto when not defined
if (headeroffset === undefined) {
// capture offset for current screen size
headeroffset = header.offset();
}
// calculate offset
var leftOffset = headeroffset.left - $(this).scrollLeft();
// set left offset
header.css('left', leftOffset);
});
// handle resize
$(window).resize(function() {
// remove left setting
// (this stops the element from being stuck after a resize event
if (header.css('left') !== 'auto') {
header.css('left', '');
headeroffset = undefined;
}
});
JSFiddle example: http://jsfiddle.net/infiniteloops/ELCq7/6/
http://jsfiddle.net/infiniteloops/ELCq7/6/show
This type of effect can be done purely in css however, i would suggest taking a look at the full page app series Steve Sanderson did recently.
http://blog.stevensanderson.com/2011/10/05/full-height-app-layouts-a-css-trick-to-make-it-easier/
As an example you could do something like this:
http://jsfiddle.net/infiniteloops/ELCq7/18/
Try this
$('#homeheader').css('left', parseInt($('body').css('margin-left')) - $this.scrollLeft());});
What I did here is just replace 20 with body's left-margin value.

Animate DIV to full height and toggle back to defined height

I am trying to animate the div to its full height when a button is pressed and come back to its original height if the button is clicked again. The full height of the div is auto as it contains text with different word counts. I tried doing the below codes but it does not work properly.
The CSS :
.category_brief{
text-align:justify;
height:100px;
overflow:hidden;
}
Example 1 : This code does not animate the div when opening to full height , but animates while coming back to old height.
$(".slide").toggle(function(){
$('.category_brief').animate({height:'100%'},200);
},function(){
$('.category_brief').animate({height:100},200);
});
Example 2 : The output of this code is the same as of Example 1
var toggle = true, oldHeight = 0;
$('.slide').click(function(event) {
event.preventDefault();
var $ele = $('.category_brief');
var toHeight = ((toggle = !toggle) ? oldHeight : newHeight);
oldHeight = $ele.height();
var newHeight = $ele.height('auto').height();
$ele.animate({ height: toHeight });
});
Example 3 : This code animates the div to its full height but does not toggle.
var slide = $('.slide');
var slidepanel = $('.category_brief');
// On click, animate it to its full natural height
slide.click(function(event) {
event.preventDefault();
var oldHeight, newHeight;
// Measure before and after
oldHeight = slidepanel.height();
newHeight = slidepanel.height('auto').height();
// Put back the short height (you could grab this first
slidepanel.height(oldHeight);
slidepanel.animate({height: newHeight + "px"});
});
If possible please provide a bit explanation also as i am a newbie..
Update : Solved by the idea from #chazm..
#chazm : thanks for the idea. I got it working by combining 1st and 3rd example ... Here is the code in case anyone needs it .
var slidepanel = $('.category_brief');
$(".slide").toggle(function(){
var oldHeight, newHeight;
// Measure before and after
oldHeight = slidepanel.height();
newHeight = slidepanel.height('auto').height();
// Put back the short height (you could grab this first
slidepanel.height(oldHeight);
slidepanel.animate({height: newHeight + "px"})
},function(){
$('.category_brief').animate({height:100},300);
});
Working with 'auto' height it always quite tricky. I think there are different issues in your examples.
1) Browser can't define correct 100% height. Possible solutions - define height to all its parents. Either set it to 100% (till html tag) or set closest parent as relative (because height is calculated from closest relative parent). If you want to animate div to 100% of the entire page - think of the absolute positioning
2)The same as above i assume
3)When this code supposed to toggle back it can't determine that it should become lower that it is now. Not absolutely sure why though. Probably because 'auto' height from 100% is set to something wrong. You may check in firebug what value it has on the computed tab after that function is toggled back. Probably it will give you a clue
Try to combine 2) and 3). The idea - if toggle is true (it shoud be lowered) then set newHeight = slidepanel.height('100').
The solution depends on your implementation needs. If you know that at first the div should be 100px etc in height and when you click, it maximizes to an unknown height, the following solution would work. If you had a structure similar to
<div class="outer">
<div class="wrapper">Content of unknown length here</div>
</div>
and css
div.wrapper { position:relative; height:100px; overflow:hidden; }
div.outer { position:absolute; height:auto; }
then you'd get a div that is 100px in height, with the content that doesn't fit in 100px cut off. Now when you press the desired button, you could get the height of the wrapper div, since it is a long as it's content is (even though you only see the top 100px) and set the outer div's height according to it. Like so
var newHeight = $('div.wrapper').height();
$('div.outer').animate({height:newHeight},200);
Which would then animate the outer div to display the whole contents. When you click the button again, you could just do
$('div.outer').animate({height:'100px'},200);
And you would again have only the 100px height.

Is there a way to hover over an element that is below another elements z-index in jquery?

I have a map split into three parts, the map background, the map labels and the map piece itself the order is as follows:
map background: z-index = 1
map label: z-index = 3
map piece (hover): z-index = 2 (to go under the label)
Is there a way to hover over the piece which is z-index = 2 if there is an element on top of that using jquery? (i.e. the label)
You can either trigger the hover on the label as well, or create invisible divs on top of everything:
$(function(){
$('.mappieces').each(function(){
var p = $(this).offset();
var w = $(this).width();
var h = $(this).height();
var $invisibleElement = $('div').addClass('invisible-style').css({
position: "absolute",
top: p.top,
left: p.left,
width: w,
height: h,
"z-index": 4 //on top of everything
}).appendTo('body');
$invisibleElement.hover(function(){...}, function(){...}); //do stuff
});
});
EDIT: Okay, this seems to work. not sure if there are any drawbacks.
http://jsfiddle.net/Sdsax/1/
Basically put both the label and the piece inside of a div. Put the hover on the div. Since the container div has no contents other than the absolutely positioned elements, it won't show. But since both elements are within that div, they hover fires on both.
EDIT 2: Updated fiddle. As you can see in the updated fiddle, since they really have the same handler, if they overlap, moving from one to the other will not fire the hover again.

Categories