Mobile Safari, scrollIntoView doesn't work - javascript

I have a problem with scroll to element on mobile Safari in iframe (it works on other browsers, including Safari on mac).
I use scrollIntoView. I want to scroll when all content has been rendered. Here is my code:
var readyStateCheckInterval = setInterval(function () {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
$browser.notifyWhenNoOutstandingRequests(function () {
if (cinemaName != null && eventId == null) {
scrollToCinema();
} else {
scrollToEvent();
}
});
}
}, 10);
function scrollToEvent() {
var id = eventId;
var delay = 100;
if (cinemaName != null) {
id = cinemaName + "#" + eventId;
}
if ($rootScope.eventId != null) {
id = $rootScope.cinemaId + "#" + $rootScope.eventId;
}
$timeout(function () {
var el = document.getElementById(id);
if (el != null)
el.scrollIntoView(true);
$rootScope.eventId = null;
}, delay);
}

ScrollIntoView does not work (currently). But you can manually calculate the position of the element and scroll to it. Here is my solution
const element = document.getElementById('myId')
Pass the element to this function
/** Scrolls the element into view
* Manually created since Safari does not support the native one inside an iframe
*/
export const scrollElementIntoView = (element: HTMLElement, behavior?: 'smooth' | 'instant' | 'auto') => {
let scrollTop = window.pageYOffset || element.scrollTop
// Furthermore, if you have for example a header outside the iframe
// you need to factor in its dimensions when calculating the position to scroll to
const headerOutsideIframe = window.parent.document.getElementsByClassName('myHeader')[0].clientHeight
const finalOffset = element.getBoundingClientRect().top + scrollTop + headerOutsideIframe
window.parent.scrollTo({
top: finalOffset,
behavior: behavior || 'auto'
})
}
Pitfalls: Smooth scroll also does not work for ios mobile, but you can complement this code with this polyfill

In my experience scrollIntoView() fails sometimes on my iphone and my ipad and sometimes it works (on my own web sites). I'm not using iframes. This is true both with safari and firefox on the above devices.
The solution that works for me is to pop the element you need to scroll to inside a DIV eg. as the first element in that DIV. Hey presto it then works fine!
Seems like a dodgy implementation by Apple.

Your most likely having the exact same issue I just debugged. Safari automatically resizes the frame to fit it's contents. Therefore, the parent of the Iframe will have the scrollbars in Safari. So calling scrollintoview from within the Iframe itself 'fails'.
If Iframe is cross domain accessing the parent document via window.parent.document will be denied.
If you need a cross domain solution check my answer here.
Basically I use post message to tell the parent page to do the scrolling itself when inside Mobile Safari cross domain.

Related

Detecting the opening or closing of a virtual keyboard on a touchscreen device

