These images resume perfectly the problem I have and the found solution.
Actual behavior Expected behavior
I thought that using the focus and blur events might be a solution, but it turns out that when I click on the OS back button, as I mentioned in the image, the input stays in the focus state, so what could be the solution?
Edited
const textfield = document.getElementById("textfield"),
bottomNav = document.getElementsByClassName("bottom-nav")[0],
viewportHeight = window.innerHeight;
textfield.addEventListener("focus", () => {
bottomNav.style.top = `${viewportHeight - 56}px`;
bottomNav.style.bottom = "auto";
});
textfield.addEventListener("blur", () => {
bottomNav.style.top = "auto";
bottomNav.style.bottom = 0;
});
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
}
.header,
.bottom-nav {
position: fixed;
z-index: 100;
left: 0;
right: 0;
width: 100%;
height: 56px;
background-color: red;
}
.header {
top: 0;
}
.bottom-nav {
bottom: 0;
}
.wrapper {
width: 100%;
padding: 72px 16px;
}
.textfield {
width: 100%;
height: 56px;
padding: 0 16px;
}
<header class="header"></header>
<main class="wrapper">
<input type="text" id="textfield" class="textfield" />
</main>
<nav class="bottom-nav"></nav>
If you add something to make the body scrollable, in Chrome for Android it works like a charm, but in Firefox it breaks, I don't know how it behaves in Safari as I don't have an iPhone, but basically the behavior it has in Chrome is the ideal state.
This solution is not bulletproof, but it works the same in both Firefox (105) and Chrome (106) for Android.
Add this to the CSS and change the JavaScript.:
.bottom-nav--hide {
top: 100vh;
bottom: auto;
}
const bottomNav = document.getElementsByClassName("bottom-nav")[0],
viewportHeight = window.innerHeight;
window.addEventListener("resize", () => {
let vh = window.innerHeight;
if (vh < viewportHeight) {
bottomNav.classList.add("bottom-nav--hide");
} else {
bottomNav.classList.remove("bottom-nav--hide");
}
});
Situations in which it doesn't work.
If the user opens the site in portrait and goes to landscape.
If the user rescales the window and the height is less than the original height.
Related
To enhance UX by catching miss-clicks in my form, I'm using the following code on a bounding box around each text field:
focusMethod = function getFocus() {
document.getElementById("myTextField").focus();
}
This works well in setting focus on the closest text field to where the user has clicked, even if not directly on the text field itself. However, the text insertion point (caret) is always automatically placed at the left side of the input, rather than the closest x point of the input.
Using vanilla JS, how can I take this one step further and find and move the text insertion point (caret) to the closest possible placement to where the user has clicked (assuming the field has text in it)?
Images:
what I have now | what I want to happen
You can overlay a sort of hacky text input that's larger, then use text positioning from it for the true input.
Otherwise, it's really, really difficult to figure out character positions... fonts are weird, and there's no way I know of in js to figure out exactly where they'll be.
const byId = (id) => document.getElementById(id);
const on = (el, event, cb) => el.addEventListener(event, cb);
const textEl = byId("Text");
const hackEl = byId("Hack");
on(textEl, "input", () => hackEl.value = textEl.value);
on(hackEl, "click", () => {
const charFocusPos = hackEl.selectionStart;
textEl.focus();
textEl.selectionStart = textEl.selectionEnd = charFocusPos;
});
#Container {
position: relative;
display: inline-block;
}
#Hack {
transform: translate(-50%, -50%) scaleY(5);
position: absolute;
top: 50%;
left: 50%;
width: 100%;
opacity: 0;
padding-top: 0px;
padding-bottom: 0px;
height: 16px;
border: none;
outline: none;
}
#Hack.showOnHover:hover {
opacity: 0.1;
}
#Hack, #Text {
font-size: 16px;
font-family: arial;
}
<div id="Container">
<input type="textbox" id="Text">
<input type="textbox" id="Hack"></div>
</div>
<button onClick="byId('Hack').classList.toggle('showOnHover')">Toggle Hack Layer</div>
You can achieve this. I have cooked up something that can be used as a starting point:
<div id="container">
<input type="text" id="input">
<br>
<br>
</div>
<script type="text/javascript">
var testInput = document.getElementById("input");
var testContainer = document.getElementById("container");
document.getElementById("container").addEventListener("click", function(event) {
testInput.focus();
var padding = 0;
console.log(event.clientX);
console.log(testInput.getBoundingClientRect().left);
console.log(testInput.getBoundingClientRect().right);
if (event.clientX > testInput.getBoundingClientRect().right) padding = (testInput.getBoundingClientRect().right * 0.8);
else if (event.clientX > testInput.getBoundingClientRect().left) padding = (event.clientX - testInput.getBoundingClientRect().left);
testInput.style["padding-left"] = padding + "px";
});
</script>
and
#container {
width: 90%;
margin: auto;
background-color: gray;
}
#input {
width: 80%;
margin-top: 100px;
margin-left: 10%;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
}
See: https://jsfiddle.net/mLqj17xe/1/
The idea is to find out where should the cursor be and use that as padding-left.
I want my .row-navigation row to be position-fixed when scrolled. So i used window.onscroll to listen to the scroll event and assign the class .sticky , to .row-navgation row , when scrolled. In the process getBoundingClientRect().top is used.
The unexpected behaviour:
When the scroll event takes places then getBoundingClientRect().top returns 0 with each alternate pixel scroll.
As a result The .row-navigationrow flickers when scrolled
Check this on codepen https://codepen.io/neel111/pen/NVaEyB
<div class="container">
<div class="row-welcome"></div>
<div class="row-navigation"></div>
</div>
.row-welcome {
height: 34px;
background-color: yellow;
}
.row-navigation {
height: 80px;
background-color: #000;
}
.row-navigation.sticky {
position: fixed;
top: 0;
width: 100%;
}
window.onscroll = function() {
var rowNavigation = document.querySelector('.row-navigation');
var nextDomElement = rowNavigation.parentElement.nextElementSibling;
console.log(rowNavigation.getBoundingClientRect().top, rowNavigation.getBoundingClientRect().right, rowNavigation.getBoundingClientRect().bottom);
if (0 > rowNavigation.getBoundingClientRect().top) {
rowNavigation.classList.add('sticky');
} else {
rowNavigation.classList.remove('sticky');
}
}
How to fix the unexpected behaviour of getBoundingClientRect().top?
Here's the jsfiddle.
It's the interface to cropping an image. As you can see the selection div takes the same background image and positions it to the negative of the top and left attributes of the selection div. In theory this should give a perfect overlap, but there's a jitter as you move the selection div around, and I can't seem to figure out what is causing it.
html
<div id="main">
<div id="selection"></div>
</div>
css
#main {
width: 600px;
height: 450px;
position: relative;
background: url("http://cdn-2.historyguy.com/celebrity_history/Scarlett_Johansson.jpg");
background-size: contain;
}
#selection {
width: 100px;
height: 100px;
position: absolute;
background: url("http://cdn-2.historyguy.com/celebrity_history/Scarlett_Johansson.jpg");
border: 1px dotted white;
background-size: 600px 450px;
}
jquery
$(document).ready(function () {
var move = false;
var offset = [];
var selection = null;
$("#selection").mousedown(function (e) {
move = true;
selection = $(this);
offset = [e.pageX - selection.offset().left, e.pageY - selection.offset().top];
});
$("#selection").mousemove(function (e) {
if (move == true) {
selection.css("left", e.pageX - offset[0]);
selection.css("top", e.pageY - offset[1]);
selection.css("background-position", (((-selection.position().left) - 1) + "px " + ((-selection.position().top ) - 1) + "px"));
}
});
$("#selection").mouseup(function (e) {
move = false;
});
})
It would appear that there is a value of 5 offset that needs to be added to ensure seamlessness
DEMO http://jsfiddle.net/nzx0fcp5/2/
offset = [e.pageX - selection.offset().left + 5, e.pageY - selection.offset().top + 5];
So, while experimenting I discovered that this was only a problem at certain sizes of the image. At the original size it is no problem, neither at half nor a quarter of this size. It wasn't simply a matter of keeping the image in proportion not having the image square or using even pixel sizes. I'm assuming this had something to do with partial pixel sizes, but I'm not sure, and I couldn't see any way to work around this, at least none that seemed worth the effort.
So while checking out the code of other croppers I took a look at POF's image cropper, they seem to have got round the problem by not using the background-position property at all (I'm not sure if it's plugin or they coded it themselves). They just set the image down and then used a transparent selection div with 4 divs stuck to each edge for the shading. So there's no pixel crunching on the fly at all. I like the simplicity and lightweight nature of this design and knocked up a version myself in jsfiddle to see if I could get it to work well.
new jitter free jsfiddle with no pixel crunching
I liked the solution for the preview box as well.
html
<body>
<div id="main">
<img src="http://flavorwire.files.wordpress.com/2012/01/scarlett_johansson.jpg" />
<div id="upperShade" class="shade" > </div>
<div id="leftShade" class="shade" > </div>
<div id="selection"></div>
<div id="rightShade" class="shade"></div>
<div id="lowerShade" class="shade" ></div>
</div>
</body>
css
#main {
position:relative;
width: 450px;
height: 600px;
}
#selection {
width: 148px;
height: 148px;
position: absolute;
border: 1px dotted white;
top: 0px;
left: 0px;
z-index: 1;
}
.shade {
background-color: black;
opacity: 0.5;
position: absolute;
}
#upperShade {
top: 0px;
left: 0px;
width: 600px;
}
#leftShade {
left: 0px;
top: 0px;
height: 150px;
width: auto;
}
#rightShade {
left: 150px;
top: 0px;
height: 150px;
width: 450px;
}
#lowerShade {
left:0px;
top: 150px;
width: 600px;
height: 300px;
}
jquery
$(document).ready(function () {
var move = false;
var offset = [];
var selection = null;
$("#selection").mousedown(function (e) {
move = true;
selection = $(this);
offset = [e.pageX - selection.offset().left, e.pageY - selection.offset().top];
});
$("#selection").mousemove(function (e) {
if (move == true) {
selection.css("left", e.pageX - offset[0]);
selection.css("top", e.pageY - offset[1]);
setShade();
}
});
function setShade() {
$("#upperShade").css("height", selection.position().top);
$("#lowerShade").css("height", 600 - (selection.position().top + 150));
$("#lowerShade").css("top", selection.position().top + 150);
$("#leftShade").css("top", selection.position().top);
$("#leftShade").css("width", selection.position().left);
$("#rightShade").css("top", selection.position().top);
$("#rightShade").css("left", selection.position().left + 150);
$("#rightShade").css("width", 450 - selection.position().left);
}
$("#selection").mouseup(function (e) {
move = false;
});
});
I have the following code that opens a new popup window while disabling the background, the problem is that I have to position this so that it's 100px from the top (already got that through the CSS #dialog) and also in the center of the screen, no matter what the user's resolution is?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script type="text/javascript">
function showPopUp(el) {
var cvr = document.getElementById("cover")
var dlg = document.getElementById(el)
cvr.style.display = "block"
dlg.style.display = "block"
if (document.body.style.overflow = "hidden") {
cvr.style.width = "1024"
cvr.style.height = "100%"
}
}
function closePopUp(el) {
var cvr = document.getElementById("cover")
var dlg = document.getElementById(el)
cvr.style.display = "none"
dlg.style.display = "none"
document.body.style.overflowY = "scroll"
}
</script>
<style type="text/css">
#cover {
display: none;
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background: gray;
filter: alpha(Opacity = 50);
opacity: 0.5;
-moz-opacity: 0.5;
-khtml-opacity: 0.5
}
#dialog {
display: none;
left: 100px;
top: 100px;
width: 300px;
height: 300px;
position: absolute;
z-index: 100;
background: white;
padding: 2px;
font: 10pt tahoma;
border: 1px solid gray
}
</style>
</head>
<body>
<div id="cover"></div>
<div id="dialog">
My Dialog Content
<br><input type="text">
<br><input type="button" value="Submit">
<br>[Close]
</div>
Show
</body>
</html>
CSS based solution to center:
You need to use these styles to make it appear dead-center:
position:absolute;
top:50%;
left:50%;
width:400px; /* adjust as per your needs */
height:400px; /* adjust as per your needs */
margin-left:-200px; /* negative half of width above */
margin-top:-200px; /* negative half of height above */
So position should be specified. The top and left should be 50%. The margin-left and margin-top should be negative one half of the width and height of the box respectively.
Notice that if you want your popup to appear on center even when page is scrolled you will have to use position:fixed instead with the draw back that it doesn't work in IE6.
Just do this:
.body {
position: relative;
}
.popup {
position: absolute;
max-width: 800px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
no matters the screen or popup size. This will center the <div class="popup"></div>.
What you need is called a light-box.
To create it you should modify HTML,CSS and JS code.
Let's say your lightbox consist only of the string "login form". (You can put everything you want there) The HTML code should look like this:
<div id = "loginBox">login form</div>
Now, we need to hide it with CSS:
div#loginBox {
display: none;
}
Now our box is not visible. Lets modify our box as you want it to be 100px from the top:
div#loginBox {
display: none;
top: 100px;
}
We will worry about disabling the background later.
Our next job is to make a button that will display the box when we need it. Easy-peasy:
<div id = "loginBox" >login form</div>
<a id = "displayButton">login</a>
Note that we don't need the "href" attribute, because that will move the screen on clicking and other unwanted behavior.
Let's attach event handler on the button via JS:
var IE = document.all ? true : false; // obligatory "browser sniffing"
function display_box() {
document.getElementsById("loginBox").style.display = "inline-block"; // or "inline"
}
window.onload = function() {
var login_box = document.getElementsById("loginBox");
if (!IE) {
login_box.addEventListener( "click", display_box , false );
}
else {
login_box.attachEvent( "onclick", display_box );
}
}
But you want it to be in the center of the screen? Then the function goes like this:
function display_box() {
var theBox = document.getElementsById("loginBox").style,
left = document.width / 2 - 50; // 150 because it is 300 / 2
theBox.display = "inline-block";
theBox.left = left.toString() + "px";
}
I would guess that you will want to close the window at some point and make the "disabled background" effect. To do so you can create a div class that extends on the whole screen, attach a "display" event on it, put some z-index in the css to be sure the loginBox is over the "disabled background", and attach a "close the loginBox" event on the "background" div. And now the final code looks like this:
Note that we care only about the placement of the login-button, because the other are hidden from view, and then modified by JS:
HTML:
<div id = "loginBox" >login</div>
<a id = "displayButton">login</a>
<div id = "backgroundDarkener"> </div>
CSS:
div#loginBox {
display: none;
top: 100px;
width: 300px; #it is important to know the width of the box, to center it correctly
z-index: 2;
}
div#backgroundDarkener {
background: #000;
display: none;
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.8;
# needless to say, you should play with opacity or if you want your
# css to validate - background image (because I suspect it won't
# validate for old versions of IE, Safari, etc.) This is just a suggestion
}
JS:
var IE = document.all ? true : false; // obligatory "browser sniffing"
function display_box() {
var theBox = document.getElementsById("loginBox").style,
background = document.getElementsById("loginBox").style,
left = document.width / 2 - 150; // 150 is 300 / 2
theBox.display = "inline-block";
theBox.left = left.toString() + "px";
background.display = "inline-block";
}
function hide_box() {
document.getElementsById("loginBox").style.display = "none";
document.getElementsById("backgroundDarkener").style.display = "none";
}
window.onload = function() {
var login_box = document.getElementsById("loginBox"),
background = document.getElementsById("backgroundDarkener");
if (!IE) {
login_box.addEventListener( "click", display_box , false );
background.addEventListener( "click", hide_box , false );
}
else {
login_box.attachEvent( "onclick", display_box );
background.attachEvent( "onclick", hide_box );
}
}
A quick Google search found this;
function PopupCenter(pageURL, title,w,h) {
var left = (screen.width/2)-(w/2);
var top = (screen.height/2)-(h/2);
var targetWin = window.open (pageURL, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left);
}
This is where flexbox comes rescue now!
.parent {
display: flex;
height: 300px; /* Or whatever */
}
.child {
width: 100px; /* Or whatever */
height: 100px; /* Or whatever */
margin: auto; /* Magic! */
}
You need to use these styles to make div center:
width:500px;
left:0;
right:0;
margin:0 auto;
Simple, margin: 100px auto;. There's no need to do calculations in JavaScript.
Live Example
I have 2 <div>s with ids A and B. div A has a fixed width, which is taken as a sidebar.
The layout looks like diagram below:
The styling is like below:
html, body {
margin: 0;
padding: 0;
border: 0;
}
#A, #B {
position: absolute;
}
#A {
top: 0px;
width: 200px;
bottom: 0px;
}
#B {
top: 0px;
left: 200px;
right: 0;
bottom: 0px;
}
I have <a id="toggle">toggle</a> which acts as a toggle button. On the toggle button click, the sidebar may hide to the left and div B should stretch to fill the empty space. On second click, the sidebar may reappear to the previous position and div B should shrink back to the previous width.
How can I get this done using jQuery?
$('button').toggle(
function() {
$('#B').css('left', '0')
}, function() {
$('#B').css('left', '200px')
})
Check working example at http://jsfiddle.net/hThGb/1/
You can also see any animated version at http://jsfiddle.net/hThGb/2/
See this fiddle for a preview and check the documentation for jquerys toggle and animate methods.
$('#toggle').toggle(function(){
$('#A').animate({width:0});
$('#B').animate({left:0});
},function(){
$('#A').animate({width:200});
$('#B').animate({left:200});
});
Basically you animate on the properties that sets the layout.
A more advanced version:
$('#toggle').toggle(function(){
$('#A').stop(true).animate({width:0});
$('#B').stop(true).animate({left:0});
},function(){
$('#A').stop(true).animate({width:200});
$('#B').stop(true).animate({left:200});
})
This stops the previous animation, clears animation queue and begins the new animation.
You can visit w3school for the solution on this the link is here and there is another example also available that might surely help,
Take a look
The following will work with new versions of jQuery.
$(window).on('load', function(){
var toggle = false;
$('button').click(function() {
toggle = !toggle;
if(toggle){
$('#B').animate({left: 0});
}
else{
$('#B').animate({left: 200});
}
});
});
Using Javascript
var side = document.querySelector("#side");
var main = document.querySelector("#main");
var togg = document.querySelector("#toogle");
var width = window.innerWidth;
window.document.addEventListener("click", function() {
if (side.clientWidth == 0) {
// alert(side.clientWidth);
side.style.width = "200px";
main.style.marginLeft = "200px";
main.style.width = (width - 200) + "px";
togg.innerHTML = "Min";
} else {
// alert(side.clientWidth);
side.style.width = "0";
main.style.marginLeft = "0";
main.style.width = width + "px";
togg.innerHTML = "Max";
}
}, false);
button {
width: 100px;
position: relative;
display: block;
}
div {
position: absolute;
left: 0;
border: 3px solid #73AD21;
display: inline-block;
transition: 0.5s;
}
#side {
left: 0;
width: 0px;
background-color: red;
}
#main {
width: 100%;
background-color: white;
}
<button id="toogle">Max</button>
<div id="side">Sidebar</div>
<div id="main">Main</div>
$('#toggle').click(function() {
$('#B').toggleClass('extended-panel');
$('#A').toggle(/** specify a time here for an animation */);
});
and in the CSS:
.extended-panel {
left: 0px !important;
}
$(document).ready(function () {
$(".trigger").click(function () {
$("#sidebar").toggle("fast");
$("#sidebar").toggleClass("active");
return false;
});
});
<div>
<a class="trigger" href="#">
<img id="icon-menu" alt='menu' height='50' src="Images/Push Pin.png" width='50' />
</a>
</div>
<div id="sidebar">
</div>
Instead #sidebar give the id of ur div.
This help to hide and show the sidebar, and the content take place of the empty space left by the sidebar.
<div id="A">Sidebar</div>
<div id="B"><button>toggle</button>
Content here: Bla, bla, bla
</div>
//Toggle Hide/Show sidebar slowy
$(document).ready(function(){
$('#B').click(function(e) {
e.preventDefault();
$('#A').toggle('slow');
$('#B').toggleClass('extended-panel');
});
});
html, body {
margin: 0;
padding: 0;
border: 0;
}
#A, #B {
position: absolute;
}
#A {
top: 0px;
width: 200px;
bottom: 0px;
background:orange;
}
#B {
top: 0px;
left: 200px;
right: 0;
bottom: 0px;
background:green;
}
/* makes the content take place of the SIDEBAR
which is empty when is hided */
.extended-panel {
left: 0px !important;
}