I have made a Fiddle that should explain the problem quite well (I hope):
JSFiddle
In short: I have a JS tooltip that is not supposed to take its parents width but rather just use auto width (until it reaches max-width and then wrap text). This works fine, unless the parent element has position:relative set, and then the tooltipchild inherits the width. I don't know how to prevent this from happening.
A solution that would work is to set a min-width but that is
not elegant
still doesn't explain why this acts the way it does
looks stupid when the tooltip is 1 or 2 words only
I have to include code for the fiddle link but it's a very extensive fiddle and since I can't pinpoint the issue, I'll just have to put something here (sorry!) - so this snippet will be of little use I'm afraid
<button id="tooltip">Click me</button>
button {
margin-left: 40%;
width: 50px;
position: relative; /* THE OFFENDING PROBLEM*/
}
var tooltip = document.getElementById("tooltip");
tooltip.addEventListener('mouseover', function() {
tlite.show(tooltip, {
text: template,
orientation: "bottom"
})
})
Maybe I found I trick that it works for you. My solution is to create a tooltip with an internal span in it. Now, we can format our new span putting parent span (our old .tlite span) to width:400px that it works like a max-width!
Ok, maybe the description is intricated, but with code become very simple. Follow me! ;)
Let's create our tooltip template with an internal span:
var template = document.createElement('span');
template.innerHTML = "<span class='internal'>ncididunt This tooltip is the.</span>";
Now we can put almost all our tooltip CSS in this new span:
.tlite {
/* here you can leave all the CSS concerning the animations and the positioning */
position: absolute;
z-index: 1000;
display: block;
visibility: hidden;
-webkit-transition: transition .25s ease-out;
transition: opacity .25s ease-out;
opacity: 0;
width: 400px; /* It's a width but it works like a max-width for internal span */
}
.tlite .internal{
display: inline-block; /* This does the trick! Super important! */
padding: .4rem .6rem;
text-align: left;
white-space: normal;
text-decoration: none;
pointer-events: none;
color: white;
border-radius: 5px;
background: green;
}
.tlite .internal::before {
position: absolute;
display: block;
width: 10px;
height: 10px;
content: ' ';
transform: rotate(45deg);
background: inherit;
}
.tlite-n .internal::before {
top: -3px;
left: 50%;
margin-left: -5px;
}
.tlite-nw .internal::before {
top: -3px;
left: 10px;
}
.tlite-ne .internal::before {
top: -3px;
right: 10px;
}
.tlite-s .internal::before {
bottom: -3px;
left: 50%;
margin-left: -5px;
}
.tlite-se .internal::before {
right: 10px;
bottom: -3px;
}
.tlite-sw .internal::before {
bottom: -3px;
left: 10px;
}
.tlite-w .internal::before {
top: 50%;
left: -3px;
margin-top: -5px;
}
.tlite-e .internal::before {
top: 50%;
right: -3px;
margin-top: -5px;
}
Now we can write how much we want and our new <span class="internal"> can grow up to 400px!
Try it:
/* he making of a tooltip is now very convulted because I had to alter a bit to fit the Fiddle; just ignore that*/
var template = document.createElement('span');
template.innerHTML = "<span class='internal'>Only few words.</span>";
var template2 = document.createElement('span');
template2.innerHTML = "<span class='internal'>This tooltip is positioned correctly and now it can grow up to 400px.</span>";
var template3 = document.createElement('span');
template3.innerHTML = "<span class='internal'>This tooltip has the width it should have but is placed wrong.</span>";
var tooltip = document.getElementById("tooltip");
tooltip.addEventListener('mouseover', function() {
tlite.show(tooltip, {
text: template,
orientation: "bottom"
})
})
tooltip.addEventListener('mouseleave', function() {
tlite.hide(tooltip);
})
var tabletooltip = document.getElementById("tabletooltip");
tabletooltip.addEventListener('mouseover', function() {
tlite.show(tabletooltip, {
text: template2,
orientation: "bottom"
})
})
tabletooltip.addEventListener('mouseleave', function() {
tlite.hide(tabletooltip);
})
var tabletooltip2 = document.getElementById("tabletooltip2");
tabletooltip2.addEventListener('mouseover', function() {
tlite.show(tabletooltip2, {
text: template3,
orientation: "bottom"
})
})
tabletooltip2.addEventListener('mouseleave', function() {
tlite.hide(tabletooltip2);
})
/*LIBRARY */
function tlite(getTooltipOpts) {
document.addEventListener('mouseover', function(e) {
var el = e.target;
var opts = getTooltipOpts(el);
if (!opts) {
el = el.parentElement;
opts = el && getTooltipOpts(el);
}
opts && tlite.show(el, opts, true);
});
}
tlite.show = function(el, opts, isAuto) {
opts = opts || {};
(el.tooltip || Tooltip(el, opts)).show();
function Tooltip(el, opts) {
var tooltipEl;
var showTimer;
var text;
el.addEventListener('mousedown', autoHide);
el.addEventListener('mouseleave', autoHide);
function show() {
if (opts['text']) {
text = opts['text'].innerHTML
} else {
text = ' ';
}
text && !showTimer && (showTimer = setTimeout(fadeIn, isAuto ? 150 : 1))
}
function autoHide() {
tlite.hide(el, true);
}
function hide(isAutoHiding) {
if (isAuto === isAutoHiding) {
showTimer = clearTimeout(showTimer);
tooltipEl && el.removeChild(tooltipEl);
tooltipEl = undefined;
delete el.tooltip; //experimental addition for the angular library version of the tooltip
}
}
function fadeIn() {
if (!tooltipEl) {
tooltipEl = createTooltip(el, text, opts);
}
}
return el.tooltip = {
show: show,
hide: hide
};
}
function createTooltip(el, text, opts) {
/*console.log('create')*/
var tooltipEl = document.createElement('span');
var grav = opts.grav || 'n';
tooltipEl.className = 'tlite ' + (grav ? 'tlite-' + grav : '');
tooltipEl.innerHTML = text;
el.appendChild(tooltipEl);
var arrowSize = 10;
var top = el.offsetTop;
var left = el.offsetLeft;
if (tooltipEl.offsetParent === el) {
top = left = 0;
}
var width = el.offsetWidth;
var height = el.offsetHeight;
var tooltipHeight = tooltipEl.offsetHeight;
var tooltipWidth = tooltipEl.offsetWidth;
var centerEl = left + (width / 2);
var vertGrav = grav[0];
var horzGrav = grav[1];
tooltipEl.style.top = (
vertGrav === 's' ? (top - tooltipHeight - arrowSize) :
vertGrav === 'n' ? (top + height + arrowSize) :
(top + (height / 2) - (tooltipHeight / 2))
) + 'px';
tooltipEl.style.left = (
horzGrav === 'w' ? left :
horzGrav === 'e' ? left + width - tooltipWidth :
vertGrav === 'w' ? (left + width + arrowSize) :
vertGrav === 'e' ? (left - tooltipWidth - arrowSize) :
(centerEl - tooltipWidth / 2)
) + 'px';
tooltipEl.className += ' tlite-visible';
return tooltipEl;
}
};
tlite.hide = function(el, isAuto) {
el.tooltip && el.tooltip.hide(isAuto);
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = tlite;
}
button {
margin-left: 40%;
width: 50px;
position: relative; /* NOW, NO PROBLEM! ;) */
}
table {
margin-left: 30%;
}
#tabletooltip {
position: relative;
}
/* library css */
.tlite {
position: absolute;
z-index: 1000;
display: block;
visibility: hidden;
-webkit-transition: transition .25s ease-out;
transition: opacity .25s ease-out;
opacity: 0;
width: 400px;
}
.tlite .internal{
display: inline-block;
padding: .4rem .6rem;
text-align: left;
white-space: normal;
text-decoration: none;
pointer-events: none;
color: white;
border-radius: 5px;
background: green;
}
/*
tables need an extra class for the positioning of the tooltip
*/
.tlite-table tr td,
.tlite-table tr th {
position: relative;
}
.tlite-visible {
visibility: visible;
opacity: 1;
}
.tlite .internal::before {
position: absolute;
display: block;
width: 10px;
height: 10px;
content: ' ';
transform: rotate(45deg);
background: inherit;
}
.tlite-n .internal::before {
top: -3px;
left: 50%;
margin-left: -5px;
}
.tlite-nw .internal::before {
top: -3px;
left: 10px;
}
.tlite-ne .internal::before {
top: -3px;
right: 10px;
}
.tlite-s .internal::before {
bottom: -3px;
left: 50%;
margin-left: -5px;
}
.tlite-se .internal::before {
right: 10px;
bottom: -3px;
}
.tlite-sw .internal::before {
bottom: -3px;
left: 10px;
}
.tlite-w .internal::before {
top: 50%;
left: -3px;
margin-top: -5px;
}
.tlite-e .internal::before {
top: 50%;
right: -3px;
margin-top: -5px;
}
<h3>
Any object that has position:relative has troubles with the width of the tooltip. EX:
</h3>
<button id="tooltip">Click me</button>
<p>
Remove the position and it works as intended.
</p>
<h3>
BUT for some situations, I need position:relative, otherwise the tooltip is displayed at the wrong place. EX:
</h3>
<table style="width:25%">
<tr>
<th>titel1</th>
<th>title2</th>
</tr>
<tr>
<td id="tabletooltip">tooltip with position:relative</td>
<td id="tabletooltip2">tooltip without position:relative</td>
</tr>
</table>
Related
I'm trying to do a navigation title on the right of the screen and add an animation to it.
The top title worked perfectly but trying to rotate the title messes up the javascript.
The animation is: 1st
and transforms into
What I'm having trouble is placing the next title vertically in the middle on the left of the page like this
So far I'm at this stage and stuck:
Here's my code with the javascript:
<div class="navbarProjects">
<div class="container">
<h1 class="spread">Projects</h1>
</div>
</div>
<div class="navbarAbout">
<h1 class="spread">About</h1>
</div>
<script>
var spread = document.getElementsByClassName('spread');
[].forEach.call(spread, function(el) {
// replace the content width divs
el.innerHTML = '<span>' + el.innerText.split('').join('</span><span>') + '</span>'
// custom :hover
el.onmouseenter = function(e) {
var childern = e.target.childNodes
var width = e.target.offsetWidth / childern.length
for (var i = 0, child; child = childern[i]; i++) child.style.minWidth = width + 'px'
}
// remove custom style again
el.onmouseleave = function(e) {
var childern = e.target.childNodes
for (var i = 0, child; child = childern[i]; i++) child.style.minWidth = '0'
}
})
</script>
.navbarProjects {
text-align: center;
top: 2%;
font-size: 32px;
}
.navbarAbout {
font-size: 32px;
padding-top: 0;
transform: rotate(90deg);
}
.spread {
text-align:center;
}
.spread span {
display: inline-block;
transition: all .5s ease;
text-align:center;
min-width: 0;
}
Here is the CSS I came up with to attempt to solve your issue:
I used classes found here: http://spotlifefilms.com/
See: https://jsfiddle.net/p8eqxpce/3/
.navbarFounder, .navbarServices, .navbarProjects, .navbarAbout {
position: fixed;
padding: 0px;
margin: 0px;
height: 70px;
}
.navbarFounder, .navbarServices {
width: 100vh;
top: 50%;
}
.navbarProjects, .navbarAbout {
width: 100vw;
right: 50%;
}
.navbarFounder {
left: 0px;
transform:
rotate(270deg)
translate(35px, calc(-50vh + 35px));
}
.navbarServices {
right: 0px;
transform:
rotate(90deg)
translate(-35px, calc(-50vh + 35px));
}
.navbarProjects {
bottom: 0px;
transform:
rotate(180deg)
translateX(-50vw);
}
.navbarAbout {
right: 50%;
transform:
rotate(0deg)
translateX(50vw);
}
so, i've come up with a solution that will only work if your font-size remains constant (if it's variable you'll need to use javascript/jquery for this particular solution to work) but if you set the margin for the about element to calc(100% - yourWidth); you'll be able to get it to work. i've made a jsfiddle:
EDIT: updated jsfiddle
https://jsfiddle.net/w7zfajea/4/
I want to make a draggle splitter between 2 panels. The following is a working version.
Now, I want to make the width of handle as thin as possible (less than 0.1px?), so there is no way to make the width (appear) smaller than 1px?
Additionally, when the splitter is thin, it is hard to select by the mouse. Is there a way to make a splitter easy to grab?
Taking JSBin as example, how did they manage to realise the splitters among the panels?
(function($) {
$.fn.drags = function(opt) {
opt = $.extend({
handle: "",
cursor: "ew-resize",
min: 10
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $el = this.find(opt.handle);
}
var priorCursor = $('body').css('cursor');
return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
priorCursor = $('body').css('cursor');
$('body').css('cursor', opt.cursor);
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
}
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
var mouseMove = function(e) {
var prev = $('.draggable').prev();
var next = $('.draggable').next();
var total = prev.outerWidth() + next.outerWidth();
var totalPercentage = parseFloat(prev.css('flex')) + parseFloat(next.css('flex'));
var offset = prev.offset();
if(offset){
var leftPercentage = ((e.pageX - offset.left - drg_w / 2) / total) * totalPercentage;
var rightPercentage = totalPercentage - leftPercentage;
if (leftPercentage * 100 < opt.min || rightPercentage * 100 < opt.min) {
return;
}
prev.css('flex', leftPercentage.toString());
next.css('flex', rightPercentage.toString());
}
}
$drag.css('z-index', 1000).parent().on("mousemove", mouseMove).on("mouseup", function() {
$(this).off("mousemove", mouseMove).off("mouseup");
$('body').css('cursor', priorCursor);
$('.draggable').removeClass('draggable').css('z-index', z_idx);
});
e.preventDefault(); // disable selection
});
}
})(jQuery);
$('.handle').drags();
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.handle {
width: 1px;
text-align: center;
background: grey;
transition: all ease-in 0.1s;
}
.draggable {
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex-box">
<div class="col">
<p>Pellentesque ...</p>
</div>
<div class="handle"></div>
<div class="col">
<p>Pellentesque ...</p>
</div>
</div>
If you'd like the handle to appear thinner try applying a negative value to the right "col" e.g. margin-left: -2px; so it overlaps the left "col" border on the left of it. I don't think you can make the width "appear" as 0.1px. Firefox is the only browser that renders such value. (https://css-tricks.com/forums/topic/0-1px-borders/)
.flex-box .col:last-child {
margin-left: -2px;
}
//raise handle layer to top
.handle {
.....
z-index: 9999;
}
Hope this helps...
*Edit:
This is the closest I could get to your request:
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.flex-box .col:last-child {
margin-left: -6px;
}
.handle {
width: 5px;
text-align: center;
transition: all ease-in 0.1s;
z-index: 999;
overflow: visible;
}
.handle-inner{
width: 5px;
height: 100%;
position: relative;
margin-left: -10px;
}
.draggable {
background: grey;
}
Jsbin :
https://jsbin.com/nupefekuhu/edit?html,css,js,output
I have a circle that expands and contracts, but there is a glitch at about 10px - 20px. Look carefully and you will see it "twitch".
It's as if the the circle has some alloted space and then "breaks" out of it.
https://jsfiddle.net/nj2u9bhy/4/
$A.Class.create('test',{
Name: 'Animator',
E: {
timer: '#timer'
},
init: function(){
this.animate();
},
animate: function(){
var s = this.E.timer.style;
var step = 2;
var state = 'up';
$A.setInterval(function(){
$A.log(step);
s.height = s.width = step + 'px';
s.borderRadius = step/2 + 'px';
if(state === 'up') {
step += 2;
}
if(state === 'down') {
step -= 2;
}
if(step === 2) {
state = 'up';
}
if(step === 42){
state = 'down';
}
}, 200);
}
});
I tried explicitly giving it space here:
https://jsfiddle.net/nj2u9bhy/5/
but same effect.
That is because it is an inline block element which vertical aligns to bottom so give it vertical align top solve the issue, or change it to a block element.
Updated fiddle
#timer{
position: relative;
top: 20px;
left: 20px;
display: inline-block;
width: 32px;
height: 32px;
vertical-align: top;
background-color: black;
border-radius: 16px;
}
And it can be easily done using CSS animation which will give a smoother transition (note that CSS animations are not supported in IE 9 and earlier)
#timer{
position: relative;
display: inline-block;
width: 0;
height: 0;
vertical-align: top;
background-color: black;
border-radius: 50%;
animation: zoom 3s linear infinite;
}
#keyframes zoom {
0% {width: 0; height: 0;}
50% {width: 32px; height: 32px;}
100% {width: 0; height: 0;}
}
<div id="timer">
</div>
I have this fiddle set up: https://jsfiddle.net/xwb9594m/
As you can see when the slide menu gets toggled off, the content wraps as the menu shrinks. I'm trying to just get it to slide away off the side of the screen cleanly.
This is my JS:
$(document).ready(function() {
var menuBtn = $('.video-search-button'),
menu = $('.video-search-menu'),
close = $('.video-search-menu .close');
menuBtn.click(function(){
menu.animate({width: 'toggle'});
});
close.click(function(){
menu.animate({width: 'toggle'});
});
});
and my SCSS:
.video-search-menu {
display: none;
position: fixed;
top: 0;
right: 0;
width: auto;
height: 100%;
overflow: hidden;
background: #24637e;
background: rgba(36, 99, 126, 0.9);
color: #fff;
z-index: 101;
&-wrapper {
position: relative;
padding: 180px 50px 0 50px;
}
.close {
position: absolute;
width: 40px;
height: 40px;
top: 15px;
left: 15px;
z-index: 9999;
cursor: pointer;
&:before, &:after {
content: '';
position: absolute;
width: 100%;
top: 50%;
height: 2px;
background: #ffffff;
transform: rotate(45deg);
}
&:after {
transform: rotate(-45deg);
}
}
}
Add a CSS rule
p{
overflow: hidden;
white-space: nowrap;
}
I updated your jsFiddle
Or copy the code below:
$(document).ready(function() {
var menuBtn = $('.video-search-button'),
menu = $('.video-search-menu'),
close = $('.video-search-menu .close');
var right = (1 - menu.width()) - 1;
menu.css('right', right);
menuBtn.click(function(){
menu.animate({right: 0}).show();
});
close.click(function(){
menu.animate({right: right});
});
});
Update: Close menu on clicking again on the button
jsFiddle
Or copy the code below:
$(document).ready(function() {
var menuBtn = $('.video-search-button'),
menu = $('.video-search-menu'),
close = $('.video-search-menu .close');
var right = (1 - menu.width()) - 1;
menu.css('right', right);
menuBtn.click(function(){
if(menu.is(':visible')) {
close.trigger('click');
}
else {
menu.animate({right: 0}).show();
}
});
close.click(function(){
menu.animate({right: right}, function() {
menu.hide();
});
});
});
Update 2:
You can also save some lines of code for your close-"icon":
jsFiddle
I have some simple transition animation, I want to make text ( A href ) invisible, so I used "display: none" and I want to make it visible with "display: block" after image coming through it using "onclick" thing from javascript on that image. Here is my jsfiddle : http://jsfiddle.net/ofy4t5a8/
#facebook_text a {
position: absolute;
font-size: 15px;
color: #000;
text-decoration: none;
margin-left: 50px;
margin-top: -10px;
z-index: 1;
display: none;
}
#facebook_image.fly {
position: absolute;
margin-left: 125px;
margin-top: 0px;
transition: all 5s ease-out;
}
#facebook_image img {
position: absolute;
z-index: 10;
height: 35px;
width: 35px;
margin-top: -15px;
}
<div id="facebook_text">
Facebook
</div>
<div id="facebook_image">
<img class="image_animation" src="facebook.jpg"></img>
</div>
<script>
document.querySelector('.image_animation').onmouseover=function() {
var d = document.getElementById("facebook_image");
d.className = d.className + " fly";
}
</script>
facebook_imageYou should catch event when it ends, you can do it like this:
transitionEnd = (function transitionEndEventName() {
var i,
el = document.createElement('div'),
transitions = {
'transition':'transitionend',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
};
for (i in transitions) {
if (transitions.hasOwnProperty(i) && el.style[i] != undefined) {
return transitions[i];
}
}
})();
var a = document.querySelector('a');
var b = document.querySelector('.facebook_image');
b.addEventListener(transitionEnd, function(){
a.style.display = "block";
}