I have an inelegant workaround for this issue, and am hoping that others may already have more robust solutions.
On a touchscreen, tapping on an editable text field will bring up an on-screen keyboard, and this will change the amount of screen space available. Left untreated, this may hide key elements, or push a footer out of place.
On a laptop or desktop computer, opening an editable text field creates no such layout changes.
In my current project, I want to ensure that certain key items are visible even when a virtual keyboard is open, so I need to detect when such a change occurs. I can then add a class to the body element, to change the layout to suit the presence of the keyboard.
When searching for existing solutions online, I discovered that:
There is no perfect way of knowing that your code is running on a mobile device
There are non-mobile devices that have touchscreens, and which may also have keyboards
A focus element may not be editable
contentEditable elements will open the on-screen keyboard
The address bar may decide to reappear and take up essential screen space at the same time the virtual keyboard appears, squeezing the available space even more.
I have posted the solution that I have come up with below. It relies on detecting a change in height of the window within a second of the keyboard focus changing. I am hoping that you might have a better solution to propose that has been tested cross-platform, cross-browser and across devices.
I've created a repository on GitHub.
You can test my solution here.
In my tests, this may give a false positive if the user is using a computer with a touchscreen and a keyboard and mouse, and uses the mouse first to (de-)select an editable element and then immediately changes the window height. If you find other false positives or negatives, either on a computer or a mobile device, please let me know.
;(function (){
class Keyboard {
constructor () {
this.screenWidth = screen.width // detect orientation
this.windowHeight = window.innerHeight // detect keyboard change
this.listeners = {
resize: []
, keyboardchange: []
, focuschange: []
}
this.isTouchScreen = 'ontouchstart' in document.documentElement
this.focusElement = null
this.changeFocusTime = new Date().getTime()
this.focusDelay = 1000 // at least 600 ms is required
let focuschange = this.focuschange.bind(this)
document.addEventListener("focus", focuschange, true)
document.addEventListener("blur", focuschange, true)
window.onresize = this.resizeWindow.bind(this)
}
focuschange(event) {
let target = event.target
let elementType = null
let checkType = false
let checkEnabled = false
let checkEditable = true
if (event.type === "focus") {
elementType = target.nodeName
this.focusElement = target
switch (elementType) {
case "INPUT":
checkType = true
case "TEXTAREA":
checkEditable = false
checkEnabled = true
break
}
if (checkType) {
let type = target.type
switch (type) {
case "color":
case "checkbox":
case "radio":
case "date":
case "file":
case "month":
case "time":
this.focusElement = null
checkEnabled = false
default:
elementType += "[type=" + type +"]"
}
}
if (checkEnabled) {
if (target.disabled) {
elementType += " (disabled)"
this.focusElement = null
}
}
if (checkEditable) {
if (!target.contentEditable) {
elementType = null
this.focusElement = null
}
}
} else {
this.focusElement = null
}
this.changeFocusTime = new Date().getTime()
this.listeners.focuschange.forEach(listener => {
listener(this.focusElement, elementType)
})
}
resizeWindow() {
let screenWidth = screen.width;
let windowHeight = window.innerHeight
let dimensions = {
width: innerWidth
, height: windowHeight
}
let orientation = (screenWidth > screen.height)
? "landscape"
: "portrait"
let focusAge = new Date().getTime() - this.changeFocusTime
let closed = !this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight < windowHeight)
let opened = this.focusElement
&& (focusAge < this.focusDelay)
&& (this.windowHeight > windowHeight)
if ((this.screenWidth === screenWidth) && this.isTouchScreen) {
// No change of orientation
// opened or closed can only be true if height has changed.
//
// Edge case
// * Will give a false positive for keyboard change.
// * The user has a tablet computer with both screen and
// keyboard, and has just clicked into or out of an
// editable area, and also changed the window height in
// the appropriate direction, all with the mouse.
if (opened) {
this.keyboardchange("shown", dimensions)
} else if (closed) {
this.keyboardchange("hidden", dimensions)
} else {
// Assume this is a desktop touchscreen computer with
// resizable windows
this.resize(dimensions, orientation)
}
} else {
// Orientation has changed
this.resize(dimensions, orientation)
}
this.windowHeight = windowHeight
this.screenWidth = screenWidth
}
keyboardchange(change, dimensions) {
this.listeners.keyboardchange.forEach(listener => {
listener(change, dimensions)
})
}
resize(dimensions, orientation) {
this.listeners.resize.forEach(listener => {
listener(dimensions, orientation)
})
}
addEventListener(eventName, listener) {
// log("*addEventListener " + eventName)
let listeners = this.listeners[eventName] || []
if (listeners.indexOf(listener) < 0) {
listeners.push(listener)
}
}
removeEventListener(eventName, listener) {
let listeners = this.listeners[eventName] || []
let index = listeners.indexOf(listener)
if (index < 0) {
} else {
listeners.slice(index, 1)
}
}
}
window.keyboard = new Keyboard()
})()
There is a new experimental API that is meant exactly to track size changes due to the keyboard appearing and other mobile weirdness like that.
window.visualViewport
https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API
By listening to resize events and comparing the height to the height to the so called "layout viewport". See that it changed by a significant amount, like maybe 30 pixels. You might deduce something like "the keyboard is showing".
if('visualViewport' in window) {
window.visualViewport.addEventListener('resize', function(event) {
if(event.target.height + 30 < document.scrollElement.clientHeight) {
console.log("keyboard up?");
} else {
console.log("keyboard down?");
}
});
}
(code above is untested and I suspect zooming might trigger false positive, might have to check for scaling changes as well)
As no direct way to detect the keyboard opening, you can only detect by the height and width. See more
In javascript screen.availHeight and screen.availWidth maybe help.
Using visualViewPort
This was inspired by on-screen-keyboard-detector. It works on Android and iOS.
if ('visualViewport' in window) {
const VIEWPORT_VS_CLIENT_HEIGHT_RATIO = 0.75;
window.visualViewport.addEventListener('resize', function (event) {
if (
(event.target.height * event.target.scale) / window.screen.height <
VIEWPORT_VS_CLIENT_HEIGHT_RATIO
)
console.log('keyboard is shown');
else console.log('keyboard is hidden');
});
}
Another approach using virtualKeyboard
This worked, but isn't supported in iOS yet.
if ('virtualKeyboard' in navigator) {
// Tell the browser you are taking care of virtual keyboard occlusions yourself.
navigator.virtualKeyboard.overlaysContent = true;
navigator.virtualKeyboard.addEventListener('geometrychange', (event) => {
const { x, y, width, height } = event.target.boundingRect;
if (height > 0) console.log('keyboard is shown');
else console.log('keyboard is hidden');
});
Source: https://developer.chrome.com/docs/web-platform/virtual-keyboard/
This is a difficult problem to get 'right'. You can try and hide the footer on input element focus, and show on blur, but that isn't always reliable on iOS. Every so often (one time in ten, say, on my iPhone 4S) the focus event seems to fail to fire (or maybe there is a race condition with JQuery Mobile), and the footer does not get hidden.
After much trial and error, I came up with this interesting solution:
<head>
...various JS and CSS imports...
<script type="text/javascript">
document.write( '<style>#footer{visibility:hidden}#media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
</script>
</head>
Essentially: use JavaScript to determine the window height of the device, then dynamically create a CSS media query to hide the footer when the height of the window shrinks by 10 pixels. Because opening the keyboard resizes the browser display, this never fails on iOS. Because it's using the CSS engine rather than JavaScript, it's much faster and smoother too!
Note: I found using 'visibility:hidden' less glitchy than 'display:none' or 'position:static', but your mileage may vary.
I'm detecting the visibility of a virtual keyboard as follows:
window.addEventListener('resize', (event) => {
// if current/available height ratio is small enough, virtual keyboard is probably visible
const isKeyboardHidden = ((window.innerHeight / window.screen.availHeight) > 0.6);
});

Make iframe click-through, but not the iframe's body

How can I make an iframe click-through, but make that iframe's body still be clickable?
I tried:
iframe.style.width = '100%'
iframe.style.height = '100%'
iframe.style.display = 'block'
iframe.style.position = 'fixed'
iframe.style.backgroundColor = 'transparent'
iframe.style.pointerEvents = 'none'
iframe.style.border = '0'
iframe.frameborder = '0'
iframe.scrolling = 'no'
iframe.allowTransparency = 'true'
and inside of my I frame I'm using the following css:
html, body {
/* background:none transparent; */
pointer-events:auto;
}
This results in body being visible (which is what I want), but it is click-through like the rest of the iframe. I want the body of the iframe to be clickable, but all the rest of the actual iframe element should be click-through.
The iframe is always bigger than the body inside of it.
Unfortunately I cannot access the the iframe content from the main site (so accessing the scrollHeight etc isn't possible), I can only change its actual source code.
DISCLAIMER:
OP created this question almost two years ago, my answer follows Ian Wise's bumping the question and elaborating on it (see comments).
What you are describing here involves logic between a document and a child document: "If a click event did nothing inside child document, apply that click event to parent document", and therefore cannot be approached using HTML/CSS.
Iframes are different documents. They do have a child-parent relationship with their containers, but an event that occurs within the iframe will be handled by the iframe.
An idea that requires some code but will work:
Place a transparent div above all the stacked iframes, and catch the
click event pos.
Parent logic ->
Iterate through array of existing iframe elements.
Send click pos until one of the iframes returns a positive response.
function clickOnCover(e, i) {
if(e && e.preventDefaule) e.preventDefault();
if(i && i >= iframes.length) {
console.log("No action.");
return;
}
var iframe = iframes[i || 0];
if(iframe.contentWindow && iframe.contentWindow.postMessage) {
iframe.contentWindow.postMessage({ x: e.clientX, y: e.clientY, i: i });
}
}
function iframeResponse(e) {
var response = e.data, iframeIndex = response.i;
if(response.success)
console.log("Action done on iframe index -> " + iframeIndex);
else
clickOnCover({ clientX: response.x, clientY: response.y }, iframeIndex+1);
}
iFrames logic ->
Have a function that accepts the clientX, clientY and checks for possible activies in that position (might be tricky!).
Will respond positively if an action occurred, and the opposite.
window.addEventListener("message", function(e) {
// Logic for checking e.x & e.y
e.success = actionExists; // Some indicator if an action occurred.
if(window.parent && window.parent.postMessage) {
window.parent.postMessage(e);
}
});
This solution keeps managing the event within the parent document and only requires iterating through whatever amount of stacked iframes.
Found a relevant SO question to further support my claim: Detect Click in Iframe
This is not possible with CSS.
The easiest way is to resize the iframe properly. Assuming you have access to iframe content, the following solution is possible:
You might add a little JS to allow the parent page to know the iframe height
mainpage.js
var iframe = getIframe();
setIntervalMaybe(() => {
// ask for size update
iframe.contentWindow.postMessage({action: "getSize"}, document.location.origin);
}, 100)
window.addEventListener("message", function receiveMessage(event) {
switch(event.data.action) {
case "returnSize":
// updateIFrameSize(event.data.dimensions);
console.log(event.data.dimensions);
break;
}
}, false);
iframe.js
window.addEventListener("message", function receiveMessage(event) {
switch(event.data.action) {
case "getSize":
event.source.postMessage({action: "returnSize", dimensions: {
width: document.body.offsetWidth,
height: document.body.offsetHeight
}}, event.origin);
break;
}
}, false);

JQuery scrollTop - cross browser compatibility issues

Yesterday I had an issue with a JQuery scrolling script that worked in Chrome but not in IE and Firefox. I asked this query (JQuery scroll() / scrollTop() not working in IE or Firefox) yesterday which I marked as being the correct answer only to realise today that it doesn't work in Chrome anymore!
Can anyone help me get this working on all modern browsers?
HTML
<div id="dotted-line">
<div id="up-arrow">^up</div>
</div>
JQuery
//get window size values (cross browser compatible)
(function(undefined) {
var container = $("html,body");
$.windowScrollTop = function(newval) {
if( newval === undefined) {
return container.scrollTop();
}
else {
return container.scrollTop(newval);
}
}
})();
//draw dotted line on scroll
$(window).scroll(function(){
if ($.windowScrollTop() > 10) {
var pos = $.windowScrollTop();
$('#dashes').css('height',pos/4);
$('#footer-dot').css('top',pos/4);
} else {
$('#dashes').css('height','6px');
$('#footer-dot').css('top','-150px');
}
});
scrollTop() will return value of only first matched element in set
$('html,body'), that's why it no more works on chrome
I think your best bet would be to use:
var container = $(document.scrollingElement || "html");

How do I scroll to an element using JavaScript?

I am trying to move the page to a <div> element.
I have tried the next code to no avail:
document.getElementById("divFirst").style.visibility = 'visible';
document.getElementById("divFirst").style.display = 'block';
scrollIntoView works well:
document.getElementById("divFirst").scrollIntoView();
full reference in the MDN docs:
https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView
You can use an anchor to "focus" the div. I.e:
<div id="myDiv"></div>
and then use the following javascript:
// the next line is required to work around a bug in WebKit (Chrome / Safari)
location.href = "#";
location.href = "#myDiv";
For Chrome and Firefox
I've been looking a bit into this and I figured this one out which somehow feels like the most natural way to do it. Of course, this is my personal favorite scroll now. :)
const y = element.getBoundingClientRect().top + window.scrollY;
window.scroll({
top: y,
behavior: 'smooth'
});
For IE, Edge and Safari supporters
Note that window.scroll({ ...options }) is not supported on IE, Edge and Safari. In that case it's most likely best to use
element.scrollIntoView(). (Supported on IE 6). You can most likely (read: untested) pass in options without any side effects.
These can of course be wrapped in a function that behaves according to which browser is being used.
The best, shortest answer that what works even with animation effects:
var scrollDiv = document.getElementById("myDiv").offsetTop;
window.scrollTo({ top: scrollDiv, behavior: 'smooth'});
If you have a fixed nav bar, just subtract its height from top value, so if your fixed bar height is 70px, line 2 will look like:
window.scrollTo({ top: scrollDiv-70, behavior: 'smooth'});
Explanation:
Line 1 gets the element position
Line 2 scroll to element position; behavior property adds a smooth animated effect
We can implement by 3 Methods:
Note:
"automatic-scroll" => The particular element
"scrollable-div" => The scrollable area div
Method 1:
document.querySelector('.automatic-scroll').scrollIntoView({
behavior: 'smooth'
});
Method 2:
location.href = "#automatic-scroll";
Method 3:
$('#scrollable-div').animate({
scrollTop: $('#automatic-scroll').offset().top - $('#scrollable-div').offset().top +
$('#scrollable-div').scrollTop()
})
Important notice: method 1 & method 2 will be useful if the scrollable area height is "auto". Method 3 is useful if we using the scrollable area height like "calc(100vh - 200px)".
You can set focus to element. It works better than scrollIntoView
node.setAttribute('tabindex', '-1')
node.focus()
node.removeAttribute('tabindex')
Try this:
var divFirst = document.getElementById("divFirst");
divFirst.style.visibility = 'visible';
divFirst.style.display = 'block';
divFirst.tabIndex = "-1";
divFirst.focus();
e.g #:
http://jsfiddle.net/Vgrey/
Here's a function that can include an optional offset for those fixed headers. No external libraries needed.
function scrollIntoView(selector, offset = 0) {
window.scroll(0, document.querySelector(selector).offsetTop - offset);
}
You can grab the height of an element using JQuery and scroll to it.
var headerHeight = $('.navbar-fixed-top').height();
scrollIntoView('#some-element', headerHeight)
Update March 2018
Scroll to this answer without using JQuery
scrollIntoView('#answer-44786637', document.querySelector('.top-bar').offsetHeight)
To scroll to a given element, just made this javascript only solution below.
Simple usage:
EPPZScrollTo.scrollVerticalToElementById('signup_form', 20);
Engine object (you can fiddle with filter, fps values):
/**
*
* Created by Borbás Geri on 12/17/13
* Copyright (c) 2013 eppz! development, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
var EPPZScrollTo =
{
/**
* Helpers.
*/
documentVerticalScrollPosition: function()
{
if (self.pageYOffset) return self.pageYOffset; // Firefox, Chrome, Opera, Safari.
if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; // Internet Explorer 6 (standards mode).
if (document.body.scrollTop) return document.body.scrollTop; // Internet Explorer 6, 7 and 8.
return 0; // None of the above.
},
viewportHeight: function()
{ return (document.compatMode === "CSS1Compat") ? document.documentElement.clientHeight : document.body.clientHeight; },
documentHeight: function()
{ return (document.height !== undefined) ? document.height : document.body.offsetHeight; },
documentMaximumScrollPosition: function()
{ return this.documentHeight() - this.viewportHeight(); },
elementVerticalClientPositionById: function(id)
{
var element = document.getElementById(id);
var rectangle = element.getBoundingClientRect();
return rectangle.top;
},
/**
* Animation tick.
*/
scrollVerticalTickToPosition: function(currentPosition, targetPosition)
{
var filter = 0.2;
var fps = 60;
var difference = parseFloat(targetPosition) - parseFloat(currentPosition);
// Snap, then stop if arrived.
var arrived = (Math.abs(difference) <= 0.5);
if (arrived)
{
// Apply target.
scrollTo(0.0, targetPosition);
return;
}
// Filtered position.
currentPosition = (parseFloat(currentPosition) * (1.0 - filter)) + (parseFloat(targetPosition) * filter);
// Apply target.
scrollTo(0.0, Math.round(currentPosition));
// Schedule next tick.
setTimeout("EPPZScrollTo.scrollVerticalTickToPosition("+currentPosition+", "+targetPosition+")", (1000 / fps));
},
/**
* For public use.
*
* #param id The id of the element to scroll to.
* #param padding Top padding to apply above element.
*/
scrollVerticalToElementById: function(id, padding)
{
var element = document.getElementById(id);
if (element == null)
{
console.warn('Cannot find element with id \''+id+'\'.');
return;
}
var targetPosition = this.documentVerticalScrollPosition() + this.elementVerticalClientPositionById(id) - padding;
var currentPosition = this.documentVerticalScrollPosition();
// Clamp.
var maximumScrollPosition = this.documentMaximumScrollPosition();
if (targetPosition > maximumScrollPosition) targetPosition = maximumScrollPosition;
// Start animation.
this.scrollVerticalTickToPosition(currentPosition, targetPosition);
}
};
Similar to #caveman's solution
const element = document.getElementById('theelementsid');
if (element) {
window.scroll({
top: element.scrollTop,
behavior: 'smooth',
})
}
A method i often use to scroll a container to its contents.
/**
#param {HTMLElement} container : element scrolled.
#param {HTMLElement} target : element where to scroll.
#param {number} [offset] : scroll back by offset
*/
var scrollAt=function(container,target,offset){
if(container.contains(target)){
var ofs=[0,0];
var tmp=target;
while (tmp!==container) {
ofs[0]+=tmp.offsetWidth;
ofs[1]+=tmp.offsetHeight;
tmp=tmp.parentNode;
}
container.scrollTop = Math.max(0,ofs[1]-(typeof(offset)==='number'?offset:0));
}else{
throw('scrollAt Error: target not found in container');
}
};
if your whish to override globally, you could also do :
HTMLElement.prototype.scrollAt=function(target,offset){
if(this.contains(target)){
var ofs=[0,0];
var tmp=target;
while (tmp!==this) {
ofs[0]+=tmp.offsetWidth;
ofs[1]+=tmp.offsetHeight;
tmp=tmp.parentNode;
}
container.scrollTop = Math.max(0,ofs[1]-(typeof(offset)==='number'?offset:0));
}else{
throw('scrollAt Error: target not found in container');
}
};
If you simply want to scroll to the bottom of a list that is inside a div, you can do this.
<body>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
</div>
<button>Scroll To</button>
<script>
const btn = document.querySelector("button");
const container = document.querySelector(".container");
btn.addEventListener("click",()=>{
const toplast = document.querySelector(".container").lastElementChild;
toplast.scrollIntoView();
})
</script>
</body>
example output
Focus can be set on interactive elements only... Div only represent a logical section of the page.
Perhaps you can set the borders around div or change it's color to simulate a focus. And yes Visiblity is not focus.
Due to behavior "smooth" doesn't work in Safari, Safari ios, Explorer. I usually write a simple function utilizing requestAnimationFrame
(function(){
var start;
var startPos = 0;
//Navigation scroll page to element
function scrollTo(timestamp, targetTop){
if(!start) start = timestamp
var runtime = timestamp - start
var progress = Math.min(runtime / 700, 1)
window.scroll(0, startPos + (targetTop * progress) )
if(progress >= 1){
return;
}else {
requestAnimationFrame(function(timestamp){
scrollTo(timestamp, targetTop)
})
}
};
navElement.addEventListener('click', function(e){
var target = e.target //or this
var targetTop = _(target).getBoundingClientRect().top
startPos = window.scrollY
requestAnimationFrame(function(timestamp){
scrollTo(timestamp, targetTop)
})
}
})();
I think that if you add a tabindex to your div, it will be able to get focus:
<div class="divFirst" tabindex="-1">
</div>
I don't think it's valid though, tabindex can be applied only to a, area, button, input, object, select, and textarea. But give it a try.
You can't focus on a div. You can only focus on an input element in that div. Also, you need to use element.focus() instead of display()
After looking around a lot, this is what finally worked for me:
Find/locate div in your dom which has scroll bar.
For me, it looked like this :
"div class="table_body table_body_div" scroll_top="0" scroll_left="0" style="width: 1263px; height: 499px;"
I located it with this xpath : //div[#class='table_body table_body_div']
Used JavaScript to execute scrolling like this :
(JavascriptExecutor) driver).executeScript("arguments[0].scrollLeft = arguments[1];",element,2000);
2000 is the no of pixels I wanted to scroll towards the right.
Use scrollTop instead of scrollLeft if you want to scroll your div down.
Note : I tried using scrollIntoView but it didn't work properly because my webpage had multiple divs. It will work if you have only one main window where focus lies.
This is the best solution I have come across if you don't want to use jQuery which I didn't want to.
In case you want to use html, you could just use this:
a href="samplewebsite.com/subdivision.html#id
and make it an html link to the specific element id. Its basically getElementById html version.
try this function
function navigate(divId) {
$j('html, body').animate({ scrollTop: $j("#"+divId).offset().top }, 1500);
}
Pass the div id as parameter it will work I am using it already

Detecting if a browser is in full screen mode

Is there any way of reliably detecting if a browser is running in full screen mode? I'm pretty sure there isn't any browser API I can query, but has anyone worked it out by inspecting and comparing certain height/width measurements exposed by the DOM? Even if it only works for certain browsers I'm interested in hearing about it.
Chrome 15, Firefox 10, and Safari 5.1 now provide APIs to programmatically trigger fullscreen mode. Fullscreen mode triggered this way provides events to detect fullscreen changes and CSS pseudo-classes for styling fullscreen elements.
See this hacks.mozilla.org blog post for details.
What about determining the distance between the viewport width and the resolution width and likewise for height. If it is a small amount of pixels (especially for height) it may be at fullscreen.
However, this will never be reliable.
Opera treats full screen as a different CSS media type. They call it Opera Show, and you can control it yourself easily:
#media projection {
/* these rules only apply in full screen mode */
}
Combined with Opera#USB, I've personally found it extremely handy.
You can check if document.fullscreenElement is not null to determine if fullscreen mode is on. You'll need to vendor prefix fullscreenElement accordingly. I would use something like this:
var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement ||
document.webkitFullscreenElement || document.msFullscreenElement;
https://msdn.microsoft.com/en-us/library/dn312066(v=vs.85).aspx has a good example for this which I quote below:
document.addEventListener("fullscreenChange", function () {
if (fullscreenElement != null) {
console.info("Went full screen");
} else {
console.info("Exited full screen");
}
});
The Document read-only property returns the Element that is currently being presented in full-screen mode in this document, or null if full-screen mode is not currently in use.
if(document.fullscreenElement){
console.log("Fullscreen");
}else{
console.log("Not Fullscreen");
};
Supports in all major browsers.
Firefox 3+ provides a non-standard property on the window object that reports whether the browser is in full screen mode or not: window.fullScreen.
Just thought I'd add my thruppence to save anyone banging their heads. The first answer is excellent if you have complete control over the process, that is you initiate the fullscreen process in code. Useless should anyone do it thissen by hitting F11.
The glimmer of hope on the horizon come in the form of this W3C recommendation http://www.w3.org/TR/view-mode/ which will enable detection of windowed, floating (without chrome), maximized, minimized and fullscreen via media queries (which of course means window.matchMedia and associated).
I've seen signs that it's in the implementation process with -webkit and -moz prefixes but it doesn't appear to be in production yet.
So no, no solutions but hopefully I'll save someone doing a lot of running around before hitting the same wall.
PS *:-moz-full-screen does doo-dah as well, but nice to know about.
While searching high & low I have found only half-solutions.
So it's better to post here a modern, working approach to this issue:
var isAtMaxWidth = (screen.availWidth - window.innerWidth) === 0;
var isAtMaxHeight = (screen.availHeight - window.outerHeight <= 1);
if (!isAtMaxWidth || !isAtMaxHeight) {
alert("Browser NOT maximized!");
}
Tested and working properly in Chrome, Firefox, Edge and Opera* (*with Sidebar unpinned) as of 10.11.2019.
Testing environment (only desktop):
CHROME - Ver. 78.0.3904.97 (64-bit)
FIREFOX - Ver. 70.0.1 (64-bit)
EDGE - Ver. 44.18362.449.0 (64-bit)
OPERA - Ver. 64.0.3417.92 (64-bit)
OS - WIN10 build 18362.449 (64-bit)
Resources:
https://developer.mozilla.org/en-US/docs/Web/API/Screen/availWidth
https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth
https://developer.mozilla.org/en-US/docs/Web/API/Screen/availHeight
https://developer.mozilla.org/en-US/docs/Web/API/Window/outerHeight
In Chrome at least:
onkeydown can be used to detect the F11 key being pressed to enter fullscreen.
onkeyup can be used to detect the F11 key being pressed to exit fullscreen.
Use that in conjunction with checking for keyCode == 122
The tricky part would be to tell the keydown/keyup not to execute its code if the other one just did.
Right. Totally late on this one...
As of 25th Nov, 2014 (Time of writing), it is possible for elements to request fullscreen access, and subsequently control entering/exiting fullscreen mode.
MDN Explanation here: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode
Straightforward explanation by David Walsh: http://davidwalsh.name/fullscreen
For Safari on iOS can use:
if (window.navigator.standalone) {
alert("Full Screen");
}
More:
https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html
This works for all new browsers :
if (!window.screenTop && !window.screenY) {
alert('Browser is in fullscreen');
}
There is my NOT cross-browser variant:
<!DOCTYPE html>
<html>
<head>
<title>Fullscreen</title>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
var fullscreen = $(window).height() + 1 >= screen.height;
$(window).on('resize', function() {
if (!fullscreen) {
setTimeout(function(heightStamp) {
if (!fullscreen && $(window).height() === heightStamp && heightStamp + 1 >= screen.height) {
fullscreen = true;
$('body').prepend( "<div>" + $( window ).height() + " | " + screen.height + " | fullscreen ON</div>" );
}
}, 500, $(window).height());
} else {
setTimeout(function(heightStamp) {
if (fullscreen && $(window).height() === heightStamp && heightStamp + 1 < screen.height) {
fullscreen = false;
$('body').prepend( "<div>" + $( window ).height() + " | " + screen.height + " | fullscreen OFF</div>" );
}
}, 500, $(window).height());
}
});
</script>
</body>
</html>
Tested on:
Kubuntu 13.10:
Firefox 27 (<!DOCTYPE html> is required, script correctly works with dual-monitors), Chrome 33, Rekonq - pass
Win 7:
Firefox 27, Chrome 33, Opera 12, Opera 20, IE 10 - pass
IE < 10 - fail
My solution is:
var fullscreenCount = 0;
var changeHandler = function() {
fullscreenCount ++;
if(fullscreenCount % 2 === 0)
{
console.log('fullscreen exit');
}
else
{
console.log('fullscreened');
}
}
document.addEventListener("fullscreenchange", changeHandler, false);
document.addEventListener("webkitfullscreenchange", changeHandler, false);
document.addEventListener("mozfullscreenchange", changeHandler, false);
document.addEventListener("MSFullscreenChanges", changeHandler, false);
This is the solution that I've come to...
I wrote it as an es6 module but the code should be pretty straightforward.
/**
* Created by sam on 9/9/16.
*/
import $ from "jquery"
function isFullScreenWebkit(){
return $("*:-webkit-full-screen").length > 0;
}
function isFullScreenMozilla(){
return $("*:-moz-full-screen").length > 0;
}
function isFullScreenMicrosoft(){
return $("*:-ms-fullscreen").length > 0;
}
function isFullScreen(){
// Fastist way
var result =
document.fullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement;
if(result) return true;
// A fallback
try{
return isFullScreenMicrosoft();
}catch(ex){}
try{
return isFullScreenMozilla();
}catch(ex){}
try{
return isFullScreenWebkit();
}catch(ex){}
console.log("This browser is not supported, sorry!");
return false;
}
window.isFullScreen = isFullScreen;
export default isFullScreen;
2021, the Fullscreen API is available. It's a Living Standard and is supported by all browsers (except the usual suspects - IE11 and iOS Safari).
// toggle fullscreen
if (!document.fullscreenElement) {
// enter fullscreen
if (docElm.requestFullscreen) {
console.log('entering fullscreen')
docElm.requestFullscreen()
}
} else {
// exit fullscreen
if (document.exitFullscreen) {
console.log('exiting fullscreen')
document.exitFullscreen()
}
}
User window.innerHeight and screen.availHeight. Also the widths.
window.onresize = function(event) {
if (window.outerWidth === screen.availWidth && window.outerHeight === screen.availHeight) {
console.log("This is your MOMENT of fullscreen: " + Date());
}
To detect whether browser is in fullscreen mode:
document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement
according to caniuse you should be fine for majority of browsers.
This property returns the Element that is currently in fullscreen mode.
document.fullscreenElement; // HTML Element or null
Also, you can subscribe to fullscreen change events with this method
addEventListener('fullscreenchange', (event) => { });
You can combine both to detect the nature of the change
addEventListener('fullscreenchange', () => {
if (document.fullscreenElement) {
// Your Logic if fullscreen
}
});
More on this here.
You can detect full screen using CSS like this:
#media all and (display-mode: fullscreen) {
// Regular CSS to be applied in full-screen mode
}

Categories