Is there any cross-browser javascript for making vh and vw units work
Update 5: .css(property) fix
Plugins like fancyBox use .css('margin-right')
to fetch the right margin of an element and .css('margin-right', '12px')
to set the right margin of an element. This was broken, because there was no check if props
is a string and if there are multiple arguments given. Fixed it by checking if props
is a string. If so and there is multiple arguments, arguments is rewritten into an object, otherwise parseProps( $.extend( {}, props ) )
is not used.
Update 4: Plugin for responsive layouts https://github.com/elclanrs/jquery.columns (in the works)
I gave this a (long) try. First here's the CSS example: http://jsbin.com/orajac/1/edit#css. (resize the output panel). Notice that the font-size
doesn't work with viewport units, at least on latest Chrome.
And here's my attempt at doing this with jQuery. The jQuery demo which works with the font as well is at http://jsbin.com/izosuy/1/edit#javascript. Haven't tested it extensively but it seems to work with most properties since it's just converting the values to pixel and then by calling the plugin on window.resize
it keeps updating.
Update: Updated code to work with many browsers. Test locally if you're using anything other than Chrome because jsBin acts a bit weird with window.resize
.
Update 2: Extend native css
method.
Update 3: Handle window.resize event inside of the plugin so the integration is now seamless.
The gist (to test locally): https://gist.github.com/4341016
/* * CSS viewport units with jQuery * http://www.w3.org/TR/css3-values/#viewport-relative-lengths */;(function( $, window ){
var $win = $(window) , _css = $.fn.css;
function viewportToPixel( val ) { var percent = val.match(/[\d.]+/)[0] / 100 , unit = val.match(/[vwh]+/)[0]; return (unit == 'vh' ? $win.height() : $win.width()) * percent +'px'; }
function parseProps( props ) { var p, prop; for ( p in props ) { prop = props[ p ]; if ( /[vwh]$/.test( prop ) ) { props[ p ] = viewportToPixel( prop ); } } return props; }
$.fn.css = function( props ) { var self = this , originalArguments = arguments , update = function() { if ( typeof props === 'string' || props instanceof String ) { if (originalArguments.length > 1) { var argumentsObject = {}; argumentsObject[originalArguments[0]] = originalArguments[1]; return _css.call(self, parseProps($.extend({}, argumentsObject))); } else { return _css.call( self, props ); } } else { return _css.call( self, parseProps( $.extend( {}, props ) ) ); } }; $win.resize( update ).resize(); return update(); };
}( jQuery, window ));
// Usage:$('div').css({ height: '50vh', width: '50vw', marginTop: '25vh', marginLeft: '25vw', fontSize: '10vw'});
How can I gracefully degrade CSS viewport units?
- Native usage
You'll at least want to provide a fallback:
h1 {
font-size: 36px; /* Some tweener fallback that doesn't look awful */
font-size: 5.4vw;
}
Also tells about mimicing the functionality with FitText.js.
For more information, read Chris Coyier's "Viewport Sized Typography" http://css-tricks.com/viewport-sized-typography/
min-height : 100vh not working in ie8
Silver Ringvee's answer is absolutely correct, except that default jQuery .css()
functionality is broken when you want to do stuff like .css('margin-right')
to get the right margin of an element. I found this issue when using fancyBox. I fixed that by checking if props is a string, if so parseProps($.extend({}, props))
is not used. I also added a check if multiple arguments were given, to support css('margin-right', '12px')
. Here's my code:
(function ($, window) {
var $win = $(window), _css = $.fn.css;
function viewportToPixel(val) {
var vwh_match = val.match(/[vwh]+/);
var digits_match = val.match(/\d+/);
if (vwh_match && vwh_match.length && digits_match && digits_match.length) {
return (vwh_match[0] == 'vh' ? $win.height() : $win.width()) * (digits_match[0] / 100) + 'px';
}
return val;
}
function parseProps(props) {
var p, prop;
for (p in props) {
prop = props[p];
if (/[vwh]$/.test(prop)) {
props[p] = viewportToPixel(prop);
}
}
return props;
}
$.fn.css = function (props) {
var self = this,
originalArguments = arguments,
update = function () {
if (typeof props === 'string' || props instanceof String) {
if (originalArguments.length > 1) {
var argumentsObject = {};
argumentsObject[originalArguments[0]] = originalArguments[1];
return _css.call(self, parseProps($.extend({}, argumentsObject)));
} else {
return _css.call(self, props);
}
} else {
return _css.call(self, parseProps($.extend({}, props)));
}
};
$win.resize(update);
return update();
};
}(jQuery, window));
CSS3 100vh not constant in mobile browser
Unfortunately this is intentional…
This is a well know issue (at least in safari mobile), which is intentional, as it prevents other problems. Benjamin Poulain replied to a webkit bug:
This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)
The base problem is this: the visible area changes dynamically as you scroll. If we update the CSS viewport height accordingly, we need to update the layout during the scroll. Not only that looks like shit, but doing that at 60 FPS is practically impossible in most pages (60 FPS is the baseline framerate on iOS).
It is hard to show you the “looks like shit” part, but imagine as you scroll, the contents moves and what you want on screen is continuously shifting.
Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.
From the data we had, using the larger view size was the best compromise. Most website using viewport units were looking great most of the time.
Nicolas Hoizey has researched this quite a bit: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html
No fix planned
At this point, there is not much you can do except refrain from using viewport height on mobile devices. Chrome changed to this as well in 2016:
- https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
- https://developers.google.com/web/updates/2016/12/url-bar-resizing
VH, VW units and Crazy IOS Mobile Browser Rendering
As you can read on caniuse.com
Partial support in iOS7 is due to buggy behavior of the "vh" unit.
known issues:
- Chrome does not support viewport units for border widths, column
gaps, transform values, box shadows or in calc() until version 34.- iOS Safari (both 6 and 7) does not support viewport units for border widths, column gaps, transform values, box shadows or in calc().
- iOS 7 Safari sets viewport unit values to 0 if the page has been left and is returned to after 60 seconds.
- Internet Explorer 9 in print-mode interprets vh as pages. 30vh = 30 pages
- iOS 7 Safari recalculates widths set in vh as vw, and heights set in vw as vh, when orientation changes.
More info about the buggy behavior
http://blog.rodneyrehm.de/archives/34-iOS7-Mobile-Safari-And-Viewport-Units.html
And a polyfill https://github.com/rodneyrehm/viewport-units-buggyfill
CSS: How to use vmin unit in IE9?
Generally, standard declarations should be placed after the non-standard/experimental features.
For instance, in this particular case it should be:
.image.medium {
width: 10vm; /* fallback for IE9 */
width: 10vmin;
height: 10vm; /* fallback for IE9 */
height: 10vmin;
}
The latter declaration is interpreted by modern web browsers supporting vmin
. And the former declaration acts as a fallback to the latter one.
Cross Browser Solutions
There are also polyfills for viewport relative lengths, for instance:
- vminpoly by Sebastian Ferreyra — A polyfill for CSS units
vw
,vh
&vmin
. - Prefixfree - Viewport Relative Units Plugin by Lea Verou — A polyfill for
vw
,vh
, andvmin
. - Viewport Units Buggyfill by Rodney Rehm — A polyfill for viewport
vh
,vw
vmin
,vmax
for Mobile Safari. - Is there any cross-browser javascript for making vh and vw units work
Get VW/VH position from onclick event in JS
You first need to get the Viewport Width (vw) by using window.innerWidth
and Viewport Height (vh) by using window.innerHeight
.
Then, divide the event.clientX
by vw
and multiply by 100
to get value in percentages. Same logic to get Y co-ordinates, i.e. divide the event.clientY
by vh
and multiply by 100
to get value in percentages.
See my demo below: (Click on Game to get the co-ordinates)
let gameEl = document.getElementById("game"),
eCXinVWEl = document.getElementById("eCXinVW"),
eCYinVHEl = document.getElementById("eCYinVH");
gameEl.addEventListener("click", function(event) {
let vw = window.innerWidth,
vh = window.innerHeight,
eCXinVW = event.clientX / vw * 100, // Multiplying by 100 to get percentage
eCYinVH = event.clientY / vh * 100; // Multiplying by 100 to get percentage
console.log(eCXinVW, eCYinVH);
eCXinVWEl.innerHTML = eCXinVW;
eCYinVHEl.innerHTML = eCYinVH;
});
.box {
padding: 50px;
}
#game {
padding: 20px;
background: red;
}
<html>
<head>
</head>
<body>
<div class="box">
<h6>Event co-ordinates X by viewport width: <span id="eCXinVW">0</span>%</h6>
<h6>Event co-ordinates Y by viewport height: <span id="eCYinVH">0</span>%</h6>
<div id="game">Game</div>
</div>
</body>
</html>
Related Topics
How to Access the Correct 'This' Inside a Callback
How to Access and Process Nested Objects, Arrays, or Json
How to Stretch Images With No Antialiasing
Is $(Document).Ready() Also CSS Ready
Show Loading Image While $.Ajax Is Performed
Detect Ipad/Iphone Webview Via JavaScript
Get a CSS Value from External Style Sheet With JavaScript/Jquery
How to Run Untrusted Code Serverside
Get Computed Font Size For Dom Element in Js
JavaScript File Per View in Rails
How to Include CSS and Jquery in My Wordpress Plugin
How to Decrypt Message With Cryptojs Aes. I Have a Working Ruby Example
Why Pass Parameters to CSS and JavaScript Link Files Like Src="../Cnt.Jsver=4.0"
How to Compare Arrays in JavaScript
What Does This Symbol Mean in JavaScript
Best Way to Detect That Html5 ≪Canvas≫ Is Not Supported